DSH Plugins Marketplace

DSH Plugins

Plugins

/

dsh-model-reasoning-levels

i

dsh-model-reasoning-levels

Manifest valid

Per-model reasoning effort levels inside DeepSeek Harness Settings -> Models, written to that model's reasoningEfforts in cordis.patch.yml.

UI (client)hasBundlePatch

dsh-model-reasoning-levels

Per-model reasoning effort levels inside DeepSeek Harness's Settings → Models. English | 简体中文

License Release CI Last commit Stars PRs welcome Node dsh

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.

What it contributes

SurfaceWhat 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-levelsEnglish and Simplified Chinese copy
scripts/reasoning-efforts.mjsvalidates 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.

What it looks like

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 Reasoning effort levels control appended inside a model entry on the Settings → Models page

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.

How the control reaches the row

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.

  • The row's id input carries an 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.
  • It appends one container per modelEntry and portals a React editor into it, so the control lives inside the model entry and disappears with the row.
  • A 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.

Saving, and the page's own Apply

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.

The level vocabulary is closed and ordered

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.

The conversion rules (they are the adapter's)

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:

SelectionResult
off, low, high, max with wire values{ off: null, low: 'low', high: 'high', max: 'max' }
off alonerefused — a model that cannot think uses false
nothing selectedrefused — omit the field to inherit
a non-off level with no wire valuerefused — it needs the value dispatch sends
an empty-string wire valuerefused
a level outside the sevenrefused
the "Non-reasoning" formreasoningEfforts: false
the "Inherit catalog" formthe 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 }.

Where the value lands in cordis.patch.yml

The 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

The two homes, and why the editor picks between them

llm-pi-ai carries a model entry in one of two mutually exclusive shapes:

HomeShapeThe editor's write
providers.<route>.models[]list, entries carry idreplace-by-value: the whole array
providers.<route>.modelOverrides.<id>dict keyed by model idone 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.

Requirements

  • DeepSeek Harness 0.2.0-rc.2 — the plugin declares it in engines.dsh and pins the @deepseek-ai/dsh-* peers to that line.
  • Node.js >= 22.17 and pnpm 11.8.0 to build from source.
  • A profile you can write to. On the desktop app the install path is Settings → Plugins (see Install).

Install

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.

Usage

  1. Open Settings → Models and expand a pi-ai provider card (for example the hand-declared baidu-team route, or a catalog route such as OpenAI).
  2. Under Customized settings → Models, every model row now carries its own Reasoning effort levels control. Pick the levels the model offers; each non-off level gets a wire-value field, prefilled with the level id.
  3. Use Inherit catalog to omit reasoningEfforts, or Non-reasoning for a model that cannot think.
  4. Apply. The control writes one settings mutation and reloads; the small code chip shows the exact YAML value.

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.

The CLI: preview the YAML and the op

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.

Limits

  • The llm-pi-ai adapter family only. llm-deepseek routes carry no per-model effort field, so the editor renders nothing for them.
  • Row discovery is structural. It follows the shipped page's own localized Model ID <n> label; a shipped row restructure would need the selector updated, and is what the MutationObserver re-runs on.
  • The plugin writes no YAML. It sends settings path ops and the host persists them. A read-only settings document leaves the control disabled, and a refused or conflicting write is reported in the row instead of retried.
  • Re-applying is bounded. The row restores an applied value at most three times before it reports the conflict.
  • Catalog routes need the host's catalog. Rows for a route that configures no models list come from llm/discoverModels; without it, only the routes that declare a models list can be edited.

FAQ

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.

License

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.

Comments

Loading…

Similar plugins

dsh-better-reasoning-effort

by HaoyueQin

Reasoning-effort editing for third-party models in DeepSeek Harness: per-model thinking levels with a knowledge base + protocol inference, edited inside the official Models page card.

Models & ProvidersManifest valid

★ 48

↓ 1k/wk

MIT

TypeScript

Sep 30, 2026

dsh plugin --profile web add dsh-better-reasoning-effort

by chr003

Separate per-session model and reasoning effort controls for DeepSeek Harness subagents.

Terminal & ClientsManifest valid

★ 0

MIT

JavaScript

Sep 7, 2026

dsh plugin --profile web add dsh-subagent-model-policy

✦

No screenshots

by aerince

Add models.dev reasoning levels to unconfigured third-party DeepSeek Harness models.

Themes & SkinsTools & CapabilitiesModels & ProvidersManifest valid

★ 3

MIT

JavaScript

Aug 15, 2026

dsh plugin --profile web add dsh-models-dev-reasoning

by Mu-scorpio

Configures provider and model reasoning-effort mappings for DeepSeek Harness, with a grouped model picker and composer slider.

Models & ProvidersManifest valid

★ 4

↓ 688/wk

MIT

TypeScript

Sep 15, 2026

dsh plugin --profile web add dsh-reasoning-effort

by Neptune810

Flash-only reasoning-effort routing for DeepSeek Harness, setting the DeepSeek flash model reasoning effort per step. The model never changes; effort max is opt-in.

Models & ProvidersDevelopment & InfrastructureManifest valid

★ 0

MIT

JavaScript

Sep 29, 2026

dsh plugin --profile web add @neptune810/dsh-model-router

by TTTPOB

DeepSeek Harness plugin with per-task model and reasoning-effort selection

Manifest valid

★ 0

MIT

TypeScript

Aug 22, 2026

dsh plugin --profile web add dsh-task-models