dsh-vision-toggle
dsh-vision-toggle 是一个为 DeepSeek Harness (dsh) 提供「支持图片」开关的插件,让你在设置页按模型一键启用/禁用图片输入
- Stars
- 0
- Language
- TypeScript
- Created
- Aug 28, 2026
- Updated
- Aug 28, 2026
Introduction
dsh-vision-toggle · Model Vision Switch Plugin
English | 中文
A model vision toggle plugin for DeepSeek Harness (dsh) desktop: let users control whether each configured model supports image input — flip a switch to enable/disable vision per model, no config file editing and no restart required.
Features
| Feature | Description |
|---|---|
| Model List | Read every model declared in the llm-pi-ai provider routes, grouped by provider |
| Vision Switch | Per-model toggle to turn image input on (['text','image']) or off (['text']) |
| Immediate Effect | Writes into the official config; llm-pi-ai re-registers on change — takes effect instantly, no restart |
| Optimistic UI | Switch flips immediately; rolls back if the host write fails |
| i18n | Chinese / English, follows the dsh desktop language setting |
Background
dsh officially supports multimodal (image understanding) with its own deepseek-v4-vision-exp model. However, the settings page offers no way to declare the input modalities (input) of custom providers or third-party models. If you add your own provider (e.g. an OpenAI-compatible service via LM Studio / vLLM / Ollama) whose model actually supports vision, sending an image still fails with:
当前模型不支持图片 (this model does not support images)
The only workaround today is to hand-edit settings.yaml and add input: [text, image] for the model — which is fragile and easy to get wrong.
This plugin removes that friction: it exposes the official llm-pi-ai settings namespace so each model gets a "Support image" switch in the settings page. Toggling it rewrites the model's input modalities for you.
Installation
Prerequisites
- DeepSeek Harness (dsh) desktop
- Node.js >= 18
Integration in dsh-desktop
- Install the plugin:
dsh plugin add @lijian-ui/dsh-vision-toggle
- Restart the desktop app.
Local Development
# Enter the plugin directory
cd extensions/dsh-vision-toggle
# Install dependencies
npm install
# Build
npm run build
# Watch mode
npm run watch
# Type check
npm run typecheck
Build output goes to lib/ and is automatically synced to node_modules/@lijian-ui/dsh-vision-toggle via junction. Restart the desktop app after each build to load the new bundle.
Usage
- Open dsh desktop
- Navigate to Settings → Model Vision (modeled after the other settings sections)
- The section lists every configured model, grouped by provider. Next to each model there is a "Support image" switch:
- On: the model accepts image input; you can now attach images in chat
- Off: the model is text-only
Turning the switch on simply sets that model's
inputto['text', 'image']; turning it off sets it back to['text']. This matches exactly how dsh decides whether a model supports images.
Technical Architecture
Directory Structure
extensions/dsh-vision-toggle/
├── src/
│ ├── index.ts # Host entry (registers the remote service + typert contract)
│ ├── remote.ts # Host RPC: listModels / setVision (reads & writes llm-pi-ai config)
│ └── client/
│ ├── index.ts # Client entry (SECTION_ID, RPC registration, inject)
│ ├── VisionToggleSection.ts # Settings component (model list grouped by provider + toggles)
│ └── client-i18n.ts # Client i18n (zh/en)
├── lib/ # Build output (index.mjs + client.js)
├── package.json
├── tsdown.config.ts
└── cordis.patch.yml
Host Side (src/remote.ts)
Provides the following RPC methods:
| Method | Function |
|---|---|
listModels() | List all models declared in providers[*].models, with their current input modalities and whether they support vision |
setVision(provider, modelId, enabled) | Rewrite one model's input to ['text', 'image'] (on) or ['text'] (off) and persist |
Config Read / Write
The plugin operates on the official llm-pi-ai settings namespace (settingsNamespace('llm-pi-ai')) owned by @deepseek-ai/dsh-llm-pi-ai — the same config that backs model selection and the "this model does not support images" error:
- Read:
settings.get('llm-pi-ai')returns the provider routes; each model's effectiveinputfalls back to the provider'sdefaultInput. - Write: uses
settings.update('llm-pi-ai', { providers: ... })with a rebuilt fullmodelsarray. The path-basedsettings.mutateAPI cannot navigate array indexes (it would replace the whole array), so we rebuild the array instead.
Because llm-pi-ai resolves input per request and re-registers on settings change, a flip takes effect immediately with no restart.
Toggle Mechanism
User clicks the switch
→ Client optimistically updates the row (immediate flip)
→ RPC call to host setVision(provider, modelId, enabled)
→ Host: read config, rebuild models[], settings.update('llm-pi-ai', …)
→ llm-pi-ai detects the change and re-registers the model route
→ Config persisted to settings.yaml; next message uses the new modalities
If the host write fails, the client restores the previous switch state and shows an error.
Internationalization
Supports Chinese and English. Translation files are in src/client/client-i18n.ts. Language follows the dsh desktop language setting.
Tech Stack
- Language: TypeScript
- Build: tsdown (rolldown)
- Frontend: React 18
- RPC:
@deepseek-ai/dsh-typert-protocol/@deepseek-ai/dsh-typert-registry(host remote) - Config:
@deepseek-ai/dsh-settings(namespacellm-pi-ai)
License
MIT