Skip to content
dsh.fish
Bundle

dsh-reasoning-language

Make the DSH agent's thinking process (reasoning) use a language you choose — Simplified Chinese by default — and expand thinking rows by default. / 让 DSH 的思考过程用指定语言(默认简体中文)输出,并把思考行默认展开。

Source
jide315
License
MIT
Updated
Updated 23 hours ago

Readme

# dsh-reasoning-language

Make the **DeepSeek Harness** agent think in a language you choose — **Simplified Chinese by
default** — and expand its thinking rows so you can actually read the reasoning while it runs.

**The problem it solves:** the model reasons in English (or another language you don't read), so
the thinking process is an opaque box and you can't tell whether it is on track. This plugin
injects the language requirement into `systemPrompt`, so the reasoning is written in your
language from the start — and expands the Think rows by default so you can watch it.

## What it does

| Capability | Behaviour |
| --- | --- |
| Thinking language | Injects a `systemPrompt` section asking the model to reason in a chosen language (Simplified Chinese by default) |
| Protects non-prose | The injected instruction explicitly requires code, identifiers, paths, commands, config keys, errors, logs, URLs and proper nouns to stay verbatim — so "make it Chinese" never degrades the reasoning |
| Answer language unchanged | Only the reasoning is constrained; the final answer still follows the user's language |
| Thinking rows expanded | Think rows open by default, **including while streaming**. A row you collapse by hand stays collapsed — the plugin never fights your clicks, and turning the setting off only reclaims rows it expanded itself |
| Configurable in the GUI | Settings → Plugins → **Thinking language**. Changes apply to the next turn with **no restart** |
| New turns only | Existing history is never rewritten (rewriting stored reasoning means rewriting compacted context — poor risk/reward) |

## Install

**From GitHub:**

```powershell
dsh plugin --profile web add github:jide315/dsh-reasoning-language
```

The package is plain JavaScript and commits its runtime files, so GitHub installs do not need a
build allowlist. Restart DSH Desktop after installation, then refresh the page.

After the catalog submission is merged, you can also install it from Settings → Plugin market by
searching for `reasoning-language`.

For local development, run this from the directory containing the checkout:

```powershell
dsh plugin --profile web add ./dsh-reasoning-language
```

> **Local-development gotcha:** don't install a local plugin with `file:*.tgz`. Measured here: the
> resulting `node_modules/dsh-reasoning-language` lost its `lib/index.js` after a later `pnpm install`,
> the Harness failed to boot with `Cannot find module ...\lib\index.js`, and the desktop's
> startup-repair quarantined the plugin. `link:` is stable and needs no repacking.

### If it fails to boot

Run `dsh plugin --profile web remove dsh-reasoning-language`. If DSH cannot boot, use the desktop's
startup-repair dialog and choose **uninstall this plugin**; it keeps a recovery backup.

## Settings

Settings → Plugins → **Thinking language**:

- **Enabled** — turning it off is exactly equivalent to not having the plugin installed.
- **Thinking language** — defaults to `简体中文`. Set it to `English` to go back to English
  reasoning; any language name works, the model reads it as natural language. Effective **from the
  next turn** (the prompt is assembled per turn); existing history is untouched.
- **Expand thinking rows by default** — on by default. Toggling it **applies to the current page
  immediately** (existing thinking rows expand or collapse) and persists across reloads.

**Reset to defaults** *clears* the fields you changed (`unset`) rather than writing the defaults
back, so no redundant "equals the default" entries are left in `settings.yaml`.

Settings live under the `reasoning-language` key of `$DSH_HOME/settings.yaml`:

```yaml
reasoning-language:
  enabled: true
  language: 简体中文
  expandThinking: true
```

## How it works

- **Host half** uses only public seams: `ctx.settings.register()` for the namespace and
  `ctx.systemPrompt.section()` for the section. The section's `text` is a function re-evaluated on
  every prompt assembly — that is why a settings change needs no restart.
- **No DSH source is modified** and no built-in component is replaced.
- **Browser half**: (1) binds the same settings namespace through `ctx.settingsScope.bind()` for the
  settings card; (2) the thinking-row collapsed state is a per-row `useState(false)` inside the
  built-in `ReasoningRow` with no global switch, so a `MutationObserver` plus a fallback poll finds
  collapsed Think rows and **dispatches a real click** — which goes through React's event
  delegation, so the component's state updates too (no "DOM expanded but state still collapsed"
  desync).
- **Bookkeeping**: only rows the plugin actually opened are recorded, so a row you collapsed by
  hand stays collapsed, a row you opened by hand is never collapsed by the plugin, and turning the
  setting off only reclaims rows the plugin expanded.
- The settings schema is a real `schemastery` schema. This matters: `settings.describe()` calls
  `registration.schema.toJSON()` unconditionally and has no fallback, so a schema that does not
  satisfy the contract breaks the **entire settings panel**, not just this card.

## Tests

```powershell
pnpm test                       # 26 assertions: host logic, settings-card interaction, expander
pnpm run test:integration       # 10 assertions: real DSH SettingsProvider / SystemPrompt
```

The smoke suite stubs the environment. The integration suite requires DSH Desktop, or a
`DSH_APP_ROOT` pointing to a compatible DSH `node_modules`; it drives DSH's own
`FileSettingsProvider` and `SystemPrompt` to prove `describe()` does not throw, the schema
serialises, and a written setting reaches the rendered prompt.

## Publishing

See [`PREPUBLISH.md`](PREPUBLISH.md) for the full market-submission process, and
`node scripts/check-release.mjs` for the pre-flight check.

## Limitations

- The thinking language is a **request to the model**, not a hard guarantee: an occasional model
  may ignore it. The instruction is placed late and specifically, which works well in practice; if
  a model does not comply, phrasing the language the way that model prefers (e.g.
  `Chinese (中文)`) usually helps.
- Only **newly generated** reasoning is affected; history is untouched.
- The expander relies on the built-in thinking row's `data-variant="think"` marker. If DSH drops
  that attribute the expander fails silently (no error, no broken UI) — update the selector.

## Compatibility

- Requires `@deepseek-ai/dsh >= 0.1.5-rc.1`.
- Developed and verified on DSH Desktop 0.9.1 (dsh 0.1.5-rc.2).
- Needs only the `slots` / `locale` / `settingsScope` client services; a missing one degrades
  rather than crashes.

## License

MIT

Install

dsh plugin --profile web add github:jide315/dsh-reasoning-language

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source