dsh-show-image
展示给用户,绝不喂给模型。
🖼️ 纯文本 LLM 也能"发图" · 🔒 图片永不进入模型上下文 · 💡 点击悬浮窗全屏查看
为 DeepSeek Harness(DSH)而写的图片展示插件
[!NOTE] 本插件由 AI agent 编写并经过真机验证(WebUI 实际跑通:卡片渲染、悬浮窗、会话不报错), 但未经安全审计、与 DeepSeek 官方无关、不提供任何担保。代码不大(host 端约 200 行、 client 端约 300 行),用之前建议通读一遍
lib/。review / PR 都欢迎。
目录
这是什么
DSH 的模型路由(pi-ai、deepseek 直连等)有个硬规则:会话历史里出现图片内容块,而当前模型不支持多模态,就抛 UNSUPPORTED_CONTENT。
由于内容块已持久化在会话日志里,之后每一轮都会重放同样的失败——会话直接废掉。
这个插件补上缺失的"输出方向":让纯文本 LLM 也能把本地图片展示给用户, 而图片字节只走展示通道,模型永远只看到文本(路径列表)。
为什么需要它
| 场景 | 原生 DSH | 本插件 |
|---|---|---|
| 文本模型想把本地截图/渲染图/图表给你看 | 没有展示工具;硬塞图片块进结果 → 会话报废 | 调用 show_image,卡片秒出,会话安全 |
| 多模态模型展示图片 | 可以,但图片进了模型上下文(费 token) | 同样展示,但模型只收到文本路径 |
| 点击图片查看大图 | — | 页面内悬浮窗(lightbox) |
它如何工作
模型调用 show_image(路径)
│
▼
Host 端 execute
├─ 读取本地图片(png / jpg / jpeg / webp / gif)
├─ 存入附件库(内容寻址去重 + 校验元数据)
└─ 生成 base64 data URL
│
▼
render(模型可见) presentationMeta(用户可见)
┌──────────────┐ ┌──────────────────────────┐
│ 1. C:\a.png │ │ images: [{ dataUrl, ... }]│
│ 2. C:\b.png │ └──────────────────────────┘
└──────────────┘ │
│ ▼
纯文本,安全 Client 端 toolview
渲染图片卡片
│ 点击
▼
shell.overlay 悬浮窗
(✕ / 点外部 / Esc 关闭)
三个设计点:
- 模型侧只有文本:
render输出纯文本路径列表——任何路由、任何纯文本模型都不会触发图片内容检查; - 展示侧走 presentation:图片字节放进工具结果的
meta(presentationMeta),由客户端直接渲染,不经过会话消息内容; - 不依赖附件引用 RPC:
session.readAttachment要求图片块出现在模型可见内容里("被会话引用"),与纯文本模型天然冲突,所以弃用;附件库仅用于元数据校验与去重。
高亮特性
- 纯文本模型零负担 —— 模型永远只收到文本;pi-ai / deepseek 直连等所有路由下都不会报
UNSUPPORTED_CONTENT; - 卡片式展示 —— 内联图片网格,支持
columns(1-6 列)与captions参数; - 悬浮窗查看 —— 点击任意图片弹出全屏 lightbox(harness 原生
shell.overlay槽位),右上角 ✕、点击遮罩、Esc 三种方式关闭; - 会话日志安全 —— 图片字节在日志里只以展示 meta 存在,不进入模型历史,旧会话不报废;
- 标准 cordis bundle ——
dsh plugin add安装,卸载自动 dispose 全部副作用。
快速开始
# ~/.dsh/profiles/<profile>/cordis.patch.yml
- insert:
- id: show-image
name: 'dsh-show-image'
config:
maxImages: 12
maxBytes: 83886080
maxEmbedBytes: 2097152
装完重启 dsh web、硬刷新浏览器,然后让模型调用 show_image:
请调用 show_image 工具,把 C:\Users\xxx\shot.png 显示给我。
安装
本包是标准 bundle(package.json 声明 dsh.client,lib/ 已编译提交,无构建步骤)。
方式一:本地目录
dsh plugin --profile web add ./dsh-show-image
方式二:从 GitHub 安装
dsh plugin --profile web add github:<你的用户名>/dsh-show-image
lib/是纯 JS,没有prepare脚本,不需要allowBuilds放行。
方式三:手动拷贝(无 pnpm 时兜底)
把整个目录拷到 ~/.dsh/profiles/<profile>/node_modules/dsh-show-image(hoisted 布局拷贝即可被 loader 解析),再在 cordis.patch.yml 挂载。
验证与注意
- 验证:重启后让模型调用
show_image,看到图片卡片即成功; - 注意:插件代码在 node_modules 里,HMR 不追踪——改代码必须重启;
- 卸载:
dsh plugin --profile web remove dsh-show-image(或 patch 行加disabled: true),重启。
配置
| 配置项 | 默认 | 说明 |
|---|---|---|
maxImages |
12 | 单次最多显示的图片数 |
maxBytes |
8 MiB | 单张读取上限(与附件服务上限取更小者) |
maxEmbedBytes |
2 MiB | 单张可嵌入会话展示的最大字节数;data URL 会随会话日志持久化,超限直接报错,避免日志膨胀 |
交互体验
- 内联卡片:网格布局,悬停显示完整路径,光标为放大镜;
- 点击图片 → 页面内悬浮窗:半透明遮罩 + 居中大图 + 下方 caption;
- 关闭:右上角 ✕、点击遮罩(图片以外区域)、按
Esc。
边界与限制
- 单张超过
maxEmbedBytes会报错而不是静默降级(防止日志膨胀);调大配置即可; - 图片以 base64 存于工具结果 meta,会随会话日志持久化——单会话大量大图会增大日志体积;
- 旧版本插件(往模型内容里塞图片块)产生的已损坏会话不会被修复,请开新会话;
- 只支持 png / jpg / jpeg / webp / gif(附件库媒体类型)。
与"让 DeepSeek 支持视觉"项目的关系
社区项目(codex-vision-proxy、codex-deepseek-vision、pi-vlm-proxy、dsh-tool-see-image 等)解决的是输入方向:拦截图片,用 OpenAI 兼容视觉模型(如免费 GLM-4V-Flash)把图转成文字,让文本模型"看见"。本插件解决输出方向:让用户在回复中看到本地图片。两者互补,可共存。
测试
手工验证清单(真机跑通项):
- 模型调用
show_image显示 4 张图(含 columns/captions)→ 卡片按 2 列渲染、caption 正确; - 点击图片 → 悬浮窗出现大图;✕ / 点外部 / Esc 均能关闭;
- 显示完图片后再问模型一个问题 → 正常回答,会话不报
UNSUPPORTED_CONTENT; - 让模型显示超过
maxEmbedBytes的图 → 得到明确报错文本而非崩溃。
贡献
PR、issue、review 都欢迎。改动后请同步 lib/index.js(host)与 lib/client.js(client)两端的协议(输出 schema、meta 结构)。
No comments yet. Be the first to write one.