DeepSeek Harness Plugin

qingmomo233/dsh-thinking-language

Stars ★ 4 Category Sessions & Messages Added 2026-08-29

Switch the language of the agent's thinking/reasoning process (chain-of-thought): 简体中文, English, Русский, Français, Deutsch, Español, 日本語, 한국어 and more, or auto-follow the system locale. Adds a Settings → General row, a system-prompt instruction (per-prompt assembly, applies to new sessions), and the /thinking-language command.

Install

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:qingmomo233/dsh-thinking-language

Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).

README

简体中文 | 🌐 English

dsh-thinking-language

A DeepSeek Harness plugin that lets you switch the language of the agent's thinking/reasoning process (chain-of-thought). Supports Chinese (Simplified and Traditional), English, Russian, French, German, Spanish, Arabic, Portuguese and Japanese, or "auto" to follow the system locale.

What it does

  • A settings page of its own — Settings → Thinking language is a page with a single row: the title and its hint on the left, one selector pill (dropdown menu) on the right — the same shape as the built-in Language / Permission rows.
  • Prompt injection — when a language is selected the plugin injects a system-prompt instruction telling the model to write its internal reasoning in that language. With Follow the system (auto) the instruction uses the system UI locale (Settings → General → Language; defaults to Chinese). The instruction is evaluated per prompt assembly, so it applies to every new session. Existing sessions keep the prompt they already composed.

The setting is stored in the standard user-settings document under the thinking-language namespace, so it survives restarts.

The final answer to the user is not affected: the setting only targets the model's internal thinking/chain-of-thought.

Supported languages

auto (follow the system) · zh-CN 简体中文 · zh-TW 繁體中文 · en English · ru Русский · fr Français · de Deutsch · es Español · ar العربية · pt Português · ja 日本語

Auto matches the system language tag hierarchically: exact id, then region variant, then language code. So en-US → English, ja → Japanese, de-AT → German, and Chinese is decided by script/region: zh, zh-Hans, zh-CN mean Simplified while zh-Hant, zh-TW, zh-HK, zh-MO mean Traditional. An unrecognised locale falls back to English (matching the shell locale plugin's own fallback).

Install

Install into the Harness home you actually run — check DSH_HOME / DSH_PROFILE, since the desktop app and the CLI do not share one by default (adjust the profile name too if you use e.g. desktop):

From GitHub (recommended):

dsh plugin --profile web add github:qingmomo233/dsh-thinking-language

Or from a local source checkout (replace <plugin-dir> with your own local path; pnpm resolves it inside the profile directory, so point it at the plugin directory itself):

dsh plugin --profile web add <plugin-dir>

Then restart the Harness (fully quit and relaunch the desktop app). The client module graph is written into index.html when the page is rendered, so a page refresh does not deliver a newly added plugin to an already-open page.

The desktop app owns its home: dsh --profile … against it is refused with profile "desktop" is managed exclusively by the Electron application, so install from the app's own plugin market instead (it accepts only a github:owner/repo[#sha] spec).

If it installs but does not show, look for skipping profile bundle in the log. A leftover entry under the old package name (renamed from dsh-plugin-thinking-language to dsh-thinking-language in v1.1) is skipped — dsh plugin --profile web remove dsh-plugin-thinking-language first. A peerDependencies mismatch against the running dsh version is skipped too (^0.1.0-rc.6 does not match 0.2.x); the log says is incompatible with dsh ….

About the settings-exposure patch (very old harnesses only)

Since DSH 0.2.6 the host exposes every registered settings namespace to the browser, and DSH 0.2.9 removed dsh-host-apiproxy entirely. Current builds therefore need no patch at all.

Only DSH ≤ 0.2.3 (the dsh-host-apiproxy@0.1.0-rc.5 generation) still keeps a hard-coded WEB_SETTINGS_NAMESPACES allowlist; there a plugin-owned namespace registers host-side but the browser gets settings-not-exposed, so the row renders but never persists. The script detects the allowlist before touching anything:

node scripts/patch-apiproxy.mjs          # dry run: detect and report only
node scripts/patch-apiproxy.mjs --write  # apply (writes a .dsh-thinking-language.bak backup first)

Usage

  1. Open Settings (gear icon) → Thinking language in the left nav.
  2. Pick a language on that page (or choose Follow the system (auto) to use the system UI locale).
  3. Start a new session — its thinking process is written in the selected language.

Compatibility

The plugin degrades instead of failing when a service or dependency is absent:

Situation Behaviour
Harness without systemPrompt the settings namespace keeps working
Harness without this settings channel (no settings service / registration refused) one warning, the prompt surfaces keep working
Harness without a settings transport (configForms / settingsScope) the page is skipped and reported once after boot
Harness without the locale service the page uses its built-in copy instead of crashing
Harness without the platform UI primitives module the page falls back to a native select and still shows
describe() unavailable or a different schema shape the picker falls back to the bundled catalog
Hand-edited/corrupt settings section treated as auto; nothing is thrown and user data is never rewritten
Unrecognised system language tag falls back to English (matching the shell locale plugin)

Both halves share one catalog: the picker's entries are derived from the host-registered settings schema (each enum value carries its endonym, e.g. 简体中文 — exactly what the picker showed before), the browser keeps only a fallback copy, and smoke-test.mjs fails when the two drift apart.

How it works

Part File Role
Pure core lib/languages.js catalog, system-locale tag matching, instruction/reminder copy (no cordis, no browser globals — directly unit-testable)
Host entry lib/index.js registers the thinking-language settings namespace and the app:thinking-language system-prompt section (order 85)
Browser bundle lib/client.js registers a dedicated Thinking language page into the settings.section slot and reads/writes the same namespace through the client settings scope
Bundle patch cordis.patch.yml inserts the plugin row into the composed profile tree
Tests smoke-test.mjs host registration, locale matrix, settings-handle shapes, browser-bundle drift and degradation paths, frozen UI copy
pnpm install   # installs the test dependencies (@deepseek-ai/cordis, @deepseek-ai/schemastery)
npm test       # smoke-test.mjs + cordis-check.mjs

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →

Community comments

Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.