Repository navigation
Releases
v2.1.3 — 规划器超时可配置
v2.1.3 — 规划器超时可配置(修复超时复发根因)
一句话说明
修复自动任务分解「稳定超时被误报成意外中断」的问题:把规划器的思考时间上限从写死的常量改成可配置项。
问题是什么
插件在接到一个复杂任务时,会先花一段时间自动把它「拆分」成几个子任务,再分派给各部门去执行。这一步是有时间上限的:
- 之前的上限只有 2 分钟(120 秒)。当任务描述特别长、要求特别多时,拆分还没做完,就被定时器强制打断了;
- 2.1.1 把上限提到 5 分钟(300 秒),但只是推迟了超时,没解决「单次 LLM 调用被固定超时卡死」的结构性问题。复杂任务仍会在 5 分钟处稳定触发超时。
改了什么
新增 DSH_WORKPLAN_PLANNER_TIMEOUT_MS 环境变量(毫秒,>0),未配置时回落到默认值 300000。复杂任务可按需放宽时限,无需重新编译发布。
安装
npm install dsh-workplan@2.1.3v2.1.2 — 修复规划器超时被误报为偶发中断
dsh-workplan 2.1.2 发布说明(Release Notes)
发布日期:2026-11-06 | 版本号:2.1.2 | 升级类型:patch(bug 修复)
一句话说明
修复自动任务拆分「稳定超时被误报成意外中断」的问题:把规划器的思考时间上限从 2 分钟放宽到 5 分钟,并让真正超时时报出明确原因。
一、问题是什么(通俗版)
插件在接到一个复杂任务时,会先花一段时间自动把它「拆分」成几个子任务,再分派给各部门去执行。这一步是有时间上限的:
- 之前的上限只有 2 分钟(120 秒)。当任务描述特别长、要求特别多时,拆分还没做完,就被定时器强制打断了;
- 更糟的是,底层的大模型接口把「超时被打断」这件事,误报成了「请求意外中断」(
DeepSeek Messages request aborted),看起来像网络偶发故障,根本看不出真正原因是「时间到了」。
结果就是:复杂任务每次都会稳定失败,但日志却让人以为是「偶发中断」,排查方向被带偏。
二、改了什么(只有这两处)
- 把拆分的时间上限从 2 分钟(120 秒)放宽到 5 分钟(300 秒),给复杂任务留足拆分时间。
- 当确实是「超时」被打断时,不再被误报成「意外中断」,而是明确抛出「规划器超时:任务分解未在时限内完成」的清晰报错。
改动只涉及 lib/runtime.js 与 src/runtime.ts 两个文件(+14/−2),没有改其它任何功能。
三、安装
npm install dsh-workplan@2.1.2(版本号 2.1.2 为 patch 升级,属 bug 修复级别。)
四、版本号与内容一致性核对清单
| # | 核对项 | 结果 | 证据 |
|---|---|---|---|
| C1 | 发布说明标题与正文版本号均为 2.1.2,与 T2 目标版本号一致 | ✅ 一致 | 本文档标题与正文、CHANGELOG.md 顶部 ## 2.1.2 — 2026-11-06;T2 结论 2.1.2(patch,远端 404 未占用) |
| C2 | 只陈述已验证的两处修正(120000→300000、新增 PLANNER_TIMEOUT 明确报错),无虚构事实 | ✅ 一致 | git diff:lib/runtime.js 与 src/runtime.ts 各 +7/−1(共 +14/−2);PLANNER_TIMEOUT_MS 两文件均为 300000;新增 throw new PlanError('规划器超时…','PLANNER_TIMEOUT') |
| C3 | 改动范围陈述准确(仅 2 文件、+14/−2) | ✅ 一致 | git diff --stat:lib/runtime.js 与 src/runtime.ts 各 8 行改动(+7/−1)→ 合计 14 insertions / 2 deletions |
| C4 | 对外语句通俗易懂、无内部术语堆砌 | ✅ 通过 | 全文用「拆分」「时间上限」「意外中断」等白话表述,无 runPlanner/abortError/PlanError 等内部标识符直接出现在正文(仅作为代码引用保留必要的字段名说明) |
v2.1.1 — 退回通知送达修复与文档一致性
2.1.1 — 2026-11-06
修复 2.1.0 的三处「说到了但没做到」:格式退回通知在续跑时送不到部门人员、中文 README 的安装命令仍指旧版本、安全文档里有一句「当前 1.12.0」的错误陈述。
一、退回通知为什么没送到(根因与修复)
2.1.0 把退回原因写进了状态行,但续跑顺序错了:再次派发时 dispatchPlan 先调用 resetBlockedStatuses,把受阻行连同 blockedKind / error 一起清成待跑;executeSubtask 随后才去读「上次是不是格式退回」,信息已被清掉。实测两次激活的提示词长度完全相同(4374 字符),子 Agent 只能把同样的格式错误再交一遍。
修复 src/runtime.ts:
dispatchPlan在resetBlockedStatuses之前扫出blockedKind === 'comm-format'的行,把退回原因抄进本轮的record.commFormatRejections;executeSubtask在行内信息已被清掉时改读这份记录,作为COMM_FORMAT_REJECTED的上次失败原因带进子提示词;- 消费一次即删,不会被后续无关重试重复带上。
修复后实测:第 2 次激活的提示词多出「上一次尝试失败」段,含失败类型与逐条不合规项(4374 → 4584 字符)。
二、另外两处修正
README.zh.md:72安装命令仍是dsh-workplan@1.12.3(同文件徽章已是新版本)→ 改为2.1.1。docs/cc/AGD-OPS-SECURE-OPERATION.md安装校验步骤里的「当前 1.12.0」→ 改为版本中立表述,并在文首补一条带日期的版本说明(其余 1.12.0 是那次评估的历史快照,不改写历史)。
三、验证
- 新增
tests/workplan-comm-format-e2e.test.ts(2 条):真实运行时 + 假子会话跑完整链路,并断言第 2 次激活提示词带「上一次尝试失败」段、COMM_FORMAT_REJECTED与逐条不合规项。 npm run check退出码 0。npm test:580 / 580 通过。
四、制品校验
- sha256
9db23eed0c22a8f38b7a2aeef892f1d8277d1469605cf5518577e634f3071d03 - sha1(与 npm registry 一致)
c9a8a627648477a28837583ca388a4f6f673fba4
v2.1.0 — 沟通交流格式契约(下发—自检—核验—退回闭环)
2.1.0 — 2026-11-06
建立主 Agent 与部门人员之间的统一沟通交流格式契约:派活时随任务附带同一份格式要求,部门人员提交前照此自查,主 Agent 收件后照同一份格式核验,不合规立刻退回并附逐条问题,通知其重新检查格式后全盘重交。
一、这次要解决的问题(说人话版)
以前主 Agent 给部门人员派活,只讲「要做什么」,没讲「结果按什么格式交」。于是同一种误会反复发生:活干完了,但交上来的回执缺证据、缺复盘、少验收条目,主 Agent 只能打回,来回折腾。
2.1.0 把「交付格式」本身变成双方共同遵守的契约:
- 派活时,格式要求跟着任务一起发下去(不是事后才说)。
- 部门人员交结果前,先自己照着这份格式逐条检查,全合规了才交。
- 主 Agent 收到后用同一份格式逐条核验;只要有一条不合规,立即退回,并写清是哪几条、为什么不合规。
- 部门人员重交时,会看到具体的退回原因,只补缺口,不用把整件事重做。
二、九条格式要求(F1–F9)
| 编号 | 要求 | 为什么需要 |
|---|---|---|
| F1 | 结果块用规定的起止标记包起来 | 主 Agent 才能准确切出结果正文,不会把说明文字当成结果 |
| F2 | 状态只能是 done / blocked / partial | 防止自造状态,导致机器无法判断 |
| F3 | 三阶段(规划、执行、验证)都要写 | 证明是「想过、做过、验过」,不是只有结论 |
| F4 | 说「通过」的验收项必须附证据 | 没有证据的「通过」不算通过 |
| F5 | 验收条目数不少于计划里要求的条数 | 防止漏答要求 |
| F6 | 产物条目格式合法(类型为文件/网址/备注,内容非空) | 让「产物在哪」可被机器核对 |
| F7 | 复盘四项(问题、弯路、解决、防再犯)各至少一条 | 经验能沉淀,下次少踩坑 |
| F8 | 报「受阻」必须写清卡在哪 | 主 Agent 才能给出有效指示,而不是干等 |
| F9 | 不得编造 | 诚信底线;由三阶段门禁与人工复核兜底 |
三、落地位置(可核对)
| 环节 | 代码位置 | 行为 |
|---|---|---|
| 下发 | src/comm-format.ts#renderCommFormatSpec → src/plan.ts#buildChildPrompt 末尾 |
每个子任务提示都附带九条规范与「提交前自查(强制)」指令 |
| 自检 | 同上(提示词内强制指令) | 部门人员提交前逐条对照 |
| 核验 | src/comm-format.ts#checkCommFormatCompliance → src/plan.ts#adjudicateResult |
主 Agent 用同一份规范逐条核验 F1–F8 |
| 退回 | adjudicateResult 返回 blockedKind:'comm-format' |
不合规即判受阻,退回通知写明逐条不合规项 |
| 重交 | src/runtime.ts#executeSubtask 的 lastFailure 注入 |
退回原因随下次激活回到子提示词,只补缺口不重做 |
四、验证
npm run check(tsc --noEmit)退出码 0。npm test:578 条用例,pass 578 / fail 0。- 新增
tests/workplan-comm-format.test.ts:F1–F8 逐条拒收、合规放行、退回通知文案、requirePhases:false兼容边界。 - 既有 1 条用例按新契约前移:
tests/workplan-evidence-contract.test.ts的 C-19 由「空证据 pass 降级 unverified 仍算完成」改为「按 F4 退回 blocked/comm-format」。 - 同时保留 2.0.5 草案的规划器 JSON 结构修复(括号/逗号/截断恢复),规划入口不再因一个字符的结构瑕疵整体降级。
五、发布渠道
- npm:
dsh-workplan@2.1.0 - GitHub Release:
v2.1.0,附dsh-workplan-2.1.0.tgz - 制品校验:
- sha256
0f015202575999b4be428bd55f2349f676a88ad48c605727cbd6e8494c9ac261 - sha1(与 npm registry 一致)
afc59da063e210f03eb0424b00da6e594f8536eb
- sha256
六、边界(不夸大)
- 只拦「即将判完成」的路径。解析失败、验收缺口、三阶段缺失已被更早的门禁拦下,保留原有更具针对性的诊断。
requirePhases:false(历史回放 / 明确关闭新契约)不追溯否决旧日志里按当时规则合法的完成记录。- F6 只校验产物声明是否合法,是否必须交付文件由各子任务的验收标准决定,避免把写作类任务误判为不合规。
- F9 不做自动判定:编造检测需要语义理解而非结构校验,写成提示词级诚信约束,由三阶段门禁与人工复核承担。
dsh-workplan 2.0.4 — 回执判定四缺陷修复 + 交互式收尾留痕
2.0.4 — 2026-11-05
修复「子 Agent 干完活却交不了差」的四条判定缺陷,并给交互式会话收尾加上「放行但留痕」。
一、问题与证据链
用户 2026-11-05 报告:计划里 5 个子 Agent 的产物都已在磁盘上,结果却被判「结果块无法解析」「未提供结构化证据块」,交付门禁反复重开;同一会话里还出现「子任务没完成就先给结论」。
逐条核对子会话原始回执后确认,这不是模型没干活,而是四处判定把「格式瑕疵」当成了「没有证据」:
| # | 事实 | 证据 |
|---|---|---|
| 1 | 3 份回执结尾各少一个 },补一个括号后 JSON.parse 立即通过 |
逐字符括号扫描;补后解析成功 |
| 2 | 2 份回执 JSON 合法,只是漏写 WORKPLAN_EVIDENCE 标记(放在代码块里) |
旧实现判「未提供证据块」,与事实相反 |
| 3 | 旧验收只做 实际文本.includes(声明原文),同义改写一律判「没回应」 |
acceptanceCoverage() |
| 4 | reported 状态没有 done 出边,复核已回报的行必撞「非法闭环迁移」 |
状态迁移表 |
| 5 | 交互式会话 steer 上限 2 次,用尽后静默放行,用户看不到「这次是没做完就收尾」 | onTurnStopping |
二、改了什么
- 回执解析有界修复:新增
closeOpenJson/lastSafeCut/repairEvidenceJson,只在结构层补括号与截断,不补内容;修不好的仍如实报错,并给出「只保留 status/summary/acceptance/artifacts/needs 后重发」的下一步。 - 无标记回执可认领:新增
rescueEvidenceFromFence(),仅在缺规定标记时,从代码块中认领「有status且至少带一个证据字段」的对象;计划载荷、配置片段这类普通 JSON 不会被误认。 - 验收匹配放宽到语义层:新增字符二元组 Dice 相似度与否定词一致性校验——同义改写、语序调整算同一条;删掉「不得」这类否定词,或只抄前半句,仍然判不覆盖。
- 状态机补齐:已回报的行再次交付时保持
reported,不再强写done,也不再报非法迁移。 - 交互式收尾「放行但留痕」(方案 B):steer 用尽时不再沉默
return,而是把releasedIncomplete(轮次、进度、未完成项)记入计划状态、向会话追加一条 notice、并写一条 warn 日志;三处使用同一组数字。headless 场景维持原有WORKPLAN_INCOMPLETE硬失败语义。 - 错误文案分档:截断、少闭合符、缺标记三种情况给出各自的修复指令,不再统一说「无法解析」。
三、验证
- 新增
tests/workplan-user-logic-204.test.ts:13 条用例覆盖同义改写、部分回应、删否定词、只抄前半句、缺括号、缺标记、误认普通 JSON、已回报复核。其中「删否定词」「只抄前半句」两类假阳性由独立复核子 Agent 用 18 条真实差异对复现后补入。 npm test:562 条用例全过,0 失败。npm run build重新生成lib/、dist/、client.js,与src/同步。npm pack --dry-run文件清单核对:不含.backups、node_modules、测试临时文件与任何凭证。
四、范围说明(重要)
本版本不含官方 @deepseek-ai/dsh-client-ui-chat 的界面文案改动。那条改动(「已完成,用时 」→「本轮过程已完成,用时 」)落在第三方包内部文件,属官方 DSH 安装目录,不随本包分发;需要的话请按仓库文档中的说明自行替换,或等待上游修复。
五、发布
- npm:
dsh-workplan@2.0.4 - GitHub Release:
v2.0.4,附dsh-workplan-2.0.4.tgz制品与 SHA256 - 索引源(dsh-plugin-catalog 链路):条目 tarball 指向
v2.0.4Release,由上游 CI 生成 catalog
安装
dsh plugin --profile web add dsh-workplan@2.0.4制品校验
dsh-workplan-2.0.4.tgz- SHA256
0060d7401e90e6c2a39f68e436577dd4c147594466545ebe5be8082ca95e894a
v2.0.3 — /goal 自动分解修复
2.0.3 — 2026-11-05
修复「官方 /goal 目标指令会让 dsh-workplan 自动分解永远不触发」的真实缺陷:goal 第一轮现在作为合法任务入口参与自动分解;已有进行中计划时 goal 轮次绝不抢跑。
一、问题与证据链
用户 2026-11-05 报告:使用官方 DeepSeek Harness 的「目标 goal」指令后,dsh-workplan 的自动任务分解似乎不会触发。核查代码后确认这不是猜测,而是一条可复现的契约缺口:
| # | 事实 | 证据位置 |
|---|---|---|
| 1 | /goal <objective> 命令只写 goal 领域状态,不产生 user/message |
@deepseek-ai/dsh-command-goal 的 create 分支 |
| 2 | goal 的自动续跑轮次由 round driver 以 source.kind = "goal" 的 user 消息送达,文本形如 <goal_round>Objective: "…"</goal_round> |
@deepseek-ai/dsh-goal-round-driver/lib/index.js 的 renderGoalRoundPrompt 与 createUserMessage |
| 3 | 2.0.2 的 humanMessages() 只接受 source.kind === 'user' 或未标记的消息 |
src/runtime.ts#humanMessages |
| 4 | maybePlan() 在 human.length === 0 时直接返回,不进入规划 |
src/runtime.ts#maybePlan |
1+2+3+4 合并后的结论:如果任务是通过 /goal 设置的,整条 goal 生命周期内都不存在「人类消息」,插件永远不会自动分解该任务。人工消息路径(普通输入框任务)不受影响。
二、改了什么
- 新增
goalRoundPlanningTask(ctx, payload, existing):只接受source.kind === 'goal'且round === 1的消息作为自动分解入口。 maybePlan()在没有任何人工消息时改走该入口;任务文本优先级为:goals领域服务的结构化objective→ 从官方<goal_round>信封解析 JSON objective → 整条消息原文。- 防抢跑:会话里存在进行中计划(
executing/paused/pending/verification等)时,goal 轮次直接放行不建计划;done/ended/cancelled/superseded/degraded/clarify属于历史记录,不拦新任务。 - 人工消息路径、
humanMessages()的既有语义、执行中变更(changeRequest)与 replan 规则全部保持不变。
三、验证
- 新增
tests/goal-round-planning.test.ts:7 条断言覆盖 round 1/round 2、goals 服务优先、信封解析、无 objective 兜底、进行中计划防抢跑、历史终态放行。 npm test:553 条用例全过;npm run check(tsc --noEmit)退出码 0。npm run build重新生成lib/、dist/、client.js,与src/同步。
四、发布
- npm:
dsh-workplan@2.0.3 - GitHub Release:
v2.0.3,附dsh-workplan-2.0.3.tgz制品 - 索引源(dsh-plugin-catalog 链路):条目 tarball 指向
v2.0.3Release,等待上游 CI 生成 catalog
v2.0.2 — 更正「第一、二阶段禁用插件」的适用范围
dsh-workplan 2.0.2 — 更正「第一、二阶段禁用插件」的适用范围
发布日期:2026-11-05(Asia/Shanghai)
一句话
2.0.2 只做一件事:把「第一、二阶段禁用 dsh-workplan 插件」更正为仅适用于 2026-11-05 本次优化会话,不再作为所有后续会话的永久产品规则。三阶段工作法、阶段三核验与自我学习复盘全部保持不变。
安装 / 升级
dsh plugin --profile web add dsh-workplan@2.0.2装完重启一次 DSH Web(或重新载入页面)。
从 2.0.1 升级时不需要迁移数据:phases 证据格式、phases.verification.retrospective、教训记忆文件 ~/.dsh/workplan/lessons.jsonl 都没有变化。
为什么要出 2.0.2
用户在 2.0.1 发布后澄清:原要求 4「第一、二阶段禁用 dsh-workplan 插件」是本次会话内对优化过程的约束,不是要求插件对所有未来会话禁用。1.13.0 起该条被写成了产品级规则(子 Agent 提示词、dsh_workplan_verify 描述、运行时报错、README 与协作文档),属于对需求范围的误读,2.0.2 全面更正。
改了什么
| 位置 | 2.0.1 及以前 | 2.0.2 |
|---|---|---|
| 子 Agent 提示词 | 「阶段一、二:dsh-workplan 插件禁用。不得调用任何 dsh_workplan_* 工具」 | 「阶段一、二先把问题、思路与执行记录写全;调用 verify 会因缺少前两阶段证据返回 PHASE_GATE(证据门禁,不是禁用插件)」 |
dsh_workplan_verify 描述 |
「阶段一、二禁用本插件」 | 「缺少 planning / execution 证据时返回 PHASE_GATE 与待补项」 |
| 运行时报错 | 「插件在阶段一、二禁用」 | 「阶段三核验缺少前两阶段证据」 |
| README(中/英) | 声明永久禁用 | 声明仅本次会话约束;主 Agent 任何阶段都可用计划、派发、查询与改判工具 |
| 协作文档与安全文档 | 表格写「禁用」 | 写「证据门禁」并加 2.0.2 更正说明 |
没有变的部分
- 三阶段「规划 → 执行 → 验证」仍是产品功能;完成判定仍要求
phases齐全。 dsh_workplan_verify仍只接受三阶段齐全的证据;缺 planning/execution 仍返回PHASE_GATE——这是证据门禁,不是插件禁用。- 阶段三复盘(问题 / 弯路 / 解决 / 防再犯)与永久教训记忆完全不变。
- 没有新增或删除模型工具,工具面仍是 11 个。
验证
npm run check(tsc --noEmit)退出码 0。npm test:全量通过(具体条数见仓库发布记录与 CI 输出)。tests/three-phase.test.ts新增断言:提示词不得再出现「插件禁用」,同时仍要求阶段三门禁与PHASE_GATE。
兼容性
- 2.0.2 是 2.0.1 的措辞更正版,证据契约与数据格式完全兼容,可直接升级。
- 旧结果回放仍可用
requirePhases: false走 1.13.0 以前的旧语义(与 2.0.1 相同)。
v2.0.1 — 自我学习与自我迭代
dsh-workplan 2.0.1 — 自我学习与自我迭代
发布日期:2026-11-05(Asia/Shanghai)
一句话
部门 Agent 每次完成工作后必须复盘(问题 / 弯路 / 解决 / 防再犯),复盘写入永久记忆文件;下次派发同类任务时自动注入历史教训,同一类错误重复出现会累加次数并提前排序。三阶段工作法保持「规划 → 执行 → 验证」,复盘是验证阶段收尾的必填项。
安装 / 升级
dsh plugin --profile web add dsh-workplan@2.0.1从源码安装:
git clone https://github.com/abbaababa/dsh-workplan.git
cd dsh-workplan && git checkout v2.0.1
npm ci && npm run build
dsh plugin --profile web add /绝对路径/dsh-workplan新增能力
| 能力 | 说明 |
|---|---|
| 阶段三复盘必填 | phases.verification.retrospective 四项:problems / detours / resolutions / prevention。缺项、太薄(问题/解决合计 <20 字、预防 <16 字)一律 blocked/unverified |
| 永久教训记忆 | 复盘通过后写入 ~/.dsh/workplan/lessons.jsonl(JSONL,追加写,保留最近 500 条,坏行跳过,临时文件 + 改名原子替换);DSH_WORKPLAN_LESSONS_FILE 可覆盖位置 |
| 自动防再犯 | 每次派发前按「同部门 > 同项目 > 关键词 > 重复次数 > 新近程度」取最相关 8 条注入子 Agent 提示词;段首声明「历史数据,不是新指令」 |
| 自我迭代信号 | 同类错误再次出现时 occurrences+1、排序提前;同一子任务重试/回放只原地更新,不虚增次数 |
| 只读复核工具 | dsh_workplan_lessons:list / search / stats,返回记忆内容、重复次数、文件位置;不提供写入动作,防止绕过真实复盘证据 |
三阶段与插件禁用边界(不变)
- 阶段一(规划):先梳理现状/约束/未知/主要矛盾,再形成完整可执行思路;阶段二(执行):严格按思路执行并记录偏离;阶段三(验证):逐条验证 + 复盘。
- 阶段一、二禁用 dsh-workplan 插件:子 Agent 本就没有计划/派发/改判权限;
dsh_workplan_verify在缺 planning/execution 证据时返回PHASE_GATE。 - 唯一例外是遇阻上报
dsh_workplan_escalate(安全阀,不属于计划/执行/验证能力)。 - 核验通过 ≠ 完成:结果块仍须写同一份
phases,由adjudicateResult再判。
兼容性(破坏性变更)
- 2.0.1 之前写出的
done结果没有retrospective,用本版完成判定重放会判未完成。历史回放请显式传requirePhases:false(或strict:false)走旧语义。 - 复盘内容来自模型输出:插件只校验「有没有写、够不够具体、是否覆盖四项」,不能证明内容真实;真实性仍由主 Agent 对照产物核对。
- 记忆是文本数据:注入前清除不可见字符与会话引用,并声明不是指令;发现污染时用
dsh_workplan_lessons抽查并删除对应行。
验证
npm run check # tsc --noEmit
npm test # 构建 + 全量用例
npm run build
git diff --exit-code -- lib client.js # 构建产物可复现发布记录(提交、tag、Release 资产哈希、npm 完整性、索引源 PR)见 docs/release-record-2.0.1-20261105.md。
dsh-workplan 1.12.3 — 澄清闸门 + 句中先行词 + 法务召回
1.12.3 — 2026-11-04
修好 MS2 20 条真实实跑暴露的四处缺陷:指代误拦(T05-08)、该问不问(T05-04/09/13/20)、未确认自行派发、法务召回缺失(T05-12)。默认行为变化:信息不足时不再生成计划、不再派发,改为向用户提问。
一、四处缺陷的修法
| 编号 | 缺陷(MS2 实测) | 1.12.3 的修法 | 代码位置 |
|---|---|---|---|
| ① 指代误拦 | T05-08「它每天具体走势」——「它」的先行词就在同一句的上半句,却被判成「找不到先行词」直接拦下 | 先在任务原文的同一句、再在上一句里找「实体型」先行词(引号跨度,或含数字/字母的中文实体片段);只有两处都找不到才拦 | src/understanding.ts resolvePronounAntecedentInline |
| ② 该问不问 | T05-04/09/13/20 四条本该澄清,却照做计划并派发 | 四条可判定规则:C1 裸表态、C2 悬空内部编号、C3 预测类无标的、C4 界面改动无对象;命中时在规划之前拦下,并给出一句可以原样问用户的话 | src/understanding.ts auditClarifyNeed;src/plan.ts buildClarifyMessage;src/runtime.ts 规划前闸门 |
| ③ 未确认自行派发 | 20 条里累计 46 次未经用户确认就启动部门 Agent | 按用户 2026-11-04 的决定:自动派发语义不变,只在「信息不足」这一类上拦截——缺信息时连计划都不生成,自然走不到派发 | src/runtime.ts clarifyGateDisabled / maybePlan |
| ④ 法务召回 | T05-12「会不会窃取用户文件和数据」判成无部门覆盖 | legal 词表增加 窃取 / 信息泄露 / 个人信息 / 数据安全 / 隐私风险 / 移动终端(刻意不用「泄露」:内存泄露属于工程问题) | src/departments.ts |
二、每一条结论的证据(可复核)
- 离线回放(不调用模型):20 条真实原文 → clarify 4/4 命中,16 条正常任务误拦 0 条;T05-12 legal 命中 2 词(窃取、移动终端);「修复内存泄露导致的崩溃」legal 命中 0 词;「参考国际标准做一下排版」仍为 1 词(低于 ≥2 门槛,不会把排版任务拉进法务)。
- 端到端(headless 真跑):用 T05-13 原文启动 headless → 事件流里 0 个计划、0 次
dsh_workplan_*工具调用,模型改为向用户提问(证据见_t_clarify_20261104/)。 - 自动化测试:
npm test523 条全过、0 失败(含新增tests/clarify-gate.test.ts、tests/antecedent-inline.test.ts);npm run check(tsc --noEmit)退出码 0。 - 修正了一条旧断言:legal 词表从 16 词增到 22 词,
tests/department-coverage.test.ts的数量断言同步更新并写明原因;C4 曾把「把红圈处改为默认收起」误判成「没说要改哪里」,用department-fit.test.ts抓出来后才补上「红圈/红框/圈出」三种说法。
三、开关与行为影响
- 新增
DSH_WORKPLAN_CLARIFY_GATE=0:关闭澄清闸门,回到旧行为(信息不足也照做计划、照派发)。默认开启。 DSH_WORKPLAN_AUTO_DISPATCH语义未变:默认自动派发照旧,只是信息不足的任务不会再走到派发这一步。- C3/C4 允许「缺的对象在最近对话里」:上一轮说过「截图红圈处的分步进度」,本轮「把它改成默认收起」就不算缺信息(否则会把正常追问也拦掉)。
四、本版没有覆盖的(如实登记,不计入修复证据)
- 同一工作区里还有一个 headless「未完成不得成功收尾」闸门(
failClosedOnIncomplete/WORKPLAN_INCOMPLETE),目前只有实现、没有自动化用例;发布前必须补测,本版不宣称它已验证。
dsh-workplan 1.12.2 — 修好 G1/G2/G3 三个写保护漏洞
1.12.2 — 2026-11-04
修好 G1/G2/G3 三个写保护漏洞(1.12.1 只记录了缺口)。这是一次有意的行为变更:已交付文件的写保护现在真正无死角,且不再区分「谁在写」。
一、修了什么(三个漏洞,逐条)
| 编号 | 1.12.1 的状态 | 1.12.2 的修法 | 代码位置 |
|---|---|---|---|
| G1 子 Agent 不受保护 | 非根会话直接放行:「门卫只认户主,保姆拿钥匙能进」 | 去掉角色判断。已交付文件在计划未就绪期间不得被原地改写,与谁在写无关。 | src/runtime.ts presentedWriteDenialReason |
| G2 只认三个工具名 | 只接管 write / edit / str_replace_editor,第四个写工具(如 apply_patch)根本不进闸门 |
改为按参数形状识别写操作:带 file_path/path,或 patch 文本含 *** Update/Add/Delete File:。一次调用含多个文件时,只要有任一命中就整单拒绝。读类工具显式白名单排除。 |
src/host.ts fileWriteGuardReason / isWriteShapedCall;src/runtime.ts writeTargets |
| G3 符号链接绕过 | 只做 path.resolve,/link/report.md 与 /real/report.md 被当成两个文件 |
两侧都归一到真实文件身份(realpath.native)。交付链接、写真实路径(或反之)都能认出来。文件尚不存在时解析最近的存在祖先;完全解析不了时退回旧行为。 |
src/runtime.ts realPathIdentity / identityPath |
二、行为影响(会影响现有使用的部分,务必读完)
- 子 Agent 写已交付文件会被拒绝(G1)。以前后台子 Agent 能改掉用户手上那份报告,现在与主 Agent 同等对待。present 仍只有主会话可用,所以「交付能力」没有扩大,只是「改写已交付文件」的口子被堵上。
- 更多工具名进入写保护(G2)。过去改一个名字(如
apply_patch、write_file)就能绕过的写法,现在同样被拦;一次 patch 改动多个文件时,只要有一个是已交付文件就整单拒绝。 - 符号链接不再是第二种写法(G3)。通过软链接路径改写已交付文件会被拦下,报错文案与直接路径完全一致。
- 照旧保留的出路:计划交付就绪后放行;计划被
dsh_workplan_cancel显式取消后放行;present 之后才新建的计划不受限制;plan 模式下写保护不生效。 - 没有削弱的权限:其余 8 处
NOT_ROOT校验(子 Agent 不能 update / replan / cancel / dispatch 主计划、不能下发指示、不能处置跨部门需求、不能补发 follow-up、不能 present)一处未动。那是「子 Agent 不能改计划」的权限,与「不能改文件」是两件事。
三、验证(双向红绿,不是只跑一次绿)
- 修复前(换回 1.12.1 的
src/runtime.ts+src/host.ts):tests 498 / pass 491 / fail 7,失败项正是 6 条 G1/G2/G3 新用例 + 1 条既有契约用例。 - 修复后:
tests 498 / pass 498 / fail 0,退出码 0;npm run check(tsc --noEmit)退出码 0。 - 用例数构成:基线 495 + G1 一条 + G2 一条 + G3 反向一条 = 498。
- 三条原本「钉住缺口」的用例已翻转成「钉住修复」:
p03-m1-write-guard-gaps.test.ts的 G3 条、p03-m1-guard-gating-gaps.test.ts的 G1/G2 条、以及既有契约workplan-presented-write-guard.test.ts中「非根会话放行」的断言。
四、事实边界(不得外推)
- 真实模型在 20 条任务上的通过率未被本版刷新,仍为 2026-11-03 的
pass 4/20。原因:模型密钥 4 个环境变量全空 + 工作区外写配置权限缺失,20 条真实模型验证无法在本轮重跑。 - 1.12.2 是代码级修复 + 回归验证的结论,不代表 20 条真实模型任务的表现有任何变化。
安装
dsh plugin --profile web add dsh-workplan@1.12.2本次不包含(如实说明)
- 真实模型 20 条验证:本机 4 个模型密钥环境变量为空,未重跑,通过率仍为 2026-11-03 的 pass 4/20。补齐密钥后可执行
rerun_ms2_20.sh复现。 - npm 包 dsh-workplan@1.12.2:https://www.npmjs.com/package/dsh-workplan