dsh-restart-handoff:在对话里重启 DeepSeek Harness

前言

在 DeepSeek Harness(DSH)里,长时间运行的工作流往往需要中途重启宿主进程。常见的做法是人在对话里打字说「继续」,或者退出命令行,再重新启动 Harness。这会打断会话、丢失子代理和待处理的指令,需要重新整理上下文。

dsh-restart-handoff 插件通过一个专用工具 restart_dsh,把「重启宿主」变成一次计划内的操作:模型发出重启请求,宿主写入交接记录,然后被另一个进程拉起,继续之前的会话和子代理,并执行待处理的指令。

是什么

这是 sadkga 维护的一个 DSH 插件,分类为「工作流」。它让模型通过 restart_dsh 工具以两步方式重启宿主,并把会话、子代理和指令交给新进程继续。插件以 Node 24 运行,需要宿主由一个 Restart=always 的 systemd 单元监管。

核心功能

计划内重启:两步调用

  1. 警告调用。 模型调用 restart_dsh,工具返回一份警告,包括原因、将重放的指令、将恢复的会话,以及一个确认令牌。这一步不执行任何重启。
  2. 确认调用。 模型带着令牌再次调用 restart_dsh,令牌匹配时,工具写入交接记录到 $DSH_HOME/restart/handoff.json,记录当前正在跑的会话、原因、待重放的指令(continuePrompt)和可继续的子代理。工具等待当前轮次变空闲后,向宿主进程发送 SIGTERM,由 Restart=always 的单元拉起新进程。
  3. 重放。 新进程读取交接记录,执行恢复:
    - 恢复重启发生时正在跑的每一个会话,并注入「请继续」指令;
    - 自上而下地唤起可继续的子代理,保证子会话只在它自己的父会话活着时才被投递;
    - 把 continuePrompt 交给发起重启的那个会话;
    - 对齐 Agent Team 名册并唤起其中的队友。

非计划重启:自动恢复

非计划退出(崩溃、被杀、断电)不会留下交接记录。插件会在下次启动时扫描持久化的会话,把「最后一轮被打断」的那些带回来,以及「收件箱里还排着没开始过的提示」的那些。

恢复判据基于最后一个 turn/end 的 reason,以及是否还有工作在等它:

最后一个 turn/end 的 reason 恢复?
interrupted 是
aborted + disposed 是
aborted + user 否
completed 否
error 否

此外,与 reason 无关地,收件箱里还排着一个从未开始的提示的会话也会被恢复。

围栏:防止模型直接执行重启

插件把重启暴露为一个工具,并看守会执行命令的工具。命令行风格的「重启 Harness」操作会被拒绝,并给出指向 restart_dsh 的提示。围栏按 shell 分隔符切分文本,剥掉包装层(sudo、env、nohup 等),看每一段的「首个动词」是否冲着宿主,从而拦截对宿主进程的 kill 信号。

保真:会话回来时还是它自己

恢复的会话保留自己的 provider、模型、思考强度和 agent preset,全部从会话日志读取,而不是使用部署默认值。

恢复性能

扫描在每次启动时都会跑。通过文件 mtime 预筛、只读日志尾部、以及向忙碌的 Agent 投递时不空等,扫描时间可从全量读的约 97 秒降到约 13 秒,其中日志读取仅约 14 毫秒。

安装与启用

用 Harness 插件 CLI 装进某个 profile:

dsh plugin --profile web add dsh-restart-handoff

从 GitHub 装(不需要 npm 账号):

dsh plugin --profile web add github:sadkga/dsh-restart-handoff

锁定某个标签:

dsh plugin --profile web add github:sadkga/dsh-restart-handoff#v0.2.1

安装后重启宿主,插件的客户端元数据与加载器会被缓存。

插件需要 Node 24(engines.node)。

配置

在 cordis.patch.yml 中可以覆盖默认配置:

- insert:
    - id: restart-handoff
      name: 'dsh-restart-handoff'
      config:
        serviceUnit: 'dsh.service'
        autoResume: true
        resumeSubagents: true
        idleTimeoutMs: 30000

常用配置项包括:

  • serviceUnit:监管该进程的 systemd user 单元(默认 dsh.service)。
  • handoffDir:交接记录写入的位置(默认 $DSH_HOME/restart)。
  • autoResume:下次启动时重放交接记录(默认 true)。
  • resumeSubagents:恢复后唤起可继续的子代理(默认 true)。
  • resumeRunningSessions:同时恢复其它正在跑或排着活的会话(默认 true)。
  • pendingTtlMs:确认令牌的过期时间(默认 300000 毫秒)。
  • handoffTtlMs:交接记录的陈旧时间(默认 1800000 毫秒)。
  • recoverInterruptedSessions:恢复非计划退出留下的会话(默认 true)。
  • recoverMaxAgeMs:被打断的会话最大年龄(默认 7200000 毫秒)。
  • recoverMaxSessions:一次启动最多恢复的会话数(默认 50)。
  • dryRun:只写交接记录,不发信号(默认 false)。

适用场景与注意

  • 适合需要长时间运行、中途可能重启宿主的 DSH 工作流场景。
  • 插件以当前 dsh 进程权限运行,安装前应检查源码与许可证。
  • 围栏是引导而非隔离,理论上仍能被混淆绕过,真正的兜底是恢复机制。
  • 宿主必须由一个 Restart=always 的 systemd 单元监管,插件会向宿主发 SIGTERM。

小结

dsh-restart-handoff 把重启宿主变成一次可计划的操作:模型通过 restart_dsh 工具两步确认,宿主写入交接记录,新进程恢复会话、子代理和指令。即便宿主被杀,工作也会通过非计划恢复机制回来。

目录页:https://www.skillhub.cn/plugins/sadkga/dsh-restart-handoff
GitHub:https://github.com/sadkga/dsh-restart-handoff

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye