DeepSeek Harness 切 /permission auto 后工具全 ABORTED 怎么修

故障排查发布于 2026-10-20作者: DeepSeek Plugin 插件市场
DeepSeek HarnessDSHauto-reviewABORTED_BEFORE_DISPATCHpermission autoCordis工具调用
DeepSeek Harness 切 /permission auto 后本轮工具全 ABORTED_BEFORE_DISPATCH,turn 仍显示 completed。根因是 auto-review 的 disposal 顺序缺陷,给三条恢复与修复路径。

症状很好认:一轮对话跑着跑着,你切到 /permission auto,从下一条工具调用开始全部变成 ABORTED_BEFORE_DISPATCH,而这一轮最后仍然显示 completed。 报错原文只有两行:tool call aborted before dispatch 与 code: "ABORTED_BEFORE_DISPATCH"。这不是模型抽风,也不是工具坏了——DeepSeek Harness(DSH)切换权限预设时会重新配置 auto-review 插件,而它的拆除流程只走了一半(来源)。

先判断:DeepSeek Harness 的取消是否跟着切预设

只要「切预设前正常、切完后续调用全取消、turn 仍 completed」三条同时成立,就可以按本文处理;少一条就先别动插件配置。

  1. 打开会话日志,找到切预设那条事件。预期:它之后的 tool/call 全部配对成 AbortError。
  2. 检查 tool/result 里有没有工具体开始执行的记录,例如文件内容或命令输出。预期:完全没有。
  3. 确认当前 profile 挂载了 auto-review,且预设是 auto。预期:插件列表里有对应条目,盾牌显示 auto。
  4. 对比切换前的调用。预期:之前的工具结果完整,失败集中在切换点之后。
  5. 记录切换时间与第一条失败事件的时间差。预期:两者几乎同时。
判据本文故障工具超时用户中断
工具体事件没有有可能有
turn 状态completed多为 failedaborted
触发点切预设后执行中手动停止

