dsh-web-search-ddg
aooyoo
Zero-token DuckDuckGo search provider for the DeepSeek Harness (DSH) web seam — local headless browser, no API key, no m…
PROJECT TOPICS
PROJECT README
English · 简体中文
Render interactive ECharts / Mermaid / Three.js and sandboxed custom HTML inline in DeepSeek Harness conversations.
dsh-artifact lets the model render real, interactive content — not hand-drawn SVG, not a wall of text — directly inside the conversation. The model calls render_artifact with a declarative payload — a plain-JSON ECharts option, a Mermaid diagram, or a Three.js 3D scene — and the Web UI renders it with the real engine (tooltip, zoom, legend, diagrams, 3D previews). A second tool, render_html, renders arbitrary custom HTML/CSS/JS in a sandboxed iframe.
| dsh-genui | dsh-visualize | dsh-artifact | |
|---|---|---|---|
| Model output | whitelisted JSON tree | arbitrary HTML/JS | declarative payload (ECharts / Mermaid / Three) |
| Real engine | ✗ (3 hand-drawn chart kinds) | ✓ (via HTML) | ✓ (ECharts + Mermaid + Three.js) |
| Inline in conversation | ✓ | ✗ (tool row only) | ✓ (tool card) |
| Interactive | ✓ | partial | ✓ (tooltip / zoom / legend / 3D) |
| Arbitrary HTML sandbox | ✗ | ✓ | ✓ (render_html) |
| Action round-trip | ✓ | ✗ | roadmap (v0.3) |
| Security model | whitelist | sandboxed iframe | pure JSON + sandboxed iframe |
dsh-genui hand-draws three chart kinds; dsh-visualize renders arbitrary HTML but has no round-trip. dsh-artifact feeds the real engines (ECharts, Mermaid, Three.js) with declarative JSON payloads the model is already excellent at writing, and adds a sandboxed HTML channel for custom widgets — full capability at a lower authoring cost, behind strict JSON-only and iframe-sandbox security boundaries.
# From GitHub (recommended — ships prebuilt assets, no build step)
dsh plugin --profile web add github:sumarilkkxx/dsh-artifact
# Local link (development)
dsh plugin --profile web add link:/path/to/dsh-artifact
# From the project directory
dsh plugin --profile web add .
Restart dsh web and hard-refresh the page (Cmd/Ctrl+Shift+R).
Requires
pnpmonPATH(thedsh plugincommand forwards to pnpm).
Ask the model for a chart:
Draw a bar chart of 2024 quarterly revenue: 120, 180, 150, 210 (in 10k CNY)
The model calls render_artifact with an ECharts option, and the chart appears as an interactive card in the conversation.
render_artifact (charts / diagrams / 3D)| Parameter | Type | Description |
|---|---|---|
engine |
string | echarts (default) · mermaid · three |
option |
object / string | ECharts option — engine=echarts (plain JSON, no functions; string templates like {c}%) |
code |
string | Mermaid diagram source — engine=mermaid (flowchart / sequenceDiagram / classDiagram / gantt / stateDiagram / pie / erDiagram / journey) |
spec |
object / string | Three.js scene — engine=three ({"meshes":[{shape,color,size,position,rotation}],"background","ambient"}) |
title |
string | Card title |
height |
number | Height in px (default 360, min 120) |
render_html (sandboxed custom widget)| Parameter | Type | Description |
|---|---|---|
html |
string | Self-contained HTML fragment or full document (inline scripts/styles allowed; external resources blocked) |
title |
string | Card title |
height |
number | Height in px (default 400, min 120) |
Example the model produces:
{
"engine": "echarts",
"title": "2024 quarterly revenue",
"option": {
"title": { "text": "Revenue (10k CNY)", "left": "center" },
"tooltip": { "trigger": "axis" },
"xAxis": { "type": "category", "name": "Quarter", "data": ["Q1", "Q2", "Q3", "Q4"] },
"yAxis": { "type": "value", "name": "Revenue" },
"series": [{ "type": "bar", "name": "Revenue", "data": [120, 180, 150, 210] }]
}
}
option / spec) must be pure JSON — functions, undefined, and symbols are rejected by the host half.render_html widgets run in a sandboxed iframe (opaque origin) with a CSP that blocks network, top navigation, and form submission; only inline scripts/styles are allowed.dsh-artifact/
├── index.js # host half: render_artifact + render_html tools + asset route
├── client.js # browser half: keyed toolviews + engine dispatch + sandboxed iframe
├── cordis.patch.yml # bundle layer (insert dsh-artifact)
├── package.json # dsh.bundle + dsh.client manifests
├── assets/ # engine UMDs (echarts/mermaid/three; built, shipped for git-install)
└── scripts/build.mjs # copies engine dists -> assets/
index.js) registers render_artifact and render_html as raw JSON-Schema definitions, injects system-prompt guidance, and serves the engine assets from /plugins/dsh-artifact/assets/*.client.js) registers keyed tool.call.toolview slots for both tools. When a result settles, the host projects the resolved payload into the result meta (via presentationMeta); the toolview dispatches on meta.engine and lazy-loads the matching engine. render_html renders into a sandboxed iframe with a CSP.runtime dependencies** — both halves are hand-written plain JS. The host uses only Node builtins; the browser half takesreactfrom the loader's module table. This deliberately avoids the developer-preview version-drift trap (the stalelatesttag on@deepseek-ai/dsh-tools`, and cross-package rc-line mismatches).>= 22.19pnpm on PATH (required by dsh plugin add)git| Path | Purpose |
|---|---|
index.js |
Host half — render_artifact + render_html tool definitions, system-prompt section, lazy-asset route |
client.js |
Browser half — keyed toolviews, engine dispatch (echarts/mermaid/three), sandboxed iframe |
cordis.patch.yml |
Bundle layer; name is a package name resolved through node_modules, not a path |
package.json |
dsh.bundle + dsh.client manifests, exports["./client"], build scripts |
assets/*.min.js |
Engine UMD builds (echarts/mermaid/three; committed so dsh plugin add github:... needs no build) |
scripts/build.mjs |
Copies engine dists → assets/ |
npm install # installs echarts/mermaid/three (build-time only; NOT runtime deps)
npm run build # copies the engine UMD bundles into assets/
The engines are devDependencies used only to produce assets/*.min.js. The plugin itself has zero runtime dependencies, so a link: install needs nothing extra. Bump an engine by editing its devDependency version and re-running npm run build.
# from the project directory
dsh plugin --profile web add .
# restart dsh web + hard-refresh the page
The host and browser halves are plain files the profile reads directly, so code edits need only a restart (no build step). Rebuild only when you change the engine asset.
# compose-check: confirms the bundle layer parses and composes
dsh --profile <name> --dump-config
# local smoke test (not shipped in the repo)
node scripts/smoke-test.mjs
# browser render check: load the profile, confirm zero console errors and a painted canvas
# (see the acceptance flow used during development)
render_artifact is registered as a plain JSON-Schema object (not defineTool) because out-of-tree resolution of @deepseek-ai/dsh-tools is unreliable on the developer-preview line. The host half owns its own validation.ctx.inject. The asset route uses ctx.inject(['webServer'], cb) so the plugin stays inert under headless profiles (no webServer service).meta (presentationMeta), which must stay pure (no file I/O) so session replay can rebuild the card.render_artifact tool (raw JSON-Schema definition, function-free option validation)/plugins/dsh-artifact/assets/* routetool.call.toolview browser slotundefined/symbol rejection + path-traversal guard)render_html): render model-written HTML/CSS/JS in a sandboxed iframe (opaque origin + CSP) for custom widgets the declarative engines cannot expresspostMessage-based [genui-action] loop: interactive components send data back to the model, which re-renders — the capability dsh-visualize explicitly lacksawesome-dsh-plugin listingPRs welcome. Please keep the host and browser halves free of @deepseek-ai/* runtime imports, and ship any engine change as a committed assets/ artifact (or update scripts/build.mjs). Add the dsh-plugin GitHub topic to help others discover the plugin.
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。