@crazx/dsh-todo-completion-guard
v0.1.6-alpha.2.zw.2
Published
Turn-end todo guard plugin: one advisory steer when a turn closes on an unfinished todo list
Readme
@deepseek-ai/dsh-todo-completion-guard
English | 中文
一个仅提供建议的回合结束守卫,而非面向模型的工具:它不会出现在工具列表中,不会否决任何回合,只增加一种行为——当一个本可完成的回合即将结束、而其当前有效 todo 清单仍有未完成项时,它会向同一回合注入一条 plugin-notice,要求模型完成并勾掉这些项、围绕明确放弃重写清单,或显式说明清单为何保持开放。是否遵从完全由模型决定;守卫每回合只提醒一次,绝不循环。决策记录见 todo-completion-guard Agent Note。
触发时机
守卫监听 agent/turn-stopping——loop 在关闭一个本可完成的回合前广播的边界(与 Claude Code Stop hook 同一条缝)。被注入的消息会让 loop 观察到待处理输入,并在同一回合里再跑一个 step。
在这个边界上,它检查当前回合的事件:
- 当前有效清单——当前回合自己的
turn/start之后的最近一次todo/write,与 todo 投影的清空规则一致。更早回合写的清单已被该规则清空,绝不追讨;没写过清单的回合对守卫不可见。 - 未完成 = 非
completed——pending和in_progress都算。被遗忘的pending项正是这个守卫要清理的残羹。 - 豁免:撞墙回合。 若回合中任何 step 以
max-tokens收尾(粘性回合结局),守卫保持沉默——强制续 step 大概率再次撞上同一输出上限,白白烧掉请求。 - 每 agent 每回合一次。 被提醒后仍以开放清单收尾的回合允许结束:提醒列出了全部出口(完成、附一行理由重写、或显式声明延后),选择保留清单的模型已经听过一次。这是守卫自带的循环上限;loop 本身没有。
提醒内容
一条 notice 形态的上下文消息,source 为 {kind: 'plugin', plugin: 'todo-completion-guard'},注入回合并作为落日志的 user/message 追加——模型可见、来源可归属、可从会话日志重建,无需新的会话事件。它列出每个未完成项及其状态,然后给出三个出口。决定——完成、重写、还是保留并显式声明——留给模型:合法延后的清单(工作延续到下一回合、等待用户)既不被延迟也不被阻塞。
组合
- id: todo-completion-guard
name: '@deepseek-ai/dsh-todo-completion-guard'无配置:这个守卫可能暴露的每个旋钮(提醒文案、每回合上限、豁免规则)都是 advisory 契约的正确性属性,而非部署选择。它是 todo/write 事件词汇的消费者;组合中未挂载 tool-todo 时它天然无害(任何回合都不会写该事件)。
已知限制与延后工作
- 仅建议——确认收到提醒却仍保留开放清单的模型,在提醒一次后即可结束回合;升级为强制延续已被拒绝(那是 loop 层的
TODO(stop-loop-guard)策略,不属于本守卫)。 - 内存态限流——每回合一次的状态是挂在活跃 agent 上的
WeakMap;从持久化恢复的会话获得全新预算,这只影响横跨进程重启的回合。 - 子代理清单设计上不可见——守卫读每个 agent 自己的会话日志;子代理的未完成清单绝不会驱动父代理(父代理自己的清单按它所见反映委派工作)。
