前言¶
在 DeepSeek Harness(DSH)里,长时间运行的工作流往往需要中途重启宿主进程。常见的做法是人在对话里打字说「继续」,或者退出命令行,再重新启动 Harness。这会打断会话、丢失子代理和待处理的指令,需要重新整理上下文。
dsh-restart-handoff 插件通过一个专用工具 restart_dsh,把「重启宿主」变成一次计划内的操作:模型发出重启请求,宿主写入交接记录,然后被另一个进程拉起,继续之前的会话和子代理,并执行待处理的指令。
是什么¶
这是 sadkga 维护的一个 DSH 插件,分类为「工作流」。它让模型通过 restart_dsh 工具以两步方式重启宿主,并把会话、子代理和指令交给新进程继续。插件以 Node 24 运行,需要宿主由一个 Restart=always 的 systemd 单元监管。
核心功能¶
计划内重启:两步调用¶
- 警告调用。 模型调用
restart_dsh,工具返回一份警告,包括原因、将重放的指令、将恢复的会话,以及一个确认令牌。这一步不执行任何重启。 - 确认调用。 模型带着令牌再次调用
restart_dsh,令牌匹配时,工具写入交接记录到$DSH_HOME/restart/handoff.json,记录当前正在跑的会话、原因、待重放的指令(continuePrompt)和可继续的子代理。工具等待当前轮次变空闲后,向宿主进程发送SIGTERM,由Restart=always的单元拉起新进程。 - 重放。 新进程读取交接记录,执行恢复:
- 恢复重启发生时正在跑的每一个会话,并注入「请继续」指令;
- 自上而下地唤起可继续的子代理,保证子会话只在它自己的父会话活着时才被投递;
- 把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