deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:drscrewdriver/dsh-thinking-levels
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
Per-round thinking-level (reasoning_effort) control for DeepSeek Harness (dsh): pick Auto (a mask) in the session model selector and the plugin schedules low / high / max from the recent tool-call history before submitting the API effort — or fix a wire level (off / on / minimal / low / medium / high / xhigh / max) manually. Cheap tool rounds stay cheap; heavy work never starves.
v0.7.0-beta.1 (2026-09-06): the short-circuit route is retired. This release no longer depends on
dsh-llm-openai-completions— custom-gateway fixes ride the officialllm-pi-aicompat surface (requires dsh ≥ v0.1.2-alpha.1); keep the adapter plugin uninstalled. See the CHANGELOG.
▼ DSH version support
This release (4.0.0) supports DSH v0.2.0-rc.1 to < 0.2.1 only.
DSH version Status Notes ≥ 0.2.0-rc.1 ✅ Supported This release (4.0.x): same declarative settings surface ( .volatile()schema fields rendered by the host; cross-plugin reads/writes through theconfigFormsservice), with the peer gate retargeted to the 0.2.0-rc segment≥ 0.1.7-rc.1 to < 0.2.0 ✅ Supported Use the 3.x line (3.4.3, npm dist-tag dsh-0.1.7): declarative settings — the host renders the Plugins form from the plugin's.volatile()schema fields; cross-plugin reads/writes go through theconfigFormsservice< 0.1.7-rc.1 ⚠️ Not supported DSH 0.1.7 removed the imperative settings registration and the per-plugin card seat the earlier lines (3.0.x and below) relied on — stay on plugin 3.0.2 for 0.1.2–0.1.6 hosts. The boundary is
0.1.7-rc.1, where DSH removed the imperative settings registration (settings.register/installSettingsSection) and the clientsettingsScopeservice. Since that boundary the runtime-adjustable config fields are marked.volatile()in the schemastery schema, the host generates the settings form from that schema alone (no registration call, no client settings card), and the plugin reads the live values per request, driven byloader/volatile-update. The 3.1.x–3.4.x lines target the 0.1.7 declarative surface; the 4.0.x line is the same surface retargeted to the 0.2.0-rc segment.
Version-range policy: every compatibility line pins its host segment tightly. Lines targeting 0.1.x hosts follow
>=0.1.x-rc.1 <0.1.(x+1)-0(3.1.x:>=0.1.7-rc.1 <0.1.8-0; 3.0.x:>=0.1.5-alpha.1 <0.1.6-0; 2.0.x:>=0.1.2-alpha.1 <0.1.3-0; 1.0.0-beta:>=0.1.0-rc.8 <0.1.2-alpha.1); lines targeting the 0.2.x segment follow>=0.2.0-rc.1 <0.2.1-0(4.0.x:>=0.2.0-rc.1 <0.2.1-0). No line ever declares an open upper bound, so a compatibility resolver can never match a plugin line against a newer host segment it was not built for. 0.4.0–0.6.0 carried no dsh peer declarations at all and are effectively compatibility-untyped — do not install them.
Compatibility note: Version
0.6.0includes Japanese (ja) and Korean (ko) dictionaries and selector entries, but the current official DSH releases expose onlyzhandenthroughLocaleRuntime. On stock DSH, selectingjaorkofails withlocale "<id>" is not registered. These languages will work after official DSH adds the locale IDs. Advanced users can use a DSH fork that updatespackages/client/locale/src/locale-settings.ts(LOCALE_IDS) andpackages/client/locale/src/client/index.ts(LOCALESlabels), together with the corresponding core dictionaries and tests, then rebuild and run the forked DSH. Changing this plugin alone cannot extend DSH's global locale list.
In a multi-step tool chain, the model re-thinks before every tool call — and that thinking dominates the wall-clock time (a 50-step agent task can spend minutes reasoning between tools). dsh-thinking-levels plugs into the agent/request waterfall that dsh re-resolves for every step (registered with prepend so the session model-selection assembly cannot overwrite its decision) and injects a thinking level into the next model request.
Screenshots of the live UI (dsh web):
| Level | Meaning | Where |
|---|---|---|
off |
thinking disabled (manual only — never auto-picked) | model selector / default level |
on |
thinking enabled (toggle-only models only): sends enable_thinking, never a think effort |
model selector / default level |
minimal |
least effort (very light tasks) | model selector / default level |
low |
manual pick for simple chat tasks (cheap rounds stay cheap) | model selector / default level |
medium |
medium effort | model selector / default level |
high |
the official default effort | model selector / default level |
xhigh |
extra high effort | model selector / default level |
max |
heavy work | model selector / default level |
auto |
mask: schedule per step from the recent tool-call history, resolved to a wire level before submission | model selector (injected by the plugin) / default level |
Wire-level facts (verified against the official DeepSeek docs and dsh's llm-deepseek adapter): low maps 1:1 on deepseek-v4-flash / v4-pro, while medium / xhigh collapse onto high. The adapter accepts off | low | high | max and rejects anything else with UNSUPPORTED_REASONING_EFFORT — auto is the plugin's mask layer, never sent to the API, always resolved to a concrete wire level before injection. on is not an effort level: it is advertised only by toggle-only models (Qwen3.6-style), and it only flips enable_thinking true — no reasoning_effort is sent; an effort-capable model never advertises on, so a manual on pick on one is stripped.
For hand-declared llm-pi-ai models, map each level to the exact value your gateway expects (borrowed from dsh-thinking-effort): tick a level and enter its wire value, e.g. high → ultra. The mapping is stored as the model's reasoningEfforts table in the llm-pi-ai config, so the Composer selection High sends ultra to the gateway. Leaving off empty means "do not send".
Off / High / Max (official DeepSeek style)Off / Low / Medium / HighThe visual editor for this mapping rode the plugin's settings card, which the DSH 0.1.7 migration removed (the seat no longer exists). Edit the
reasoningEffortstable through the official Models settings surface instead — the host-side detection and injection read it live either way.
The composer tool-row quick control (next to the model/effort select) edits a context window limit: preset stops 64K / 128K / 256K / 400K / 512K / 1M, a custom integer input, and a clear button. The value is written to the llm-pi-ai model entry contextWindow (integer 2000–1000000) — or to the llm-deepseek entry for official DeepSeek models.
Upstream, the harness consumes it through resolveModelInfo(...).context.contextWindow for compaction thresholds, context-overflow detection and context-pressure projections. Because llm-pi-ai re-reads the live config on every resolve and the compat sync does not block model discovery, a settings edit takes effect on the next request without a restart.
The plugin config also accepts models['provider/model'].contextWindow as a validated (integer 2000–1000000) declaration at the composition/config surface.
The plugin never sends a reasoning_effort to a model that does not advertise one. Custom
openai-completions routes (e.g. a local Qwen3.6 without reasoningEfforts) are classified
non-reasoning via ctx.llm.resolveModelInfo, and any effort — inherited or scheduled — is
stripped instead of sent, so dsh's per-request UNSUPPORTED_REASONING_EFFORT rejection
cannot fire. Unsupported fields are never passed to an API that cannot take them.
Version behavior:
| dsh version | low handling |
|---|---|
| rc.6 (old) | not native: the selector only shows it when a configurer-confirmed models override names it; the level is then advertised (selector + request validation) and passed through verbatim |
| rc.7+ (new) | native: the plugin neither rewrites nor re-injects it; a manual low pick passes through unchanged |
The auto scheduler may still pick low for supporting models — the capability guard above is
what keeps it away from models that cannot take it.
The session model selector (next to the model) now offers Auto after the wire levels (injected into the model-directory metadata by the plugin):
| Model-selector pick | Behavior |
|---|---|
| Auto | plugin schedules via tool history + the upgrade/downgrade toggles, resolves to low / high / max before submission |
off / on / minimal / low / medium / high / xhigh / max |
manual choice wins — plugin does not intervene (on stays on on toggle-only models, never lifted to an effort; effort-capable models strip it) |
| unset | the plugin's default level applies (below) |
The hub is high (the official default). auto schedules between low / high / max; it never picks off.
| Recent tool calls | Level |
|---|---|
| none (fresh prompt, pure chat) | low |
| ≥75% simple tools, small args, downgrades allowed | low |
| mixed / heavy tools | high |
| very heavy payloads, upgrades allowed | max |
The scheduling policy is the same source as dsh-tool-turbo (same simple-tool whitelist / payload thresholds / 75% ratio rule).
See INSTALL.md for the full official-CLI guide (profile discovery, upgrade, migration, verification, troubleshooting). Quick start:
# 1. install the plugin into a profile from npm (web shown; any profile works)
# (the web profile is a pnpm workspace root, so -w is required)
dsh plugin --profile web add dsh-thinking-levels -w
# GitHub alternative:
# dsh plugin --profile web add https://github.com/drscrewdriver/dsh-thinking-levels.git -w
# local-path alternative (no network needed):
# dsh plugin --profile web add /absolute/path/to/dsh-thinking-levels
# 2. restart dsh web (a running instance does not hot-load new bundle layers)
dsh web
Note: the dsh runtime uses pnpm 11, whose
minimumReleaseAgesupply-chain policy may block a freshly published version withERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION— add the version tominimumReleaseAgeExcludein~/.dsh/profiles/web/pnpm-workspace.yamlto lift the cooling period.
Manual link: registration (alternative to dsh plugin add):
# ~/.dsh/profiles/web/package.json dependencies:
# "dsh-thinking-levels": "link:<absolute path to dsh-thinking-levels>"
# ~/.dsh/profiles/web/cordis.patch.yml:
# - insert:
# - id: thinking-levels
# name: dsh-thinking-levels
cd ~/.dsh/profiles/web && pnpm install && dsh web
Two surfaces share one schema:
config: in the profile composition (e.g. cordis.yml):config:
level: auto # off | on | minimal | low | medium | high | xhigh | max | auto — the default level when the session picks nothing
allowDowngrade: true # let the scheduler drop below `high`
allowUpgrade: false # forbid the scheduler lifting to `max`
.volatile() config fields (enabled, level, allowDowngrade, allowUpgrade): DSH 0.1.7 renders the Plugins settings form from the declared schema, and committed changes reach the plugin as live config references (loader/volatile-update) — they apply to the next model request, no restart needed. (models stays a configurer-level field: edit it in the profile composition.)Per-model capability overrides (models, keyed provider/model) confirm what auto-detection
finds; the configurer has the final word:
config:
level: auto
models:
llm-pi-ai/Qwen3.6-35B-A3B: # non-reasoning thinking model (thinking toggle + budget)
vision: false
thinking: true
efforts: false # never send reasoning_effort (stripped at request time)
llm-pi-ai/Qwen3.8-27B: # effort-capable model (rc.6-era adapter without low)
efforts: [low, high] # confirm low → advertised in the selector + passed through
For Qwen thinking on/off + budget, configure the llm-pi-ai route instead:
compat.thinkingFormat: qwen(→ wireenable_thinking+thinking_budgetviathinkingBudgets), orqwen-chat-template(→chat_template_kwargs.enable_thinking) for effort models like Qwen3.8-27B.
Defaults: { enabled: true, level: 'auto', allowDowngrade: true, allowUpgrade: false, models: {} }.
Semantics: the model-selector pick outranks the plugin's default level. Pick
auto(mask) → plugin schedules; pick a wire level → applied directly; pick nothing → the plugin'sleveldefault is used.allowDowngrade/allowUpgradeconstrainautoscheduling only.
Once custom gateways (vLLM / LM Studio / self-hosted OpenAI-compatible proxies) declare
thinking, this plugin writes the fixes into the official llm-pi-ai compat surface
(introduced in dsh ≥ v0.1.0-rc.8, commit 884f7b9c41) —
dsh-llm-openai-completions
is no longer needed and should stay uninstalled:
llm-pi-ai.providers for routes that are custom openai-completions gateways
(api: openai-completions or a non-official baseURL) and declare a reasoningEfforts
table on any model (including modelOverrides), then writes:compat.supportsDeveloperRole: false — the system prompt goes out as
system, fixing the vLLM / SGLang Unexpected message role 400;compat.thinkingFormat: 'qwen-chat-template' on toggle-style thinking rows
(thinking table without row-level supportsReasoningEffort) — pi-ai then sends
chat_template_kwargs.enable_thinking (bare vLLM servers ignore the top-level
enable_thinking of the plain qwen format);settings.update('llm-pi-ai', …)), so dsh's schema validates the write where it is
written: a dsh older than rc.8 rejects the fields with a log warning — no silent
misconfiguration; explicit values on any layer are never clobbered;llm/adapters-updated, and llm-pi-ai config changes — no
manual config editing;<think> splitting remains a gateway concern: bare vLLM needs
--reasoning-parser qwen3 (pi-ai parses only reasoning_content / reasoning /
reasoning_text).The host half does not value-depend on @deepseek-ai/dsh-settings — since the DSH 0.1.7 line there is no settings registration at all: the settings form is generated by the host from the plugin's declared schemastery schema (.volatile() fields), and the client half talks to the configForms service provided by the dsh runtime. No need to install official packages into the profile manually. dependencies is just @deepseek-ai/schemastery (installed automatically with the package).
npm run lint # eslint (typescript-eslint flat config)
npm run typecheck # tsc --noEmit
npm test # vitest — 46 tests
Test coverage: level policy (manual pass-through incl. the extended levels, on clamping, auto scheduler, validation, simple-tool boundary), the model-capability guard (reasoningEffortSupported, resolveEffortInjection stripping/passthrough), session-event parsing (guards, window cap, malformed records), the config schema (defaults lockstep, out-of-band rejection, models overrides), and the official-compat sync (identification, explicit-value respect, identity idempotence, write-time schema gating).
MIT
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。