dsh-auto-continue

34Star3Fork0Issue1Watching

为 DSH Web UI 自动续跑因网络等原因中断的请求,遇到认证失败等永久性错误会跳过并通知。

语言
TypeScript
License
MIT
分支
main
auto-continueautomaticcordisdeepseek-harnessdshdsh-pluginpluginweb-ui

安装

$ dsh plugin --profile web add github:HsiangNianian/dsh-auto-continue

在终端中运行以上命令,通过 dsh CLI 安装此插件。可在右上角切换 Profile。 第一次用 dsh?看这篇新手教程

一句话定位

为 DSH Web UI 在请求被网络中断时自动续跑的插件——把"继续"模拟成普通用户消息自动发送,遇到永久性错误会跳过并通知。

核心能力

  • 检测回合结束事件,对临时性失败(网络/超时/5xx/429 等)和 token 超限自动发送"继续"消息
  • 自适应退避:连续失败时冷却时间按倍数递增(默认 20s → 40s → 80s…),避免对故障上游狂发请求
  • 幂等护栏:续跑前检查上一步工具调用状态,若工具结果未确认或已完成,给模型加上一段提示,避免重复执行
  • 循环守卫:识别运行中回合的空转(连续短句、同工具反复调用、相同消息重复),自动取消并用循环提示文本重启回合
  • 启动/重连扫描:浏览器关闭期间若宿主崩溃遗留中断的回合,恢复后会扫描并自动续跑
  • 设置卡片统计今日自动继续次数、跳过数、恢复数、失败数、达上限停止、循环打断,可按错误码分类并一键清零
  • 可选浏览器通知:自动继续/放弃/永久性错误时弹窗,可直接点"立即续跑"或"暂停该会话 1 小时"

技术实现

  • 语言: TypeScript
  • 关键依赖: @deepseek-ai/cordis、@deepseek-ai/schemastery、@deepseek-ai/dsh-settings、@deepseek-ai/dsh-client-runtime
  • 架构模式: 宿主-浏览器双半插件;宿主侧单实例引擎订阅会话事件流(session/event),通过 agent.followup 发送、agent.cancel 取消;浏览器侧瘦壳只提供设置卡片和 SSE 状态桥
  • 入口文件: src/index.ts(宿主侧)/ src/client/index.ts(浏览器侧)

适用场景

使用 DSH Web 跑长时间任务时,网络抖动或服务端瞬时 5xx 会让回合中断,常见做法是手动点重发。本插件免去这个动作——只要网络或服务端是临时性故障,等几秒就会自动接着跑。也适合浏览器关闭后回来发现任务半途而废的场景,开页即恢复。

前置依赖与兼容性

依赖最低版本说明
DSH≥ 0.1.0-rc.7低于 rc.7 时设置卡片加载失败(list slot ... requires options.id),必须升级 DSH
Node.js≥ 18仅在从源码手动构建时要求;通过 dsh plugin add 安装预构建包不要求
平台跨平台插件无原生模块依赖,无平台限制
原生模块引擎基于宿主进程内的内存状态,无 node-pty / sqlite 等原生依赖

安装方式

dsh plugin --profile web add github:HsiangNianian/dsh-auto-continue

配置项

配置类型说明默认值
paused布尔全局暂停:实时与扫描都不再自动发送,已排队的待发送也会取消
continueText文本中断后自动发送的消息内容,支持 {code} {tool} {message} 等占位符继续
continueTextMaxTokens文本达到输出 token 上限时自动发送的文本,支持相同占位符继续
guardTools布尔续跑前检查上一步工具调用并加护栏提示,避免重复执行
guardPendingText文本工具结果未确认时附加的提示文本,支持 {tool} 占位符(上一步工具「{tool}」可能未完成, 先确认状态再继续, 不要重复执行)
guardDoneText文本工具已成功时附加的提示文本,支持 {tool} {result} 占位符(上一步工具「{tool}」已完成, 结果: {result}; 不要重复执行, 直接继续)
graceMs数字中断后等待宿主自行恢复的宽限期,期间恢复则取消自动发送(毫秒)3000
cooldownMs数字同一会话两次自动"继续"的最小间隔,失败尝试也计入(毫秒)20000
maxConsecutive数字同一会话连续自动"继续"的上限;超过后停止,等用户介入或成功回合3
scanOnBoot布尔页面启动或重连时扫描最近中断的会话并自动续跑(如浏览器关闭期间宿主崩溃)
scanLimit数字启动扫描最多检查多少个最近更新的会话(不含运行中和子代理会话)8
freshMs数字扫描只处理该时间窗内的中断(毫秒)900000(15 分钟)
classify布尔错误分类:仅自动恢复临时性错误;认证/余额/模型不存在等永久性错误跳过并通知
backoffFactor数字连续失败时冷却间隔的倍率2
backoffMaxMs数字自适应退避上限,防止等待过久(毫秒)300000(5 分钟)
notify布尔自动继续/放弃/永久性错误时弹浏览器通知(首次会请求权限)
loopGuard布尔检测运行中的回合空转并自动取消重启
loopShortChars数字模型消息短于该字符数视为一条短句(空转信号)40
loopWindowMs数字连续短句必须落在该时间窗内才计入空转(毫秒)30000
loopShortCount数字时间窗内连续多少条短句且无工具调用时判定空转循环12
loopRepeatText数字连续多少条完全相同的消息时判定空转循环(不限长度,最强信号)4
loopToolRepeat数字同工具+同参数+同结果连续调用多少次时判定死循环5
loopText文本循环守卫打断后重启回合时发送的文本,支持 {tool} 占位符(检测到你可能陷入循环, 请停止重复刚才的动作, 换一种方式继续)
verbose布尔在浏览器控制台输出 [auto-continue] 日志

