Files
deepseek-harness/.agents/notes/implemented/feature/2026-08-03-fs-tool-error-remedy.zh.md
T
2026-08-09 17:43:53 +08:00

3.3 KiB
Raw Blame History

Agent Note: 受防护变更错误在模型边界追加恢复指令

Status: implemented

English | 中文

问题

受防护的 write 与 edit 失败以只陈述条件、不给出唯一正确恢复方式的消息到达模型:FS_STALE_VERSION("file changed since it was read")与 FS_NOT_OBSERVED("edit requires reading … first")。模型必须自行猜测恢复方式是重新读取(或首次读取)后重试,而基于结构化错误码路由的重试/权限/UI 层看到的也是同一段消息文本。提供方拥有的消息属于存储 seam 的面向机器词汇(文件系统能力 seam),因此恢复指令不能放在那里,否则会把面向模型的措辞泄漏给 FsError 的每个消费方。

决策

dsh-tool-fs 拥有一个面向模型的错误包装层 remediateFsError(位于 src/error.ts),在 write.ts 与 edit.ts 中于沙箱拒绝映射之后应用。它为两个受防护变更错误码追加恢复指令,其余错误原样透传:

  • FS_STALE_VERSION(包括缺失的编辑目标——它与陈旧错误共用同一错误码)追加 — re-read the file, then retry。
  • FS_NOT_OBSERVED 追加 — read the file, then retry。

结构化 FsError 错误码保持不变,使重试/权限/UI 层继续基于它路由;原始错误作为 cause 链入。提供方消息保持面向机器且不变。

在 edit.ts 中,fs/edit-intent waterfall(瀑布式事件)现在与提供方变更位于同一个 try 内,因此策略插件从 intent slot 抛出的 FS_NOT_OBSERVED 拒绝也会获得恢复指令——两条拒绝路径都以相同的恢复措辞到达模型。

考虑过的替代方案

  • 在 dsh-fs / dsh-fs-local 的提供方消息中追加恢复指令。 被拒绝:这些消息是面向机器的 seam 词汇,除面向模型的接口外还被重试、权限与 UI 层消费;面向模型的措辞应位于模型边界,即 dsh-tool-fs 已经拥有结果格式化之处(文件系统能力 seam)。
  • 改为在提示词引导中加入恢复方式。 被拒绝:失败发生在任务中途;静态指令无法可靠地影响重试决策,而错误消息恰好在模型必须行动时出现。
  • 用新的 FsError 错误码表达恢复指令。 被拒绝:这两种失败对应的条件,重试层本就已经处理;拆分错误码会使相同语义采用不同路由。

后果

两个错误码的模型可见文本发生变化;fs-policy-reject 无密钥快照被重新录制,dsh-tool-fs 与 dsh-fs-policy 的 README 逐字固定追加后的文本。单元测试直接覆盖包装层(恢复指令文本、错误码保留、cause 链、其他错误码与非 FsError 值的透传),组装后的工具路径断言两个错误码的恢复指令都到达模型。

文件系统缺失观测后续决策使外部删除场景下的陈旧恢复指令能够生效。失败的重新读取仍返回 FS_NOT_FOUND,但会记录确认缺失:随后 edit 返回 FS_NOT_FOUND,不再附加陈旧恢复指令;write 则以原子 createIfAbsent 重试,并保留任何并发创建者写入的文件。