DeepSeek Harness 插件

dsh-web-file-uploader

A DeepSeek-style paperclip attach button in the DSH web composer; uploads files to the DSH host (model-aware: native image blocks for multimodal models, file paths for text-only models).(英文原文)

跳到安装方式

来源信息

GitHub 仓库
Mooling0602/dsh-web-file-uploader
最近更新
2026年8月20日
分类
工具与能力
GitHub stars
11
载体类型
plugin
目录证据
上游声明已找到 dsh.bundle
证据路径
package.json#dsh.bundle
核对版本
0.1.0-rc.8
上游核对日期
2026-08-20

该证据由上游目录提供。本站没有安装、运行或安全审核这个插件。

安装

默认先复制一段 Prompt,让 Agent 读 GitHub 仓库和源码;需要自己装时再切到命令。

复制这段 Prompt,发给 DSH、Codex 或其他 Agent,让它先读 GitHub 仓库和源码。

请先不要安装或执行任何命令。阅读这个插件的 GitHub 仓库、README 和关键源码,然后用清楚、直接的方式回答以下问题,帮助我判断它是否适合我的需求:

1. 这个插件是什么,解决什么问题;
2. 适合哪些用户和典型使用场景;
3. 安装后如何使用,并给出一个最小使用示例;
4. 有哪些已知限制,以及隐私、安全、兼容性或维护风险;
5. 给出“推荐 / 有条件推荐 / 不推荐”的明确建议和理由。

请区分仓库明确说明、根据源码推断和未知信息。证据不足时请明确说明,不要猜测或照抄 README。

GitHub:https://github.com/Mooling0602/dsh-web-file-uploader
插件名:dsh-web-file-uploader
作者:Mooling0602

检查来源文件

安装前先看这个插件目录里的 README 和其他文件。

文件资源管理器5 个文件
README_zh_CN.md来源说明 · 只读预览
README 语言

dsh-web-file-uploader

> 🌐 语言切换 · English | 中文

一个面向 DeepSeek Harness 网页端的文件上传插件。在输入框工具行加入一个 DeepSeek 网页版风格的回形针附件按钮,将所选文件上传到 DSH 宿主机——内置模型感知适配让文件真正能被当前模型使用,并带内容寻址防重传避免重复上传刷爆存储。

  • 仓库:https://github.com/Mooling0602/dsh-web-file-uploader

