MST19711/dsh-session-files0

@deepseek-ai/dsh-session-files

Session file upload for the DeepSeek Harness Web UI: an attach button lets the user upload arbitrary files (not just model-native images); files land in the session workspace under uploads/<sessionId>/, and an injected in-session note tells the model which directory belongs to this session; a share_session_file tool lets the model hand files to the user as clickable download cards inline in the conversation. Since 0.3.0 the upload entry yields to the built-in uploader when the harness ships one (dsh >= 0.1.5), and the model is told that share_session_file delivers to the user's browser while the built-in present tool only opens files on the Host desktop.

包名
@deepseek-ai/dsh-session-files
版本
0.3.0
许可证
MIT
最近更新
2026年9月12日

安装

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:MST19711/dsh-session-files

Session Files — DSH 会话文件的任意文件上传

npm 包名 / 仓库名 @deepseek-ai/dsh-session-files

让用户可以在 DSH Web 界面里给当前会话上传任意文件(不限图片),并把文件落到本会话工作区的专用目录:

/uploads//
  • ``:当前会话的工作目录(session cwd);
  • uploads/:专门存放此类内容的目录(约定名,可通过代码顶部常量调整);
  • /:对应该 session 的子目录。

上传成功后插件自动向该会话注入一条消息,引导 LLM 知道「哪一个目录对应本 session」并提供文件清单;会话恢复时若该目录已存在,也会再次提示模型。

特性

  • 🖇 聊天输入区左侧新增「上传文件」按钮(DSH 官方回形针图标),支持多选、任意类型(文本/PDF/压缩包/音视频/二进制…)
  • 📁 文件落在 /uploads//,只有用户真正上传时才创建目录(无上传则目录不存在)
  • 🧠 上传成功后经 agent.inject 注入模型可见消息:会话上传目录绝对路径 + 相对路径约定 + 文件清单
  • 🔁 会话启动/恢复时,若上传目录已存在,自动注入同等的目录提示(休眠会话也能知道该看哪里)
  • 🗂 输入区上方 dock 显示已上传文件芯片:点击打开/预览,× 删除
  • 📥 文件可通过浏览器直接下载(文本/图片/PDF 内联预览,其余附件下载)
  • 🎁 模型提供文件下载(v0.2.0):模型调用 share_session_file 工具即可把工作区内 任意文件(处理结果等)递到对话流——渲染为可点击的下载卡片(文件名/类型/大小/说明), 会话恢复后卡片依然可见
  • ⚙️ 设置页可配:启用开关、检测到 dsh 自带上传时自动让位、是否显示文件 dock;展示单文件大小上限与当前让位状态
  • 🚀 上传入口让位(v0.3.0):dsh 0.1.5 自带任意文件上传,输入区已有「添加附件」。本插件 默认在检测到它时隐藏自己的回形针,避免出现两个功能重叠的按钮;取消该设置即可切回本插件的 入口(两者落点不同:本插件 → 会话工作区,内置 → DSH 附件库)
  • 💬 交付语义消歧(v0.3.0):把「用 share_session_file 把文件发到用户浏览器(可下载)」 与「内置 present 在 DSH 主机桌面上打开文件」明确区分给模型,并注册为 system prompt 规则(每会话恒在)——远程访问 Web 时后者根本用不上,模型却容易误以为已经交付
  • 🔐 安全:sessionId 白名单 + 文件名净化;path 下载/分享严格锁定在会话工作区内 (拒绝 ..、越出 cwd 的绝对路径);单文件大小上限默认 512 MiB

界面

  • 输入区左侧(会话存在时):回形针图标按钮,上传中显示剩余计数角标。 dsh ≥ 0.1.5 上默认让位给内置的「添加附件」,此按钮不出现(见「上传入口让位」)
  • 输入区上方 dock:「已上传 N」+ 文件芯片(名称/大小/删除),以及「本会话上传目录」的绝对路径
  • 对话流:模型调用 share_session_file 后,该条工具调用渲染为文件卡片 (图标 + 文件名 + 类型/大小 + 说明 + 「下载」按钮),点击即保存
  • 设置:「设置 → 会话文件上传」——三个开关 + 单文件上限 + 当前让位状态 (「[生效] …」/「[已让位] …」,让位是显式可见的,不会"回形针悄悄消失")

安装(官方方式)

前置:dsh 已安装且目标 profile(默认 web)在运行。本插件通过官方的 dsh plugin add 安装(dsh plugin 是 pnpm 的薄转发层);包内声明了 dsh.bundle.patch(自带 cordis.patch.yml),因此 plugin add 一步即可完成安装,无需手动编辑任何 profile 配置

# 方式一:仓库脚本(自动 npm pack + dsh plugin add)
bash install.sh

# 方式二:手动执行官方命令
npm pack -y                        # 产物 deepseek-ai-dsh-session-files-.tgz
dsh --profile web plugin add ./deepseek-ai-dsh-session-files-.tgz

安装成功后重启 dsh(让 profile 重新组合 bundle 层),刷新浏览器即可在输入区左侧看到 📎 按钮。

验证

