Releases: shengyvself/dsh-autoresume
Release list
v0.1.5
dsh-autoresume v0.1.5 — 缺陷 A/B 修复
两个分类 bug 修复(用户明示「绝对的 bug」):
缺陷 B:用户手动停止触发自动继续
根因:turn/end kind='aborted' 是驱动主动收尾(cancel 的 finally 写出 turn/end、边界闭合),与「环境杀死进程」(turn/end 缺失、open turn)本质不同。旧分类器见 openStep / 无结果 tool/call 一律判 interrupted 并注入「继续」,等于推翻用户指令。全量取证:133 个 aborted/user 事件全数无悬挂边界——旧代码靠「边界恰好闭合」这一巧合才未误注入,保证脆弱。
修复:① 悬挂边界只在轮次仍打开(openTurn)时计入可继续判据;闭合轮次一律按 turn/end 原因判定。② 新增显式 aborted 分支判 settled(动因 user/disposed),位置在 reasons 判定之后——上一个 aborted 后若又起新轮次并被环境杀死,仍判 interrupted 继续。
顺带消除:闭合轮次 + 悬挂 tool/call 旧判 interrupted 并注入;新按 turn/end 分流(网络 error → network-stopped 不变,completed → 不注入)。
缺陷 A:工具调用被中断于「记录为开始」之前自动继续完全不生效
根因:宿主补写 ToolNotStartedError 的 tool/result("interrupted before the Harness recorded it as started. Retry it if it is still needed."),上一条 assistant/message 是未执行的工具请求,轮次并未结束。旧代码见 lastType === 'assistant/message' 一律判 completed,不设例外。
修复:新增 messageHasToolCall(message)——lastType === 'assistant/message' 且不含 tool-call 块时才判 completed;含 tool-call 块落到 open turn 判定接手续跑。
验证
node --checksrc + lib:通过- build src → lib:64715 bytes 一致
tests/manual-stop.test.mjs:12/12 PASS- 全量:26/26 PASS(14 既有 + 12 新增)
- 负向对照:回退 3 处改动 → 4 PASS / 8 FAIL(8 项正是缺陷 A/B 回归用例)
- 全量回放:147 会话 / 110,439 事件,新旧分类并跑,状态分布完全一致(completed=100, settled=43, interrupted=2, pending-input=2)——零行为回归
安装
npm install https://github.com/shengyvself/dsh-autoresume/releases/download/v0.1.5/dsh-autoresume-0.1.5.tgz
兼容性
- DSH >= 0.1.5-rc.2
@deepseek-ai/cordis>= 4.0.1- 配置无变更(未新增配置项)
Asset
dsh-autoresume-0.1.5.tgz · 40686 bytes · SHA256 770c75ebd72e16c951215728920f5f5443b696fe1ab3a5db3f16d621f6208dca
v0.1.4 — align to npm + visual assets
What changed
- package.json version 0.0.21 → 0.1.4 (align to npm sequence 0.1.0-0.1.3)
- Dark-mode adaptive banner via
<picture>+prefers-color-scheme: dark - GitHub social-preview OG card (1200×630) for social sharing
- Decision flow workflow diagram (triggers → classify → guards → inject → result)
- README.md + README.zh.md updated to use banner + workflow.svg
Visual assets
| Asset | File | Purpose |
|---|---|---|
| Banner (light) | assets/banner.svg | Hero area, light theme |
| Banner (dark) | assets/banner-dark.svg | Hero area, dark theme |
| Social preview | assets/social-preview.svg | GitHub OG card |
| Workflow | assets/workflow.svg | Decision flow diagram |
npm publish: npm publish
v0.0.21 — 0.1.5 adaptation fixes
v0.0.21 — 2026-09-13
0.1.5 adaptation fixes: inspect removal + AgentSetup callback + queue guard
What's Fixed
- 0.1.5 SessionPersistence.inspect() removal: DSH 0.1.5 removed the inspect() method. New inspectSession() uses open('read') + handle.read() to read session events without breaking the persistence contract.
- 0.1.5 AgentSetup callback signature: The callback now receives (agentCtx, agent) instead of just (agentCtx). Fixed 3 setup closures to use the two-arg form.
- Queue guard (skipWhenInputPending): Prevents injecting auto-resume messages when user messages are queued in the inbox. Uses persistent spliced-inbox analysis + live agent.inbox check.
DSH 0.1.5-rc.2 Adaptation
- Session format v3: session.v3.jsonl.zstd (was session.jsonl.zstd)
- Enumerates by generation, taking the highest available format
Tests
- tests/inspect-open.test.mjs: 4/4 PASS (static guards + end-to-end)
- tests/pending-input.test.mjs: 27/27 PASS (generation selection, inbox folding, queue guard, regression)
- node --check all green, build src==lib verified
Install
[WARN] Tarball download average speed 43 KiB/s (size 46 KiB) is below 50 KiB/s: https://codeload.github.com/shengyvself/dsh-autoresume/tar.gz/9943ef170feefcec44738b398ba01c0d2410a596 (GET)
✓ Lockfile passes supply-chain policies (verified 1h ago)
[WARN] Tarball download average speed 41 KiB/s (size 46 KiB) is below 50 KiB/s: https://codeload.github.com/shengyvself/dsh-autoresume/tar.gz/9943ef170feefcec44738b398ba01c0d2410a596 (GET)
Packages: +178
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 178, reused 176, downloaded 1, added 178, done
[WARN] Issues with peer dependencies found. Run "pnpm peers check" to list them.
dependencies:
- dsh-autoresume github:shengyvself/dsh-autoresume
Done in 7.7s using pnpm v12.3.4
v0.0.19 — README cross-platform fixes (docs only)
Highlights
- README cross-platform fixes (docs only, no source change). User report: "the plugin intro has problems — not everyone is on Linux."
What was wrong
The plugin's source is already cross-platform — process.env.HOME ?? os.homedir() + node:path give identical behavior on Windows / Linux / macOS. But the README had three Unix/Linux assumptions that confused non-Linux users:
~/.dsh/sessions— the~shorthand is Unix-only (Windows uses%USERPROFILE%)- Unix
/path separators (Windows uses\) - Install / restart commands that only work on Linux:
mkdir -p node_modules/@deepseek-ailn -sfn /usr/lib/node_modules/@deepseek-ai/dsh/node_modules/@deepseek-ai/dsh-agent node_modules/@deepseek-ai/dsh-agentsudo systemctl restart dsh-web
What changed
- Cross-platform callout at the top of README:
<home>= user home directory (Linux/macOS:~, Windows:%USERPROFILE%), auto-resolved by Node'sos.homedir(). - All
~/.dsh/sessions→<home>/.dsh/sessions; the behavior section now notes thatnode:pathhandles separators per-platform automatically. - Install section split into two code blocks:
bash(Linux/macOS):mkdir -p+ln -sfnunchangedpowershell(Windows):New-Item -ItemType Directory -Force+mklink /D, with the DSH global install dir discovered vianpm root -ginstead of hardcoding/usr/lib/
- Restart section now lists all three platforms in parallel:
sudo systemctl restart dsh-web(Linux systemd)brew services restart dsh-web(macOS Homebrew)Restart-Service dsh-web(Windows admin PowerShell)
Diff
README.md— +39 / -5 (install & restart sections rewritten, cross-platform callout added)CHANGELOG.md— +5 (new0.0.19entry)package.json—0.0.18→0.0.19src/service.js/lib/service.js— unchanged (docs-only patch)
Validation
node --checkon all 5 JS files — pass- Privacy scan regex (
/home/ubuntu | world-Shengyv | narrative | ox-alpha | 考研 | 111.231 | shengyv.cn | 4ecb3d7d | ShengyvServer.pem) — 0 hits tar tzf dsh-autoresume-0.0.19.tgz | grep -cE '\.bak|\.broken'— 0 (no backup files leaked into the tarball)
Install
npm install shengyvself/dsh-autoresume@0.0.19Or from the release asset: dsh-autoresume-0.0.19.tgz (18.6 KB, SHA256 81e0782cf28997dff16fbeb1b9f29443c282d4341acf524faf5df4789b7608e1).
Notes for contributors
If you find further platform-specific wording in this repo, please open an issue — this is the second such report in two months, so it's worth treating as a general lint check on any new README/CHANGELOG edit.
v0.0.18 — maxResumeAttempts=2 (double-resume on SenseNova quota exhaustion) + new 429 forms + v0.0.17 backport
Highlights
- Continuous 2-time auto-resume for SenseNova (
maxResumeAttempts, default2,failStreakcounter): SenseNova's daily quota window is long and often produces two consecutive 429s (rpm exhausted/inference exceeds tpm/rpm limit). Previously the loop-guard converted tosettledafter a single no-output retry. Now network-class failures allow one more injection before settling (inject → fail → inject → fail → stop). Balance failures (isBalanceFailure) remain single-shot — the v0.0.15 infinite-loop guard is unchanged. - New 429 forms recognized:
type=quota_exceeded_error(code="8", messagerpm exhausted),type=rate_limit_error(code="429001", messageinference exceeds tpm/rpm limit), and messages containingtpm exhausted/rpm exhausted/429001. - v0.0.17 backport:
insufficient_quotamoved fromBALANCE_LLM_CODEStoRETRYABLE_LLM_CODES(SenseNova uses this code for tpm/rpm rate limiting, not persistent balance shortage);RATE_LIMIT_MESSAGE_PATTERNadded for message-level arbitration against QUOTA-wrapped 429 envelopes (the persisted form: outercode=QUOTA+ inner429: {"message":"inference exceeds tpm/rpm limit",...}).
Two fixes explained
1. Continuous 2-time resume (v0.0.18, 2026-09-08)
SenseNova's daily quota produces long rate-limit windows. The old loop-guard fired on lastOursSeq > -1 && lastTurnEnd > lastOursSeq && !assistantAfterOurs — i.e. one injection with no progress → settled. With maxResumeAttempts=2 the new predicate is:
const continuedThenFell =
lastOursSeq > -1 && lastTurnEnd > lastOursSeq &&
(balanceFailed || failStreak >= maxResumeAttempts);failStreak increments on each no-output retry; resets to 0 when any assistant or tool output appears after the injection (re-arming). Balance failures bypass failStreak — they settle after a single failed retry, preserving the §五十四 402-loop guard.
2. New 429 forms + QUOTA wrapper arbitration (v0.0.17, 2026-09-02)
Three paths previously failed to detect the SenseNova tpm/rpm limit:
insufficient_quotawas inBALANCE_LLM_CODES(but blocked byisNetworkFailure's gate first, and the balance/limit semantics conflict) → moved toRETRYABLE_LLM_CODESrate_limit_errorwas not inRETRYABLE_LLM_TYPES→ added- message
inference exceeds tpm/rpm limitdid not matchNETWORK_FAILURE_PATTERN→ added
The persisted form is a QUOTA-wrapped 429: outer code=QUOTA (ambiguous — could be balance or limit), with the real 429 body nested inside the message. isBalanceFailure now checks RATE_LIMIT_MESSAGE_PATTERN first — if the message contains any of 429|too many requests|rate[-_ ]?limit|rate_limit_error|tpm\/rpm|insufficient_quota, the error is reclassified as non-balance (injectable). Balance semantics are still enforced via BALANCE_LLM_CODES (QUOTA / insufficient_balance / payment_required) and the 402 pattern, so the §五十四 infinite-loop guard is preserved.
Validation
node --checkonsrc/service.js,lib/service.js,src/client.js,lib/client.js,scripts/build.mjs— all passbuild—srcandlibidentical (md5492a3f16..., no rebuild needed)- Scenario matrix (per CHANGELOG 0.0.18): 18/18 PASS
- A (new forms, 5 cases):
rpm exhaustedin all shapes / message only / type only / 429001 / bareinsufficient_quota→network-stopped - B (double-resume, 4 cases): inject→fail 1×→still
network-stopped(2nd allowed); inject→fail 2×→settled; inject→tool/text output→fail→network-stopped(re-armed) - C (balance loop-guard, 3 cases): QUOTA first fail→inject; inject→fail again (with or without output)→
settled - D (regression, 6 cases):
UNKNOWN_MODEL/CTX/429/service_unavailable/completed/QUOTA-wrapped 429
- A (new forms, 5 cases):
- DSH restart verification per CHANGELOG (PID change, Result=success, 3× HTTP 200)
Diff
package.json— version0.0.16→0.0.18CHANGELOG.md— +2 entries (0.0.18,0.0.17)README.md— 2 new feature highlights + config tablemaxResumeAttemptsrowcordis.patch.yml— new defaultmaxResumeAttempts: 2src/service.js/lib/service.js— 68 lines added / 40 removed (identical)RETRYABLE_LLM_CODES+=insufficient_quotaRETRYABLE_LLM_TYPES+=quota_exceeded_error,rate_limit_errorBALANCE_LLM_CODES-=insufficient_quota- new
RATE_LIMIT_MESSAGE_PATTERN(rate-limit message arbitration) NETWORK_FAILURE_PATTERN+=rpm exhausted,tpm exhausted,rate_limitanalyzeSessionEvents(...)signature: addedmaxResumeAttempts = 2parameter- new
failStreakcounter +positiveInt(config.maxResumeAttempts, 2)default
Install
npm install shengyvself/dsh-autoresume@0.0.18Or from the release asset: dsh-autoresume-0.0.18.tgz (17.9 KB, SHA256 7f7ffbef03621cf30d50b23a291cf4b442fd32990126eef90752622b68f5aee3).
v0.0.10
v0.0.10
Highlights
- Permanent automatic watch (
bootGraceMsdefault → Infinity): the plugin now watches indefinitely by default, covering sessions stuck longer than the previous 30-minute grace window (e.g. a session stopped by a network error 14h+ ago is resumed against on this process's boot). - Deeper error-envelope unwrapping +
429/service_unavailablerecognition: multi-level{error:{...}}and failure-payload envelopes are peeled correctly; 429 and "service unavailable" style responses are treated as retryable network failures and trigger auto-continue. - Adds the model-selection-on-self-resume fix for the
{{model}}assembly error path (subagent first-turn). - Sample config no longer hardcodes
bootGraceMs(server default is the Infinity permanent watch; opt-out via an explicit value). - Note: v0.0.10.x release describes the trigger-scenario UX; this tag is the code state.
Install
npm install dsh-autoresume@0.0.10
v0.0.9
v0.0.9
Authoritative server build.
Highlights
- Global interrupted-session scan: on boot, scans all sessions whose last event-stream state is an open/interrupted turn and resumes them.
- Network-failure auto-continue: sessions stopped by network/transient failures (
EMPTY_RESPONSE/RATE_LIMIT/SERVER/TIMEOUT/TRANSPORT, or a message matching network patterns) get a继续(自动)injected once. Config/model errors (e.g.UNKNOWN_MODEL,MISSING_CREDENTIAL) stay untouched. liveWatch(default true) + dead-loop guard: keeps polling after boot (mtime-changed sessions only) and re-injects on mid-session transient failure; the guard settles (stops injecting) if a post-inject message produces no progress and fails again with the same network error — prevents infinite empty-return loops.- Marketplace hygiene:
@deepseek-ai/dsh-agentmoved to peer-only per marketplace guideline. - Version numbering fixed: this lineage is
v0.0.9(legacyv0.1.xfrom initial releases ==v0.0.3of this lineage).
Install
npm install dsh-autoresume@0.0.9
v0.0.16 — ctx.agents inactive-context guard + 402/balance loop fix (v0.0.15 backport)
Highlights
Two independent fixes shipped together as one maintenance release:
v0.0.16: ctx.agents inactive-context guard (boot crash fix)
DSH 0.1.2-alpha.3 plugin tree load fails when ctx.agents.get() runs before the plugin context becomes active / service injection settles — cordis inactive context throws a fatal load failure (journal: 13 restart loop observed). Fix: defensive helper getAgent(sessionId) wraps try/catch, logs warn, returns undefined; checkOnce()/injectIfIdle() use it. Settles gracefully, next 5s poll retries. Mirrors the prompt-polish ctx 服务访问 try/catch 降级 pattern.
v0.0.15 (backport): 402 / balance failure infinite-loop guard
Two root causes for the observed 真没余额后自动继续无限循环 (401860fc reproduced 9 times):
assistant/chunkusage/finish(LLM billing/shutdown metadata) was miscounted as "progress after inject" — loop-guard never fired. Fix: only real output blocks (text-delta/reasoning-delta/tool-call-delta/block-start/block-end) count (newPROGRESS_CHUNK_TYPES).- Balance failures (
402/QUOTA/insufficient_balance/payment_required) are persistent, not transient. Fix: newBALANCE_LLM_CODES/BALANCE_FAILURE_PATTERN/isBalanceFailure()— inject once, thensettledon subsequent balance failure. First 402 still injects (covers "post-topup recovery").
Plus:
NETWORK_FAILURE_PATTERNgains\b400\b(tokenrhythm fallback400 status code (no body)) + Chinese transient features (模型服务暂时不可用/请稍后重试/当前繁忙/ etc.).- New
PERMANENT_LLM_CODESexcludesUNKNOWN_MODEL/MISSING_CREDENTIAL/NO_ADAPTER/INVALID_MODEL_INFO/CONTEXT_WINDOW_EXCEEDED/MODEL_NOT_FOUND— keeps v0.0.12 regression baseline (e.g.CONTEXT_WINDOW_EXCEEDEDsettles even when its message contains400 status code (no body)).
Validation
- DSH web restart verified: journal clean (no
cannot get required service "agents", noinactive context, nostatus=1),[dsh-autoresume]logs normal, stable across 60s. - Restart executed by server-ops per protocol (this release commit does not self-restart).
- Replay 401860fc event stream: first 402 →
network-stopped(inject once); second 402 →settled(loop cut). Real recovery succeeded — turn 13 produced normal output. - Regression matrix 19/19 PASS (transient 429/5xx/upstream-with-output still injectable; first 402 still injects;
completed/aborted/interrupted/UNKNOWN_MODEL/emptyunaffected). - 400 + Chinese transient matrix 16/16 PASS.
Diff
5 files, +212 / −21. node --check clean, build src → lib md5 3c1733df... matches.
Install
npm install dsh-autoresume@0.0.16Then rebuild your profile (dsh plugin --profile web add <path>) — the inactive-context guard is automatic; no config changes required.
版本历史
GitHub 可见 Releases:v0.0.9 / v0.0.10 / v0.0.11 / v0.0.12 / v0.0.13 / v0.0.14 / v0.0.16(各带 tgz 资产)。
早期版本 v0.0.2 ~ v0.0.8 为 legacy 编号期:CHANGELOG.md 有逐版本文字记载,但 git 历史无独立 commit(源码不可追溯),故无 tag/Release(不补造);v0.0.10.1(docs-only)与 v0.0.15(并入本版 backport)无独立 Release。完整变更见 CHANGELOG.md,下载见 Releases 页。
v0.0.14 — double-inject guard + assistant/chunk + inject# audit
dsh-autoresume v0.0.14 — 2026-09-01
修复「双注入」bug(核心)
dsh-web 崩溃循环(如会话日志文件损坏导致的连续重启失败)后,一个会话被注入两条「继续(自动)」——先后两个进程各注入一次,造成重复执行。
根因
死循环守卫原本只覆盖「网络错误」路径;当注入「继续」后模型尚未产生任何内容(流式推理块或工具调用都还没有)进程就被再次杀死,新进程重扫时会话尾部呈 interrupted 形态,与「用户手动重启打断」无法区分 → 误判为可恢复 → 再次注入。
修复
- 新增 interrupted 分支循环守卫:若「我们上次注入后零产出即再次被打断」,判定为环境噪音(进程死亡/重启循环)→ 转
settled不再注入,把决定权交还用户; assistant/chunk(流式推理块)计入「注入后进展」——模型已开始产出内容再被打断,仍视为真实中断并正常续跑,不误伤;- 注入日志带
inject#<唯一 id>,跨进程审计可精确定位「同一进程第几次注入」与「不同进程各注入一次」。
判定健壮性
- 守卫逻辑基于持久化会话事件流判定(不依赖进程内存态),跨进程/跨重启一致生效;
- 真实中断(注入后已有产出或工具调用)不受影响,照常自动继续。
顺带修复
agentOptions自动注入到ctx.agents.resume(),修复 sidechat.start 子代理首轮装配报prompt variable "{{model}}" has no value的隐性 race。
验证
- 13/13 场景矩阵 PASS(双注入守卫两路 + assistant/chunk 计入 + agentOptions 透传;回归 loop-guard / UNKNOWN_MODEL / network-stopped / 真实中断四路全绿)。
- 与
ARCHITECTURE.json架构版本 0.0.58 联动。
安装
npm install dsh-autoresume@0.0.14完整 changelog
详见仓库 CHANGELOG.md。
v0.0.13
v0.0.13
Highlights
- "Provider returned error" recognized as transient upstream failure: the
NETWORK_FAILURE_PATTERNnow matchesprovider returned error— the standard wording OpenRouter returns for an upstream provider outage (e.g. minimax). pi-ai adapter buckets itPI_AI_ERROR; it is a transient upstream fault that can recover on the same provider shortly after, and sessions stopped by it now get a继续(自动)injection. - Verified against a real session that spent 78s with no output, ending in
PI_AI_ERROR: Provider returned error(previouslysettled, no injection); a manual same-provider继续moments later succeeded — confirming it is transient and should be auto-injected. - Scenario matrix 14/14 PASS (real failed session →
network-stopped→ injected + self-resumed; loop-guard /UNKNOWN_MODEL/completed/TRANSPORT/ 504 nested envelope / open-turn regressions all green).
Install
npm install dsh-autoresume@0.0.13