dsh-task-guard
DeepSeek Harness(DSH)插件:让 todo_write 计划跟着实际工作推进,解决“完成一个阶段后忘记把下一个阶段标成 in_progress,甚至后面完全不再更新 todo”的问题。
GitHub 仓库:MCviseron/dsh-task-guard · npm 包名:dsh-task-guard
English | 简体中文
目录
为什么需要它
DSH 的 todo_write 是整表替换。模型完成阶段 A 后,常见的错误写法是:
[
{ "content": "阶段 A", "status": "completed" },
{ "content": "阶段 B", "status": "pending" }
]
官方工具只校验“至多一个 in_progress”,不校验“还有工作就必须有一个 in_progress”。这种清单会被静默接受,之后 UI 上没有任何进行中的任务;再往后模型甚至不会再调用 todo_write。
dsh-task-guard 把这条隐含契约变成可折叠的插件 notice,并在模型长时间不更新计划时把它拉回来。
它做什么
插件不修改系统提示词,也没有常驻提示词段落,只在两个明确的结构性时机介入:
-
阶段边界提醒
当 todo_write 的完整清单里还有 pending、却没有任何 in_progress 时,在工具结果后追加一条 notice,提示把下一阶段标为 in_progress(或明确结束清单)。默认不会把这次写入变成错误。
-
停滞提醒
距离上次成功 todo_write 已过 staleAfterCalls 次工具调用、清单仍有未完成项时,在紧随其后的工具结果上追加一条 notice;之后可按 repeatEveryCalls 重复。同一 step 的并行调用最多只追加一条。
notice 走 DSH 官方的 additionalContexts + source.kind = 'plugin:task-guard' + form = 'notice' 通道(session format v4 的 producer-owned source kind),可以被 UI 折叠,也不占用常驻上下文。
它不做什么
- 不注册新工具,不替换
todo_write。
- 不自动改写模型提交的 todo 列表(无法从工具结果可靠判断阶段是否完成)。
- 不访问网络,不读取凭据,不写入用户目录。
- 不修改系统提示词,不注入 system message。
如果确实需要更硬的约束,可显式开启 rejectMissingActive: true 或 blockAfterCalls: N(见下文)。
安装
本地链接安装
dsh plugin --profile desktop add "link:<path-to-repo>"
dsh plugin 会把包写入 profile 的 dependencies 和 dsh.profile.bundles;包内 cordis.patch.yml 负责插入 id: task-guard。安装后重启 DSH(bundle 列表在启动时读取)。
如果手动编辑 profile:
-
package.json 的 dependencies 增加:
"dsh-task-guard": "link:<path-to-repo>"
Windows 例如:link:D:/Program/DSH-Plugin-Class/dsh-task-fix。
-
package.json 的 dsh.profile.bundles 增加 "dsh-task-guard"。
-
在 profile 目录执行 pnpm install,然后重启 DSH。
发布到 npm 后
dsh plugin --profile desktop add dsh-task-guard
当前 npm 包尚未发布;首次发布、账号暂停恢复与 Trusted Publisher 配置见 docs/release.md。发布后这条命令即可用。
配置
所有字段都可省略;非法值会在插件加载时直接报错,不会静默降级。
| 字段 | 默认值 | 说明 |
|---|
enabled | true | 总开关。 |
locale | zh | 模型可见文本的语言:zh / en。 |
staleAfterCalls | 5 | 成功调用多少次非 todo_write 工具后发第一条停滞 notice。 |
repeatEveryCalls | 4 | 之后每隔多少次再提醒;0 表示只提醒一次。 |
blockAfterCalls | 0 | 超过多少次仍未更新就硬拦截下一次工具调用;0 关闭。开启时必须大于 staleAfterCalls。 |
rejectMissingActive | false | 为 true 时,拒绝“还有 pending、但没有 in_progress”的 todo_write;默认只发 notice。 |
sourceKind | auto | notice source kind:auto 按 session.header.version 选 v3/v4;也可强制 v3 / v4。 |
include | [] | 只统计这些工具名(支持 * 通配);空表示全部。 |
exclude | todo_write, ask_user_question | 不统计的工具名。 |
maxListItems | 6 | notice 中最多列出多少个剩余任务。 |
示例:
- id: task-guard
name: dsh-task-guard
config:
enabled: true
locale: zh
staleAfterCalls: 5
repeatEveryCalls: 4
blockAfterCalls: 0
rejectMissingActive: false
sourceKind: auto
maxListItems: 6
推荐档位
- 保守(默认):阶段边界即时 notice + 每 4 次调用一次的停滞 notice,不拦截任何工具。
- 强约束:
blockAfterCalls: 12。模型连续 12 次成功调用都没有更新 todo 时,下一次工具调用会被拒绝,并收到“先调 todo_write”的明确错误;更新后自动恢复。
- 严格校验:
rejectMissingActive: true。任何“还有 pending、但没有 in_progress”的 todo_write 都会被拒绝;这可能打断模型原有的计划写入,所以默认关闭。
- 只想提醒一次:
repeatEveryCalls: 0。
模型看到什么
阶段边界 notice:
【todo 同步】清单里还有 2 个待办,但没有任何 in_progress 任务。如果还要继续,请把下一阶段标为 in_progress;如果本次工作已经结束,请清空清单或把任务全部标为 completed。
停滞 notice:
【todo 同步】距上次 todo_write 已过 6 次工具调用。
进行中:阶段 B
剩余:
[~] 阶段 B
[ ] 阶段 C
如果当前阶段还没完成,请忽略本提醒;一旦完成,请立刻调用 todo_write:把该阶段标为 completed,并把下一阶段标为 in_progress(有剩余任务时不要留空)。
严格模式下的工具错误:
todo_write 未执行:清单里还有 2 个待办,但没有任何 in_progress 任务。只要还有工作,就必须保持恰好一个任务为 in_progress。请重新提交完整清单:把已完成的阶段标为 completed,并把下一阶段标为 in_progress。
兼容性
| 项目 | 状态 |
|---|
DSH 0.2.0-rc.2 / session format v4 | ✅ 历史 live 验证 |
DSH 0.2.1-rc.2 / session format v4 | ✅ 当前桌面端;包类型审计 + live 冒烟(即时/停滞 notice 均正常) |
DSH 0.1.5-rc.2 / format v3 | ✅ sourceKind: auto 自动切换为 v3 source(单测) |
| Node.js | `^22.19.0 |
| 运行时依赖 | 无(只使用 Node 内置模块) |
sourceKind: auto(默认)读取 session.header.version:< 4 使用 v3 形状,>= 4 使用 v4 形状。也可以强制 v3 / v4。
v3:
{ kind: 'plugin', plugin: 'task-guard', form: 'notice', summary: '...' }
v4:
{ kind: 'plugin:task-guard', form: 'notice', summary: '...' }
在 v4 上使用旧写法会触发:
format v4 message requires a producer-owned source kind
完整的版本审计见 docs/compatibility.md。
验证
cd <path-to-repo>
pnpm check
typecheck + build 通过;
- 18 个测试全部通过(含真实 Cordis Context、hook waterfall、v3/v4 source kind、patch 配置一致性);
- live 测试:
- 只含
pending 的 todo_write 成功,并收到阶段边界 notice;
- 设为
in_progress 后连续 5 次工具调用,收到停滞 notice;
- 两轮均无
format v4 错误;
- 真实三阶段任务中,阶段边界提醒和停滞提醒都推动了下一阶段更新。
详细记录见 VERIFICATION.md。
开发
pnpm install
pnpm typecheck
pnpm build
pnpm test
pnpm check
项目结构:
src/index.ts 插件入口、hook、配置与 notice 构造
test/ node:test + 真实 Cordis Context 测试
cordis.patch.yml bundle 默认配置
build.mjs esbuild 构建 lib/index.js
.github/workflows/ CI
- 不引入运行时依赖;
lib/ 由 pnpm build / prepare 生成,不提交到仓库。
- 修改 hook 或 source kind 后,请同步更新
CHANGELOG.md 并在 VERIFICATION.md 记录验证方式。
已知边界
- 无法从工具结果判断“当前阶段是否真的完成”;
blockAfterCalls 是启发式兜底,默认关闭。
- 模型如果完全不调用
todo_write,插件只能提醒/拦截,不能替它编造完成状态。
- 提醒是模型可见上下文,会进入会话历史;阈值设得太低会增加 token 消耗。
- 计划在
turn/start 时清空是官方投影行为;跨 turn 的清单需要模型重新写入。
- 当前只面向 session format v4;v3 运行时需要单独兼容版本。
贡献与安全