Bundle
dsh-continue
Fail-closed network recovery, recommended answers, and safe unattended continuation for DeepSeek Harness.
- Source
- JuwanXu
- stars
- 1 stars
- License
- MIT
- Updated
- Updated 5 days ago
Readme
# dsh-continue
中文说明:[docs/README.zh-CN.md](./docs/README.zh-CN.md)
`dsh-continue` is an opt-in DeepSeek Harness plugin for safe unattended task continuation. It combines deterministic recovery after downstream retries, exact `(provider, model, error-code)` adaptive network learning, task-scoped configuration injection, and narrowly bounded automation for unique recommendations, binary continue prompts, valid Plan Mode exits, and plain-text continuation. It is designed for projects where transient interruptions and routine low-risk questions should not require someone to watch every turn.
The 0.2.x feature set also includes `/continue status`, `/continue explain`, pause/resume controls, durable activity and learning events, project-scoped decision memory with task-scope fallback, verified manual-decision provenance, suggest-only continuation candidates, configurable retry budgets, and fail-closed safety boundaries. Task session overrides take precedence over plugin defaults; unknown, ambiguous, risky, or unverified input is delegated to the official UI. Learning is off by default, and Continue never uses an LLM to guess what a question or error means.
Every executable capability is **off by default**. Installation alone changes no task interaction, retry, learning, or approval behavior.
## How Continue differs from related plugins
Choose `dsh-continue` when the primary problem is task-level recovery and safe unattended handling of routine questions. The projects below overlap in retry or continuation terminology, but they solve different layers of the problem.
| Related plugin | Primary focus | What Continue adds or deliberately does not do |
| --- | --- | --- |
| [`@syncended/dsh-retry`](https://www.npmjs.com/package/@syncended/dsh-retry) | Generic and transient model-error retries, provider filters, exponential backoff, and `Retry-After` | Continue is a task-level continuation layer: it first delegates request recovery, then handles configured network failures, recommendation prompts, binary continuation, and Plan Mode transitions. It does not replace generic model-error retry. |
| [`dsh-client-auto-continue`](https://www.npmjs.com/package/dsh-client-auto-continue) / [`dsh-auto-continue`](https://github.com/HsiangNianian/dsh-auto-continue) | Web UI interruption recovery by sending a configured “continue” follow-up, with adaptive backoff, loop detection, and idempotency guards | Continue uses deterministic DSH events and structured state, does not blindly send a generic user message, and adds exact route learning, verified decision memory, recommended answers, Plan Mode handling, and fail-closed risk boundaries. |
| [`@linxin666/dsh-chat-recovery`](https://www.npmjs.com/package/@linxin666/dsh-chat-recovery) | Manual Web UI recovery by editing the previous message, forking a session, and retrying a failed turn | Continue automates only eligible recovery and decisions without rewriting history or forking; ambiguous or risky cases still return to the user. |
| [`@deepseek-ai/dsh-llm-retry`](https://www.npmjs.com/package/@deepseek-ai/dsh-llm-retry) | Official exact-provider agent-loop retry with durable retry events and bounded/always policies | Continue gives this lower-level retry path first refusal, then handles the higher-level network/decision workflow after it declines. It adds task policy, learning, and safety controls rather than duplicating provider retry events. |
These comparisons describe scope, not endorsements; check each project for its current release behavior. Continue never approves privileged or irreversible actions and never uses an LLM to guess what a question or error means.
`dsh-camel` is complementary rather than a comparison target here: install both when a project needs Camel's free-model `RATE_LIMIT` protection and Continue's non-rate network recovery or safe unattended decisions. By default, Camel owns rate limits and Continue owns `TIMEOUT`, `TRANSPORT`, and `SERVER` recovery.
## Install
After the package is published to npm, add it to a profile:
```sh
dsh plugin --profile <profile-name> add dsh-continue
```
It can be installed with `dsh-camel`. No `commands`, `settings`, `systemPrompt`, or Plan Mode service is required for the base plugin to load; an unavailable optional service disables only its corresponding integration.
## Quick start and presets
Use a task command for a one-task override:
```text
/continue preset recommended
/continue preset resilient
/continue preset unattended-safe
```
The presets are ordinary task patches. They never enable learning.
| Preset | Enables |
| --- | --- |
| `recommended` | unique explicit recommended-option selection |
| `resilient` | transient network recovery and recommended-option selection |
| `unattended-safe` | `resilient`, binary continue confirmation, valid Plan Mode exit, and narrow plain-text continuation |
For a smaller explicit policy:
```text
/continue set {"network":{"enabled":true},"recommended":{"enabled":true}}
/continue set {"continuation":{"enabled":true,"autoConfirmContinue":true}}
```
## Configuration and task injection
Precedence is always:
```text
task session override > plugin global defaults > built-in values
```
Set global defaults in the plugin row of `cordis.patch.yml`:
```yaml
- id: continue
config:
defaults:
network:
enabled: true
mode: bounded
maxRetries: 5
recommended:
enabled: true
continuation:
enabled: false
```
A launcher, preset, or another plugin can inject an isolated policy for one task:
```ts
ctx.continue.setTaskConfig(agent, {
network: { enabled: true },
recommended: { enabled: true },
})
```
The patch is copied and written as a version-1 `continue/config` event. It survives resume and is inherited by a fork. `null` resets an override. Legacy version-1 config and control events remain replayable.
All input is schema- and runtime-validated. Unknown fields, invalid bounded retry policies, unsafe counts, oversized local timer delays, a multiplier below 1, and overlapping affirmative/negative labels are rejected.
## Commands and control
When the optional `commands` service is available:
```text
/continue status
/continue set <JSON object>
/continue off
/continue reset
/continue preset <recommended|resilient|unattended-safe>
/continue pause [<Nms|Ns|Nm|Nh>]
/continue resume
/continue explain
/continue learn <on|off|status|candidates|approve <candidate-id>|forget <record-id|--all>>
```
`pause` stops Continue-owned waiting, plain-text steering, structured automatic answers, and Plan Mode auto-approval for the task; `resume` re-enables eligible automation. `status` prints the effective policy, pause state, learning resolution, storage scope, and latest activity. `explain` reports the last automatic/delegated/blocked decision. `off` writes explicit false switches; unlike `reset`, it cannot re-inherit enabled global defaults.
## Network recovery and Camel coexistence
Built-in network codes are `TIMEOUT`, `TRANSPORT`, and `SERVER`. `RATE_LIMIT` is deliberately excluded and is delegated to `dsh-camel`. Continue handles it only if the task or global policy explicitly adds `RATE_LIMIT` to `network.codes`; this configuration logs an ownership-overlap warning, so configure exactly one retry owner for that code.
Classification is deterministic, in this order:
1. an unclaimed `RATE_LIMIT` is delegated to Camel;
2. an explicitly configured network code is transient;
3. configured permanent code, then permanent HTTP status;
4. configured retryable HTTP status;
5. optional message-pattern fallback (permanent patterns before retryable patterns);
6. unknown failures pass through.
On a matching transient failure, Continue first gives downstream middleware, including `dsh-llm-retry` and Camel, the chance to recover. If downstream already returns `{ kind: 'retry' }`, Continue returns it unchanged and writes no retry event. Otherwise it writes the standard `llm/retry` and `llm/retry-started` events using `policyKey: "dsh-continue:network:v1"`, waits, then retries.
The default backoff is 2 seconds, multiplier 2, local cap 60 seconds, and `mode: unlimited` once network recovery is enabled. Use `mode: bounded` with `maxRetries` for a limit. A valid provider `Retry-After` wins when enabled and is capped only by the Harness/Node single-timer limit (`2147483647ms`). Cancellation, unload, `pause`, or an ineligible policy change stops the wait. A persisted wait keeps its original deadline, preventing duplicate retry schedules.
### Adaptive network learning
Network adaptation is separately configurable under `learning.network`. If `network.enabled=true` and no explicit learning-frequency or delay control is supplied, it uses safe adaptive defaults: increase ratio `2`, decrease ratio `0.75`, recovery streak `3`, state TTL `7d`. An explicit `learning.enabled=false` or `learning.network.enabled=false` disables it. Task settings override global settings.
Learned delay state is isolated by the exact `(provider, model, error-code)` triple. If the provider/model route cannot be verified (including a missing model), Continue safely uses static backoff and neither reads nor writes learned network state.
A recovery is recorded immediately only after the durable `assistant/message` for the same turn, step, provider, and model arrives. The latest `continue/network-learning` snapshot is authoritative: if it is malformed or expired, Continue logs once and uses static backoff rather than reviving an older learned delay.
## Automatic decisions and safety boundary
`recommended.enabled=true` selects only a unique option ending in `(Recommended)` or `(推荐)`. `onMissingRecommendation` is `ask` by default; `first` is only for interchangeable low-risk choices, and `stop` fails the unattended flow when a recommendation is absent.
`continuation.enabled=true` plus `autoConfirmContinue=true` accepts only a single-choice binary continue/stop question with exactly one configured affirmative and one configured negative label. `autoApprovePlan=true` only exits an active Plan Mode through the official state transition, for a plan that has a non-empty `#` heading. Plain-text continuation additionally requires `plainTextFallback=true`, a current-turn whitelist match, and no risk-pattern match; it is capped at one steer per turn by default.
All automatic paths fail closed to the official UI when the agent is not a verifiable live root, the turn/question shape is incomplete, a selection is ambiguous, a question is multi-select or free-form, a limit is reached, or any text matches the risk boundary. The plugin never approves `approval/request`, sandbox or privilege escalation, credentials, payments, external sends, releases/deployments, production actions, or irreversible operations. It never invents business data.
## Controlled learning and project storage
Learning is off by default. `/continue learn on` enables the task learning master switch and decision-learning switch; if network recovery is also enabled, leave `learning.network.enabled` explicitly `false` when adaptive network learning is not wanted.
Decision memory is for exact, eligible, verified manual selections only. Records use confirmation and conflict tracking, expire by TTL, and have a maximum-use limit. The raw Harness `tools/post-execute` hook exposes no trustworthy human-confirmation provenance, so it fails closed by itself. A host UI may provide a `continueManualDecisionSource` service implementing the exported `ContinueManualDecisionSource` interface; only results that its `verify(exec, result)` method authenticates are trained. The verifier must use trusted UI-side state, not merely inspect answer shape. Missing, rejecting, or throwing verifiers never train, and plugin-generated answers are excluded independently.
Set `learning.decisions.scope` to `project` to use the optional `@deepseek-ai/dsh-settings` peer. The plugin registers its settings namespace once per runtime and reuses it across agents. Project identities are hashed; missing, read-only, invalid, or failing settings storage degrades to task scope with a visible status reason. `/continue learn forget` reports success for project scope only after the empty snapshot is stored. If that write fails, the command returns an error, status reports `projectForget.state: "failed"`, and the current runtime blocks old project memory fail-closed; it does not claim that an erase survives restart.
Continuation-pattern candidates are always suggest-only. View them with `/continue learn candidates`; only `/continue learn approve <candidate-id>` can add an eligible candidate to this task's plain-text patterns. Approval never bypasses the risk boundary.
## Events, migration, and examples
Public session events are append-only and versioned:
| Event | Purpose |
| --- | --- |
| `continue/config` | task override or reset |
| `continue/control` | pause or resume |
| `continue/network-learning` | adaptive network snapshot |
| `continue/decision-learning` | task decision-memory snapshot |
| `continue/pattern-candidate` | suggest-only candidate lifecycle |
| `continue/activity` | latest automatic, delegated, blocked, cancelled, or learned activity |
Version 1 config/control events continue to replay. To migrate from earlier releases, keep existing task events, upgrade the package, and explicitly opt into any new capability. Do not add `RATE_LIMIT` to both Camel and Continue. For an existing global profile, start with `recommended`, then `resilient`, and only enable `unattended-safe` after reviewing project-specific question and risk patterns.
Example task policy with project decision scope but no network adaptation:
```text
/continue set {"network":{"enabled":true},"learning":{"enabled":true,"network":{"enabled":false},"decisions":{"enabled":true,"scope":"project","minConfirmations":2,"ttlMs":2592000000,"maxUses":50}}}
```
Install
dsh plugin --profile web add github:JuwanXu/dsh-continue
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-continue from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.