dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Per-model reasoning effort levels inside DeepSeek Harness Settings -> Models, written to that model's reasoningEfforts in cordis.patch.yml.
Per-model reasoning effort levels inside DeepSeek Harness's Settings → Models. English | 简体中文
Model Reasoning Levels — the reasoning-effort control each model entry is
missing, written straight into that model's reasoningEfforts in the profile's
cordis.patch.yml.
The shipped Models page edits a model's id, display name, context window,
max-output tokens and input types, and deliberately edits no reasoning
effort: effort is a per-model capability while that editor is per-provider.
This plugin adds the missing control inside each model entry — directly
under the id/name line, or under the expanded context-window/input-types area —
and converts the selection into the model's reasoningEfforts in the profile's
cordis.patch.yml.
| Surface | What it does |
|---|---|
settings.models.provider-card (keyed llm-pi-ai) | reaches each pi-ai provider card, discovers its model rows, and portals a per-model effort editor into every model entry — hand-declared routes included |
Locale namespace dsh-model-reasoning-levels | English and Simplified Chinese copy |
scripts/reasoning-efforts.mjs | validates a selection and prints the reasoningEfforts YAML and the settings path op it becomes |
Browser half only: the host half (exports["."]) exists so the Loader row can
carry the browser half (exports["./client"]). No route, no service, no Config.
Settings → Models → Baidu Team → Customized settings → Models
┌─────────────────────────────────────────────────────────────┐
│ [deepseek-v4.1-flash] [DeepSeek-V4.1-Flash] ⌄ 🗑 │
│ Reasoning effort levels Inherited │
│ [Off] [Minimal] [Low] [Medium] [High] [XHigh] [Max] │
│ Low wire value: low High wire value: high │
│ [Inherit catalog] [Non-reasoning] [Apply] { off: null, … } │
└─────────────────────────────────────────────────────────────┘

