Letter2025/dsh-approval-llm ↗★ 1
dsh-approval-llm
基于模型的权限审批(approve-for-me)用于 DeepSeek Harness:一个由独立审查模型支持的审批/请求应答器
安装
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:Letter2025/dsh-approval-llm说明文档
阅读完整 README ↗dsh-approval-llm
面向 DeepSeek Harness 的模型审批插件(approve-for-me)。
English | 中文
一个社区插件:为 DeepSeek Harness 增加一个**"帮我批准"权限模式**。在该模式下,approval/request 的审批请求由独立的评审模型代替人工判定——评审模型给出 ALLOW / DENY / ESCALATE,只有拿不准或模型故障时才转人工。在其他任何权限模式下插件保持沉默,模型审批永远不会抢在人工审批前面。
它对应 Codex 的 approvals_reviewer=auto_review(--approve-for-me),并遵循 AGENTSCOPE-PLAN-058 / 062 / 063 的评审设计(正交的 reviewer 维度、三值决策、路由策略、Prompt 隔离、fail-to-human、熔断)。
警告:AI 评审是一种策略选择,不是安全保证。它可能被工具输出或 agent 自身理由中的提示注入欺骗。建议用于低风险工作流;务必收紧
humanOnlyList、denyList和熔断参数。
设计对照
| 本插件概念 | Codex | AGENTSCOPE-PLAN-058 |
|---|---|---|
| 专门的权限模式激活评审模型 | approvals_reviewer: auto_review + --approve-for-me | UI 档位 帮我批准 = DEFAULT + ApprovalReviewer=MODEL |
| 该模式之外全部委托 | 人工审批不变 | 请求批准 = DEFAULT + HUMAN |
应答 approval/request 瀑布 | approvals_reviewer: auto_review | ApprovalReviewer = MODEL(与权限模式正交) |
| 模型调用前的确定性路由 | "确定性沙箱/网络 allowlist 在 guardian 评审之前执行" | SAFE_ALLOW / DENY / HUMAN_ONLY 路由策略 |
评审模型判定 ALLOW / DENY / ESCALATE | Guardian 子代理(Approved / Denied / TimedOut / Abort) | ALLOW / DENY / ESCALATE |
| 评审模型持有隔离的安全策略 | Guardian prompt 与主 agent 隔离 | §4.5 Prompt 隔离 |
| 评审时动态注入工具描述 | — | §4.5 工具描述动态注入 |
| 从会话日志取回工具参数 | 信任分层(评审参数而非只看工具名) | §4.4 参数级风险 |
| 模型故障 → 转人工,不计熔断 | fail-closed guardian | §4.8 fail-to-human 与策略拒绝分离 |
| 连续 DENY 达阈值 → 转人工 | 熔断(连续 3 次) | §4.14 熔断 |
显式 provider/model,否则回退会话路由 | — | PLAN-062 每 agent 配置 + 回退 |
| 决策以用户可见消息写入会话 | UI 上的 guardian 徽标 | DENY 事件推送到前端(§4.17.5) |
工作方式
approval/request(瀑布)
│
├─ enabled=false? ────────────────────────────► next()(原样委托)
│
├─ 模式门:会话 preset ≠ modePreset ───────────► next()(人工审批不变)
│ (默认 modePreset = model-approval)
│
├─ RoutingPolicy(确定性,无模型调用)
│ ├─ 命中 denyList ─────────────────────────► 'rejected'
│ ├─ 命中 allowlist ────────────────────────► 'allowed-once'
│ ├─ 命中 humanOnlyList ────────────────────► next()(人工决定)
│ └─ 其余:REVIEW
│
├─ 熔断:连续 DENY ≥ max ──────────────────────► next()(人工接管)
│
├─ 评审模型(隔离的安全策略 prompt)
│ 输入:工具名 + 描述(ctx.tools)
│ + reason + 工具参数(来自会话日志 tool/call)
│ 判定:ALLOW ──────────────────────────────► 'allowed-once'(计数归零)
│ DENY ──────────────────────────────► 'rejected'(计数 +1)
│ ESCALATE ──────────────────────────► next()
│ 超时 / 解析失败 / 模型故障 ─────────► next()(fail-to-human)
│
└─ ALLOW / DENY 还会往会话追加一条用户可见的决策消息,
主链路因此记录"为什么通过/拒绝"。
- ALLOW / DENY / ESCALATE 与 dsh 结果词汇一一对应(
allowed-once/rejected/ 委托)。ESCALATE 和模型故障永远不会伪造拒绝——它们把请求交给下一个 answerer(人工 UI);没有人工 answerer 的部署按 fail-closed 解析为unavailable,调用方视为拒绝,与 Codex 的 fail-closed guardian 一致。 - 模式门保证各模式互斥。在
帮我批准预设下评审模型应答;在请求批准(及其他预设)下插件全部委托,人工审批行为与装插件前完全一致。两个预设共享 sandbox/approval 旋钮,靠记录的permission/preset选择区分。 - 一个部署一个 terminal answerer。dsh 审批链不是多个裁判的优先级列表——只组合一个 answerer。要保留人工兜底,就把人工 UI answerer 放在本插件之后(瀑布的
next()会到达它)。 - 参数从会话日志读取,而非审批请求本身(审批请求刻意不带参数,避免渲染出第二份可能漂移的副本)。
配置
所有字段都由 Loader schema 校验,省略时取默认值。
| 字段 | 默认值 | 含义 |
|---|---|---|
enabled | true | 总开关;false 时所有请求原样委托。 |
modePreset | model-approval | 激活评审模型的权限预设名。设置后,只有当会话的有效预设等于该值时插件才应答;其他会话全部委托给人工通道。设为 '' 则审查所有请求。 |
provider / model | 未设置 | 显式评审路由。必须成对出现;未设置时复用会话日志中最后一次 request/header 的对话路由,日志中没有则 fail-to-human。 |
timeoutMs | 60000 | 评审请求端到端超时;超时后转人工(TIMEOUT,不计熔断)。 |
maxOutputTokens | 256 | 评审输出上限。 |
systemPrompt | 内置策略 | 评审模型的自定义安全策略。内置策略是"默认放行、关键危害才拒绝"的短规则集,见 src/reviewer.ts。 |
allowlist | [] | 免模型调用直接放行的工具名(SAFE_ALLOW)。 |
denyList | [] | 免模型调用直接拒绝的工具名。优先于 allowlist。 |
humanOnlyList | [] | 必须人工决定的工具名;绝不自动评审。 |
maxConsecutiveDenials | 3 | 每会话连续 DENY 阈值,达到后评审模型转人工;0 关闭熔断。ALLOW 会重置计数。 |
maxArgsChars | 4000 | 渲染给评审模型的工具参数 JSON 上限。 |
includeArgs | true | 是否从会话日志取回工具参数参与评审。 |
notifyUser | true | 每次模型 ALLOW/DENY 后往会话追加一条用户可见的决策消息(✅ 模型审批通过 / ❌ 模型审批拒绝,含风险与理由),主链路可复查。 |
示例覆盖层(profile 的 cordis.patch.yml):
- id: approval-llm
config:
provider: deepseek-official
model: deepseek-v4-flash
allowlist: [read, read_image, glob, grep]
humanOnlyList: [delete, terminal_send]
denyList: [job_kill]
maxConsecutiveDenials: 3
安装
复制给 AI 的一句话——把这一句话交给任意 AI 编程 agent,让它帮你完成安装:"请阅读 https://github.com/Letter2025/dsh-approval-llm/blob/main/README.md 并遵循其『## 安装』章节,把
dsh-approval-llmbundle 安装进 DeepSeek Harness 的 web profile,然后重启dsh web服务,并确认权限选择器里出现带盾牌+星芒图标的model-approval(帮我批准)预设。"
作为可安装 bundle(推荐)
本包在 package.json 中声明了 dsh.bundle.patch,安装后会激活一个配置层:既插入插件行,也往 permission 权限表添加 model-approval("帮我批准")预设——无需再手动配置预设:
dsh plugin --profile web add dsh-approval-llm # 从 npm 安装已发布的包
重启 dsh web,然后在权限选择器(输入栏的 Access chip,带盾牌+星芒图标)里选 帮我批准,即可把该会话的审批人切换为模型。预设表是进程级的,修改预设需要重启 dsh。
In-box bundle 的行名从 dsh 安装本身解析;@deepseek-ai/* 导入是 peerDependencies,由宿主 dsh 提供,所以请锁定 dsh 版本(项目处于开发者预览,有破坏性变更)。想从本地检出安装:先 pnpm run build,再在父目录执行 dsh plugin --profile web add ./dsh-approval-llm。
源码覆盖层(开发用)
- insert:
- id: approval-llm
name: './src/index.ts' # 本包入口的路径,或绝对路径
config:
provider: deepseek-official
model: deepseek-v4-flash
用 dsh web --patch ./cordis.patch.yml 运行,或把该行并入 profile 的 cordis.patch.yml。源码覆盖层只插入插件行,不含预设——要么同时安装上面的 bundle 层,要么自己往 permission 行里加 model-approval 预设(patch 会替换整行 config,所以要写全所有预设):
- id: permission
config:
presets:
read-only:
sandbox: read-only
approval: ask
name: 只读
workspace-write:
sandbox: workspace-write
approval: ask
name: 请求批准
model-approval:
sandbox: workspace-write
approval: ask
name: 帮我批准
description: 审批由独立的评审模型决定;拿不准或模型故障时转人工。
danger-full-access:
sandbox: danger-full-access
approval: never
name: 完全放开
构建与测试
插件位于 DeepSeek Harness 检出内部的 custom_plugin/dsh-approval-llm;@deepseek-ai/* 解析到该检出自己的 node_modules(构建产物 lib 声明 + @types),因此请在仓库根目录保持 harness 已构建(pnpm run build)。指向 harness node_modules 的 junction 由检出提供。
pnpm run typecheck # tsc --noEmit(严格模式)
pnpm run test # vitest:39 个单元测试,无网络
pnpm run build # tsc 产出 lib/(ESM,相对导入重写)
路线图
- 客户端徽标与开关:给本包加浏览器半(
dsh.client),可以在工具卡片上渲染评审模型的决策徽标(盾牌图标),并提供写回enabled/modePreset的设置行(写入热重载的设置命名空间)。宿主 loader 已经从同一行发现dsh.client包,安装路径不变。 - 批量评审(PLAN-063):一次评审多个待审批工具,需要 approval 服务先支持批量入口。
- 通配符 / 参数模式路由:确定性策略支持按工具名/参数模式匹配。
安全模型
- 模式门保证人工审批不变:在配置的预设之外插件全部委托,
请求批准的行为与装插件前完全一致。 - Prompt 隔离:评审 prompt 由本插件依据自身配置组装,主 agent 永远看不到安全策略,无法针对评审定制请求。工具描述取自实时注册表(
ctx.tools.schemas()),参数取自持久化日志——评审模型评判的是真实调用,而不是 agent 的自述。 - fail-to-human:
TIMEOUT、PARSE_ERROR和 provider 错误产生 ESCALATE(委托),绝不伪造拒绝,且不计入熔断(PLAN-058 §4.8 模型故障与策略拒绝分离)。 - 组合即 fail-closed:没有人工 answerer 的部署解析为
unavailable,调用方按拒绝处理。 - 熔断:单会话连续 DENY 达到
maxConsecutiveDenials后,该会话后续请求转人工——评审模型持续拒绝时就不再当裁判。 - 敏感数据:评审输入(工具参数、reason)仅用于评审请求和结构化日志,除常规会话日志与控制台输出外不额外落盘。参数敏感时可关闭
includeArgs。
已知限制
- 没有专门的机器可读审计事件。模型决策以
user/message通知的形式出现在主链路(可持久化、可重放),内置的approval/asked+approval/decided审计对记录请求与结果。专门的机器可读审计事件(如携带完整评审上下文的session/approval-llm-request)仍受 harness 对仓库外事件类型的持久化策略限制;等 harness 开放注册通道后应补充。 - 暂无客户端徽标。决策通知以对话消息呈现;Codex 式锚定在工具卡片上的盾牌图标需要客户端插件(本包暂未提供浏览器半)。见路线图。
- 一次请求一次模型调用。PLAN-063 的批量评审需要 approval 服务先支持批量入口;单请求延迟受
timeoutMs和评审模型选择约束。 - AI 评审的信任是部署决策。评审模型可能被工具输出提示注入。请配置好
humanOnlyList、denyList和熔断;不要在高风险无人值守工作流中启用。 - 仅精确名称路由。列表匹配完整工具名,不支持通配符或参数模式匹配。
许可证
MIT