dsh-file-fix:給 DSH Web 補上統一文件導入

前言

如果你在 DSH Web 上試過傳文件,大概率遇到過這些問題:拖入非圖片文件,界面提示「僅支持 PNG、JPG、WebP、GIF」;拖錯之後「拖入圖片」的遮罩卡住不消失;輸入框沒有文件選擇按鈕;Ctrl+V 粘貼文件沒有反應。就算文件已經在服務器上,agent 也拿不到任何文件清單,只能反覆猜路徑——README 裏記錄過一個例子,agent 一路猜了 75 步。

dsh-file-fix 解決的就是這條鏈路。它把文件導入統一成一種方式:任意後綴的文件,拖入、粘貼或點擊選擇,字節直接上傳到附件庫,文件清單隨消息注入模型上下文,歷史消息下方顯示可下載的文件氣泡。下面介紹它的定位、實現與安裝方法。

這是什麼

dsh-file-fix(v0.4.0)是 re-ITRT 維護的 DeepSeek Harness(DSH)插件,client 端目標平臺爲 web(dsh.client.platformweb)。一句話定位:DSH 上傳體驗優化插件,提供統一的文件導入體系——上傳入庫、清單進上下文、歷史可下載、agent 可讀取或導出,文件鏈路完全不使用 DSH 官方圖片導入鏈路。

工作方式:從拖入到注入

插件處理一個文件分三步。

1、上傳。文件字節通過 filefix/persistFile 接口寫入 host 側的內容尋址附件庫 ~/.dsh/attachments/filefix/,以 sha256 去重,manifest.jsonl 做索引。附件庫與工作區完全解耦,不依賴文件在磁盤上的路徑,因此服務器部署的 DSH 也能用。

2、注入。發送消息時,插件通過 agent/pre-step 注入一條文件清單消息(role=user,來源標記爲 plugin,notice 表單)。界面上只顯示「📎 附件 N 個文件」一行摘要,模型讀到的則是完整清單和每個文件的 attachment_id

3、讀取或導出。模型拿到 attachment_id 後,用下面兩個工具處理內容。

模型側的兩個工具

read_attachmentattachment_id 讀取附件內容,支持分段:offset / limit / more,默認每段 48 KB。大文件會自動鏡像一份完整副本到工作區 .dsh-uploadux/reads/ 目錄,配合官方 read 工具讀取全量。48 KB 這個默認值是爲了避開 win32 上 dsh spill-policy 的 50 KB 內聯閾值,後文注意事項會展開。

place_attachment 把附件字節導出到會話工作區的任意路徑,帶邊界校驗,防止 ../ 逃逸出工作區。

歷史消息的文件氣泡

插件用 filefix/files 會話事件(ignorable)記錄「消息 ↔ 文件」的關聯。客戶端註冊官方 Conversation Node(filefix-files Definition + keyed renderer),在對應文字氣泡下方渲染文件列表:文件名、大小、下載鏈接。下載走 /plugins/dsh-file-fix/download/<attachmentId> 路由。

兩層拖放 UI 與視覺上下文標記

輸入框上方是兩層橫向列表:

  • 圖像層:圖片拖到這裏,走 DSH 官方圖片注入鏈路,直接進模型上下文;
  • 文件層:任意文件拖到這裏,走插件的文件鏈路(字節入附件庫 + 清單注入)。

拖到空白區時按文件類型自動分流:圖片進圖像層,其餘進文件層。

視覺上下文標記:session 一旦包含任何直接圖片注入(draft image 提交、read_image / add_image_to_context 的調用結果),就標記爲「需要視覺」。此時模型選擇器中不支持圖片輸入的模型置灰不可選;從不需要視覺的 session 切走則無限制。visual_assist(返回文本)不觸發標記。

交互與實現結構

交互參照 Hermes 風格:

  • 統一 rail 混排,縮略圖走降採樣隊列;
  • chip 三態:上傳中 / 完成 / 失敗,失敗可點擊重試;
  • 刪除 chip 連帶刪除附件;
  • Esc 取消拖拽,drop 後焦點回到輸入框。

