dsh-hitl:在 DSH Web UI 里为任意工具调用加上人工审批门

前言

在 DeepSeek Harness(DSH)里跑智能体时,工具调用往往会在你未看清参数前就执行:改文件、跑 shell、调 MCP 等,一旦误触很难撤回。常见做法是自己在插件里写一层确认逻辑,或只在少数危险工具上手工拦截,维护成本高,且不同插件之间行为不一致。

下面介绍社区插件 dsh-hitl(维护者 YunpengDon,分类:工作流):它把「执行前先让人看、再批准 / 修改 / 拒绝」做成可挂载的门,目标工具不必改业务代码,也可由其他插件通过 API 一行挂载。

这是什么

dsh-hitl 是 DSH 的可安装 bundle 插件:在工具真正执行前,在 DSH Web UI 展示决策卡片(标题、待执行提案、批准 / 修改 / 拒绝按钮)。简介原文为:Human-in-the-loop gate for DSH tool calls: mount any tool behind an approve / modify / reject decision card in the DSH Web UI.

实现上为零依赖、零构建的纯 JS(index.js 宿主侧 + client.js 浏览器侧 + lib/),安装后刷新页面即可注入 window.__DSH_HITL__。npm 包版本为 0.2.1,许可证 MIT,Node 引擎要求 ^22.19.0 || >=24.0.0。

核心功能

挂载方式

  • 配置一行:在 cordis.patch.yml 的 hitl 插件 config.protect 里列出要保护的工具名(支持 mcp__* 等模式)。
  • API 一行:其他插件 inject: ['hitl'] 后调用 ctx.hitl.protect(...),建议传入调用方 ctx 作为 owner,以便插件卸载时自动解除挂载。

决策卡片与提案展示

执行前展示标题与待执行内容;提案字段可配置为:并排 diff(只读)、纯文本输入、可编辑 / 可渲染的 Markdown;文本与 Markdown 可只读或可编辑。未配置 fields 时,默认展示该次调用的全部参数(键名或 schema 的 title,值以 Markdown 输入形式展示,非字符串为格式化 JSON)。

修改与拒绝

编辑提案文本后,主按钮由【Approve】变为【Modify】,修改内容作为修订意见回传给智能体。【Reject】可带反馈框,拒绝原因一并返回。

倒计时

可配置倒计时及三种结束行为:自动批准、自动拒绝、将超时报告给智能体。

与 DSH 运行模型的配合

  • 进程内子智能体透传:spawn / fork 子 Session 内的工具调用同样过门;请求会挂在子 Session 与当前查看的 Session 下,卡片可标注「from subagent Session xxx」并提供【Open that Session】。文档说明进程外后端不会经过此门。
  • 不在对话页时的提醒:在插件页、设置页或未选中 Session 时,页面顶部浮动通知(数量、工具名、来源 Session、剩余时间 + 批准 / 拒绝 / 打开 Session),避免必须停在原对话才能处理。

服务 API(诊断与生命周期):protect(matcher, options?, owner?)、unprotect(matcher)、list()、pending()。同一工具多次挂载时,以最近一次为准(配置行先注册,插件可覆盖配置)。

安装与启用

官方安装方式如下(<your profile> 换成你的 profile 名):

# 从 npm(推荐)
dsh plugin --profile <your profile> add dsh-hitl

# 从 GitHub(无需构建)
dsh plugin --profile <your profile> add github:YunpengDon/dsh-hitl

# 本地目录(开发时改代码后需重启 dsh)
dsh plugin --profile <your profile> add /path/to/dsh-hitl

也可在 GUI:Settings → Plugins → install bundle。

安装后:

  1. 刷新浏览器页面一次(首次安装必须;已打开页无法拿到注入 token,仅靠热重载不够)。
  2. 在 cordis.patch.yml 配置 protect 列表,或让其他插件调用 ctx.hitl.protect(...)。

卸载:

dsh plugin --profile <profile> remove dsh-hitl

典型用法

方式一:仅改配置,不动目标工具代码

在 cordis.patch.yml 中为 hitl 插件增加或覆盖一行(注意:patch 覆盖整行 config 时需写全仍要保留的键):

- id: hitl
  name: 'dsh-hitl'
  config:
    protect:
      - tool: bash
        title: Confirm before running
        countdown: { seconds: 30, action: reject }
        reject: { feedback: true }

方式二:在自有插件代码里挂载

export const name = 'my-plugin'
export const inject = ['hitl']

export function apply(ctx) {
  ctx.hitl.protect('bash', {
    title: 'Run this command?',
    countdown: { seconds: 30, action: 'reject' },
    reject: { feedback: true },
  }, ctx)

  ctx.hitl.protect(['write', 'edit'], {
    title: 'Confirm before editing',
    diff: { path: 'file_path', before: 'old_string', after: 'new_string' },
    countdown: null,
  }, ctx)
}

matcher 支持工具名、含 * 的 glob、RegExp、数组或 (exec) => boolean。若挂载未随插件卸载而消失,可用 ctx.hitl.list() 排查,并用 ctx.hitl.unprotect('bash') 或在插件页开关 hitl 行重建状态。

适用场景与注意

适合:需要在 DSH Web UI 统一给 bash、写文件、MCP 工具等加人工门的工作流;多插件生态里由各自 protect 绑定生命周期,避免散落手写确认框。

注意:

  • 插件与当前 dsh 进程同权限 运行,安装前请自行查看 GitHub 仓库 源码与 MIT 许可证。
  • 社区目录 SkillHub 插件页 为独立生态站点,与 DeepSeek / 幻方无官方从属关系;DSH 本身遵循「一切皆插件」,本插件是其中一类工作流扩展。
  • 更多交互示例见项目 Landing 站点。

结尾

dsh-hitl 把「工具执行前的人工决策」收敛成可配置、可 API 挂载的一层,减少每个工具各自实现确认 UI 的重复劳动。需要试用或查文档时,可访问目录页与仓库:

  • 目录页:https://www.skillhub.cn/plugins/YunpengDon/dsh-hitl
  • GitHub:https://github.com/YunpengDon/dsh-hitl
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