据讨论中的用户扫描,有样本在 5 个会话里累计 47 次该错误,全部落在切预设或插件重配置之后(#10041)。

根因:DeepSeek Harness 的 disposal 为什么只拆一半

disposal 在修复会话之前就把 accepting 置为 false,而修复用的 sweep 又会抛错;抛错让后面摘除 gate 的清理全部跳过。

  1. disposal 第一句执行 accepting = false。预期:gate 不再接受新的审查请求。
  2. 接着遍历活跃会话,把预设从 auto 改回 danger-full-access。预期:这一步要读 sessionProjections。
  3. 拆除期间 fiber 正在卸载,读取抛 inactive context。预期:sweep 中断。
  4. disposer 串在一条 promise 链上,sweep reject 后 stopContribution 与 stopListener 都不执行。预期:gate 留在原地。
  5. 结果:预设仍注册 auto,gate 仍安装,accepting 却是 false。预期:每条工具调用都拿到 cancel。

注册顺序是 stopListener、stopContribution、sweep,逆序执行时 sweep 反而第一个跑。可抛错的清理排在摘 gate 之前,这就是缺陷的形状。结束本轮也不管用,因为坏状态挂在插件上,而 turn 只是执行单元。

另有一份独立样本补充:部分取消发生在一次完整审查往返之后,说明坏状态不只「gate 已关」一条路径,但只要预设仍是 auto,出口只有一个。

路径一:切回固定预设,让 DeepSeek Harness 放行工具

这是恢复最快、也最该先做的一步:让会话不再解析为 auto,gate 的第一道判断就会直接放行。顺序不能反。

  1. 在输入框执行 /permission workspace-write 或你惯用的固定预设。预期:状态栏盾牌变成固定预设。
  2. 先别结束本轮,触发一条只读工具,例如读一个已知文件。预期:正常返回,不再出现 ABORTED_BEFORE_DISPATCH。
  3. 确认恢复后,正常结束本轮。预期:历史记录里不再追加取消项。
  4. 如果还想用 auto,等下一轮开始后再切。预期:切完先跑一条低风险工具观察。
  5. 记录这次切换的时间。预期:下次复现时能和日志对上。
  6. 再跑一条写操作工具。预期:权限按固定预设执行,而不是被取消。
  7. 检查状态栏。预期:盾牌一直显示固定预设,没有跳回 auto。

这条路的代价是暂时失去 auto 审查。急着干活时值得,但别把它当成修复。

路径二:重启 DeepSeek Harness 或换新会话

重启会重建整条 disposal 链,新会话则绕开已经半拆除的 gate;两者都能用,但都不修复根因。

  1. 完全退出 DSH,包含托盘和后台进程。预期:任务管理器里没有残留。
  2. 启动后先新建会话,不要直接继续原会话。预期:权限状态从默认值开始。
  3. 在新会话里跑一条最小工具调用,例如列目录。预期:正常返回,无取消。
  4. 需要旧会话上下文时,把文件路径和结论带过来。预期:不在原 turn 上硬接。
  5. 观察十分钟。预期:没有再次出现取消。
  6. 在旧会话里补一条只读调用。预期:如果仍取消,说明坏 gate 被持久化了。
  7. 对比新旧会话的权限状态。预期:新会话干净,旧会话带残留。

如果你经常重载 DSH插件 或切预设,这条路只能顶一阵。下一次重配置还可能把 gate 拆坏。

路径三:改 DeepSeek Harness 的 disposal 顺序

根治方向只有一句:把可能抛错的 sweep 放到最后执行,并且逐会话容错;gate 关闭时返回带原因的 deny,而不是静默 cancel。

  1. 调整注册顺序,把 sweep 的 yield 放到 stopListener、stopContribution 之前。预期:逆序执行时先摘 gate。
  2. 把 sweep 内部改成逐会话 try/catch,单个会话读不到投影时记日志并继续。预期:一个坏会话不影响其余。
  3. 把 gate 在 accepting === false 时的返回值从 cancel 改成带理由的 deny。预期:用户看到「auto-review 不可用」。
  4. 写一条回归:在 sweep 里注入一次投影读取失败。预期:gate 仍被摘除,后续调用收到 deny 理由。
  5. 补一条顺序测试:模拟 disposal 中途 reject。预期:剩余 disposer 仍执行。
  6. 在 PR 里附上 47 次错误的样本分布。预期:维护者能判断影响面。
  7. 把 gate 的返回值写进类型定义。预期:后续调用方知道会收到 deny 而不是 cancel。

顺序测试比功能测试更重要。这个缺陷只在「某一步抛错」时暴露,正常路径永远测不出来。

验证与边界:DeepSeek Harness 复现与取证

复现要在有 auto-review 的 profile 里做,并且必须在一轮已经开始后再切预设;没有正在跑的 turn,sweep 没有要修的东西。

  1. 新建会话,选 workspace-write,发一条会连续触发两个工具调用的请求。预期:两个工具都正常执行。
  2. 在第一个工具执行完、第二个还没开始时切 /permission auto。预期:后续调用出现 ABORTED_BEFORE_DISPATCH。
  3. 立刻切回 workspace-write,再补一条工具调用。预期:恢复执行。
  4. 记录切预设前后的日志行。预期:能找到一次 disposal 抛错。
  5. 对照 turn 状态。预期:显示 completed,但工具体没有跑过。
  6. 统计本次取消次数。预期:与切换后触发的工具调用数一致。
  7. 再用固定预设跑一轮。预期:零取消,作为对照。
  8. 保存两份日志。预期:取消与非取消的差异一眼能看出来。

取证时只盯三样东西:取消的位置、有没有工具体事件、切预设附近有没有 disposal 抛错。边界有四条:不要反复切预设试探;关掉 auto-review 也能止血,但那是规避;turn 显示 completed 不代表成功,依赖工具副作用的步骤要重跑;讨论里没有官方修复版本,0.2.1-rc.2 仍可复现。相关的启动期死锁见 权限预设 auto 死锁,服务缺失的通用判断见 sessionProjections inactive context。

常见问题

DeepSeek Harness 切 auto 后工具全报 ABORTED_BEFORE_DISPATCH,为什么?

这是 DeepSeek Harness 的 auto-review gate 返回 cancel,不是工具失败。切换触发插件重配置,disposal 先关 accepting 再遍历会话,抛错跳过了摘 gate;对仍解析为 auto 的会话一律取消。

为什么切回 workspace-write 后 DeepSeek Harness 工具立刻恢复,结束本轮却没用?

DeepSeek Harness 的 gate 第一道判断是预设是否等于 auto。坏 gate 只在会话不再解析为 auto 时放行,结束本轮不改预设,取消会跨轮继续。

DeepSeek Harness 重启后 auto-review 看起来正常,过一会又取消,是没修好吗?

重启只是让这次拆除完整跑完,并没有修复 DeepSeek Harness 的顺序缺陷。只要再次发生插件重配置、且当时有 auto 会话在跑,半拆除状态就会重现。

怎么从日志确认是 DeepSeek Harness 的 gate 在取消,而不是工具超时或用户中断?

看 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

来源