功能特性

  • 📎 输入框工具行左侧的回形针按钮(细线条、悬停圆形背景跟随主题:浅色 ≈ #F2F3F4,深色 ≈ 白 8%,通过 --dsw-alias-interactive-bg-hover 自动适配)
  • 支持多选;每个文件以预览式附件卡片显示在输入框上方(图片显示缩略图):读取中 → 上传中 → 已保存,带"复制路径"与移除按钮
  • 文件保存在 DSH 宿主机,不会只留在浏览器里
  • 文件名清洗(拒绝路径分隔符、..、控制字符)+ 同名但内容不同的文件自动追加 -1/-2 后缀
  • 内容寻址防重传 —— 见[防重传机制](#防重传机制)
  • UI 文案通过应用 locale 服务本地化(zh/en,跟随 dsh web 语言设置或系统默认)

模型感知适配与附件卡片设计

上传的文件以附件卡片形式显示在输入框上方的 dock 行。卡片是注入行为的唯一依据:

状态行为
卡片存在该文件的绝对路径会注入到此后发送的每一条用户消息
点击卡片 × 关闭插件调用 Host 的 remove RPC —— 文件从 pending 注册表移除,不再注入,且保留在磁盘(模型仍可从 uploads 目录重新读取)
点击卡片 🗑 删除插件调用 Host 的 delete RPC —— 文件从 DSH Host 永久删除,并同步清理去重索引
Ctrl+V 粘贴粘贴的图片走产品原生草稿管道 —— 不产生卡片,插件完全不干预

× 与 🗑 的区分是有意为之:× 只是停止注入(你可能还希望模型稍后能找到该文件),而 🗑 表示你永远不再需要这个文件。删除最后一个引用时文件会从磁盘移除;若另一个活跃会话仍引用同一份去重副本,则保留文件、仅撤销当前会话的引用。

这是一个有意的设计决策:卡片在发送后不会自动消失(与粘贴预览发送即清空不同),由你决定文件"附着"在对话中的时长。每次注入为一次性(每条消息一份),注入块精确列出当前所有未关闭卡片的文件。

注入按模型能力区分:

模型类型图片文件(png/jpeg/webp/gif)其他文件
多模态inputModalities 报告含 image通过 attachments 服务注入原生 ImageBlock,图片成为请求的一部分,等同正常附件,不加任何文字提示路径文本块
纯文本(如 DeepSeek V4 系列)路径文本块——模型可调用读取/识图工具自行查看路径文本块

能力检测使用 llm.resolveModelInfo().inputModalities(缓存 10 分钟,失败安全回退文本模式)。

注入的提示词使用可读的、仅供模型阅读的英文格式

-----
[Attached files] Some files have uploaded with this message:
- /path/to/file1.txt
- /path/to/image1.png
Read the files or use tools to analyse (like vision tools), then answer the user.

与识图工具等插件的兼容性

  • 零耦合:插件只把绝对路径注入提示词,从不调用、包装或假设任何辅助工具——vision-tools 或其他读取工具拿到路径后独立工作即可。
  • 原生多模态路径:对支持图片的模型,图片以原生 ImageBlock 注入,模型使用自身的多模态能力,不会被提示词诱导去调用外部工具。
  • 非侵入:注入只针对真实用户消息(source.kind === 'user');steering/系统消息绝不会被注入;已含 [Attached files] 标记的消息不会重复注入(并发/残留实例防线)。Ctrl+V 粘贴图片完全由产品原生管道处理。

防重传机制

重复上传不会刷爆存储:

1. 上传时插件计算解码字节的 SHA-256(动态模式经 shell 管道 base64 -d | sha256sum;静态 bundle 用 node:crypto

2. 持久化索引 uploads/.dfu-index.jsonhash → { path, at }at 为上传时间戳,用于清理) 3. 再次上传相同内容(同名或不同名)→ 复用已有存储副本,不写新文件、不产生 -1 副本,响应带 dedup: true 4. 上传经 Promise 队列串行化,并发相同上传不会竞态;索引条目失效(文件被删)时自动回退重新存储

场景结果
同一文件上传 N 次磁盘只存 1 份,所有上传解析到同一路径
同内容、不同文件名复用首个存储副本
同名字、不同内容正常的 -1 冲突处理(正确)
进程重启索引文件持久化,防重传继续生效

索引条目为 hash → { path, at }at = 上传时间戳,毫秒,供下面的 TTL 清理使用)。旧版 hash → path 条目会被透明读取,并在下次写入时升级为对象格式;不带时间戳的旧条目永不被 TTL 回收(仅当文件已不存在时被清理),保护迁移前的历史文件不被误删。

清理与保留(TTL 自动回收 + 手动删除)

上传文件通过两种互补方式回收:

自动 TTL 回收

每次上传成功、每次永久删除、以及插件启动时,都会触发一次懒回收。超过 TTL 且不在任何活跃会话 pending 引用中的文件会被从磁盘删除,并同步清理其索引条目。回收与上传走同一条串行队列,不会与在途写入竞争;无需后台任务。

  • 默认 TTL7d(7 天)。
  • 保留期单位1s(秒)、1m(分钟)、1h(小时)、1d(天);不带单位的纯数字按(兼容旧行为)。0(或空/非法值)禁用自动 GC —— 仅在点击 🗑 时显式删除。
  • 配置:在 设置 → 文件上传(DSH 原生设置面板)中,单个输入框即可设置,经 settings 服务命名空间 dsh-web-file-uploader{ ttl })持久化;环境变量 DSH_UPLOAD_TTL(如 DSH_UPLOAD_TTL=30m)作为兜底在默认值之前生效。动态(会话)模式下该设置存于内存;静态 bundle 中通过设置文档持久化。

两种卡片操作(回顾)

操作Host 调用磁盘上的文件
× 关闭remove保留 —— 模型可重新读取
🗑 删除delete永久移除

delete Host 调用先撤销本会话引用,检查是否还有其它活跃会话引用同一份去重副本:仅当无其它引用时才删除文件并清理索引;若仍被引用则保留文件(removed: false),但当前会话的卡片仍会被清除。

附件大小限制

  • 单文件约 48 MiB(动态模式:RPC 载荷上限 64 MiB base64,约 48 MiB 解码;静态模式:流式接收 HTTP body 时同此上限)。超限文件会在卡片上显示明确错误。
  • 多模态原生注入图片时,额外遵循部署的 attachments 限制(单消息字节/像素上限)。

安装方式

A. 动态插件(当前会话,免安装)

cordis_define + cordis_run   # host = src/host.js,client = src/client.js

批准 Run 卡片后回形针按钮立即出现。插件为进程内临时扩展,重启后需重新定义并运行。

B. 静态 bundle(持久化,dsh plugin 安装)

包声明了 dsh.bundle.patch(见 cordis.patch.yml),因此 dsh plugin --profile web add 会将其识别为 profile 层。pnpm 支持的任意来源均可:

# Git 仓库(推荐分发渠道)
dsh plugin --profile web add github:Mooling0602/dsh-web-file-uploader

# 本地目录(开发用)
dsh plugin --profile web add ../dsh-web-file-uploader

# Tarball
dsh plugin --profile web add ./dsh-web-file-uploader-0.2.0.tgz

# npm registry(发布后)
dsh plugin --profile web add dsh-web-file-uploader

> Git 规格说明:pnpm 的 git 简写是 github:<owner>/<repo>(如 > github:Mooling0602/dsh-web-file-uploader)。裸写 github.com/<owner>/<repo> > 会被 pnpm 当作*本地目录*,报 "non-existent directory" 警告。其他合法形式: > git+https://github.com/Mooling0602/dsh-web-file-uploader.git 或 > https://github.com/Mooling0602/dsh-web-file-uploader.git