實現分兩側:

  • host 側:filefix Typert Remote 服務,方法包括 persistFile / limits / removeFile / markPending / unmarkPending / listFiles / checkAvailable,外加清理與視覺配置的 RPC 和下載路由;附件庫、橋(session 事件監聽 → 關聯表 + pre-step 注入)與兩個模型工具也在這側。
  • client 側:document 級 drop/paste 攔截(捕獲階段)、rail、📎 選擇按鈕、文件氣泡渲染,以及設置頁(視覺輔助 / 附件清理)。

安裝與啓用

推薦走 npm 官方渠道:

dsh plugin --profile web add dsh-file-fix

裝完重啓 dsh web 即生效,輸入框會出現「上傳文件」按鈕。

卸載:

dsh plugin --profile web remove dsh-file-fix

依賴與 bundles 登記隨卸載自動移除;重裝再跑一次 add 命令即可全部恢復。README 稱這套生命週期在乾淨 profile 上實測通過。

一個已知問題:pnpm 10+ 首次 add 可能報 [ERR_PNPM_IGNORED_BUILDS]——dsh 官方依賴的原生模塊構建被 pnpm 攔截,任何插件都會遇到。此時再跑一次 add 即可。

從源碼構建與開發

先構建,再掛載到 profile:

npm install        # 或 pnpm install(package-lock 已提交)
npm run build      # host 側 tsc 編譯到 lib/,esbuild 打包 dist/client.js
node scripts/mk-junction.cjs node_modules "<你的 dsh profile>/node_modules"
node scripts/mk-junction.cjs "<你的 dsh profile>/web/node_modules/dsh-file-fix" "$PWD"

然後在 profile 的 cordis.patch.yml 里加載本插件,可參照倉庫裏的 cordis.dev.yml。插件依賴 @deepseek-ai/cordis ^4.0.1、一組 @deepseek-ai/dsh-* ^0.1.1-rc.2 包和 react ^18.2.0,完整列表見 package.json 的 peerDependencies。

開發循環在 deepseek-harness 目錄跑:

pnpm dsh web --patch ../dsh-file-fix/cordis.dev.yml --port 3081

host 側改動:npm run build 後重啓 dsh(lib/ 是包入口);client 側改動:npm run build 重建 dist/client.js 後刷新頁面。類型檢查用 npm run typecheck,覆蓋 host 與 client。

限制與注意事項

  • 大小限制的默認值爲單文件 50 MB、每批 20 個、批量總量 200 MB,可通過插件 config 覆蓋;超限時整批拒絕並提示。
  • win32 平臺:dsh spill-policy 閾值 50 KB,純文本工具結果超限會被替換爲「頭尾預覽 + spill 路徑」,而 spill 路徑是 Windows 路徑,agent 的 bash 是 Linux 語義,讀不了。插件以 48 KB 默認分段加工作區鏡像規避這個問題。
  • 工具集沒有 shell 執行能力時,agent 無法解壓或運行導出的文件,這是環境限制,不是插件問題。
  • 日誌前綴 [dsh-file-fix],失敗帶 code:TOO_LARGE / EMPTY / SESSION_NOT_FOUND / NO_WORKSPACE / WRITE_FAILED / INVALID_PATH / REMOVE_FAILED
  • 倉庫附帶 scripts/repair-sessions.mjs 會話日誌修復工具,流程爲幀級 zstd 解壓、清洗、再重壓。

最後提醒一點:插件以當前 dsh 進程的權限運行,安裝前建議先到倉庫過一遍源碼,並確認許可證信息是否符合你的使用要求。

小結

經過上面的步驟,DSH Web 的文件導入從「只收圖片」補齊爲「任意後綴文件入庫 + 清單進上下文 + 歷史可下載」,用戶和 agent 看到的是同一份文件狀態。倉庫地址:https://github.com/re-ITRT/dsh-file-fix ;社區目錄(獨立站點,與 DeepSeek、幻方無官方從屬關係)的收錄頁:https://www.skillhub.cn/plugins/re-ITRT/dsh-file-fix 。

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

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

小夜