dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Host-only DeepSeek Harness (DSH) bundle: remembers the reasoning effort last in effect per (provider, model) and restores it when a session switches back.
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.
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.
(provider, model); the value is the effort id that was
last in effect on that route.A -> B, the plugin remembers A's effort, then:
B has a remembered effort and B currently advertises it, it
re-issues one selection through ctx.sessionController.selectModel(...), so
the session's durable selection becomes { B, that effort };B keeps its own default. This is deliberate:
a first visit to a never-used model lands on that model's default.modelSelection projection at
session/created — attach time, while that projection still reflects the
stored log alone. Reading the seed from inside the event handler would be
vacuous: stateOf materializes at the session's current cursor, which
already includes the event being handled, so the seed would always equal
the event itself.reasoning
missing, or reasoningEfforts: false in settings) gets no reasoningEffort
and no error.dsh-custom-reasoning-effort) falls back to the model's default silently, with
no retry.client.js, no slot, no React, no UI.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.ctx.llm.resolveModelInfo(provider, model) is consulted
before any re-issue, because selectModel throws
UNSUPPORTED_REASONING_EFFORT for a level the target does not advertise.session/event firehose; a seq < session.firstLiveSeq guard 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.defineDomain/domainTable are identity
wrappers and the runtime calls only valueSchema.parse(raw), so the domain
spec is declared inline; a link: install does not install a linked package's
own dependencies, so a bare import of zod or
@deepseek-ai/dsh-storage-domain would not resolve.effort_memory, table efforts, key JSON.stringify([provider, model]),
record { reasoningEffort }.UNIT_NAME_RE = /^[a-z][a-z0-9_]*$/, which forbids
the hyphen — hence the domain is effort_memory while the package, the bundle
patch row id, and the exported plugin name all stay effort-memory.single-layout document lands at
$DSH_HOME/storages/effort_memory.json and survives restarts.ctx.storageDomain, memory degrades to a process-local Map (a warning
is logged at apply time) and is lost on restart.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.
| 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.
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.
selectModel path
itself (agentDefaultModel.saveSelection → settings.replace('agent-default-model', …)).
This plugin adds no settings namespace and no settings write of its own.(provider, model) — shared by every session and
workspace, as specified.agents
dependency.sessionProjections there 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.domain/changed does not cross processes.MIT © 2026 Jason Li