dsh-vision-router 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +151 -38
- package/README.zh.md +147 -36
- package/docs/doctor.md +52 -0
- package/docs/http-provider-compatibility.md +73 -0
- package/docs/update-check.md +42 -0
- package/docs/update-check.zh-CN.md +42 -0
- package/index.js +746 -81
- package/lib/client.js +824 -57
- package/lib/doctor-cli.js +113 -0
- package/lib/doctor.js +113 -0
- package/lib/http-compat.js +264 -0
- package/lib/self-update.js +165 -0
- package/lib/update-check.js +223 -0
- package/package.json +11 -3
package/README.md
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
12
|
<a href="https://awesome-dsh-plugin.com"><img src="https://awesome-dsh-plugin.com/badge.svg" alt="awesome · DSH plugin" /></a>
|
|
13
|
-
<a href="https://github.com/ysr666/dsh-vision-router/releases/tag/v1.
|
|
14
|
-
<a href="tests"><img src="https://img.shields.io/badge/verified-
|
|
13
|
+
<a href="https://github.com/ysr666/dsh-vision-router/releases/tag/v1.2.0"><img src="https://img.shields.io/badge/release-v1.2.0-5B4CF0?style=flat-square" alt="Release v1.2.0" /></a>
|
|
14
|
+
<a href="tests"><img src="https://img.shields.io/badge/verified-144%20tests-2EA44F?style=flat-square" alt="Verified: 144 tests" /></a>
|
|
15
15
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-2EA44F?style=flat-square" alt="License: MIT" /></a>
|
|
16
16
|
<a href="package.json"><img src="https://img.shields.io/badge/Node.js-%3E%3D22-339933?style=flat-square&logo=nodedotjs&logoColor=white" alt="Node.js >=22" /></a>
|
|
17
17
|
<img src="https://img.shields.io/badge/runtime-no%20Python-8A2BE2?style=flat-square" alt="No Python" />
|
|
@@ -21,11 +21,12 @@
|
|
|
21
21
|
<p align="center">English · <a href="README.zh.md">中文</a></p>
|
|
22
22
|
|
|
23
23
|
> [!WARNING]
|
|
24
|
-
> 📌 **Announcement (v1.
|
|
24
|
+
> 📌 **Announcement (v1.2.0)**
|
|
25
25
|
>
|
|
26
|
-
>
|
|
26
|
+
> v1.2.0 closes the loop on zero-config vision: the lower-right chat picker only selects conversation models, settings only select user vision models, internal `Vision HTTP` is hidden, and a five-model anonymous OVH chain remains the final no-signup/no-key fallback. It also adds the three-step model guide, durable inline `vision_present` images, BOM doctor/repair, resilient update checks/safe updates, and fixes image tool results poisoning text-only DeepSeek histories.
|
|
27
27
|
|
|
28
28
|
<p align="center">
|
|
29
|
+
<img src="assets/vision-demo.gif"<p align="center">
|
|
29
30
|
<img src="assets/vision-demo.gif" width="640" alt="Demo: paste an image, the agent locates the send button with vision_ground / vision_crop / vision_pixel_diff and answers with coordinates" />
|
|
30
31
|
</p>
|
|
31
32
|
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
Most DSH vision plugins bridge images to DeepSeek as *text descriptions* — lossy, one-shot, and blind to pixels. This plugin keeps the **original pixels on the vision model's side** and DeepSeek on the reasoning side, and makes looking at an image an **ordinary tool call**:
|
|
35
36
|
|
|
36
37
|
- **One command install.** The package ships its own composition patch (`dsh.bundle.patch`): `dsh plugin add` wires the row, the admission wrapper and the attachment limits automatically — zero manual file edits. Taking over the official DeepSeek route is an optional setting (stealth mode, off by default).
|
|
37
|
-
- **Free by default.**
|
|
38
|
+
- **Free by default.** Vision tools end with a five-model OVHcloud anonymous fallback: no account, no key, 2 requests/minute per IP per model, roughly 10 RPM in theory across independent buckets. User-provided vision models run first.
|
|
38
39
|
- **No Python.** The whole pipeline — downscale, grounding, crop, pixel diff, palette, OCR, SVG trace, cutout, HTML screenshot — runs on sharp / potrace / tesseract / system Chrome.
|
|
39
40
|
- **Continuous multi-step image work.** An image turn is a text turn that calls tools: `vision_ground` → `vision_crop` → `vision_describe` → `vision_pixel_diff` → fix → screenshot again. The agent keeps iterating until the work is done.
|
|
40
41
|
- **DeepSeek stays the brain.** Text turns are untouched in model, cost and context. The vision model is only the eyes, called on demand; answers are cached by image content.
|
|
@@ -48,29 +49,60 @@ The closest alternative is [@anionex/dsh-vision-toolkit](https://github.com/Anio
|
|
|
48
49
|
|---|---|---|
|
|
49
50
|
| Image Q&A out of the box | ✅ Built-in free chain (anonymous OVHcloud endpoint) — no account, no key | Requires your own vision API key (local pixel tools work without one) |
|
|
50
51
|
| Runtime | ✅ Node only — no Python | Python 3.11+ managed runtime |
|
|
51
|
-
| Getting an image in | ✅
|
|
52
|
+
| Getting an image in | ✅ Pick a “+ Auto Vision” group once, then paste directly | Workspace path + `/vision-tools` command, then explicit tool calls |
|
|
52
53
|
| Turn routing | ✅ Image turns switch to vision, text turns switch back to DeepSeek — optional stealth takeover keeps the model picker looking stock | Tool-driven; no whole-turn auto-routing |
|
|
53
54
|
| Profiles | Web | Web + Headless |
|
|
54
55
|
| Playbooks | The pixel loop: ground → crop → diff → fix → screenshot again | Richer case library (long-screenshot OCR, UI restoration, GUI automation) |
|
|
55
|
-
| Tests |
|
|
56
|
+
| Tests | 144 | 162 |
|
|
56
57
|
| Install | One command | One command (npm) |
|
|
57
58
|
|
|
58
59
|
Both are MIT-licensed and one command away. Pick this plugin when you want images to *just work* with zero setup; pick theirs when you need headless profiles or the extended playbook library. (Feature comparison reflects their README as of 2026-08.)
|
|
59
60
|
|
|
60
61
|
## Quick start
|
|
61
62
|
|
|
63
|
+
### 1. Install and load the plugin
|
|
64
|
+
|
|
65
|
+
Recommended for normal npm/npx installs (the same launch style used by the DSH README):
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
npx @deepseek-ai/dsh plugin --profile web add dsh-vision-router
|
|
69
|
+
npx @deepseek-ai/dsh web
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
If you run DeepSeek Harness from a source checkout with pnpm, use the workspace script instead — `dsh` is not necessarily on your shell `PATH`:
|
|
73
|
+
|
|
62
74
|
```sh
|
|
63
|
-
|
|
75
|
+
cd deepseek-harness
|
|
76
|
+
pnpm dsh plugin --profile web add dsh-vision-router
|
|
77
|
+
pnpm dsh web
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
If you already installed the DSH CLI globally and `dsh` is on `PATH`, the shorter `dsh ...` form works too.
|
|
81
|
+
|
|
82
|
+
> [!NOTE]
|
|
83
|
+
> If you install the plugin **into a Web process that was already running long-term**, let that DSH Web process reload once so the plugin bundle itself is discovered. After the plugin is loaded, adding/removing models or changing wrapper scope **hot-updates without further DSH restarts**.
|
|
84
|
+
|
|
85
|
+
### 2. Switch to a “+ Auto Vision” model group in chat
|
|
86
|
+
|
|
87
|
+
Once loaded, the plugin discovers the model groups enabled under **Settings → Models** and creates same-name auto-vision entries. For example:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
opencode-go ← original model group, unchanged
|
|
91
|
+
opencode-go + Auto Vision ← choose this when sending images
|
|
64
92
|
```
|
|
65
93
|
|
|
66
|
-
|
|
94
|
+
> [!IMPORTANT]
|
|
95
|
+
> **Before sending an image, open the model selector in the lower-right corner of the chat composer and choose a group marked “+ Auto Vision”.**
|
|
96
|
+
>
|
|
97
|
+
> Vision Router deliberately **does not modify the original model group**. If the conversation still uses the original text-only opencode / DeepSeek route, DSH can reject the image with “the current model does not support images” *before Vision Router gets a chance to handle it*. That is a model-entry selection issue, not a broken vision backend.
|
|
98
|
+
|
|
99
|
+
The auto-vision group follows the live DSH model catalog. Adding models or changing wrapper scope does not require a restart.
|
|
67
100
|
|
|
68
|
-
|
|
69
|
-
- the default vision chain is the built-in free endpoint;
|
|
70
|
-
- custom/third-party routes (e.g. opencode) gain image input through **Extra vision wrappers**;
|
|
71
|
-
- every setting is editable live in **Settings → Plugins → Plugin config → 视觉路由(自动识图)**.
|
|
101
|
+
### 3. Paste or upload the image
|
|
72
102
|
|
|
73
|
-
|
|
103
|
+
After choosing the “+ Auto Vision” group, paste or upload an image normally. The agent auto-mounts the vision tools and can use `vision_describe`, `vision_ground`, `vision_crop`, and the rest across multiple steps when needed.
|
|
104
|
+
|
|
105
|
+
The built-in anonymous OVH vision fallback is already configured, so normal image use needs no signup or API key. **The lower-right chat picker selects only the brain/conversation model**; vision backends do not belong there. Advanced options live under **Settings → Plugins → Plugin config → 视觉路由(自动识图)**: each vision-backend row selects one image-capable user model already configured under **Settings → Models**. Leaving every user row empty is valid; the OVH chain remains the final fallback. `Vision HTTP` is an internal transport route, not a model group users should select.
|
|
74
106
|
|
|
75
107
|
### See it in action
|
|
76
108
|
|
|
@@ -148,11 +180,14 @@ vision_long_screenshot_ocr image="chat-log.png" chunkHeight=1200 overlap=120
|
|
|
148
180
|
|
|
149
181
|
## Provider fallback chain
|
|
150
182
|
|
|
151
|
-
The vision
|
|
183
|
+
The vision tools try backends in order and surface an error only after all of them fail:
|
|
184
|
+
|
|
185
|
+
1. **User vision models**: one per settings row, top to bottom; only models under **Settings → Models** that explicitly declare image input are shown;
|
|
186
|
+
2. **Advanced custom HTTP vision endpoints**: legacy/advanced `httpProviders`, when present, run after the user models;
|
|
187
|
+
3. **Built-in anonymous OVH fallback**: always last and never exposed in a model picker. The current quality-first chain is `Qwen3.5-397B-A17B` → `Qwen2.5-VL-72B-Instruct` → `Qwen3.6-27B` → `Mistral-Small-3.2-24B-Instruct-2506` → `Qwen3.5-9B`. OVH anonymous limits are **2 requests/minute per IP per model**. The five models have independent buckets, so spreading requests across them is about **10 RPM in theory**, subject to OVH's actual rate limiting. No signup or API key is required.
|
|
152
188
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
3. configured `providers` / `provider` + `fallbacks` (any adapter-backed provider, e.g. a Pi-AI profile like OpenRouter or Zhipu).
|
|
189
|
+
> [!IMPORTANT]
|
|
190
|
+
> This “vision chain” is the **eyes** used by Vision Router: each settings row selects one user vision model, while the lower-right chat picker selects the **brain/conversation model**. The two are deliberately separate. Text-only DeepSeek/opencode models are filtered out of the vision-backend dropdown, and the internal `Vision HTTP` transport route is no longer exposed to users.
|
|
156
191
|
|
|
157
192
|
> In the legacy `routing: true` mode, the whole-turn chain walks only `provider + fallbacks` — `httpProviders` (including the free fallback) do not participate there. The default `routing: false` (tools-first) tries everything.
|
|
158
193
|
|
|
@@ -172,21 +207,29 @@ With stealth on, the plugin takes over the official `deepseek-official` route: t
|
|
|
172
207
|
|
|
173
208
|
With the stock row present, the plugin falls back to the visible wrapper entry. Conversely, with stealth off but the stock row still disabled, the plugin performs a keep-alive takeover so the DeepSeek models don't vanish (the settings card explains this); to restore the fully official route, flip the `disabled` above back to `false` and restart.
|
|
174
209
|
|
|
175
|
-
> Stealth mode **only affects the official DeepSeek route**. Custom/third-party routes
|
|
210
|
+
> Stealth mode **only affects the official DeepSeek route**. Custom/third-party routes such as opencode are auto-wrapped into “+ Auto Vision” groups by default.
|
|
211
|
+
|
|
212
|
+
## Auto-vision model groups and manual wrappers
|
|
176
213
|
|
|
177
|
-
|
|
214
|
+
`autoWrapProviders` is on by default. The plugin discovers the provider/model entries currently enabled under **Settings → Models** and registers a same-name “+ Auto Vision” model group for them. **The original group is never changed**: choose the auto-vision group for images, or keep using the original group for plain text. DSH `llm/adapters-updated` events are synced live, so adding/removing models does not require a restart.
|
|
178
215
|
|
|
179
|
-
`wrappedProviders`
|
|
216
|
+
`wrappedProviders` is an **optional manual scope control**, not a required setup step. Use it only when:
|
|
217
|
+
|
|
218
|
+
1. automatic wrapping is off and you want to pick which provider/models receive an auto-vision entry; or
|
|
219
|
+
2. automatic wrapping remains on but one provider should expose only selected models in its “+ Auto Vision” group.
|
|
220
|
+
|
|
221
|
+
The settings card uses provider + model dropdowns; an empty model means every model on that route. Add multiple rows to select multiple models. Changes apply immediately with no restart.
|
|
180
222
|
|
|
181
223
|
## Web settings
|
|
182
224
|
|
|
183
|
-
The Web profile registers a **视觉路由(自动识图)** card under **Settings → Plugins → Plugin config
|
|
225
|
+
The Web profile registers a **视觉路由(自动识图)** card under **Settings → Plugins → Plugin config**. Its top callout spells out the only step most users need: **return to chat → lower-right model selector → choose a “+ Auto Vision” model group → send the image**. The remaining controls are advanced customization:
|
|
184
226
|
|
|
185
|
-
-
|
|
186
|
-
- **
|
|
187
|
-
-
|
|
188
|
-
-
|
|
189
|
-
-
|
|
227
|
+
- **Auto-create “+ Auto Vision” model groups**: enabled by default; follows the live model catalog with no restart;
|
|
228
|
+
- **Manual auto-vision scope (optional)**: only for disabling auto-wrap or limiting selected models;
|
|
229
|
+
- **Vision backend chain**: the real image-capable models used by `vision_describe` and friends; the built-in free Qwen is normally enough, and text-only models should not be placed here;
|
|
230
|
+
- switches for legacy whole-turn routing, vision tools, image-block rewriting and stealth mode (official DeepSeek route only);
|
|
231
|
+
- timeout, wrapper/chain route names, proxy and other advanced parameters;
|
|
232
|
+
- every field shows an overridden badge with one-click reset plus discard/save;
|
|
190
233
|
- a **Test connection** button probes the first vision provider and reports latency inline;
|
|
191
234
|
- artifact-producing tools render dedicated call cards with result facts and open-file buttons.
|
|
192
235
|
|
|
@@ -202,15 +245,16 @@ Everything is optional; defaults work out of the box. Edit via the Web card or a
|
|
|
202
245
|
|
|
203
246
|
| Field | Default | Meaning |
|
|
204
247
|
|---|---|---|
|
|
205
|
-
| `provider` / `model` | `vision-http` / `ovh/Qwen2.5-VL-72B-Instruct` | shorthand
|
|
206
|
-
| `fallbacks` | `[]` | backup models for the shorthand provider |
|
|
207
|
-
| `providers` | built-in free `vision-http` pair | multi-provider chain `{ provider, model, fallbacks[] }`, tried in order;
|
|
248
|
+
| `provider` / `model` | `vision-http` / `ovh/Qwen2.5-VL-72B-Instruct` | shorthand **vision backend** route (adapter-backed provider + model that genuinely accepts images) |
|
|
249
|
+
| `fallbacks` | `[]` | backup image models for the shorthand vision provider |
|
|
250
|
+
| `providers` | built-in free `vision-http` pair | multi-provider **vision backend** chain `{ provider, model, fallbacks[] }`, tried in order; do not put text-only models here |
|
|
208
251
|
| `httpProviders` | built-in OVH entry | direct OpenAI-compatible endpoints `{ name, baseURL, model, apiKeyEnv, maxTokens }` |
|
|
209
|
-
| `
|
|
252
|
+
| `autoWrapProviders` | `true` | discover enabled provider/models and live-sync same-name “+ Auto Vision” groups; original groups stay unchanged |
|
|
253
|
+
| `wrappedProviders` | `[{ provider: 'deepseek-official', models: [] }]` | optional manual wrapper scope `{ provider, models[] }`, used after disabling auto-wrap or to restrict one provider to selected models; changes apply live, no restart |
|
|
210
254
|
| `routing` | `false` | legacy whole-turn chain routing (one-shot answer). `false` = tools-first flow (recommended) |
|
|
211
255
|
| `reverseRouting` | `true` | with `routing: true`, route text turns back to `textProvider` |
|
|
212
256
|
| `wrapperRoute` / `chainRoute` | `deepseek-vision` / `vision-chain` | admission wrapper route name / fallback chain route name (empty disables) |
|
|
213
|
-
| `stealth` | `false` | take over the official `deepseek-official` route (official row only; custom routes
|
|
257
|
+
| `stealth` | `false` | take over the official `deepseek-official` route (official row only; custom routes are auto-wrapped by default) |
|
|
214
258
|
| `textProvider` | `deepseek-official` / `deepseek-v4-pro` | the model that reasons (your daily model) |
|
|
215
259
|
| `tool` / `progressiveTools` / `autoActivateOnImage` | `true` ×3 | vision tools on / progressive mounting / auto-mount on image turns |
|
|
216
260
|
| `rewriteImages` | `true` | rewrite image blocks in the model input (cached description or tool-hint marker); the UI log keeps images |
|
|
@@ -222,7 +266,7 @@ Everything is optional; defaults work out of the box. Edit via the Web card or a
|
|
|
222
266
|
|
|
223
267
|
## Requirements
|
|
224
268
|
|
|
225
|
-
- DeepSeek Harness
|
|
269
|
+
- DeepSeek Harness Web profile. Normal installs can use `npx @deepseek-ai/dsh ...`; source checkouts use `pnpm dsh ...`. A bare `dsh ...` command only works when the CLI is already on your shell `PATH`.
|
|
226
270
|
- Node ≥ 22 (host side).
|
|
227
271
|
- No API key for the default free chain; a credential reference (`apiKeyEnv`) only for paid `httpProviders`.
|
|
228
272
|
- Chrome / Chromium / Edge only for `vision_html_screenshot`; every other tool works without a browser.
|
|
@@ -232,12 +276,21 @@ Everything is optional; defaults work out of the box. Edit via the Web card or a
|
|
|
232
276
|
|
|
233
277
|
### Install
|
|
234
278
|
|
|
279
|
+
Normal npm/npx install:
|
|
280
|
+
|
|
281
|
+
```sh
|
|
282
|
+
npx @deepseek-ai/dsh plugin --profile web add dsh-vision-router
|
|
283
|
+
npx @deepseek-ai/dsh --profile web --dump-config | grep vision-router
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
From a DeepSeek Harness source checkout:
|
|
287
|
+
|
|
235
288
|
```sh
|
|
236
|
-
dsh plugin --profile web add dsh-vision-router
|
|
237
|
-
dsh --profile web --dump-config | grep vision-router
|
|
289
|
+
pnpm dsh plugin --profile web add dsh-vision-router
|
|
290
|
+
pnpm dsh --profile web --dump-config | grep vision-router
|
|
238
291
|
```
|
|
239
292
|
|
|
240
|
-
|
|
293
|
+
When first adding the plugin to an already long-lived Web profile, let that Web process reload the plugin bundle; the host discovers the browser bundle through `dsh.client` at startup. **After the plugin is loaded, model-catalog and wrapper-scope changes hot-update and do not require a restart.**
|
|
241
294
|
|
|
242
295
|
### Disable / re-enable
|
|
243
296
|
|
|
@@ -251,19 +304,79 @@ Set it back to `false` to re-enable. Unloading removes the wrapper routes, tools
|
|
|
251
304
|
### Upgrade
|
|
252
305
|
|
|
253
306
|
```sh
|
|
254
|
-
|
|
307
|
+
# normal npm/npx install
|
|
308
|
+
npx @deepseek-ai/dsh plugin --profile web update dsh-vision-router
|
|
309
|
+
|
|
310
|
+
# DeepSeek Harness source checkout
|
|
311
|
+
pnpm dsh plugin --profile web update dsh-vision-router
|
|
255
312
|
```
|
|
256
313
|
|
|
257
314
|
Settings live in the profile's settings provider and survive upgrades.
|
|
258
315
|
|
|
316
|
+
> **Upgrading from a pre-bundle-patch install (v0.x):** the package now mounts
|
|
317
|
+
> itself through its own bundle patch, so a leftover manual row in
|
|
318
|
+
> `~/.dsh/profiles/<profile>/cordis.patch.yml` duplicates it and `dsh web`
|
|
319
|
+
> fails at startup with `duplicate loader entry id: vision-router`. Delete the
|
|
320
|
+
> old block:
|
|
321
|
+
>
|
|
322
|
+
> ```yaml
|
|
323
|
+
> - insert: # remove this whole block
|
|
324
|
+
> - id: vision-router
|
|
325
|
+
> name: dsh-vision-router
|
|
326
|
+
> ```
|
|
327
|
+
>
|
|
328
|
+
> To keep custom settings, replace it with a plain by-id override (no
|
|
329
|
+
> `insert`):
|
|
330
|
+
>
|
|
331
|
+
> ```yaml
|
|
332
|
+
> - id: vision-router
|
|
333
|
+
> config:
|
|
334
|
+
> # your overrides …
|
|
335
|
+
> ```
|
|
336
|
+
|
|
259
337
|
### Uninstall
|
|
260
338
|
|
|
261
339
|
```sh
|
|
262
|
-
|
|
340
|
+
# normal npm/npx install
|
|
341
|
+
npx @deepseek-ai/dsh plugin --profile web remove dsh-vision-router
|
|
342
|
+
|
|
343
|
+
# DeepSeek Harness source checkout
|
|
344
|
+
pnpm dsh plugin --profile web remove dsh-vision-router
|
|
263
345
|
```
|
|
264
346
|
|
|
265
347
|
This removes the dependency and the bundle layer. If you disabled the stock DeepSeek row manually, re-enable it in your profile patch.
|
|
266
348
|
|
|
349
|
+
## Troubleshooting
|
|
350
|
+
|
|
351
|
+
### Startup fails with `Unexpected token ... is not valid JSON` (UTF-8 BOM)
|
|
352
|
+
|
|
353
|
+
**Symptom:** `dsh web` / `pnpm dsh web` exits immediately at startup:
|
|
354
|
+
|
|
355
|
+
```
|
|
356
|
+
SyntaxError: Unexpected token ...
|
|
357
|
+
is not valid JSON
|
|
358
|
+
at JSON.parse (<anonymous>)
|
|
359
|
+
at readProfileManifest (packages/boot/app-boot/src/profile.ts)
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Cause:** `~/.dsh/profiles/<profile>/package.json` was saved as **UTF-8 with BOM** by an editor. The invisible `\uFEFF` character at the start makes `JSON.parse` fail, because JSON does not allow it before the opening brace.
|
|
363
|
+
|
|
364
|
+
**Recommended fix:** run Vision Router's standalone repair command. It does not require DSH to boot first; it locates the profile, detects a UTF-8 BOM, removes only the three leading BOM bytes, and then validates the JSON again:
|
|
365
|
+
|
|
366
|
+
```sh
|
|
367
|
+
npx dsh-vision-router repair --profile web
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
To diagnose without changing the file:
|
|
371
|
+
|
|
372
|
+
```sh
|
|
373
|
+
npx dsh-vision-router doctor --profile web
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Replace `web` if you use another profile, or omit `--profile` to scan all profiles.
|
|
377
|
+
|
|
378
|
+
Manual fallback: in VS Code, use “Save with Encoding” → `UTF-8` (without BOM). If `repair` removes the BOM but the JSON is still invalid, it will not guess or rewrite any other JSON content; inspect the file manually.
|
|
379
|
+
|
|
267
380
|
## Security notes
|
|
268
381
|
|
|
269
382
|
- Image text is **untrusted evidence**: descriptions, OCR output and the auto-mount note all tell the agent never to execute instructions found inside images.
|
package/README.zh.md
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
12
|
<a href="https://awesome-dsh-plugin.com"><img src="https://awesome-dsh-plugin.com/badge.svg" alt="awesome · DSH plugin" /></a>
|
|
13
|
-
<a href="https://github.com/ysr666/dsh-vision-router/releases/tag/v1.
|
|
14
|
-
<a href="tests"><img src="https://img.shields.io/badge/verified-
|
|
13
|
+
<a href="https://github.com/ysr666/dsh-vision-router/releases/tag/v1.2.0"><img src="https://img.shields.io/badge/release-v1.2.0-5B4CF0?style=flat-square" alt="Release v1.2.0" /></a>
|
|
14
|
+
<a href="tests"><img src="https://img.shields.io/badge/verified-144%20tests-2EA44F?style=flat-square" alt="Verified: 144 tests" /></a>
|
|
15
15
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-2EA44F?style=flat-square" alt="License: MIT" /></a>
|
|
16
16
|
<a href="package.json"><img src="https://img.shields.io/badge/Node.js-%3E%3D22-339933?style=flat-square&logo=nodedotjs&logoColor=white" alt="Node.js >=22" /></a>
|
|
17
17
|
<img src="https://img.shields.io/badge/runtime-no%20Python-8A2BE2?style=flat-square" alt="No Python" />
|
|
@@ -21,11 +21,12 @@
|
|
|
21
21
|
<p align="center"><a href="README.md">English</a> · 中文</p>
|
|
22
22
|
|
|
23
23
|
> [!WARNING]
|
|
24
|
-
> 📌 **公告(v1.
|
|
24
|
+
> 📌 **公告(v1.2.0)**
|
|
25
25
|
>
|
|
26
|
-
>
|
|
26
|
+
> v1.2.0 把“开箱即用”这条链路完整收口:聊天页右下角只选会话模型,设置页只选用户视觉模型,内部 `Vision HTTP` 不再暴露;内置 5 模型 OVH 匿名免费链固定在最后兜底,免注册、免 Key。新增三步模型引导、`vision_present` 持久内联图片、BOM doctor/repair、版本检查/安全更新,并修复图片工具结果污染纯文本 DeepSeek 历史导致后续对话崩溃的问题。
|
|
27
27
|
|
|
28
28
|
<p align="center">
|
|
29
|
+
<img src="assets/vision-demo.gif"<p align="center">
|
|
29
30
|
<img src="assets/vision-demo.gif" width="640" alt="演示:粘贴图片,Agent 用 vision_ground / vision_crop / vision_pixel_diff 定位发送按钮并给出坐标" />
|
|
30
31
|
</p>
|
|
31
32
|
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
大多数 DSH 视觉插件把图片“翻译”成一段文字描述再喂给 DeepSeek——有损、一次性、看不见像素。本插件把**原图像素留在视觉模型侧**、把推理留在 DeepSeek 侧,并把“看图”变成一次**普通的工具调用**:
|
|
35
36
|
|
|
36
37
|
- **一条命令安装。** 包自带组合补丁(`dsh.bundle.patch`):`dsh plugin add` 自动完成插件行挂载、准入包装与附件限制放宽——不用手改任何文件。是否接管官方 DeepSeek 路由由「隐身模式」开关决定(默认关)。
|
|
37
|
-
- **默认免费。**
|
|
38
|
+
- **默认免费。** 视觉工具最终兜底为 5 个 OVHcloud 匿名视觉模型:免注册、免 Key,每 IP、每模型 2 次/分钟,独立限额理论合计约 10 次/分钟;用户自备视觉模型会优先调用。
|
|
38
39
|
- **无 Python。** 整条管线——缩放、定位、裁剪、像素对比、取色、OCR、SVG 矢量化、抠图、HTML 截图——全部基于 sharp / potrace / tesseract / 系统 Chrome。
|
|
39
40
|
- **可连续多步看图。** 图片轮 = 调用工具的文本轮:`vision_ground` → `vision_crop` → `vision_describe` → `vision_pixel_diff` → 修复 → 再截图,Agent 可以一直迭代到任务完成。
|
|
40
41
|
- **DeepSeek 始终是大脑。** 文字轮在模型、成本、上下文上完全不动;视觉模型只当“眼睛”、按需调用,答案按图片内容缓存。
|
|
@@ -48,29 +49,60 @@
|
|
|
48
49
|
|---|---|---|
|
|
49
50
|
| 开箱图片问答 | ✅ 内置免费视觉链(OVHcloud 匿名端点),免注册免 Key | 远程工具需自备视觉 API Key(本地像素工具免 Key) |
|
|
50
51
|
| 运行时 | ✅ 纯 Node,无需 Python | 需要 Python 3.11+ 受管运行时 |
|
|
51
|
-
| 图片怎么进来 | ✅
|
|
52
|
+
| 图片怎么进来 | ✅ 选一次「+ 自动识图」模型组后直接粘贴 | 工作区路径 + `/vision-tools` 命令,再显式调用工具 |
|
|
52
53
|
| 轮次路由 | ✅ 图片轮切视觉、文本轮切回 DeepSeek——可选隐身接管,模型选择器与官方一致 | 工具驱动,无整轮自动路由 |
|
|
53
54
|
| 支持 profile | Web | Web + Headless |
|
|
54
55
|
| 玩法库 | 像素循环:定位 → 裁剪 → 对比 → 修复 → 再截图 | 更丰富的案例库(长截图 OCR、UI 还原、GUI 自动化) |
|
|
55
|
-
| 测试 |
|
|
56
|
+
| 测试 | 144 | 162 |
|
|
56
57
|
| 安装 | 一条命令 | 一条命令(npm) |
|
|
57
58
|
|
|
58
59
|
两者都是 MIT 许可、一条命令安装。想要图片**粘贴即用**、零配置就选本插件;需要 Headless 部署或更丰富的案例库,可以看 @anionex/dsh-vision-toolkit。(功能对比以其 README 2026-08 状态为准。)
|
|
59
60
|
|
|
60
61
|
## 快速开始
|
|
61
62
|
|
|
63
|
+
### 1. 安装并让插件加载
|
|
64
|
+
|
|
65
|
+
普通 npm / npx 安装方式推荐这样用(与 DSH 官方 README 的启动方式一致):
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
npx @deepseek-ai/dsh plugin --profile web add dsh-vision-router
|
|
69
|
+
npx @deepseek-ai/dsh web
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
如果你是从 DeepSeek Harness 源码仓库通过 pnpm 运行,`dsh` 不一定在系统 `PATH` 里,请改用工作区脚本:
|
|
73
|
+
|
|
62
74
|
```sh
|
|
63
|
-
|
|
75
|
+
cd deepseek-harness
|
|
76
|
+
pnpm dsh plugin --profile web add dsh-vision-router
|
|
77
|
+
pnpm dsh web
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
如果你已经全局安装 DSH CLI,并且终端里能直接执行 `dsh`,也可以继续使用较短的 `dsh ...` 写法。
|
|
81
|
+
|
|
82
|
+
> [!NOTE]
|
|
83
|
+
> 如果你是把插件**首次安装进一个已经长期运行的 Web 进程**,需要让 DSH Web 进程重新加载一次插件本体。插件加载完成后,新增/删除模型、修改自动识图包装范围都会**热更新,无需再重启 DSH**。
|
|
84
|
+
|
|
85
|
+
### 2. 在聊天页切换到「+ 自动识图」模型组
|
|
86
|
+
|
|
87
|
+
插件加载后会自动发现 **设置 → 模型** 里已启用的模型组,并为它们额外创建同名的自动识图入口。例如:
|
|
88
|
+
|
|
89
|
+
```text
|
|
90
|
+
opencode-go ← 原模型组,保持不变
|
|
91
|
+
opencode-go + 自动识图 ← 发图片时选这个
|
|
64
92
|
```
|
|
65
93
|
|
|
66
|
-
|
|
94
|
+
> [!IMPORTANT]
|
|
95
|
+
> **发图前,请点击聊天页输入区右下角的模型选择器,选择带「+ 自动识图」的模型组。**
|
|
96
|
+
>
|
|
97
|
+
> Vision Router 故意**不修改原模型组**。因此如果当前仍选着原来的纯文本 `opencode-go` / DeepSeek 路由,DSH 会在插件处理图片之前先提示“当前模型不支持图片”。这不是视觉后端配置失败,只是还没有切到自动识图入口。
|
|
98
|
+
|
|
99
|
+
这个模型组的模型列表会跟随 DSH 的模型目录实时同步;新增模型或修改包装范围后无需重启。
|
|
67
100
|
|
|
68
|
-
|
|
69
|
-
- 默认视觉链就是内置免费端点;
|
|
70
|
-
- opencode 等自定义/第三方路由用「额外识图包装」获得发图能力;
|
|
71
|
-
- 全部配置可在 **设置 → 插件 → 插件配置 → 视觉路由(自动识图)** 实时修改。
|
|
101
|
+
### 3. 直接粘贴或上传图片
|
|
72
102
|
|
|
73
|
-
|
|
103
|
+
选好「+ 自动识图」模型组后,直接往对话里贴图即可。Agent 会自动挂载视觉工具,通过 `vision_describe`、`vision_ground`、`vision_crop` 等工具看图,需要时连续多步操作。
|
|
104
|
+
|
|
105
|
+
默认已经有内置 OVH 匿名视觉兜底,无需注册、无需 Key。**聊天页右下角只选择“脑子/会话模型”**;视觉模型不要在那里选。高级配置在 **设置 → 插件 → 插件配置 → 视觉路由(自动识图)**:视觉后端链每一行只选择一个你在 **设置 → 模型** 中已经配置且支持图片输入的用户模型;一行都不填也可以,OVH 免费链会固定在最后兜底。插件内部的 `Vision HTTP` 只是传输实现,不是用户需要选择的模型组。
|
|
74
106
|
|
|
75
107
|
### 实际效果
|
|
76
108
|
|
|
@@ -148,11 +180,14 @@ vision_long_screenshot_ocr image="chat-log.png" chunkHeight=1200 overlap=120
|
|
|
148
180
|
|
|
149
181
|
## 供应商降级链
|
|
150
182
|
|
|
151
|
-
|
|
183
|
+
视觉工具按顺序逐个尝试,全部失败才报错:
|
|
184
|
+
|
|
185
|
+
1. **用户视觉模型**:设置卡里一行一个,从上到下;只显示 **设置 → 模型** 中明确声明支持 image 输入的模型;
|
|
186
|
+
2. **高级自定义 HTTP 视觉端点**:如果旧配置/高级配置中存在 `httpProviders`,在用户模型之后尝试;
|
|
187
|
+
3. **内置 OVH 匿名免费兜底**:固定最后尝试,不需要出现在任何模型选择器里。当前内置链按质量优先为 `Qwen3.5-397B-A17B` → `Qwen2.5-VL-72B-Instruct` → `Qwen3.6-27B` → `Mistral-Small-3.2-24B-Instruct-2506` → `Qwen3.5-9B`。OVH 匿名限额为 **每 IP、每模型 2 次/分钟**;5 个模型是独立限额,因此理论上分散请求可到约 **10 次/分钟**,实际仍以 OVH 当时的限流为准。免注册、免 Key。
|
|
152
188
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
3. 配置的 `providers` / `provider` + `fallbacks`(任何有适配器的供应商,例如 Pi-AI 配置的 OpenRouter 或智谱)。
|
|
189
|
+
> [!IMPORTANT]
|
|
190
|
+
> 这里的“视觉链”是 Vision Router 调用的**眼睛**:设置页里每一行只选一个用户视觉模型;聊天页右下角选择的是**脑子/会话模型**,两者完全分开。纯文本 DeepSeek / opencode 不会出现在视觉后端下拉里;内部 `Vision HTTP` 也不会再暴露给用户。
|
|
156
191
|
|
|
157
192
|
> 在旧版 `routing: true` 模式下,整轮链只走 `provider + fallbacks`——`httpProviders`(含免费兜底)不参与。默认的 `routing: false`(工具优先)会尝试全部。
|
|
158
193
|
|
|
@@ -172,20 +207,28 @@ vision_long_screenshot_ocr image="chat-log.png" chunkHeight=1200 overlap=120
|
|
|
172
207
|
|
|
173
208
|
官方行在场时,插件自动回退为可见包装入口。反过来,隐身模式关闭但官方行仍被禁用时,插件会做 keep-alive 兜底接管,保住 DeepSeek 模型(设置卡片会给出提示);想完全恢复官方原生行,把上面的 `disabled` 改回 `false` 再重启即可。
|
|
174
209
|
|
|
175
|
-
> 隐身模式**只作用于官方 DeepSeek 路由**。opencode
|
|
210
|
+
> 隐身模式**只作用于官方 DeepSeek 路由**。opencode 等自定义/第三方文本路由与隐身模式无关——默认会被自动包装成「+ 自动识图」模型组。
|
|
211
|
+
|
|
212
|
+
## 自动识图模型组与手动包装
|
|
176
213
|
|
|
177
|
-
|
|
214
|
+
默认开启 `autoWrapProviders`:插件会自动发现 **设置 → 模型** 中当前已启用的 provider / model,并额外注册同名的「+ 自动识图」模型组。**原模型组完全不变**;发图片时选自动识图组,纯文字仍可继续用原组。DSH 的 `llm/adapters-updated` 变化会触发同步,所以新增/删除模型后无需重启。
|
|
178
215
|
|
|
179
|
-
`wrappedProviders`
|
|
216
|
+
`wrappedProviders` 是**可选的手动范围控制**,不是普通用户必须配置的步骤。只有两种情况需要它:
|
|
217
|
+
|
|
218
|
+
1. 关闭了自动包装,想手动指定哪些 provider / model 获得自动识图入口;
|
|
219
|
+
2. 自动包装保持开启,但只想让某个 provider 的部分模型出现在「+ 自动识图」组。
|
|
220
|
+
|
|
221
|
+
设置卡片里用两个下拉(provider + 模型)配置;模型留空 = 包装该路由的全部模型,同一 provider 要限定多个模型就添加多行。修改即时生效,无需重启。
|
|
180
222
|
|
|
181
223
|
## Web 设置
|
|
182
224
|
|
|
183
|
-
Web 配置页在 **设置 → 插件 → 插件配置**
|
|
225
|
+
Web 配置页在 **设置 → 插件 → 插件配置** 下注册「视觉路由(自动识图)」卡片,顶部会直接提示最重要的使用步骤:**回到聊天页 → 右下角模型选择器 → 选择「+ 自动识图」模型组 → 发图**。其余设置主要用于高级定制:
|
|
184
226
|
|
|
227
|
+
- **自动创建「+ 自动识图」模型组**:默认开启,自动发现已有模型;模型目录变化热更新,无需重启;
|
|
228
|
+
- **手动限定自动识图范围(可选)**:仅在需要关闭自动包装或限制部分模型时使用;
|
|
229
|
+
- **视觉后端链**:给 `vision_describe` 等视觉工具调用的真正图片模型,默认内置免费 Qwen 即可;不要填纯文本模型;
|
|
185
230
|
- 开关:整轮自动路由(旧模式)、识图工具、图片块改写、隐身模式(仅官方 DeepSeek 路由);
|
|
186
|
-
-
|
|
187
|
-
- 视觉请求超时、包装/链路由名;
|
|
188
|
-
- **视觉模型链**(每行一个 `provider/model`,自上而下降级)与文本模型;
|
|
231
|
+
- 视觉请求超时、包装/链路由名、代理等高级参数;
|
|
189
232
|
- 每个字段都有「已覆盖」徽标与一键恢复组合默认,以及放弃/保存;
|
|
190
233
|
- 「测试连接」按钮探测第一个视觉提供方并内联显示延迟/失败原因;
|
|
191
234
|
- 产出制品的工具在对话里渲染专用调用卡(关键字段 + 打开文件按钮)。
|
|
@@ -202,15 +245,16 @@ Web 配置页在 **设置 → 插件 → 插件配置** 下注册「视觉路由
|
|
|
202
245
|
|
|
203
246
|
| 字段 | 默认值 | 含义 |
|
|
204
247
|
|---|---|---|
|
|
205
|
-
| `provider` / `model` | `vision-http` / `ovh/Qwen2.5-VL-72B-Instruct` |
|
|
206
|
-
| `fallbacks` | `[]` |
|
|
207
|
-
| `providers` | 内置免费 `vision-http` 条目 |
|
|
248
|
+
| `provider` / `model` | `vision-http` / `ovh/Qwen2.5-VL-72B-Instruct` | 简写视觉后端链路(有适配器且真正支持图片输入的供应商 + 模型) |
|
|
249
|
+
| `fallbacks` | `[]` | 简写视觉供应商的备用图片模型 |
|
|
250
|
+
| `providers` | 内置免费 `vision-http` 条目 | 多供应商视觉后端链 `{ provider, model, fallbacks[] }`,按序尝试;优先于简写形式。不要填写纯文本模型 |
|
|
208
251
|
| `httpProviders` | 内置 OVH 条目 | OpenAI 兼容直连端点 `{ name, baseURL, model, apiKeyEnv, maxTokens }` |
|
|
209
|
-
| `
|
|
252
|
+
| `autoWrapProviders` | `true` | 自动发现当前已启用 provider / model,并热更新同名「+ 自动识图」模型组;原模型组不变 |
|
|
253
|
+
| `wrappedProviders` | `[{ provider: 'deepseek-official', models: [] }]` | 可选的手动包装范围 `{ provider, models[] }`;用于关闭自动包装后手动指定,或限制某个 provider 只包装部分模型。改动即时生效,无需重启 |
|
|
210
254
|
| `routing` | `false` | 旧版整轮链路由(一次性整轮回答)。`false` = 工具优先流程(推荐) |
|
|
211
255
|
| `reverseRouting` | `true` | 开启 `routing` 时,文字轮路由回 `textProvider` |
|
|
212
256
|
| `wrapperRoute` / `chainRoute` | `deepseek-vision` / `vision-chain` | 准入包装路由名 / 降级链路由名(置空关闭) |
|
|
213
|
-
| `stealth` | `false` | 接管官方 `deepseek-official`
|
|
257
|
+
| `stealth` | `false` | 接管官方 `deepseek-official` 路由(仅官方行;自定义路由默认由自动包装处理) |
|
|
214
258
|
| `textProvider` | `deepseek-official` / `deepseek-v4-pro` | 负责思考的模型(你的日常模型) |
|
|
215
259
|
| `tool` / `progressiveTools` / `autoActivateOnImage` | `true` ×3 | 视觉工具开关 / 渐进式挂载 / 图片轮自动挂载 |
|
|
216
260
|
| `rewriteImages` | `true` | 模型输入层改写图片块(缓存描述或工具提示标记);界面日志保留图片 |
|
|
@@ -222,7 +266,7 @@ Web 配置页在 **设置 → 插件 → 插件配置** 下注册「视觉路由
|
|
|
222
266
|
|
|
223
267
|
## 环境要求
|
|
224
268
|
|
|
225
|
-
- DeepSeek Harness 的 Web profile
|
|
269
|
+
- DeepSeek Harness 的 Web profile。普通安装可用 `npx @deepseek-ai/dsh ...`;从源码仓库运行时用 `pnpm dsh ...`。只有 CLI 已经进入系统 `PATH` 时才能直接写 `dsh ...`。
|
|
226
270
|
- Node ≥ 22(宿主侧)。
|
|
227
271
|
- 默认免费链路无需 API Key;付费 `httpProviders` 只需一个凭据引用(`apiKeyEnv`)。
|
|
228
272
|
- `vision_html_screenshot` 才需要 Chrome / Chromium / Edge;其余工具无浏览器也能用。
|
|
@@ -232,12 +276,21 @@ Web 配置页在 **设置 → 插件 → 插件配置** 下注册「视觉路由
|
|
|
232
276
|
|
|
233
277
|
### 安装
|
|
234
278
|
|
|
279
|
+
普通 npm / npx 安装:
|
|
280
|
+
|
|
281
|
+
```sh
|
|
282
|
+
npx @deepseek-ai/dsh plugin --profile web add dsh-vision-router
|
|
283
|
+
npx @deepseek-ai/dsh --profile web --dump-config | grep vision-router
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
从 DeepSeek Harness 源码仓库运行:
|
|
287
|
+
|
|
235
288
|
```sh
|
|
236
|
-
dsh plugin --profile web add dsh-vision-router
|
|
237
|
-
dsh --profile web --dump-config | grep vision-router
|
|
289
|
+
pnpm dsh plugin --profile web add dsh-vision-router
|
|
290
|
+
pnpm dsh --profile web --dump-config | grep vision-router
|
|
238
291
|
```
|
|
239
292
|
|
|
240
|
-
|
|
293
|
+
首次把插件装进已经长期运行的 Web profile 时,需要让 Web 进程重新加载插件本体;宿主在启动时通过 `dsh.client` 声明发现浏览器端包。**插件加载完成后,模型目录与包装范围的变化会热更新,不需要为这些变化重启。**
|
|
241
294
|
|
|
242
295
|
### 禁用 / 恢复
|
|
243
296
|
|
|
@@ -251,19 +304,77 @@ dsh --profile web --dump-config | grep vision-router # 一行,由 bundle 补
|
|
|
251
304
|
### 升级
|
|
252
305
|
|
|
253
306
|
```sh
|
|
254
|
-
|
|
307
|
+
# 普通 npm / npx 安装
|
|
308
|
+
npx @deepseek-ai/dsh plugin --profile web update dsh-vision-router
|
|
309
|
+
|
|
310
|
+
# DeepSeek Harness 源码仓库
|
|
311
|
+
pnpm dsh plugin --profile web update dsh-vision-router
|
|
255
312
|
```
|
|
256
313
|
|
|
257
314
|
设置存放在 profile 的设置提供方里,升级不丢失。
|
|
258
315
|
|
|
316
|
+
> **从 bundle 补丁之前(v0.x)升级:** 现在插件由自带的 bundle 补丁自动挂载,
|
|
317
|
+
> 若 `~/.dsh/profiles/<profile>/cordis.patch.yml` 里还残留旧版手动行,会与之
|
|
318
|
+
> 重复,`dsh web` 启动即报 `duplicate loader entry id: vision-router`。删除
|
|
319
|
+
> 旧块:
|
|
320
|
+
>
|
|
321
|
+
> ```yaml
|
|
322
|
+
> - insert: # 删除整块
|
|
323
|
+
> - id: vision-router
|
|
324
|
+
> name: dsh-vision-router
|
|
325
|
+
> ```
|
|
326
|
+
>
|
|
327
|
+
> 若要保留自定义配置,改为不带 insert 的按 id 覆盖行:
|
|
328
|
+
>
|
|
329
|
+
> ```yaml
|
|
330
|
+
> - id: vision-router
|
|
331
|
+
> config:
|
|
332
|
+
> # 你的配置…
|
|
333
|
+
> ```
|
|
334
|
+
|
|
259
335
|
### 卸载
|
|
260
336
|
|
|
261
337
|
```sh
|
|
262
|
-
|
|
338
|
+
# 普通 npm / npx 安装
|
|
339
|
+
npx @deepseek-ai/dsh plugin --profile web remove dsh-vision-router
|
|
340
|
+
|
|
341
|
+
# DeepSeek Harness 源码仓库
|
|
342
|
+
pnpm dsh plugin --profile web remove dsh-vision-router
|
|
263
343
|
```
|
|
264
344
|
|
|
265
345
|
同时移除依赖与 bundle 层。若你曾手动禁用官方 DeepSeek 行,记得在 profile 补丁里恢复。
|
|
266
346
|
|
|
347
|
+
## 故障排查
|
|
348
|
+
|
|
349
|
+
### 启动报错 `Unexpected token ... is not valid JSON`(UTF-8 BOM)
|
|
350
|
+
|
|
351
|
+
**现象**:`dsh web` / `pnpm dsh web` 启动时直接退出:
|
|
352
|
+
|
|
353
|
+
```
|
|
354
|
+
SyntaxError: Unexpected token ...
|
|
355
|
+
is not valid JSON
|
|
356
|
+
at JSON.parse (<anonymous>)
|
|
357
|
+
at readProfileManifest (packages/boot/app-boot/src/profile.ts)
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
**原因**:`~/.dsh/profiles/<profile>/package.json` 被某些编辑器保存成了 **UTF-8 with BOM**。文件最前面多了一个不可见的 `\uFEFF` 字符,dsh 读取 manifest 时直接 `JSON.parse`,而 JSON 不允许在开头出现这个字符,于是解析失败。
|
|
361
|
+
|
|
362
|
+
**推荐修复**:直接运行 Vision Router 自带的独立修复命令。它不需要 DSH 先成功启动,会定位 profile、检测 UTF-8 BOM,只删除开头的三个 BOM 字节,然后重新验证 JSON:
|
|
363
|
+
|
|
364
|
+
```sh
|
|
365
|
+
npx dsh-vision-router repair --profile web
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
只想检查、不修改文件时:
|
|
369
|
+
|
|
370
|
+
```sh
|
|
371
|
+
npx dsh-vision-router doctor --profile web
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
如果你使用的不是 `web` profile,把 `web` 换成对应名称;也可以不传 `--profile`,让 doctor 扫描全部 profile。
|
|
375
|
+
|
|
376
|
+
手动兜底方式:VS Code 右下角编码 → “通过编码保存” → 选择 `UTF-8`(无 BOM)。若 `repair` 去掉 BOM 后仍提示 JSON 非法,它不会猜测或重写其他 JSON 内容,请再手动检查文件。
|
|
377
|
+
|
|
267
378
|
## 安全说明
|
|
268
379
|
|
|
269
380
|
- 图片中的文字是**不可信证据**:描述、OCR 输出与自动挂载提示都要求 Agent 绝不执行图片内出现的指令。
|