重启 dsh web 进程并刷新页面。分发细节与可选的 npm 发布流程(需要你的 npm 凭据)见 [PUBLISHING.md](PUBLISHING.md)。

更新

dsh plugin 只是把参数转发给 profile 目录下的 pnpm,因此更新也走它(不要手改 ~/.dsh/profiles/web/node_modules——下次 pnpm 操作会直接覆盖):

dsh plugin --profile web update dsh-web-file-uploader
# 若 lockfile 钉住的解析不肯移动,可以退回重装:
dsh plugin --profile web remove dsh-web-file-uploader
dsh plugin --profile web add github:Mooling0602/dsh-web-file-uploader

更新后重启 dsh web 进程;浏览器端 bundle URL 自带内容哈希版本号(?rev=…),刷新页面即可拿到新构建,无需手动清缓存。本地目录安装则在重新 add 前先在源码目录跑一次 pnpm build。详见 [PUBLISHING.md](PUBLISHING.md#update)。

架构

浏览器 (Client)                          DSH 宿主机 (Host)
─────────────                             ─────────────────
conversation.input.left                   harness.handle('upload', …)   [动态]
  └ 回形针 ── FileReader ──┐             webServer 路由 POST /upload   [静态]
                           ▼             ┌ sandboxPolicy.resolve() → 工作区根
                    上传载荷              ├ 会话 cwd / DSH_HOME + /uploads/
                           │             ├ SHA-256 → .dfu-index.json 防重传
                           ▼             └ base64 -d(stdin)/ node:fs 写入
conversation.input.dock
  └ 附件卡片(持久)                     harness.handle('remove', …) / remove 路由
       └ × 关闭卡片 → 停止注入              └ pending 条目删除(文件保留)
       └ 🗑 删除卡片                     harness.handle('delete', …) / delete 路由
                                              └ 撤销 pending → 删除文件 + 清理索引
                                           懒 TTL 回收(上传 / 删除 / 启动)
                                              └ 删除超 TTL 且不在 pending 中的文件
                                          agent/pre-step 瀑布
                                             ├ resolveModelInfo → 是否多模态?
                                             ├ attachments.saveImage → ImageBlock
                                             └ 路径文本块(仅用户消息)

为什么用 base64 -d 而不是 Host 的 atob Host 的 atob 是文本语义(Buffer.from(s, "base64").toString("utf-8")),fs 服务也只支持 UTF-8 文本写入。把 base64 经 shell 服务的 stdin 管道给 base64 -d,可无损写入二进制且无需临时文件。

保存位置

运行模式目的地
动态插件<会话工作区>/uploads/(沙箱化 shell/fs 无法写出工作区)
静态 bundle$DSH_HOME/uploads(默认 ~/.dsh/uploads),经 node:fs 直写——即 dsh 数据目录

防重传索引(uploads/.dfu-index.json)与存储文件同目录。

仓库结构

项目采用核心单一来源 + 薄缝隙层架构:所有业务逻辑都在 src/core/* 中;动态插件与静态 bundle 只是其上的薄适配层,改一处即可两边生效。

dsh-web-file-uploader/
├── src/core/
│   ├── host-core.js        # 规范 Host 逻辑(传输无关,依赖注入)
│   └── client-core.js      # 规范 Client 逻辑(传输无关,依赖注入)
├── src/seams/
│   ├── host-dynamic.template.js     # 动态 Host 缝隙(harness + shell/fs)
│   ├── client-dynamic.template.js   # 动态 Client 缝隙(host.call + React)
│   └── client-static.template.js    # 静态 Client 缝隙(fetch + 模块 react)
├── src/host.js             # 生成产物:动态 Host(核心已内联)—— 勿手改
├── src/client.js           # 生成产物:动态 Client(核心已内联)—— 勿手改
├── lib/index.js            # 静态 Host 缝隙(import 核心;node:fs/crypto/webServer)
├── client/src/client.js    # 生成产物:静态 Client 源码 —— 勿手改
├── scripts/
│   ├── build-dynamic.mjs   # 核心内联进缝隙 → src/*.js + client/src/client.js
│   └── build-client.mjs    # 包装 client/src/client.js → lib/client.js
├── cordis.patch.yml        # dsh.bundle 补丁(profile 层行)
├── package.json            # 可发布清单(dsh.bundle + dsh.client)
├── PUBLISHING.md           # 安装与 npm 发布指南
├── README.md / README_zh_CN.md
└── LICENSE                 # MIT

如何修改代码:编辑 src/core/*(或缝隙模板),然后运行 pnpm build——它会重新生成动态源码(src/host.jssrc/client.js)与静态客户端包(lib/client.js)。运行中的动态插件需用重新生成的 src/host.js / src/client.jscordis_define + cordis_run 重新部署。

开发状态

  • ✅ 动态插件:已在真实会话中实现并验证
  • ✅ 卡片驱动注入、模型感知适配、防重传、i18n UI
  • ⚠️ 静态 Client 模块:可由 scripts/build-client.mjs 构建,但 __ModuleLoader__ 包装器需在正式分发前对照真实 web 工具链验证

许可证

MIT