DeepSeek Harness 切 /permission auto 后工具全 ABORTED 怎么修
症状很好认:一轮对话跑着跑着,你切到 /permission auto,从下一条工具调用开始全部变成 ABORTED_BEFORE_DISPATCH,而这一轮最后仍然显示 completed。 报错原文只有两行:tool call aborted before dispatch 与 code: "ABORTED_BEFORE_DISPATCH"。这不是模型抽风,也不是工具坏了——DeepSeek Harness(DSH)切换权限预设时会重新配置 auto-review 插件,而它的拆除流程只走了一半(来源)。
先判断:DeepSeek Harness 的取消是否跟着切预设
只要「切预设前正常、切完后续调用全取消、turn 仍 completed」三条同时成立,就可以按本文处理;少一条就先别动插件配置。
- 打开会话日志,找到切预设那条事件。预期:它之后的
tool/call全部配对成AbortError。 - 检查
tool/result里有没有工具体开始执行的记录,例如文件内容或命令输出。预期:完全没有。 - 确认当前 profile 挂载了 auto-review,且预设是
auto。预期:插件列表里有对应条目,盾牌显示 auto。 - 对比切换前的调用。预期:之前的工具结果完整,失败集中在切换点之后。
- 记录切换时间与第一条失败事件的时间差。预期:两者几乎同时。
| 判据 | 本文故障 | 工具超时 | 用户中断 |
|---|---|---|---|
| 工具体事件 | 没有 | 有 | 可能有 |
| turn 状态 | completed | 多为 failed | aborted |
| 触发点 | 切预设后 | 执行中 | 手动停止 |
据讨论中的用户扫描,有样本在 5 个会话里累计 47 次该错误,全部落在切预设或插件重配置之后(#10041)。
根因:DeepSeek Harness 的 disposal 为什么只拆一半
disposal 在修复会话之前就把 accepting 置为 false,而修复用的 sweep 又会抛错;抛错让后面摘除 gate 的清理全部跳过。
- disposal 第一句执行
accepting = false。预期:gate 不再接受新的审查请求。 - 接着遍历活跃会话,把预设从
auto改回danger-full-access。预期:这一步要读sessionProjections。 - 拆除期间 fiber 正在卸载,读取抛
inactive context。预期:sweep 中断。 - disposer 串在一条 promise 链上,sweep reject 后
stopContribution与stopListener都不执行。预期:gate 留在原地。 - 结果:预设仍注册
auto,gate 仍安装,accepting却是 false。预期:每条工具调用都拿到cancel。
注册顺序是 stopListener、stopContribution、sweep,逆序执行时 sweep 反而第一个跑。可抛错的清理排在摘 gate 之前,这就是缺陷的形状。结束本轮也不管用,因为坏状态挂在插件上,而 turn 只是执行单元。
另有一份独立样本补充:部分取消发生在一次完整审查往返之后,说明坏状态不只「gate 已关」一条路径,但只要预设仍是 auto,出口只有一个。
路径一:切回固定预设,让 DeepSeek Harness 放行工具
这是恢复最快、也最该先做的一步:让会话不再解析为 auto,gate 的第一道判断就会直接放行。顺序不能反。
- 在输入框执行
/permission workspace-write或你惯用的固定预设。预期:状态栏盾牌变成固定预设。 - 先别结束本轮,触发一条只读工具,例如读一个已知文件。预期:正常返回,不再出现 ABORTED_BEFORE_DISPATCH。
- 确认恢复后,正常结束本轮。预期:历史记录里不再追加取消项。
- 如果还想用 auto,等下一轮开始后再切。预期:切完先跑一条低风险工具观察。
- 记录这次切换的时间。预期:下次复现时能和日志对上。
- 再跑一条写操作工具。预期:权限按固定预设执行,而不是被取消。
- 检查状态栏。预期:盾牌一直显示固定预设,没有跳回 auto。
这条路的代价是暂时失去 auto 审查。急着干活时值得,但别把它当成修复。
路径二:重启 DeepSeek Harness 或换新会话
重启会重建整条 disposal 链,新会话则绕开已经半拆除的 gate;两者都能用,但都不修复根因。
- 完全退出 DSH,包含托盘和后台进程。预期:任务管理器里没有残留。
- 启动后先新建会话,不要直接继续原会话。预期:权限状态从默认值开始。
- 在新会话里跑一条最小工具调用,例如列目录。预期:正常返回,无取消。
- 需要旧会话上下文时,把文件路径和结论带过来。预期:不在原 turn 上硬接。
- 观察十分钟。预期:没有再次出现取消。
- 在旧会话里补一条只读调用。预期:如果仍取消,说明坏 gate 被持久化了。
- 对比新旧会话的权限状态。预期:新会话干净,旧会话带残留。
如果你经常重载 DSH插件 或切预设,这条路只能顶一阵。下一次重配置还可能把 gate 拆坏。
路径三:改 DeepSeek Harness 的 disposal 顺序
根治方向只有一句:把可能抛错的 sweep 放到最后执行,并且逐会话容错;gate 关闭时返回带原因的 deny,而不是静默 cancel。
- 调整注册顺序,把 sweep 的
yield放到stopListener、stopContribution之前。预期:逆序执行时先摘 gate。 - 把 sweep 内部改成逐会话
try/catch,单个会话读不到投影时记日志并继续。预期:一个坏会话不影响其余。 - 把 gate 在
accepting === false时的返回值从cancel改成带理由的deny。预期:用户看到「auto-review 不可用」。 - 写一条回归:在 sweep 里注入一次投影读取失败。预期:gate 仍被摘除,后续调用收到 deny 理由。
- 补一条顺序测试:模拟 disposal 中途 reject。预期:剩余 disposer 仍执行。
- 在 PR 里附上 47 次错误的样本分布。预期:维护者能判断影响面。
- 把 gate 的返回值写进类型定义。预期:后续调用方知道会收到 deny 而不是 cancel。
顺序测试比功能测试更重要。这个缺陷只在「某一步抛错」时暴露,正常路径永远测不出来。
验证与边界:DeepSeek Harness 复现与取证
复现要在有 auto-review 的 profile 里做,并且必须在一轮已经开始后再切预设;没有正在跑的 turn,sweep 没有要修的东西。
- 新建会话,选
workspace-write,发一条会连续触发两个工具调用的请求。预期:两个工具都正常执行。 - 在第一个工具执行完、第二个还没开始时切
/permission auto。预期:后续调用出现 ABORTED_BEFORE_DISPATCH。 - 立刻切回
workspace-write,再补一条工具调用。预期:恢复执行。 - 记录切预设前后的日志行。预期:能找到一次 disposal 抛错。
- 对照 turn 状态。预期:显示 completed,但工具体没有跑过。
- 统计本次取消次数。预期:与切换后触发的工具调用数一致。
- 再用固定预设跑一轮。预期:零取消,作为对照。
- 保存两份日志。预期:取消与非取消的差异一眼能看出来。
取证时只盯三样东西:取消的位置、有没有工具体事件、切预设附近有没有 disposal 抛错。边界有四条:不要反复切预设试探;关掉 auto-review 也能止血,但那是规避;turn 显示 completed 不代表成功,依赖工具副作用的步骤要重跑;讨论里没有官方修复版本,0.2.1-rc.2 仍可复现。相关的启动期死锁见 权限预设 auto 死锁,服务缺失的通用判断见 sessionProjections inactive context。
常见问题
这是 DeepSeek Harness 的 auto-review gate 返回 cancel,不是工具失败。切换触发插件重配置,disposal 先关 accepting 再遍历会话,抛错跳过了摘 gate;对仍解析为 auto 的会话一律取消。
DeepSeek Harness 的 gate 第一道判断是预设是否等于 auto。坏 gate 只在会话不再解析为 auto 时放行,结束本轮不改预设,取消会跨轮继续。
重启只是让这次拆除完整跑完,并没有修复 DeepSeek Harness 的顺序缺陷。只要再次发生插件重配置、且当时有 auto 会话在跑,半拆除状态就会重现。
看 DeepSeek Harness 的 tool/call 与 tool/result 配对:本文场景里只有 AbortError 与 ABORTED_BEFORE_DISPATCH,没有工具体开始事件,也没有超时字段。切预设附近通常还能看到一次 disposal 抛错。
相关术语
- ABORTED_BEFORE_DISPATCH
- ABORTED_BEFORE_DISPATCH 是 DeepSeek Harness 工具调用在派发前被拒绝时返回的错误码,附带 AbortError。它表示工具体从未开始执行,区别于执行中途被中断。— https://github.com/deepseek-ai/deepseek-harness/discussions/10041
- auto-review
- auto-review 是 DeepSeek Harness 的实验性自动审查集成,在 tools/pre-execute 钩子上逐次评估工具调用风险,返回 allow、deny、ask 或 cancel。它只在权限预设为 auto 时介入。— https://github.com/deepseek-ai/deepseek-harness/discussions/10041
- disposer 链
- disposer 链是 Cordis fiber 卸载时按注册顺序逆序执行的一组清理函数,实现上把每一步串成 promise 链。任意一步 reject 后,链上后续的 disposer 都不再执行。— https://github.com/deepseek-ai/deepseek-harness/discussions/10041
来源
- #10041 — 中途切 /permission auto 后本轮所有工具调用 aborted before dispatch· deepseek-ai(GitHub Discussions)
- DeepSeek Harness 官方仓库· deepseek-ai(GitHub)