dsh-files-fallback:DSH 的多类型文件附件与桌面端零拷贝引用插件

前言

在 DSH(DeepSeek Harness)里做智能体开发时,经常要把文件交给模型:贴一张截图、拖一份日志、上传一个数据集目录。原生 Web GUI 对附件的处理比较克制,浏览器侧没有可靠的文件路径概念,文字模型也「看不懂」图片;桌面上用户拖进来的往往不只是小文件,还有目录和几个 GB 的日志,直接上传既不现实,落盘副本又会很快把工作区堆满。

下面介绍的插件 xinstart-1/dsh-files-fallback 就是处理这一层的:它把「拖入 / 粘贴 / 上传」统一成一条落盘管线,用 @绝对路径 让文本模型也能引用附件;在桌面壳里能拿到真实操作系统路径时,则直接 @原路径 引用,零拷贝、无大小限制,只把「目录、超大文件、上传失败」这类无法落盘的情况兜住。

这是什么

  • 维护者:xinstart-1
  • 类型:标准 dsh 插件包,声明了 dsh.bundle.patch(package.json 中含 dsh.bundle manifest,patch + client)
  • 版本:0.9.12(来自 package.json)
  • 许可证:MIT
  • 运行环境:Node.js >= 18
  • 定位:DSH Web GUI 的文件引用与附件插件,宿主侧(Host 半)落盘与 VLM 调用,客户端侧(Client 半)拦截拖入 / 粘贴 / 📎 按钮并插入引用。

解决的问题分三块:

  1. 浏览器里没有路径概念,任何类型的文件都要先落成一份稳定副本,再让模型能引用它;
  2. 桌面上能拿到真实路径时,不该再复制一份,目录和大文件更不该被上传卡住;
  3. 文字模型不理解图片,需要一个视觉模型把图片转成文字描述。

插件对这三块分别给了落盘管线、@原路径 兜底引用和 VLM 识别。

核心能力

三种入口,任意文件类型

拖入、Ctrl+V 粘贴、接管 dsh 原生 📎 附件按钮(位置在加号右侧、modes 左侧,可多选),PC 与移动端浏览器均可。不再设扩展名白名单,任意文件都能进来,无需配置。

统一落盘管线

文件字节流由 Host 半经 node:fs/promises 直接写盘,平铺保存到:

<会话工作区>/.dsh-file-attachment/<文件名>

补充规则:

  • 同名冲突在扩展名前追加 -N,绝不覆盖;
  • 上传前按「文件名 + 文件大小」查重,命中直接复用已有路径、零字节上传,索引文件是 .dsh-file-attachment/.index.json;
  • 单文件上限 50MB,空文件跳过;
  • 会话工作区回退顺序为 session.header.cwd → sandboxPolicy.workspaceRoot → process.cwd(),每个项目维护自己的 .dsh-file-attachment/。

桌面端零拷贝引用

在 DSH 桌面壳里,插件通过 Electron webUtils 拿到拖入文件的真实操作系统路径,然后一律直接插入 @原路径 引用:不复制、不上传、不落副本,没有大小上限。文件被移动、改名或删除后,引用它的消息在读取时会明确报「文件不存在」,而不是展示一份过期副本。

纯浏览器拿不到路径时,才走上面的落盘管线,把 @绝对路径 插入光标处。

输入框 chip 与聊天区缩略图

引用以草稿里的原生 @路径 chip 呈现(蓝色),不额外渲染附件条,避免同一附件在附件条和草稿里出现两次。鼠标移到 chip 上,左侧文件图标变成 ×,点击即删除该引用,其他 chip 与文本不受影响。聊天区的图片渲染为可点击放大的缩略图(Lightbox),目录以文件夹图标 chip 呈现。

VLM 图片识别

非多模态模型下,图片自动调用视觉模型生成中文描述回填草稿,且只注入模型上下文。视觉模型从 harness 模型目录下拉选取,默认走 harness 自带模型;在设置里填了 Base URL + API Key 则走自定义 OpenAI 兼容端点。agent 也可以主动调用 describe_image 工具。