The control inside one model entry: the seven level chips, one wire-value field
per selected thinking level, Inherit catalog / Non-reasoning / Apply,
and the exact reasoningEfforts value the current selection becomes.
The shipped page declares no seat inside a model row, and its ModelRow is
an internal component. The only sanctioned row-level change is shadowing the
whole settings.section models entry — a shadowed copy of the page. This plugin takes
the narrower path instead: it owns the provider-card seat, then discovers each
model row structurally.
aria-label built from the shipped page's own
settings.models locale namespace (Model ID 1, 模型 ID 1, …). The plugin
binds that namespace and matches the label, so discovery follows the active
language and never depends on a hashed CSS class name.modelEntry and portals a React editor into it,
so the control lives inside the model entry and disappears with the row.MutationObserver re-runs discovery when the fold opens, a row is added or
removed, or the page re-renders. A shipped row restructure would need the
selector updated.The editor writes through the settings transport (settings.mutate path ops);
the host persists the result. The shipped page keeps its own draft of the
model list and its own Apply writes the whole models array for a hand-declared
route, which can restore the reasoningEfforts value the card loaded at open.
To keep the editor's value authoritative, the row remembers the declaration the user applied and, if a later settings change reverts it, writes it again — up to three times, so a refusal is reported instead of retried forever. Applying the effort and then using the card's Apply for another field therefore converges on the effort value you chose.
For a catalog route the editor uses the narrow
providers.<route>.modelOverrides.<id>.reasoningEfforts path, which the page's
model editor does not touch — unless the page materializes a models array (by
editing the model list), which the adapter refuses beside modelOverrides. The
row's re-apply covers that case while the card is open.
off, minimal, low, medium, high, xhigh, max — exactly the harness's own
THINKING_LEVELS, in escalation order. The editor always emits the map in that
order, whatever order the chips were clicked. off means "do not think"; the
other six are thinking levels.
Each chosen level becomes a key whose value is the spelling dispatch sends, so a
gateway with its own vocabulary can be renamed (max: ultra). The plugin
enforces @deepseek-ai/dsh-llm-pi-ai's resolveModelReasoning rules before the
write:
| Selection | Result |
|---|---|
off, low, high, max with wire values | { off: null, low: 'low', high: 'high', max: 'max' } |
off alone | refused — a model that cannot think uses false |
| nothing selected | refused — omit the field to inherit |
a non-off level with no wire value | refused — it needs the value dispatch sends |
| an empty-string wire value | refused |
| a level outside the seven | refused |
| the "Non-reasoning" form | reasoningEfforts: false |
| the "Inherit catalog" form | the field is unset, restoring inheritance |
A declared map replaces the model's capability set: levels not declared are
not offered. That is why off must be present in the map when the user keeps
it, and why "off only" is false rather than { off: null }.
cordis.patch.ymlThe editor writes settings path ops; the host persists them into the profile's
cordis.patch.yml. reasoningEfforts sits beside the fields the shipped row
already edits:
- id: llm-pi-ai
name: "@deepseek-ai/dsh-llm-pi-ai"
config:
providers:
baidu-team:
models:
- id: deepseek-v4.1-flash
reasoningEfforts: { off: null, low: 'low', high: 'high', max: 'max' }
contextWindow: 1000000
maxTokens: 256000
input: [text, image]
name: DeepSeek-V4.1-Flash
The expanded spelling is equivalent and easier to hand-edit:
reasoningEfforts:
off:
low: 'low'
high: 'high'
max: 'max'
A model that cannot think, and one that keeps the installed catalog capability:
- id: acme-plain
reasoningEfforts: false # no selector beyond off
- id: acme-catalog
contextWindow: 128000 # reasoningEfforts omitted -> inherits
llm-pi-ai carries a model entry in one of two mutually exclusive shapes:
| Home | Shape | The editor's write |
|---|---|---|
providers.<route>.models[] | list, entries carry id | replace-by-value: the whole array |
providers.<route>.modelOverrides.<id> | dict keyed by model id | one narrow path: reasoningEfforts only |
The adapter refuses modelOverrides beside a models list, on a hand-declared
route, and for an id the installed catalog does not describe. So the editor uses
models when the route configures one (or is hand-declared), and the minimal
modelOverrides path when the catalog describes the route and no models list
exists. For models, the complete array is materialized so one edited entry
never deletes the rest of the catalog; a narrow modelOverrides write pins
nothing else on the entry.
The editor reads the list the way the page does — the user layer when it owns
models, else the composition base, else the schema default — and loads the
installed catalog through llm/discoverModels (no endpoint I/O for a catalog
provider) when neither declares a list. It never quotes the resolved value
into a write.
0.2.0-rc.2 — the plugin declares it in engines.dsh
and pins the @deepseek-ai/dsh-* peers to that line.This repository ships TypeScript source only — lib/ is gitignored — so build
the bundle before installing it:
git clone https://github.com/icrefin/dsh-model-reasoning-levels.git
cd dsh-model-reasoning-levels
pnpm install
pnpm build # tsc -> lib/, tsdown -> lib/client.js
sh scripts/install.sh # packs dist/ and prints the install path
sh scripts/install.sh --profile <profile> # or pack and install into that profile
scripts/install.sh packs dist/dsh-model-reasoning-levels-<version>.tgz and
prints what to do with it. With --profile <profile> it installs the tarball
into a CLI-managed profile instead of printing instructions.
The desktop profile is owned by the Electron application, so install the tarball
from Settings → Plugins (a plugin-manager tool works too); dsh plugin add
refuses that profile. Adding a bundle to a running profile needs a restart;
the client half additionally needs the page reloaded.
The development suite runs the same checks:
pnpm check # typecheck both halves, build, then vitest
pnpm yaml check --levels off,low,high,max --wire low=low,high=high,max=ultra
pnpm check typechecks the host and the browser halves separately, builds the
bundle and runs the suite — 50 tests in 5 files.
baidu-team route, or a catalog route such as OpenAI).off level gets a wire-value field, prefilled with the level id.reasoningEfforts, or Non-reasoning for
a model that cannot think.llm-deepseek routes have no per-model field — their effort is route-scoped —
so this editor renders only for the llm-pi-ai adapter family.
node scripts/reasoning-efforts.mjs check --levels off,low,high,max --wire low=low,high=high,max=ultra
node scripts/reasoning-efforts.mjs yaml --route baidu-team --model deepseek-v4.1-flash \
--levels off,low,high,max --wire low=low,high=high,max=max
node scripts/reasoning-efforts.mjs ops --route acme --model acme-think --overrides \
--levels off,high --wire high=high
node scripts/reasoning-efforts.mjs none --model acme-plain
pnpm yaml is the same script. --json prints machine-readable output. Exit
code 1 means the selection is invalid and the reason goes to stderr.
llm-pi-ai adapter family only. llm-deepseek routes carry no
per-model effort field, so the editor renders nothing for them.Model ID <n> label; a shipped row restructure would need the selector
updated, and is what the MutationObserver re-runs on.models list come from llm/discoverModels; without it, only the routes
that declare a models list can be edited.The value I applied disappeared when I used the page's own Apply.
The shipped page keeps its own draft of the model list, and its Apply writes the
whole models array for a hand-declared route — restoring the reasoningEfforts
value the card loaded when it opened. The row notices and writes your value
again, up to three times; if it reports the conflict instead, reload the card
and apply once more.
A level the model used to offer is gone from its selector. A declared map is the model's whole capability set: levels the map does not list are not offered. Add the level back here, or choose Inherit catalog to drop the declaration and keep the installed catalog entry's capability.
Why is off on its own refused?
A model that can do nothing but "do not think" is a non-reasoning model, and the
adapter spells that reasoningEfforts: false. Use Non-reasoning. Inside a
map, off means "send nothing when this level is asked for", so it belongs
beside at least one thinking level.
The control does not appear in a model row.
Check the route: only llm-pi-ai cards get it. If the row's id field is empty,
save the model first — an editor with no model id has nothing to address, and
says so.
MIT — see LICENSE.
If this plugin saves you from hand-editing one more YAML patch, a ⭐ star helps other DSH users find it.
An independent plugin for DeepSeek Harness — not affiliated with DeepSeek.