让对话中的图片仅在首次请求内联,后续自动换占位文字
30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/10 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/senyayume/dsh-image-once.git状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
是什么
生态应用
桌面端 / Web 外壳,不以 dsh plugin add 安装
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 24 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🟢 扫描:未发现敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 图片仅首次请求内联
- 后续替换占位文本
DSH 插件:图片块只在首次出现的请求里内联,之后换成 harness 自带的占位文本
README
由 DeepSeek 最新模型翻译生成dsh-image-once
「图片只发一次」:对话里的每个图片块只在它出现的那一次请求里以 base64 内联,之后的请求换成 DSH 自带的占位文字(占位文字里带本地只读路径,模型要看时自己 read_image)。
它长什么样 · 为什么 · 做什么 · 配置 · 客户端半体 · 代价 · 装配
它长什么样
设置 → 插件,找到 dsh-image-once 那一行(行右侧开关控制整个插件是否生效):
插件页上的插件行与「配置」入口
点该行的「配置」进入本插件页面,就是一张 provider 名单:每行一个开关,关掉即该 provider 完全不进本插件;行右侧「限定模型」可以把这个 provider 收窄到几个模型 id。改完即时生效、不用重启。
插件页上的 provider 名单卡片
上面两张都是本机实机截图(亮色主题,DSH Desktop 自带 harness)。卡片里那几行 provider 是本机装了哪些 provider 就是哪些——本插件不认识任何 provider 名,它只是把宿主注册表里的名字原样列出来。
为什么
dsh-llm-pi-ai 会把对话里每个未 offload 的图片出现在每一次请求里重新 base64 内联。于是一旦贴过几张截图,整轮对话的每个 step 都在背几 MB 的请求体。
展开完整文档(README 剩余 1 节)
dsh-image-once
「图片只发一次」:对话里的每个图片块只在它出现的那一次请求里以 base64 内联,之后的请求换成 DSH 自带的占位文字(占位文字里带本地只读路径,模型要看时自己 read_image)。
它长什么样 · 为什么 · 做什么 · 配置 · 客户端半体 · 代价 · 装配
它长什么样
设置 → 插件,找到 dsh-image-once 那一行(行右侧开关控制整个插件是否生效):
插件页上的插件行与「配置」入口
点该行的「配置」进入本插件页面,就是一张 provider 名单:每行一个开关,关掉即该 provider 完全不进本插件;行右侧「限定模型」可以把这个 provider 收窄到几个模型 id。改完即时生效、不用重启。
插件页上的 provider 名单卡片
上面两张都是本机实机截图(亮色主题,DSH Desktop 自带 harness)。卡片里那几行 provider 是本机装了哪些 provider 就是哪些——本插件不认识任何 provider 名,它只是把宿主注册表里的名字原样列出来。
为什么
dsh-llm-pi-ai 会把对话里每个未 offload 的图片出现在每一次请求里重新 base64 内联。于是一旦贴过几张截图,整轮对话的每个 step 都在背几 MB 的请求体。
实测(commandcode,同一张图):
| 请求体 | 首字节 |
| 49B(纯文本)| 2.5s |
| 350KB | 4.7s |
| 1.36MB | 9-11s |
| 4.10MB(12 张小图)| 25.7-27.6s |
| 4.38MB(1 张大 PNG)| 23.5-26.3s |
同尺寸 body 在 deepseek 官方 / workbuddy 上只要 1-3.5s。原始 TLS 分腿测出 4.38MB 上传只花 231ms、首字节 33.2s —— 慢在网关侧 ingest,与我们上行无关。
做什么
每个「图片出现」= sessionId + message.id + 内容树路径 + attachmentId:
- 第一次见到 → 原样内联(保证模型第一次看全),该请求产出第一个 chunk 后才记账(失败/重试不算已发);
- 之后任何请求 → 该出现标 offloaded: true,DSH 自带逻辑把它换成带本地只读路径的占位文字;
- 模型 read_image 重看 = 新出现 → 再内联一次;
- 带 purpose 的辅助请求(会话标题、摘要)不改写、不记账;
- 记账只在内存、只影响本次请求的副本,不写回会话;offloaded 是共享合同字段(DSH 自己的图片压缩流程也用它)。
图片的两种形状,都处理
read_image 的返回在不同 DSH 版本里形状不同,插件必须都认(否则会静默失效:图片每请求重新内联,却不报任何错):
| 形状 | 出自 | 结构 |
| 扁平 | app.asar 内置 dsh 的 createToolResultMessage | { role: "tool", content: [text, image] } |
| 嵌套 | profile 里的 @deepseek-ai/dsh-llm-pi-ai 的 message 构造 | { role: "user", content: [{ type: "tool-result", content: [text, image] }] } |
插件的扫描与改写递归进 tool-result,与 DSH 自己 contentHasImage 的口径一致。判定用 sessionId + message.id + 路径 + attachmentId:顶层路径是纯数字("3")、嵌套是点分("3.1"),所以升级不会让已记账的顶层图片重发一次。
改写是逐块重建:未改动的块(含图片之后的文本、tool-result 外壳)原样保留。
两个已修的缺陷
都由 test/host.mjs 的用例钉住,且都先验证过「旧代码会失败」(不是先写测试再让它过):
1. 丢块 —— 旧实现以 content.slice(0, index) 起手、循环里只 push 图片块,于是第一张图之后的块全部从请求里静默消失:
| 原消息 | 旧实现实际发出 |
| [text:A, image, text:B] | text:A image(offloaded) —— 丢 text:B |
| [image, text:"说明"] | image(offloaded) —— 丢整段说明 |
2. 漏嵌套 —— 旧实现只看 message.content 顶层,tool-result 里的图片完全看不见(read_image 结果在嵌套版本上每请求重发)。
判据不是读注释:先用运行面的真实形状把两个缺陷复现成数据,再改,再让同一组用例由红转绿。
配置(可选)
设置 → 插件 → dsh-image-once 那一行 → 「配置」,就是一张 provider 名单:每行一个开关,关掉即该 provider 完全不进本插件。也可以给某个 provider 限定模型(行右侧「限定模型」)。
缺省对所有 provider、所有模型生效;关掉某些行 = 只收窄那些 provider。
界面上改的就是这一段,也可以直接手写在同一位置
- id: image-once
config:
providers:
<适配器注册名>: enabled: false # 该 provider 完全不进本插件
models: [deepseek/deepseek-v4.1-flash] # 只对这些模型生效;空数组 = 该 provider 全部模型
语义:没出现过的 provider = 生效;providers 为空 = 全部 provider 生效。provider 名匹配适配器注册名(宿主日志里 已包裹 provider "commandcode" 即此名,不是 displayName);models 匹配 options.model,也就是模型 id。
改完即时生效,不用重启(配置是 volatile 的,本插件每次请求现读)。
手写 YAML 的位置与边界
要手写就写 profile 的补丁文件(~/.dsh/profiles/<name>/cordis.patch.yml),它是对包自带那一行的覆盖(补丁层顺序 bundle → profile → home → CLI,后层覆盖前层,且 config 是整块替换而不是 merge):
- id: image-once
config:
providers:
commandcode:
models:
- deepseek/deepseek-v4.1-flash
这里不要再写 insert: —— 包自己的 cordis.patch.yml 已经插入了 id: image-once 这一行,重复 id 会让插件安装的试启动校验回滚。
插件 config 由 cordis 作为 apply(ctx, config) 的第二个参数传入。不要写 ctx.config——未注入 config 服务的插件访问它会抛 cannot get property "config" without inject,宿主会把该 entry 记成 did not activate。
界面与 YAML 是同一份 stored config,只有一个真源;两边不要同时改。
客户端半体
本包有 dsh.client(platform: "web")+ exports["./client"],因此浏览器里会加载 lib/client.js,在 plugins.row.config 槽上按 key = dsh-image-once#image-once 注册上面那张名单卡片。该 bundle 是手写的平台闭包工厂(window.__ModuleLoader__.load({id, factory}),只 require("react"),走平台 seed),没有构建步骤。
配色契约:只用 DSH 自己的 token
卡片的样式表不写任何颜色字面量,全部走 --dsw-alias- 角色 token(外加 --dsw-radius-、--dsw-focus-ring-*、--ds-font-family-code),因此亮/暗主题各自成立、皮肤覆盖也跟着走。
这条规矩是被一次真实事故逼出来的:早先的样式表读的是 --dsh-text / --dsh-border / --dsh-accent / --dsh-danger——这四个名字 DSH 从来没有定义过(本机 app.asar 与 @deepseek-ai/dsh-client-ui-theme 里定义数为 0,扫描 31829 个文件同样为 0)。var() 引用了不存在的自定义属性时整条声明无效,于是
- 文字色回退到浏览器默认色(亮色主题下接近不可见);
- 开关/选中态用上了插件自己写的深色兜底值(蓝 #4c8dff、rgba(120,170,255,.22))。
判据(插件页那张截图):全部文字实测 #e6e6e6(正是 CSS 里写的兜底值),而同一页官方文字是 #0f1115;开关胶囊实测正好 rgb(76,141,255) = 兜底值 #4c8dff 的逐字节相等——不是"看起来像",是字面值落地。
test/client.mjs 现在有一道门禁:抽取 bundle 真正注入的样式表,逐个 var() 名字比对显式白名单,并要求零颜色字面量。新增 token 前先确认它由 @deepseek-ai/dsh-client-ui-theme(或 shipped ui-primitives)定义,再进白名单——写错名字会测试失败,不再静默渲染成错的颜色。
代价
模型对每张图的「视觉记忆」只有内联那一次;之后它只知道这张图存在(sha256 / 尺寸 / 文件名 / 本地只读路径),要再看细节会自己 read_image,那次请求再内联一次。对「贴图看一眼然后文字讨论」几乎免费。
装配
本地包形态(dsh.bundle.patch + cordis.patch.yml),用 dsh plugin --profile <profile> add <本包目录|github:senyayume/dsh-image-once> 安装,进 dsh.profile.bundles,插件页可见、可开关。
package.json 的 peerDependencies 里必须保留 @deepseek-ai/schemastery:宿主半体 import z from "@deepseek-ai/schemastery",而本包在 profile 里是 linked 形态,bare specifier 只会在祖先目录的 peerDependencies 里被 routeLinked 拦到真实安装目录。
改了 lib/index.js、lib/client.js、cordis.patch.yml 或 package.json 后要整包重启 DSH Desktop:宿主热重放补丁层时会复用 Node 的 ESM 模块缓存,.mjs/.js 的改动热更吃不到;package.json 的 dsh.client/exports 变更还要让 client-modules 重新扫描 roster。
测试
node test/run.mjs
两半都跑:test/host.mjs(请求投影、occurrence 记账键、两种图片形状、上面两个已修缺陷、首个 chunk 后才记账)与 test/client.mjs(token 白名单、零颜色字面量门禁、zh/en 键对齐)。test/run.mjs 需要 @deepseek-ai/schemastery 这个 dev peer,缺了会直接以 missing dev peer at … 停下,而不是当成通过。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
senyayume/dsh-image-once
让对话中的图片仅在首次请求内联,后续自动换占位文字
相关插件 · 视觉能力
智能体工作台Devin-AXIS/iPolloWork
企业级、本地优先的智能体工作台,面向个人和智能体团队——一个工作区,容纳多个智能体引擎;一套统一体系,管理插件和技能;支…
★ 7,359已汉化DSH
72
开源设计工作台nexu-io/open-design
OpenDesign:首个协作式 AI 设计智能体工作区
★ 105,514已汉化DSH
71.8
多智能体编码工作区spacering-net/codeg
多智能体协作的 AI 编程工作区:汇总 Claude Code、Codex、OpenCode、Pi、Grok Build 等来源的会话。支持桌面应用、自托管服务器或 Docker。
★ 4,289已汉化DSH
71.6
GPT 图像提示词库freestylefly/awesome-gpt-image-2
Prompt as Code | GPT Image 2 / 2.5 提示词与案例库,530+ 个案例、20+…
★ 34,534已汉化DSH
71.5
架构图生成器tt-a1i/archify
把你想理解、规划或分享的事,变成可以互动的可视化作品。
★ 92,675已汉化DSH
71.2
AI 用量桌面小部件Javis603/token-monitor
EN | 简 | 繁 | KO | JA | PT
★ 3,522已汉化DSH
71
这是你的仓库?认领条目