常见问题

Q: 哪些中断会触发自动续跑,哪些不会?

A: 临时性失败(网络/超时/5xx/429)会触发;达到输出 token 上限也会。用户主动停止(aborted)、策略拒绝(blocked)以及永久性错误(401/403 状态码,或匹配认证/凭据/余额/配额/模型不存在/上下文超限等关键词)一律不续跑,而是跳过并通知。

Q: 多个浏览器标签页同时打开会重复发送吗?

A: 不会。自 0.8.0 起引擎跑在宿主进程内(src/host/engine.ts),全局只有一个实例,多标签同时打开也不会重复发送;浏览器标签全部关掉引擎仍在值守。

Q: 需要重启 dsh web 才能生效吗?

A: 安装后首次启用需要重启 dsh web。之后所有改动通过设置卡片即时保存(写入 ~/.dsh/settings.yaml),保存后立即生效,已打开的页面也会刷新;如遇个别字段不生效,重启 dsh web 即可。

Q: 怎样手动关闭自动继续?

A: 打开"设置 → 插件",找到"自动继续"卡片,把全局"暂停自动继续"开关打开即可实时取消一切自动发送。需要只暂停某一个会话时,可点浏览器通知里的"暂停该会话 1 小时"按钮,或在卡片底部"已暂停会话"列表里逐个解除。

Q: 卸载插件后留在 ~/.dsh/settings.yaml 的段落需要清理吗?

A: 可以不清理。卸载插件时该段落保留在配置文件里无害;想彻底清理时手动删除 auto-continue 段落即可。

Q: 循环守卫会不会误判?会把我手动停止的回合重启吗?

A: 不会误判你手动停止。循环守卫发起的取消带有内部来源标记,引擎只对守卫取消触发自动重启,用户手动停止不会触发任何动作。阈值、时间窗、提示文本均可调,遇到误判可放宽 loopShortCount / loopWindowMs

Q: 提示文本里的占位符怎么写?

A: continueTextcontinueTextMaxTokens 支持 {code} {message} {status} {tool} {turn} {errorCount} {sessionTitle} {elapsed}。护栏文本(guardPendingText / guardDoneText / loopText)支持 {tool}{result}(结果摘要)。例如 继续 ({tool}: {code}) 会渲染成 继续 (git push: UPSTREAM)

上手难度

入门 — 安装一行命令,默认配置即可工作,需要调整时打开设置卡片对照说明修改,无需写代码。

已知问题与限制

  • reconnectScanDelayMs(重连扫描延迟,默认 5000ms)与 reconnectBackoffMs(重连退避,默认 3000ms)为遗留字段:引擎自 0.8.0 迁入宿主后不再使用,仅为兼容旧配置保留;改动这两个值不会生效。
  • 在 DSH < 0.1.0-rc.7 上安装会因 settings.plugin.item slot 不支持 keyed 注册而加载失败,需要先升级 DSH。
  • isTransientFailure 通过正则匹配错误关键词(auth、credential、api_key、balance、quota、context length 等),若上游错误信息使用不常见的措辞且未命中 401/403,可能被误归类为临时性错误触发无意义的重试——可通过关闭 classify 改为全量续跑。
  • 浏览器通知依赖浏览器 Notification API 与用户授权,被拒绝后不会再次请求。