Inkotake
dsh-rich-artifacts
DeepSeek Harness Artifact/Deliverable plugin: publish workspace files as chat artifacts with inline image previews and download cards.
- Stars
- 0
- Language
- TypeScript
- Created
- Aug 16, 2026
- Updated
- Aug 16, 2026
Introduction
dsh-rich-artifacts
中文 | English
A DeepSeek Harness (dsh) dual-face plugin that turns workspace files into chat artifacts: raster images render inline in the conversation, other files become download cards.
No more file:///... links or “the file is in output/” — when the model creates a user-facing file, it calls publish_artifact and the file is durably delivered through the chat UI.
Features
publish_artifacttoolpath(required): workspace file to publishtitle(optional): display titledisplay:auto(default) ·inline·download
- ArtifactStore
- SHA-256 content-addressed blob storage
- metadata stored separately under
~/.dsh/artifacts/v1/
- Durable session event
artifact/published- only artifact metadata enters the session log
- historical sessions keep showing artifacts after reload / fork
- HTTP endpoints
GET /api/artifacts/:id/content— inline-safe previewGET /api/artifacts/:id/download— attachment download
- Web UI turn-tail gallery
- PNG / JPEG / WebP / GIF render inline
- everything else gets a file card with a download button
- Security
- workspace containment via
fs.resolve+fs.contains - final-component symlink rejection
- magic-byte MIME sniffing (a
.pngthat is actually HTML will not inline) - SVG / HTML are download-only in V0.1
- file size, image size and image-pixel limits
- workspace containment via
Install
dsh plugin --profile web add github:Inkotake/dsh-rich-artifacts
For a locked, reproducible source install:
dsh plugin --profile web add github:Inkotake/dsh-rich-artifacts#<commit>
Then restart dsh web (or the profile you installed into).
Usage
The plugin registers a system-prompt section, so the model should call the tool on its own when it creates a deliverable. You can also ask for it directly:
Create a training-loss chart, export it to CSV, and publish both files as artifacts.
The agent then runs:
publish_artifact({ "path": "output/loss.png", "display": "auto" })
publish_artifact({ "path": "output/loss.csv" })
and the turn tail shows the image inline plus a CSV download card.
Configuration
In the profile cordis.patch.yml:
- id: dsh-rich-artifacts
name: dsh-rich-artifacts
config:
root: ~/.dsh/artifacts
maxFileBytes: 104857600
maxTurnBytes: 524288000
maxImageBytes: 20971520
maxImagePixels: 40000000
inline:
png: true
jpeg: true
webp: true
gif: true
svg: false
| Field | Default | Meaning |
|---|---|---|
root | ~/.dsh/artifacts | Artifact storage root |
maxFileBytes | 104857600 | Per-file size cap |
maxTurnBytes | 524288000 | Reserved per-turn cap (not yet enforced in V0.1) |
maxImageBytes | 20971520 | Max inline image size |
maxImagePixels | 40000000 | Max inline image pixels (best-effort parse) |
inline.* | png/jpeg/webp/gif: true, svg: false | Which image types may render inline |
Build
pnpm install
pnpm run build
lib/index.js is the ESM host plugin, lib/client.js is the browser bundle
(window.__ModuleLoader__.load(...)). Both are committed so source installs
work without a build step.
Test
node tests/artifact-store.test.mjs
Architecture
DeepSeek Agent
│ creates file
▼
Workspace File
│ publish_artifact
▼
ArtifactStore ──────────────► artifact/published session event
│ │
│ (blob + metadata) │ (artifact_id + metadata)
▼ ▼
HTTP /api/artifacts/:id/* Session log (replayable)
│ │
└──────────────┬───────────────────┘
▼
Web UI turn-tail
┌─────────┴──────────┐
▼ ▼
ImageArtifact FileArtifact
Notes
artifact/publishedis a log-only event. Because the current harness has no registration surface for out-of-repo session event types, the host adds it toKNOWN_SESSION_EVENT_TYPESat startup so persisted sessions remain loadable while the plugin is installed.- MIME type is decided by magic bytes first; extensions are only a secondary hint.
- SVG and HTML are intentionally not inlined in V0.1.
License
MIT