dsh-effort-memory
Manifest validHost-only DeepSeek Harness (DSH) bundle: remembers the reasoning effort last in effect per (provider, model) and restores it when a session switches back.
dsh-effort-memory
An out-of-tree DeepSeek Harness
(DSH) plugin that remembers the reasoning effort last actually in effect for
each (provider, model) route and restores it when a session switches back to
that model.
Why
The composer's model seat renders the effort from the durable modelSelection
projection. Picking a different model sends that model's own defaultEffort
(dsh-client-ui-model-selection/lib/client.js:427,883), and the host resolver
materializes the adapter default when a caller omits an effort
(dsh-llm/lib/index.js:2116-2130). So a model switch always lands on the new
model's default, and the level chosen on the model being left is not restored on
return.
This plugin closes that gap by re-issuing exactly one selection through the same public command interface the GUI calls — it appends no session events itself, registers no service, and writes no settings.
Behavior
- The memory key is
(provider, model); the value is the effort id that was last in effect on that route. - On a route change
A -> B, the plugin remembersA's effort, then:- if
Bhas a remembered effort andBcurrently advertises it, it re-issues one selection throughctx.sessionController.selectModel(...), so the session's durable selection becomes{ B, that effort }; - otherwise it does nothing and
Bkeeps its own default. This is deliberate: a first visit to a never-used model lands on that model's default.
- if
- A route change is recognized across a restart too: each session's
pre-switch route is seeded from the durable
modelSelectionprojection atsession/created— attach time, while that projection still reflects the stored log alone. Reading the seed from inside the event handler would be vacuous:stateOfmaterializes at the session's current cursor, which already includes the event being handled, so the seed would always equal the event itself. - A target model that declares no reasoning capability (resolved
reasoningmissing, orreasoningEfforts: falsein settings) gets noreasoningEffortand no error. - A remembered effort the target no longer advertises (for example rewritten by
dsh-custom-reasoning-effort) falls back to the model's default silently, with no retry. - Effort-only changes on the model already selected are never touched.
Design constraints
- Host half only. No
client.js, no slot, no React, no UI. - One lever.
ctx.sessionController.selectModel— the same public command interface the GUI calls. The plugin never appends session events itself and never rewrites in-memory selection state. - Capability first.
ctx.llm.resolveModelInfo(provider, model)is consulted before any re-issue, becauseselectModelthrowsUNSUPPORTED_REASONING_EFFORTfor a level the target does not advertise. - Loop-safe. Only a route change can trigger a re-issue, only when the event's effort differs from the remembered one, and the re-issue keeps the same route — so the event it produces cannot re-enter the rule as a change.
- Replay-safe. Constructor seeds (replay, fork, resume) never publish on the
session/eventfirehose; aseq < session.firstLiveSeqguard is kept as belt-and-braces. The pre-switch route of a session not yet seen in this process comes from the attach-time seed above, never from the projection inside an event handler. - No services, no settings, no retries. Any failure is logged and skipped; nothing is ever surfaced to the user.
- Zero runtime dependencies.
defineDomain/domainTableare identity wrappers and the runtime calls onlyvalueSchema.parse(raw), so the domain spec is declared inline; alink:install does not install a linked package's own dependencies, so a bare import of zod or@deepseek-ai/dsh-storage-domainwould not resolve.
Persistence
- Domain
effort_memory, tableefforts, keyJSON.stringify([provider, model]), record{ reasoningEffort }. - The domain name must match
UNIT_NAME_RE = /^[a-z][a-z0-9_]*$/, which forbids the hyphen — hence the domain iseffort_memorywhile the package, the bundle patch row id, and the exported plugin name all stayeffort-memory. - With the base storage stack mounted, the
single-layout document lands at$DSH_HOME/storages/effort_memory.jsonand survives restarts. - Without
ctx.storageDomain, memory degrades to a process-localMap(a warning is logged at apply time) and is lost on restart.
Install
From a checkout, by path:
dsh plugin --profile <name> add link:<absolute path to this repository>
Directly from GitHub:
dsh plugin --profile <name> add github:cup113/dsh-effort-memory
dsh plugin forwards to pnpm in the profile directory and then reconciles
dsh.profile.bundles: a dependency resolving to a package that declares
dsh.bundle joins the layer stack automatically. A new bundle row and its Node
ESM module are both loaded at boot, so restart dsh after installing or
after editing index.js.
Layout
| Path | Role |
|---|---|
index.js | Host half: event listener, service calls, storage memory (apply, inject, name) |
decide.js | Pure rules: route keys, effort normalization, the decision table |
cordis.patch.yml | The one bundle row (id: effort-memory, name: dsh-effort-memory) |
test/ | Test suites: pure layer, packaging parity, and an integration test |
_verify/ | Harness used against a live DSH: a dynamic host probe, a multi-frame session-log extractor, a mutation check |
Only the root files listed in files are the bundle; test/ and _verify/ are
inert to the Loader.
Tests
node test/all.mjs
Twenty-two assertions: the pure decision table, packaging parity (bundle row id,
package name, storage-domain name), and an integration suite that drives the
real apply() against a fake Cordis context — listener shape, event ordering,
the re-issue loop breaker, replay-seed rejection, the restart seed, and the
storage-less fallback. CI runs the same entry on
Node 20 and 22.
node --test is deliberately not used: it runs each file in a child process with
piped stdio, which a confined sandbox refuses.
_verify/mutation-check.mjs proves the decision assertions are not vacuous: with
the restore branch removed from decide.js, the canonical assertion flips.
Known limitations
- One settings write per switch is performed by the public
selectModelpath itself (agentDefaultModel.saveSelection→settings.replace('agent-default-model', …)). This plugin adds no settings namespace and no settings write of its own. - Memory is global per
(provider, model)— shared by every session and workspace, as specified. - The plugin acts on every live session whose route changes, subagent sessions
included. Restricting to root sessions would require an extra
agentsdependency. - Without
sessionProjectionsthere is no attach-time seed, so a session's first switch after a restart only establishes a baseline and is not restored; every later switch in the same process is. - A stale remembered level is kept in the domain (harmless): if a model's effort table later regains that level, it will be restored again.
- Single-process visibility only;
domain/changeddoes not cross processes.
License
MIT © 2026 Jason Li
Comments
Loading…
From the same category
by tt-a1i
Agent skill for beautiful, verifiable architecture, workflow, sequence, data-flow, and lifecycle diagrams—self-contained HTML with motion and crisp export.
★ 73.4k
↓ 5.1k/wk
MIT
JavaScript
Sep 28, 2026
dsh plugin --profile agent add @tt-a1i/archify-dshDeepSeek Harness plugin for Reactive Resume: bridges your resumes and job applications into a Harness session over MCP.
★ 41.7k
↓ 292/wk
MIT
Aug 24, 2026
dsh plugin --profile web add dsh-plugin-reactive-resumeby Tencent
Open-source LLM knowledge platform: turn raw documents into a queryable RAG, an autonomous reasoning agent, and a self-maintaining Wiki.
★ 30.9k
↓ 1.1k/wk
NOASSERTION
Go
Sep 28, 2026
dsh plugin --profile web add @wxg-prc-cpg/dsh-weknoraby anywhere-labs
为 DeepSeek Harness (DSH) 插件生态打造的现代化桌面端解决方案。万物皆「插件」,桌面本身也是「插件」。
★ 29.3k
↓ 195/wk
MIT
TypeScript
Sep 28, 2026
dsh plugin --profile web add dsh-plugin-desktopdeepseek-harness-desktop is a interface plugin for DeepSeek Harness. See the repository documentation for its documented capabilities.
★ 28.6k
MIT
by titanwings
Distilly — Distill how they think into reusable Skills for any Agent or Bot. Formerly Colleague Skill(原同事 Skill).
★ 25.1k
MIT
TypeScript
Sep 22, 2026