重启并刷新页面后:

  • 打开一个会话,输入区左侧出现 📎;点它选任意文件上传,输入区上方出现「已上传 N」芯片;
  • 命令行核对(把 `` 换成你实际访问 dsh 的地址):
    # 客户端插件已加载(应以 window.__ModuleLoader__.load( 开头)
    curl -s http:///plugins/@deepseek-ai/dsh-session-files/client.js | head -c 80
    # 配置端点
    curl -s http:///dsh-session-files/config
    # 列表端点(目录不存在时返回空列表,不创建目录)
    curl -s 'http:///dsh-session-files/list?sessionId='
    
  • 工作区核对:`ls /uploads//` 应能看到刚上传的文件;未上传过的会话不应存在 uploads// 目录

上传入口让位(v0.3.0)

dsh 0.1.5 起自带任意文件上传(@deepseek-ai/dsh-client-file-upload,宿主服务 fileUploads, 客户端服务 fileUpload),输入区自带「添加附件」回形针。本插件若照旧渲染自己的回形针, 用户会看到两个功能重叠的按钮

设置项 检测到 DSH 自带上传时自动让位(默认开) 控制这件事。刻意做成设置项而不是 硬编码自动判断,因为两者落点语义不同,静默切换会埋雷:

本插件内置(dsh ≥ 0.1.5)
落点会话工作区 uploads//$DSH_HOME/attachments/v1/(内容寻址)
属性可写;随工作区备份;文件侧栏可见只读副本;不在工作区;侧栏看不到
模型拿到一条说明本会话上传目录的注入消息逐条 prompt 的文本 handle + 只读路径

探测走两条渠道取「或」,因此不会出现按钮先闪出来再消失:客户端服务(ctx.get("fileUpload"), apply 时同步可得)与宿主 /configbuiltinUpload(权威但异步,作为兜底)。 dsh 0.1.0-rc.x 上两条都是 false,行为与 v0.2.2 完全一致。

交付语义:「发给用户」≠「在用户电脑上打开」(v0.3.0)

内置的 present 工具(dsh 0.1.5 新增,挂在 agent preset 里)只把工作区文件声明为交付物, 它提供的动作是在 DSH 主机(服务器)的桌面上打开文件 / 在文件管理器中显示。用户远程访问 Web 时那个动作不可用(宿主在打开前就用 workspaceDesktop().available 拦掉),而模型很容易 把「我调用了 present」当成「用户已经拿到文件了」,于是不再调用 share_session_file

share_session_file 走的是浏览器下载卡片,是远程用户真正拿到文件的唯一方式 (dsh 0.1.5 全库只有 dsh-session-log-export 用了 Content-Disposition,没有任何 download 属性或下载包;文件侧栏只是有界预览)。三处让模型知道:

  1. share_session_file工具描述(首句即「把文件直接发给用户」);
  2. 注入的会话消息尾部(短句,只在真有上传文件时出现);
  3. system prompt section dsh-session-files:delivery-vs-open(每会话恒在)——与官方 ui-deliverables 宿主半用的同一个缝;其 order 在版本间变过(0.1.0-rc.x 是字面量 190,0.1.5 起是 getSectionOrder("DELIVERABLE_FILE_REFERENCES") = 9000), 因此本插件走 getSectionOrder(...) + 1,旧版回退 190 + 1,两代都紧跟在官方指引之后。

文案写成「若你的工具列表里有 present」的条件句式,不做存在性探测:0.1.0-rc.x 上该工具 还不存在;0.1.5 上它在 agent preset(agent plane)里,而 profile 作用域的 tools.get() 看到的是全局层视图,探测并不可靠。

目录与模型引导

  • 上传目录固定为会话 cwd 下的 uploads//,模型可通过 fs 工具直接访问(相对 cwd 或绝对路径);
  • 上传成功后注入的模型可见消息包含:目录绝对路径、相对路径约定、本次文件清单,以及「用户提到上传的文件时,先列目录再按需读取」的指引;
  • 会话启动/恢复时(agent/session-start)若目录已存在,注入同类提示;目录不存在则不做任何事(也不会创建);
  • 引导消息同时告知 share_session_file 工具:用户索要文件时,应调用它(而不是只报路径)。

安全说明

  • sessionId 必须匹配 [A-Za-z0-9._-]{1,80} 且是当前已加载的会话;
  • 文件名只取叶子名,拒绝路径分隔符、控制字符、./..、隐藏文件与超长名;
  • 单文件大小上限默认 512 MiB(uploads 目录在首次上传时创建,临时文件写在同一目录并以 .part- 前缀隔离,成功后原子 rename);
  • 下载端点做了类型映射与目录锁定,GET 只能读取该会话目录内的文件。

卸载(官方方式)

dsh --profile web plugin remove @deepseek-ai/dsh-session-files

随后重启 dsh 并刷新页面;plugin remove 会自动把本插件从 dsh.profile.bundles 层移除(不再加载),无需手动清理配置。已上传的文件保留在 uploads//,不会被删除。

打包与发布

npm pack          # 产物 deepseek-ai-dsh-session-files-.tgz

发布到 npm 前把 package.json"private": true 去掉。发布到 GitHub: 仓库即本目录(不含 node_modules/);tgz 可保留在仓库中作为安装资产, 或改用 GitHub Releases 附件 + 仓库内保留 install.sh 与文档。更新发行物时 请同时新增 RELEASE_NOTES-v.md 并更新本 README 与 GITHUB_INTRO.md。

License

MIT