# dsh-vision-opencode

> 给 DSH 的纯文本主模型挂一个可配置的识图模型：聊天发图自动转成文字，保留原生多模态模型不变。

## Metadata

- Author: [@poiuyjie](https://github.com/poiuyjie)
- Repo: <https://github.com/poiuyjie/dsh-vision-opencode.git>
- GitHub: [poiuyjie/dsh-vision-opencode](https://github.com/poiuyjie/dsh-vision-opencode)
- Stars: 13
- Language: JavaScript
- License: [MIT](https://spdx.org/licenses/MIT.html)
- Topics: `deepseek-harness`, `dsh`, `dsh-plugin`, `dsh-plugin-market`, `dsh-plugins`
- Forks: 2
- Open Issues: 0
- Last push: 2026-08-20T20:19:07.000Z
- Added: 2026-08-20T00:00:00.000Z

## Install

```bash
dsh plugin --profile web add github:poiuyjie/dsh-vision-opencode
```

## Wiki

## 一句话定位
给 DSH 的纯文本主模型配一个独立的识图模型：聊天里发的图片会先被识图模型"翻译"成文字描述，再交给主模型，主模型不用切也能"看"图；原生多模态主模型则完全走 DSH 原生链路，不会被插件干涉。

## 核心能力
- 聊天发图自动转文字：纯文本主模型也"看"得到图，图片被识图模型分析成一段"图片内容分析"文本后注入上下文，原图仍留在会话历史里（UI 可见）
- 原生多模态模型自动放行：插件通过 `resolveModelInfo` 实时识别路由的图片输入能力，自带 image 能力的主模型完整保留 DSH 原生图片链路
- `vision_read_image` 工具：模型可显式调用，按 PNG/JPEG/WebP/GIF 路径直接读图、分析、回传文本（OCR、图表、截图场景）
- 输入框右侧"识图模型"下拉 + 设置→Vision：自动列出所有供应商里支持图片输入的模型，可设置"关闭思考/强制关闭"等推理策略
- 内置兜底：识图失败 → 60s 超时 → 1 次退避重试 → 重试耗尽降级为占位文本，主模型回合不会被识图失败拖垮
- 旧版本 modelOverrides 自动还原：升级前写入的 llm-pi-ai 图片闸门在首次启动时由插件根据内置 `gateState` 所有权记录精确还原

## 技术实现
- **语言**: JavaScript（ESM，type: module）
- **关键依赖**: `@deepseek-ai/dsh-llm`（BlockAssembler / createUserMessage / freezeMessage）、`@deepseek-ai/dsh-tools`（defineTool）、`@deepseek-ai/dsh-settings`（settingsNamespace）、`@deepseek-ai/schemastery`（运行时校验）
- **架构模式**: Cordis 插件；后端 `index.js` 通过 `ctx.on('llm/stream')` 拦截含图请求、用 `Symbol('vision-bypass')` 短路自递归、`tools.guard` 拒绝内置 `read_image` 在纯文本主模型上注入真图；前端 `client.js` 通过 `window.__ModuleLoader__.load` 注入 React 组件到 `conversation.input.right` slot；`core.js` 暴露纯函数供 host/client 复用
- **入口文件**: `index.js`（后端，注入 llm/stream / tools / settings / webServer），`client.js`（前端，识别模型选择器 + 设置页），`core.js`（图片计数、替换、模型信息兼容层）

## 适用场景
当你用 DSH 配的是纯文本主模型（比如早期 DeepSeek 系列、开源 Qwen2.5 等），但又希望聊天里能直接发截图、菜单截图、图表让 AI 看到时，这个插件让你不用把主模型换成多模态也能"看图"——所有供应商里支持图片输入的模型都能被指定为辅助识图模型，搭配"强制关闭思考"还能省下首 token 延迟。如果你的主模型本身是原生多模态（如 Vision 系列），本插件不会做任何事，原生链路直接生效。

## 前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DSH（含 dsh-llm / dsh-tools / dsh-settings） | `>=0.1.0-rc.6 <0.2.0` | peerDependencies 区间，4 个 DSH 核心包同区间 |
| @deepseek-ai/dsh-skill | 同上 | 可选，缺失时仅 skill 注册跳过，工具与自动转换仍可用 |
| @deepseek-ai/schemastery | 任意 | 运行时配置校验 |
| Node.js | `>=20.3` | 仅部分 await / AbortSignal.any 等 ES2022 特性依赖 |
| 平台 | DSH Web 客户端 | `dsh.client.platform: "web"`，CLI / 桌面端无 HTTP 端点与 SSE 进度 |
| 原生模块 | 无 | 纯 JS 实现，不引入 node-pty / sqlite / native addons |

## 安装方式
```bash
dsh plugin --profile web add github:poiuyjie/dsh-vision-opencode
```

也可选 `scripts/install.sh`（Ubuntu 一键脚本，支持 `--vision-provider` / `--vision-model` / `--proxy` 等参数）或 `scripts/install.ps1`（Windows 脚本）。装完重启 dsh，浏览器硬刷新（Ctrl+Shift+R），输入框右侧会出现"识图模型"下拉。

## 配置项
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| `vision-opencode.provider` | 字符串 | 识图模型供应商路由 id（如 `opencode-go`、`my-custom`） | 空 |
| `vision-opencode.model` | 字符串 | 识图模型 id | 空 |
| `vision-opencode.visionModels` | 数组 | 插件自管的识图模型清单（含 `id` / `provider` / `model` / `name` / `description` / `baseUrl` / `requestFormat` / `reasoning`），与宿主 provider 目录解耦 | `[]` |
| `vision-opencode.autoConvert` | 布尔 | 聊天发图自动转换开关；关闭后只保留工具与选择器 | `true` |
| `vision-opencode.visionReasoning` | 布尔 | 是否在识别图片时启用思考（true=跟随供应商默认档；false=默认关闭思考） | `false` |
| `vision-opencode.apiKey` | 字符串（隐藏） | 强制关闭模式下直连网关（opencode-go）时使用的 API Key；留空则读取 `OPENCODE_GO_API_KEY` 环境变量 | 空 |
| `vision-opencode.mainProvider` | 字符串 | 旧版/手动兼容的主模型供应商；当前版本通常由适配器能力自动识别 | 空 |
| `vision-opencode.mainModels` | 数组 | 同上的兼容主模型列表 | `[]` |
| `vision-opencode.ignoredModels` | 数组 | 设置页里被用户主动叉掉的"未导入系统模型"清单，持久化避免下次重开又提示 | `[]` |
| `vision-opencode.gateState` | 字符串（隐藏） | 旧版本 modelOverrides 所有权记录（base64url），卸载时用于精确还原 | 空 |

设置页（Settings → Vision）会基于上述 schema 自动生成表单；同时也支持直接编辑 `~/.dsh/settings.yaml`。

## 常见问题

**Q: 装了之后必须挑一个识图模型吗？**

A: 强烈建议。设置→Vision 或输入框右侧下拉里挑一个；没挑时插件以占位文本提示"未配置识图模型"，主模型仍能正常回答但看不到图——这相当于"装了一半"。

**Q: 只想关掉自动转换、保留工具和选择器可以吗？**

A: 可以。`~/.dsh/settings.yaml` 把 `vision-opencode.autoConvert` 改为 `false` 再重启 dsh；`vision_read_image` 工具和输入框右侧的识图模型下拉都还在，只有聊天发图自动转文字这条链路被停用。

**Q: 图片转换失败 / 选择器不出现怎么办？**

A: 十有八九是识图模型没选，或选了不被插件当多模态模型识别的 id。先看 settings 里 `provider` 和 `model` 字段都填了，再打开浏览器开发工具看 Console 报错，最后去插件仓库 issue 区贴日志发问题。

**Q: 切到原生多模态主模型（比如带 image 输入的）会受影响吗？**

A: 不会。插件挂着 `resolveModelInfo` 钩子，识别到当前路由原生支持图片（`inputModalities` 含 `image`）时直接放行，走 DSH 自带图片链路，不会被拦截重转。

**Q: "关闭思考"真的能省吗？**

A: 取决于供应商是否真的为该模型声明了关闭档位。极少数模型有真"关闭"档（hy3 `off:"none"` 之流）；大多模型只能在"强制关闭"档顺序试 `thinking:{type:disabled}` / `reasoning_effort:"none"` / `enable_thinking:false` 三种 wire 参数，插件逐个试并记住哪个对该供应商标 `0 reasoning_tokens` 后复用，但不能保证每个供应商都能跑通。

**Q: 卸载前需要注意什么？**

A: 先备份包含图片的会话。卸载后旧会话里的图片辅助分析会被清掉，纯文本主模型重启后拿不到那些分析结果；如果不重新发图，模型就不知道那张图原来是什么。

**Q: 支持哪些图片格式？**

A: PNG / JPEG / WebP / GIF 四种。`vision_read_image` 工具和聊天发图都用这同一份白名单；其他格式在 attachments 服务层就直接被拒。

**Q: 能在 DSH CLI / 桌面端用吗？**

A: 不能。仓库在 `package.json` 把 `dsh.client.platform` 显式声明为 `web`，HTTP 端点（`/vision-opencode/config` 等）、SSE 进度推送（`/vision-opencode/events`）、设置面板与 React 组件都绑定 DSH Web 客户端。

## 上手难度
入门 — 安装一行命令、重启 DSH、刷新浏览器，然后从输入框右侧下拉里选一个识图模型即可；想完全自定义时再进 Settings → Vision 调 schema 表单。

## 已知问题与限制
- "关闭思考"靠供应商目录 / adapter 元数据判断：插件尽力区分"真申报 off"与"未申报（仅返回思考档位）"，但 pi-ai 形态变化（JSON 文件 vs 模块导出）时可能触发 warn 日志并回退适配器面值（`index.js:594`）；强制关闭通过直连网关试三种参数，不能保证每个供应商都能真正关掉
- 主模型若非 `dsh-llm-pi-ai` 适配器（典型如 `dsh-llm-deepseek`）：插件 warn 后跳过图片提交闸门兼容层安装（`index.js:229`），这种主模型上的图片提交仍可能直接被 DSH 拒绝
- 60s 强制超时 + 1 次退避重试（`index.js:508-512`）：超长 OCR 或大型图表识别可能被打断；当前内置 `attachments.imageLimits` 决定图片像素上限（`index.js:1746-1764`），大图会被先在服务层裁切
- 内置 `read_image` 工具在纯文本主模型上被强制拦截（`index.js:251-265`）：返回的"工具结果"会引导模型改用 `vision_read_image`，但若模型坚持调用，会不断收到"blocked"提示而非真实图
- 旧版本（≤0.3.2）写过 `llm-pi-ai.modelOverrides`：升级时插件用 `gateState` 所有权记录精确还原，还原失败时保留 `gateState` 等待下次重启重试（`index.js:458-462`）
- 卸载走 `POST /vision-opencode/uninstall`（需带 `X-Vision-Opencode-Action: uninstall` 自定义头）：仅清理本插件 settings 与旧 modelOverrides；DSH 本身的依赖、profile 目录、cordis.patch.yml 里的 `insert` 条目需手动卸载（`index.js:1671-1674`）
- 仅支持 DSH Web 客户端：`dsh.client.platform: "web"` 在 `package.json:49` 显式声明，CLI / 桌面端 / 移动端等其他宿主没有对应 bundle
- 跨版本兼容：DSH 升级换 hash 前缀时，前端组件能通过扫描 `document.styleSheets` 自动适配（`client.js:63-105`），但若官方 React slot 名发生变化，组件可能需要重新定位注入位置

---

This document is auto-generated by [deepseek-plugin.org](https://deepseek-plugin.org). HTML page: [dsh-vision-opencode](https://deepseek-plugin.org/plugins/poiuyjie/dsh-vision-opencode)
Wiki generated by AI (model: `MiniMax-M3`)
