XIMOYA/dsh-danger-reflection ↗★ 0
dsh-danger-reflection
Danger Reflection (危险反思): a DeepSeek Harness permission preset that replaces the human approval prompt for sandbox escalation with a same-model review that replays the whole conversation. 适合希望减少人工介入、通过模型自我反思来处理沙箱提权审批的用户。
설치
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:XIMOYA/dsh-danger-reflection配置
配置写在插件自身的 bundle patch(cordis.patch.yml)里。
| 字段 | 默认值 | 含义 |
|---|---|---|
presets | ["danger-reflection"] | 哪些权限等级(preset key,不是显示名)需要反思 |
onDeny | reject | 模型判定拒绝时:reject 直接拒绝(模型的反思就是最终结论);ask 转交给人类应答者再要一次意见 |
onFailure | ask | 审查没能作出判定时(模型报错、超时、输出不合协议):ask 把问题交还给人类;unavailable 以「审查无法作答」结束(fail-closed);allow 无判定直接放行 |
timeoutMs | 120000 | 单次审查调用超时 |
maxContextChars | 400000 | 重放上下文的上限;超出时保留最近的消息 |
maxOutputTokens | 8192 | 审查调用的 token 上限。给得宽是故意的:推理模型会先花这块预算做隐藏推理,DSH 的 DeepSeek 适配器默认 effort 是 high,上限给小了就会在说出判定之前被截断(2048 实测踩过) |
temperature | 0 | 审查采样温度(0 有意义) |
reviewPrompt | 内置 | 审查员的判断规则,可整个替换 |
announce | true | 是否把审查结果作为消息放进对话(见上) |
audit | true | 是否记录审计(JSON Lines) |
auditPath | "" | 显式指定审计文件绝对路径;留空则由宿主推导到 /danger-reflection/audit.jsonl |
verbose | false | 是否把每次「拒绝」也写进日志(「放行」始终以 warn 记录) |
审计记录
因为这是一个「不需要人类确认就放行」的功能,默认会留一条审计线索。位置由宿主的 profile 上下文推导(/danger-reflection/audit.jsonl),不依赖环境变量——组合插件的主进程不保证导出 DSH_HOME。文件里每行一个 JSON 对象:
{"kind":"loaded",...}:插件加载时写入一次,带sourceHash—— 即当前正在运行的lib/index.js的 SHA-256 前 16 位。用它可以把某次决定归因到确切的代码版本,而不是「当时插件目录里碰巧是什么」。{"kind":"review",...}:每次反思一行,含会话、工具名、调用 id、审批理由、原始命令参数、模型判定、理由、最终动作(allow/deny/ 失败策略)、announced与notice(对话里实际发出的通知全文)、provider/model、耗时。
审计写入是「尽力而为」的:写失败只会记一条警告,绝不会影响判定结果。
默认策略是 fail-closed:只有模型明确说出 allow 才会放行。任何含糊、超时、报错、协议不符,都会回到人类手上,绝不会静默放行。
失败 ≠ 拒绝
这条是刻意做进设计里的,不是措辞问题。
DSH 的审批结果词汇是封闭的四个值:allowed-once / rejected / cancelled / unavailable——没有「失败」这一格。所以审查没作出判定时,必须在这四个里挑一个,而 rejected 是错的那个:调用方(dsh-sandbox)会把它渲染成
the user rejected escalating this command to "danger-full-access"
也就是说,它会把一个没人做过的判断说成事实——既替模型认了罪,也替你认了罪。正确的落点是 unavailable,调用方渲染为「审批通道无法作答」,这才是实际发生的事。
因此 onFailure 不接受 reject(写了会在加载时明确报错并告诉你该用哪个),而且插件里所有地方都做了区分:
- 通知的标题只讲模型判了什么,
✅ 模型判定:放行/🛑 模型判定:拒绝/⚠️ 未得出结论,不看最终动作; - 通知的结尾只讲实际发生了什么,
未获放行/已转交人工确认/未获放行:审查没有作出判定;失败路径不会出现「被拒绝」字样; - 审计记录里
verdict与decided分开记,decided: false明确表示「没有判定」,action用unavailable而不是reject。
顺带一提,allow 只被描述成它实际做的事(无判定也放行),不会被包装成一条判定——失败在两个方向上都不能冒充结论。
使用
- 在输入框下方的权限等级选择器里选 危险反思(也可以用
/permission danger-reflection)。 - 之后当某条命令需要更宽权限时,模型会先自我反思,而不是弹窗问你。
- 想留档就打开审计记录(默认已开,见上)。
权限等级是按会话生效的。切换只影响当前会话。
改了插件代码之后需要重启 DSH(首次安装后也需要一次),然后刷新页面。 原因有两层:
- 宿主侧模块代码:DSH 的 HMR 默认
root: [],模块监视是 opt-in 且必须在启动前配置好,所以lib/index.js的改动不会热加载。- 浏览器侧半边:宿主把包元数据按 Loader specifier 缓存至重启,新出现的
dsh.client声明要重启后才会被扫描并提供;而客户端插件在没有pnpm run dev:web的情况下也不会热更新。安装/启用插件、以及
cordis.patch.yml里的配置改动都是即时生效的,只有代码不是。本插件已经替你把第 1 层配好了:profile 的
cordis.patch.yml末尾加了一段带# BEGIN/END DANGER REFLECTION (managed)注释的hmr行,把插件源码目录加入root。重启一次之后,改lib/index.js就会实时生效。想恢复默认就删掉那一段(原始文件已备份为cordis.patch.yml.bak-danger-reflection)。第 2 层没有等价开关,改lib/client.js仍需重启 + 刷新。