设置页路径是「设置 → 文件附件」,包含思考模式开关(默认禁用)和超时时间(默认 60 秒)。未选模型时不启用图片识别。

安装与启用

安装命令直接来自官方 README(在插件目录下执行,参数会转发给 profile 目录的 pnpm):

dsh plugin --profile web add ./dsh-files-fallback

安装后会自动进入 profile 的 dsh.profile.bundles,无需手改 profile 的 package.json。改完 lib/*.js 后重启 web GUI 即生效。升级用:

dsh plugin --profile web update dsh-files-fallback

典型用法

以下行为来自 README 的行为一览,可直接作为验收清单。

1、拖入单个文件。桌面端插入 @原路径 引用;纯浏览器落盘后在光标处插入 @绝对路径,成功不提示,失败给简短 toast。

2、一次多个文件。批量处理并一次性插入全部引用;部分失败只提示「N 个已跳过」。

3、拖入目录。桌面端插入 @路径/ 引用(文件夹图标 chip);纯浏览器 toast 提示「不支持拖入目录」。

4、单文件超过 50MB 或空文件。桌面端仍按 @原路径 引用(零拷贝、不受限制);纯浏览器跳过并提示;单条目上传失败时,桌面端可取到真实路径就自动转为 @路径 引用,否则提示「文件处理失败」。

5、当前模型不支持多模态。自动调 VLM 生成中文描述回填草稿;agent 可用 describe_image 工具。

6、粘贴纯文本。不改写,完全原生行为。

7、移除引用。鼠标移到输入框里的 @路径 chip 上点击 ×,或把光标顶到 chip 后按退格。

存储与清理

落盘文件默认永久保留在 .dsh-file-attachment/,不随会话删除而清理。如果同时装了提供「删除会话」能力的插件(README 以 dsh-session-delete 为例),可以在「设置 → 文件附件 → 会话清理联动」打开开关(默认关闭),实现删除会话时连带清理该会话上传的落盘附件。

联动机制要点:

  • 监听 api-session/removed 总线事件触发清理;
  • 按引用计数删除,同名同大小被多个会话共享的条目,只有最后一个引用它的会话被删除时才真正删除;
  • 启用联动之前上传的旧文件没有归属记录,永远不会被自动清理;
  • 会话到文件的引用关系随去重索引写入 .index.json,重启 GUI 不丢失;
  • 可通过 GET /dsh-file-attachment/cleanup-status?sessionId=<id> 查询该会话上传的文件数与总字节,删除前预览将回收的空间。

适用场景与注意

适合下面这批人:

  • 主要在 DSH Web GUI 里工作,需要频繁把本地文件交给模型;
  • 同时使用桌面壳和浏览器,希望两边对同一批文件的处理方式一致;
  • 模型是纯文本模型,需要靠 VLM 把图片内容转成文字;
  • 已经在用或准备用删除会话类插件,希望附件一起清干净。

需要注意:

  • 插件以当前 dsh 进程权限运行,配置落在 ~/.dsh/file-attachment.json,附件落在会话工作区的 .dsh-file-attachment/,安装前先检查源码与许可证(MIT);
  • 桌面端的零拷贝引用依赖真实路径始终有效,文件移走后引用会报「文件不存在」,这是设计行为,不是 bug;
  • 浏览器侧 50MB 上限和目录不支持是浏览器能力限制,桌面侧没有这类限制;
  • 会话清理联动默认关闭,需要配合删除会话插件手动打开;
  • 该插件目前星标数为 0,属于早期项目,功能描述以仓库 README 为准。

结尾

总结一下:dsh-files-fallback 把 DSH 里散落的文件入口统一成一条管线——浏览器侧落盘加 @绝对路径 引用,桌面侧零拷贝 @原路径 兜底,再叠上 VLM 图片识别和可选的会话清理联动。它不改变 DSH 的模型能力,只是把「文件怎么进上下文」这件事变得可预期、可复现。

目录页:https://www.skillhub.cn/plugins/xinstart-1/dsh-files-fallback
GitHub:https://github.com/xinstart-1/dsh-files-fallback

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