前言¶
如果你在 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.platform 爲 web)。一句話定位: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_attachment 按 attachment_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 側:
filefixTypert 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 。