无人值守时自动推进会话,断网退避重试并复活目标
29.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/19 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add kenjoe41/dsh-autocontinue该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
是什么
dsh 原生插件 · chat
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 14 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件
查看扫描证据(共 13 处,展示前 12 条)
- 写入本地文件lib/index.js:263
appendFileSync(config.debugFile, `${new Date().toISOString()} ${text}\n`) - 写入本地文件lib/index.js:643
mkdirSync(join(homedir(), '.dsh', 'autocontinue'), { recursive: true }) - 读取本地文件lib/index.js:646
previous = Number(readFileSync(lastPidFile(), 'utf8').trim()) - 写入本地文件lib/index.js:650
writeFileSync(lastPidFile(), `${process.pid}\n`) - 读取本地文件lib/index.js:663
const value = JSON.parse(readFileSync(restoreStateFile(), 'utf8'))?.[sessionId] - 读取本地文件lib/index.js:675
state = JSON.parse(readFileSync(restoreStateFile(), 'utf8')) - 写入本地文件lib/index.js:680
mkdirSync(join(homedir(), '.dsh', 'autocontinue'), { recursive: true }) - 写入本地文件lib/index.js:681
writeFileSync(`${restoreStateFile()}.tmp`, `${JSON.stringify(state, null, 2)}\n`) - 写入本地文件lib/index.js:682
renameSync(`${restoreStateFile()}.tmp`, restoreStateFile()) - 读取本地文件lib/index.js:700
workspaces = await readdir(root, { withFileTypes: true }) - 读取本地文件lib/index.js:709
sessions = await readdir(workspaceDir, { withFileTypes: true }) - 读取本地文件lib/index.js:718
files = await readdir(sessionDir, { withFileTypes: true })
扫描于 2026/10/31(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-agent@deepseek-ai/dsh-llm@deepseek-ai/schemastery给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
DeepSeek Harness 支持同一会话自动续接、退避重试、目标复活和重启恢复。
README
由 DeepSeek 最新模型翻译生成dsh-autocontinue
一个 dsh 插件,让会话在无人看管时继续干活:它会自己把对话推进下去,遇到服务商或网络故障就退避重试,并且不让目标会话卡住。
版本 0.1.13 · 已在 dsh 0.2.1-rc.2 上验证。
- 为什么需要它
- 它做什么
- 快速开始
- 行为
- 1. 续跑
- 2. 故障重试
- 3. 目标复活
- 与目标轮次驱动器配合
- 可见性
- 命令
- 配置
- 安装与更新
- 踩坑笔记
Why
长时间无人值守的运行会以三种无聊的方式死掉:模型跑完一轮就停下等人;上行链路断了,这一轮以 TRANSPORT 结束;或者目标悄悄丢了激活状态——轮次驱动器在出错时解除目标,而会话恢复或分叉又故意让它保持解除状态。这三种情况下工作其实都还能接着做。这个插件负责把它接上。
What it does
| | 行为 |
| 续跑 | 已武装的会话里,智能体空闲时插件会为它排入下一轮,而不是等人来敲「continue」。 |
| 重试 | 因服务商或网络失败的一轮,默认永远重试,采用指数退避,最终稳定在固定 5 分钟间隔。 |
| 复活 | 目标不再被驱动时——失败后解除、恢复或分叉后保持解除、或者被暂停——插件会重新武装它,让目标继续推进。 |
会话武装之前,什么都不会发生(见快速开始)。
展开完整文档(README 剩余 1 节)
dsh-autocontinue
一个 dsh 插件,让会话在无人看管时继续干活:它会自己把对话推进下去,遇到服务商或网络故障就退避重试,并且不让目标会话卡住。
版本 0.1.13 · 已在 dsh 0.2.1-rc.2 上验证。
- 为什么需要它
- 它做什么
- 快速开始
- 行为
- 1. 续跑
- 2. 故障重试
- 3. 目标复活
- 与目标轮次驱动器配合
- 可见性
- 命令
- 配置
- 安装与更新
- 踩坑笔记
Why
长时间无人值守的运行会以三种无聊的方式死掉:模型跑完一轮就停下等人;上行链路断了,这一轮以 TRANSPORT 结束;或者目标悄悄丢了激活状态——轮次驱动器在出错时解除目标,而会话恢复或分叉又故意让它保持解除状态。这三种情况下工作其实都还能接着做。这个插件负责把它接上。
What it does
| | 行为 |
| 续跑 | 已武装的会话里,智能体空闲时插件会为它排入下一轮,而不是等人来敲「continue」。 |
| 重试 | 因服务商或网络失败的一轮,默认永远重试,采用指数退避,最终稳定在固定 5 分钟间隔。 |
| 复活 | 目标不再被驱动时——失败后解除、恢复或分叉后保持解除、或者被暂停——插件会重新武装它,让目标继续推进。 |
会话武装之前,什么都不会发生(见快速开始)。
Quick start
1. install into a profile (see Install and update for the why-tarball)
dsh plugin --profile web add /path/to/dsh-autocontinue-0.1.4.tgz
2. arm the current session, from the session itself
/autocontinue on
目标会话会自己武装(goalSessions: true)。那些不是由人启动会话的配置档——cron、无头模式、「被调用」——设置 enabled: true,该配置档里的每个会话都会自动武装。
Behaviour
1. Continuation
已武装会话里的智能体空闲时,插件会排入一轮:一条普通的用户消息,开头是 <autocontinue> Round n/…,告诉模型继续干,把工作区和工具结果当作权威依据,并在任务真正完成时用完成标记结束回复。对话记录读起来就是一次普通对话。
以下任一条件成立时循环停止:模型用完成标记(AUTOCONTINUE: DONE)结束回复;某一轮被中止(你按了停止——人为打断会被尊重);达到 maxRounds;或者你运行 /autocontinue off。
2. Retry through outages
默认值针对不可靠的上行链路调过——永远重试,退避到固定 5 分钟间隔:
| 连续失败次数 | 重试前等待 |
| 1 | 15 s |
| 2 | 30 s |
| 3 | 60 s |
| 4 | 2 min |
| 5 | 4 min |
| 6+ | 5 min,永久(除非设置了 maxRetries) |
每轮重试都会指明具体的失败原因,并要求模型重试失败的那个动作,而不是重头再做已完成的工作。把 maxRetries 设为 N,重试 N 次后放弃;保持 0 则无论故障持续多久都会一直重试。
如果你要改这段代码,有两个实现细节值得注意:
- 重试由 turn/end 驱动,条件是 reason.kind === 'error' —— 也就是拥有失败请求的那个 turn 边界,它携带 harness 结构化的 LlmFailure(TRANSPORT、AUTH 等)。
- agent/error 刻意不计入。失败的 turn 会先发 agent/error,再发带同一失败的 turn/end;两者都计数会让每次故障消耗两个重试额度,于是 maxRetries: 2 在一次真正的重试后就放弃了。只有 turn/end 是计数器。
3. 目标复活
目标会因为与目标本身无关的原因停止推进,而停滞的目标比失败的 turn 更糟,因为没有任何东西会重试它:
- 轮次驱动器在 agent/error 时解除目标,所以一次网络抖动就会终结目标自身的续跑;
- 会话恢复或分叉后,活跃目标按设计处于解除状态(驱动器从不自行恢复工作);
- 目标可以暂停。
开启 reviveGoals: true(默认)时,插件调用获准的 ctx.goals.resume(agent, ref) —— 它不带调用方权限门 —— 目标轮次驱动器随即收回轮次,保持目标自身的轮次记账权威。
刻意不复活的情况:
- blocked —— 这是模型或目标工具策略在声明工作无法继续。覆盖它会与 harness 自身的重复阻塞策略相冲突。
- 轮次预算已耗尽的目标 —— resume 会抛错;maxGoalRounds 是目标自己的决定,不归这个插件管。
复活次数受 maxGoalRevives 限制(默认 5),这样反复暂停目标的东西就无法与它无限拉锯;目标一旦真正开始一轮,计数器立即重置。每次复活都会在聊天中公告。
4. 重启恢复
服务器切换(dsh-update 的分阶段安装 + 重载)或崩溃会在 turn 仍打开时停掉进程:持久化日志结束在 turn/start 内部,没有 turn/end,也没有存活的智能体继续它。启动时这个插件扫描会话语料,对每个最近写入、仍结束在 turn 内部的日志,走 Web GUI 用的同一条路径(resolveAgent)重新打开会话,并排入一个恢复轮次。
这做了三件不能指望浏览器完成的事:
- harness 追加它合成的 interrupted 收尾,于是旧 turn 被配平,而不是看起来像永久运行中;
- 会话的智能体预设和模型选择被重新组合,目标会话则由目标轮次驱动器重新接手工作;
- 没有浏览器标签页的会话仍会继续运行,正因如此,切换工作区时不会把另一个工作区里的工作变成孤儿。
恢复的会话会被告知究竟发生了什么,免得它花一轮时间去自己琢磨:通知和恢复轮次都会点名持久化的断点(turn N, step M),说明这次中断属于基础设施问题——更新或崩溃——而不是对计划的裁决,并告诉模型不要调查它,也不要从头重新规划。目标会话会得到同样的解释,形式是一条随目标轮次一起下发的 autocontinue 通知。
扫描还会重建死掉的进程拥有过什么,因为恢复的模型单凭对话记录无法知道这些:
- 待处理输入。 进程退出时,harness 会持久化取消队列中的收件箱消息,所以轮次进行中输入的消息会在重启后消失。扫描会重放原始的 agent/inbox/spliced 历史,把那次关闭时取消的消息重新入队,并与仍待处理或已被接纳的输入去重(一次 steer 操作表现为一次取消加一次重新插入)。每个会话都会持久化最后处理的取消 seq,因此即使某个标签页在扫描前重新接上并追加了新的 session/end-seed,也无法用新的恢复标记掩盖关闭时的取消。
- 后台任务。 同一代中 job/registered 减去 job/settled 的结果会列在恢复轮次里。进程已经没了;把它们列出来,模型才能决定重新启动哪些。
- 子代理会话。 同一代中创建的、恢复会话的直接子会话会被列出,它们的工作不会悄无声息地变成孤儿。
- 活跃目标。 如果会话最新的 goal/change 是 phase: active 且还有剩余轮次,那么即使上一轮已完成,它也会被重新打开,这样目标轮次驱动器就能继续推进目标,而不是把它搁置到有人打开工作区为止。暂停、阻塞和已完成的目标不动。
只考虑在 resumeWindowMs 内修改过的日志,每次启动最多恢复 resumeMax 个会话,每个会话的失败都被隔离并记录日志。
恢复通知长这样:
[autocontinue] dsh server restarted mid-run (turn 3, step 12); background jobs
from the old process are gone — continuing from there
与目标轮次驱动器协作
dsh-base 总会挂载 dsh-goal-round-driver,它只在目标处于活跃状态且已武装时继续会话。autocontinue 恰好在这种状态下让位(queue skipped: an armed goal round driver owns the rounds),所以目标会话永远不会拿到双份轮次,并在驱动器退场时接管。两者互补:驱动器负责推进,本插件负责持久化。
可见性
在聊天中
通知行会出现在对话记录里,形状与 harness 用于模型切换横幅的相同:
[autocontinue] armed (profile default) — this session keeps taking rounds until the model reports completion or /autocontinue off
[autocontinue] 上一轮失败(TRANSPORT: DeepSeek Messages transport failed)—— 已排队第 2 次重试,下次退避最长 300s
[autocontinue] 目标原本处于激活/解除武装状态 —— 已重新武装(revive 1),目标继续推进
通知永远不会作为一轮排队:插件通过 agent/pre-step 钩子把它追加到当前步骤自己的消息列表里,因此它跟随下一轮执行,无法自行开启一轮。用 notices: false 让它们静默。
按需查询
/autocontinue status
报告武装状态、轮数、连续失败次数、待执行的等待、最后一次失败、目标的阶段/激活状态、谁持有这些轮次,以及复活次数。
调试追踪
debug: true 会把每个生命周期决策 —— 武装、调度、每次跳过原因、重试记账、复活尝试 —— 追加到 debugFile(默认 /tmp/dsh-autocontinue.log)。正是这个工具发现了来之不易的笔记里描述的两个 bug。
命令
/autocontinue # status for this session
/autocontinue on|off # arm / disarm this session
/autocontinue reset # zero the round, failure and revival counters
配置
每个键及其默认值。配置档补丁会替换整个 config,所以想保留的键都要重新写一遍。
| 键 | 默认值 | 含义 |
| enabled | false | 武装此配置档下的每个会话。启动器/定时任务/无头配置档请打开。 |
| goalSessions | true | 武装带目标的会话。 |
| reviveGoals | true | 重新武装已停止驱动或已暂停的目标。blocked 永不覆盖。 |
| maxGoalRevives | 5 | 放弃并报告前的连续复活次数;目标开始一轮时重置。0 = 不限。 |
| maxRounds | 0 | 每个会话的续接轮数。0 = 不限。 |
| maxRetries | 0 | 连续失败重试次数。0 = 永远重试。 |
| idleDelayMs | 0 | 空闲后到下一轮之间的宽限期。一次性启动器请保持 0(见下文)。 |
| retryBaseDelayMs | 15000 | 首次退避;每连续失败一次翻倍。 |
| retryMaxDelayMs | 300000 | 退避上限(5 分钟)。 |
| doneMarker | AUTOCONTINUE: DONE | 停止循环的精确最后一行。 |
| notices | true | 在武装/重试/复活时发布聊天通知行。 |
| debug | false | 把决策追踪追加到 debugFile。 |
| debugFile | /tmp/dsh-autocontinue.log | 追踪写入的位置。 |
| resumeUnfinished | true | 启动时,重新打开日志结束于未闭合轮次内的会话,并排队一轮续接。 |
| resumeDelayMs | 5000 | 重启扫描前、以及续接轮排队前的稳定等待时间。 |
| resumeWindowMs | 86400000 | 只考虑在此时间窗内修改过的日志用于续接。0 = 不限时间窗。 |
| resumeMax | 5 | 每次启动最多续接的中断会话数。0 = 不限。 |
| resumeDryRun | false | 只记录重启扫描会续接什么,不重新打开任何东西。 |
| resumeGoalSessions | true | 即使会话最后一轮已完成,只要目标仍有效,就重新打开该会话。 |
| restorePendingMessages | true | 恢复因关闭而被取消的用户消息,并在恢复后排队。 |
| resumeJobLimit | 5 | 恢复提示词中点名的未完成后台任务数量。0 = 仅提示。 |
| resumeSubagentLimit | 5 | 恢复提示词中点名的子代理会话数量。0 = 仅提示。 |
cron 或 headless 配置档通常需要: yaml
<profile>/cordis.patch.yml
- id: autocontinue
config:
enabled: true
goalSessions: true
reviveGoals: true
maxGoalRevives: 5
maxRounds: 0
maxRetries: 0
idleDelayMs: 0
retryBaseDelayMs: 15000
retryMaxDelayMs: 300000
doneMarker: 'AUTOCONTINUE: DONE'
notices: true
安装与更新
每次改动都要提升 package.json 里的 version。 这个包从 GitHub、打包好的 tarball 或链接的 checkout 安装;提升版本号才能回答「实际跑的是哪个构建?」,也让插件管理器的记录保持准确。
从 GitHub 安装: sh
dsh plugin --profile <profile> add github:kenjoe41/dsh-autocontinue
or pin a release
dsh plugin --profile <profile> add github:kenjoe41/dsh-autocontinue#v0.1.13
从本地 checkout 安装(维护者): sh
from this directory
pnpm pack --pack-destination /tmp
dsh plugin --profile <profile> add /tmp/dsh-autocontinue-<version>.tgz
让 peerDependencies 与运行时保持一致(dsh -V):peer 不匹配时,插件管理器会拒绝安装,并回滚配置档。
如果配置档链接的是这个目录,改动在下次重载时生效,无需重新打包: sh
dsh plugin --profile <profile> add /path/to/dsh-autocontinue
踩坑记录
在 dsh 0.2.1-rc.2 上实测,下面每一条都花掉一轮调试:
- sessionQuery.observeSession 无法告诉你会话被中断了。 这个查询读取时会在内存里平衡未闭合的尾部(合成 turn/end 收尾),所以扫描它的事件只会看到干净的日志,什么也恢复不了——第一版重启恢复构建就这样只找到 2 个中断会话中的 0 个。要通过 ctx.sessionPersistence.open(id, 'read') 读原始日志;harness 自己的恢复路径也是用同样的读法跑 interruptedTurnClosers。
- 重新连接的标签页会在 5 秒扫描跑起来之前就恢复会话。 标签页 attach 时会追加 harness 合成的 turn/end,其 reason.kind === 'interrupted',所以只检查未闭合的 turn/start 恰好会漏掉浏览器已经半恢复的会话。把最后一轮以 interrupted 结束(之后没有新的 turn/start)的日志视为仍需一轮恢复,也不要因为已有智能体在运行就跳过该会话。
- 关闭会持久地取消待处理的收件箱输入。 agent/inbox/spliced 条目带 outcome: 'canceled',就是排队消息丢失的方式;一次 steer move 产出的形状相同(下一轮移除 canceled,随后在下一步插入同一条 message id),所以一次 cancel 并不能证明消息丢失。只有当被取消的消息既不在 pending 中、也不在 user/message 事件里时,才恢复它。必须读原始持久化日志:投影和 observeSession 都只显示平衡/已取消状态。
不要把最后一个 session/end-seed 当作恢复截止点——标签页可能在重启后几毫秒内重新挂载,它新写入的标记会把截止点推到扫描要找的那次 cancel 之后(第一个 pending-message 恢复测试就是这样失败的)。改为持久化已处理的 cancellation seq。
- 以 tarball 安装(或用 shim 链接),绝不要用裸目录。 link: 安装会让 Node 从包的真实路径解析 @deepseek-ai/dsh-llm,该路径在配置档之外,插件在 import 时就会报 Cannot find package '@deepseek-ai/dsh-llm' 而挂掉——就会话而言,这是静默失败。本包自带 node_modules/@deepseek-ai/{dsh-llm,schemastery} shim,所以链接安装也能解析。
- 一次性启动器必须把 idleDelayMs 设为 0。 无头运行在智能体空闲且收件箱为空的那一刻就会销毁整棵插件树;留 200 ms 宽限期时,定时器从未触发。设为 0 后,这一轮会在空闲转换内部入队,运行得以继续。待处理的一轮刻意不做成 unref 的定时器,因此它会保持进程存活。
- 不要通过 agent.inbox.prepend('next-step', …) 投递通知。 在 agent.followup() 之后立刻发出的通知会与正在组装的那一步竞争,然后被无声丢弃(arm 通知之所以幸存,只是因为发出时智能体仍处于空闲)。改为在 agent/pre-step 中追加到该步的消息列表。
- 一次失败,一次重试额度。 见 Retry through outages;agent/error 和 turn/end 描述的是同一次失败。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
kenjoe41/dsh-autocontinue
无人值守时自动推进会话,断网退避重试并复活目标
相关插件 · 对话 / 记忆
上下文中枢oceanbase/powercontext
上下文跟着工作走 —— 跨会话、跨智能体、跨人。
★ 1,462已汉化DSH
73
智能体记忆库plastic-labs/honcho
Honcho 是记忆基础设施,用来构建有状态的智能体。这些智能体能理解不断变化的人、智能体、群组、项目和想法。
★ 7,848已汉化DSH
71.7
长程智能体控制面loopx-project/loopx
给 Agent 一个目标,让工作持续向前。
★ 6,358已汉化DSH
71.3
智能体上下文数据库volcengine/OpenViking
给 AI 智能体用的上下文数据库
★ 41,246已汉化DSH
71.3
长效机器人团队Fei2411/DS-Bot
DS Bot 是一个基于 DeepSeek Harness简称 dsh的 bot 插件,插件将 dsh 改造为 bot…
★ 4,717已汉化DSH
71.1
可携带记忆层EverMind-AI/EverOS
为什么选择 EverOS
★ 13,711已汉化DSH
71.1