@jayyuen66/dsh-session-rescue
Automatic recovery when a turn ends badly: resume after a transient failure, continue after output truncation, re-run after an unfinished todo list, plus a request-level 429 backstop and a client dock with edit-resend, manual retry and stop-and-re-ask.
Install
dsh plugin --profile web add @jayyuen66/dsh-session-rescue
Sandbox test
This plugin has not been tested yet. Submit a test →
README
<p align="center">
<img src="https://cdn.jsdelivr.net/gh/JayYuen666/dsh-session-rescue@main/icon.svg" width="96" height="96" alt="dsh-session-rescue logo" />
</p>
<h1 align="center">dsh-session-rescue</h1>
<p align="center"><em>When a turn ends badly, the session picks itself back up: auto-resume after transient failures, auto-continue after truncation, catch-up for open todo lists — plus manual rescue actions below the input box.</em></p>
<p align="center">
<a href="https://www.npmjs.com/package/@jayyuen66/dsh-session-rescue"><img src="https://img.shields.io/npm/v/@jayyuen66/dsh-session-rescue?style=flat-square&logo=npm&logoColor=white" alt="npm version" /></a>
<a href="https://www.npmjs.com/package/@jayyuen66/dsh-session-rescue"><img src="https://img.shields.io/npm/d18m/@jayyuen66/dsh-session-rescue?style=flat-square" alt="npm downloads (total)" /></a>
<a href="https://github.com/JayYuen666/dsh-session-rescue/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/JayYuen666/dsh-session-rescue/ci.yml?branch=main&style=flat-square&label=ci" alt="ci" /></a>
<img src="https://img.shields.io/badge/license-MIT-4c1?style=flat-square" alt="MIT" />
<img src="https://img.shields.io/badge/node-%3E%3D24.9-4c1?style=flat-square&logo=nodedotjs&logoColor=white" alt="node" />
<img src="https://img.shields.io/badge/dsh-%5E0.2.1--rc.5-658EFF?style=flat-square" alt="dsh" />
<a href="https://github.com/deepseek-ai/deepseek-harness"><img src="https://img.shields.io/badge/powered_by_dsh-4D6BFE?style=flat-square&logo=deepseek&logoColor=white" alt="powered by dsh" /></a>
</p>
<p align="center">
<img src="https://skillicons.dev/icons?i=typescript,nodejs,react,vitest,githubactions" alt="tech stack" />
</p>
<p align="center">
<a href="https://github.com/JayYuen666"><img src="https://img.shields.io/badge/GitHub-JayYuen666-181717?style=flat-square&logo=github&logoColor=white" alt="GitHub" /></a>
<a href="mailto:cqwkkj@gmail.com"><img src="https://img.shields.io/badge/Email-cqwkkj@gmail.com-EA4335?style=flat-square&logo=gmail&logoColor=white" alt="Email" /></a>
<a href="https://twitter.com/JayYuen666"><img src="https://img.shields.io/badge/Twitter-X%2FJayYuen666-000000?style=flat-square&logo=x&logoColor=white" alt="Twitter/X" /></a>
<a href="./README.zh-CN.md"><img src="https://img.shields.io/badge/lang-简体中文-658EFF?style=flat-square" alt="简体中文" /></a>
</p>
A dsh plugin: three automatic user-role injections when a turn ends badly (transient failure / max-tokens truncation / an open todo list), a request-level 429 backstop, and a client dock with manual rescue actions and a settings card. Zero model tools, zero HTTP routes of its own.
<img src="https://api.iconify.design/lucide/file-text.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> Contents
- [What it does](#what-it-does)
- [How a decision is made](#how-a-decision-is-made)
- [Install](#install)
- [Shared version floor](#shared-version-floor)
- [Verify it is live](#verify-it-is-live)
- [What it does not provide](#what-it-does-not-provide)
- [Enabling it in dsh](#enabling-it-in-dsh)
- [The three automatic actions](#the-three-automatic-actions)
- [Settings](#settings)
- [Public interface](#public-interface)
- [Data and privacy](#data-and-privacy)
- [Known boundaries](#known-boundaries)
- [FAQ](#faq)
- [Development](#development)
- [License](#license)
<img src="https://api.iconify.design/lucide/shield.svg?color=%23658EFF&height=22" height="22" width="22" align="absmiddle" alt="" /> What it does
- Three automatic injections when a turn ends badly, each with its own delay / cooldown / quota gates (
lib/resume-scheduler.ts, cooldowns tracked per kind): - resume —
agent/errorwhose failureclassifyFailure(lib/failure-classify.ts) judges transient; the message lands afterresumeDelayMs. - continue — the turn ended with
reason.kind === "max-tokens"; "continue from the truncation" lands aftercontinueDelayMs. - unfinished — the turn ended
completed, but the todo list that turn itself wrote still holds open items (lib/turn-review.ts, a purely structural signal, no text guessing); the catch-up message lands afterunfinishedDelayMs. - Every injection is a
role: "user"message withsource: { kind: "plugin:session-rescue" }sent throughagent.followup()— the model keeps running, so tokens and quota keep being spent. - A request-level 429 backstop, engaged only when the host resolved no
retryPolicyfor that provider: it listens onagent/request-error(waterfall) and returns{ kind: "retry" }on rate limiting, so the host re-sends that request inside the same turn. - Fixed backoff ladder (defaults 2 s / 5 s / 10 s / 20 s / 30 s, at most 5 retries per session — deployment values); a provider
Retry-Afterwins over the ladder, and anything above the cap is not waited out but delegated back tonext(). The counter resets when the turn closes. - When a policy exists the official
llm-retryowns the retry (code filtering, provider retry-after, jitter, durable events). The deepseek adapter resolves a policy even when none is configured, so this ladder only ever engages for adapters that resolve none. - A client dock below the input box: edit-resend (this session) / fork-resend (new branch) / stop-and-reask / manual retry and continue-output / a countdown banner / a per-session switch. Stop-and-reask queues your re-ask first and then cancels, so the message survives the cancel; the manual retry stays disabled while the host's built-in retry is still in progress.
- Connection-aware: an injection whose send failed (transport trouble) is suspended instead of dropped, shown as a reconnecting banner, and re-armed with its remaining delay once the connection returns.
/statepolling is a self-scheduling two-tier loop: 1 s while a pending
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::9,最后更新 2026-11-05