Introduction¶
If you have tried uploading files on DSH Web, you likely encountered these issues: dragging in non-image files, the interface prompting “Only PNG, JPG, WebP, GIF supported”; the “Drop image” mask getting stuck after a wrong drop; the input box lacking a file selection button; and Ctrl+V pasting having no response. Even if the file is already on the server, the agent cannot retrieve any file list, only guessing the path repeatedly—README records an example where the agent guessed 75 steps.
dsh-file-fix addresses this entire chain. It unifies file import into a single method: files of any suffix can be dragged in, pasted, or selected via click; bytes are uploaded directly to the attachment library, the manifest is injected into the model context along with the message, and downloadable file bubbles are displayed below historical messages. Below is an introduction to its positioning, implementation, and installation method.
What is this¶
dsh-file-fix (v0.4.0) is a DeepSeek Harness (DSH) plugin maintained by re-ITRT, with the client-side target platform being web (dsh.client.platform is web). One-sentence positioning: a DSH upload experience optimization plugin that provides a unified file import system—uploading to the library, injecting the manifest into the context, making history downloadable, and allowing the agent to read or export files. The entire file chain completely bypasses DSH’s official image import chain.
How it works: From drag to injection¶
The plugin processes a file in three steps.
-
Upload. File bytes are written to the host-side content-addressable attachment library
~/.dsh/attachments/filefix/via thefilefix/persistFileinterface, deduplicated using SHA256, and indexed viamanifest.jsonl. The attachment library is completely decoupled from the workspace and does not rely on the file’s path on disk, allowing DSH deployed on a server to function correctly. -
Injection. When sending a message, the plugin injects a manifest message via
agent/pre-step(role: user, source marked as plugin, notice form). The interface only displays a single-line summary “📎 Attachments N files”, while the model receives the full manifest and theattachment_idfor each file. -
Read or Export. After the model obtains the
attachment_id, it uses the two tools below to process the content.
Two tools on the model side¶
read_attachment reads attachment content by attachment_id and supports segmentation: offset, limit, and more, with a default segment size of 48 KB. Large files are automatically mirrored as a full copy to the workspace .dsh-uploadux/reads/ directory, working in conjunction with the official read tool to read the entire file. The default value of 48 KB is to avoid the 50 KB inline threshold of the dsh spill-policy on Windows; the following notes will elaborate.
place_attachment exports attachment bytes to an arbitrary path in the session workspace, including boundary validation to prevent ../ from escaping the workspace.
File bubbles in historical messages¶
The plugin uses the filefix/files session event (ignorable) to record the association between “messages” and “files”. The client registers the official Conversation Node (filefix-files Definition + keyed renderer) to render a list of files below the corresponding text bubbles: filename, size, and download link. Downloads are handled via the /plugins/dsh-file-fix/download/<attachmentId> route.
Two-layer drag-and-drop UI and visual context markers¶
Above the input box are two layers of horizontal lists:
- Image layer: dragging images here triggers DSH’s official image injection chain, sending them directly into the model context;
- File layer: dragging any file here triggers the plugin’s file chain (bytes to attachment library + manifest injection).
When dragging to an empty area, it automatically routes based on file type: images go to the image layer, and the rest go to the file layer.
Visual context marker: once a session contains any direct image injection (draft image submission, or results from read_image / add_image_to_context calls), it is marked as “Needs Vision”. At this point, models in the model selector that do not support image input are grayed out and unselectable; switching away from a session that does not require vision is unrestricted. visual_assist (which returns text) does not trigger this marker.
Interaction and Implementation Structure¶
The interaction follows the Hermes style:
- Unified rail mixed layout, thumbnails go through a downsampling queue;
- Chip three states: Uploading / Completed / Failed, with failed states clickable for retry;
- Deleting a chip also deletes the attachment;
- Pressing Esc cancels the drag, and focus returns to the input box after the drop.
The implementation is split into two sides:
- Host side: The
filefixTypert Remote service, with methods includingpersistFile,limits,removeFile,markPending,unmarkPending,listFiles, andcheckAvailable, plus RPCs for cleanup and visual configuration and download routes; the attachment library, the bridge (session event listening → association table + pre-step injection), and the two model tools are also on this side. - Client side: Document-level drop/paste interception (capture phase), the rail, the 📎 selection button, file bubble rendering, and the settings page (Visual Assist / Attachment Cleanup).
Installation and Enablement¶
It is recommended to use the official npm channel:
dsh plugin --profile web add dsh-file-fix
Restart dsh web after installation to activate it, and the “Upload File” button will appear in the input box.
Uninstall:
dsh plugin --profile web remove dsh-file-fix
Dependencies and bundle registrations are automatically removed upon uninstallation; reinstalling and running the add command restores everything. The README states that this lifecycle has been tested on a clean profile.
A known issue: the first add with pnpm 10+ may result in an error [ERR_PNPM_IGNORED_BUILDS]—this occurs because pnpm intercepts the native module builds of dsh’s official dependencies, affecting any plugin. Simply running the add command again resolves this.
Building and Development from Source¶
Build first, then mount to the profile:
npm install # or pnpm install (package-lock is committed)
npm run build # host side tsc compiles to lib/, esbuild bundles dist/client.js
node scripts/mk-junction.cjs node_modules "<your dsh profile>/node_modules"
node scripts/mk-junction.cjs "<your dsh profile>/web/node_modules/dsh-file-fix" "$PWD"
Then load this plugin in the profile’s cordis.patch.yml, referring to cordis.dev.yml in the repository. The plugin depends on @deepseek-ai/cordis ^4.0.1, a set of @deepseek-ai/dsh-* ^0.1.1-rc.2 packages, and react ^18.2.0; see package.json for the full list of peerDependencies.
Run the development cycle in the deepseek-harness directory:
pnpm dsh web --patch ../dsh-file-fix/cordis.dev.yml --port 3081
Host-side changes: restart dsh after npm run build (the lib/ directory is the package entry); Client-side changes: rebuild dist/client.js with npm run build then refresh the page. Run npm run typecheck for type checking, covering both host and client.
Limitations and Considerations¶
- The default size limits are 50 MB per file, 20 per batch, and 200 MB total per batch, which can be overridden via the plugin config; exceeding these limits will reject the entire batch and show a prompt.
- Windows 32-bit platform: The dsh spill-policy threshold is 50 KB. If the result of a pure text tool exceeds the limit, it is replaced with a “head/tail preview + spill path”, but the spill path is a Windows path, while the agent’s bash runs on Linux semantics and cannot read it. The plugin uses a default segment size of 48 KB and workspace mirroring to circumvent this issue.
- When the toolset lacks shell execution capabilities, the agent cannot unzip or run exported files; this is an environment limitation, not a plugin issue.
- Log prefix
[dsh-file-fix], failures include the code:TOO_LARGE,EMPTY,SESSION_NOT_FOUND,NO_WORKSPACE,WRITE_FAILED,INVALID_PATH,REMOVE_FAILED. - The repository comes with the
scripts/repair-sessions.mjssession log repair tool, which performs frame-level zstd decompression, cleaning, and recompression.
A final reminder: the plugin runs with the permissions of the current dsh process. It is recommended to review the source code in the repository before installation and confirm that the license information meets your usage requirements.
Summary¶
Following the steps above, DSH Web’s file import has been completed from “only accepting images” to “any suffix file to library + manifest to context + history downloadable”, ensuring users and agents see the same file state.
Repository address: https://github.com/re-ITRT/dsh-file-fix; The listing page on the community directory (an independent site with no official affiliation with DeepSeek or Huafan): https://www.skillhub.cn/plugins/re-ITRT/dsh-file-fix.