deepseek-harness-intelligent-ui 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -1
- package/README.md +189 -84
- package/README.zh-CN.md +181 -78
- package/client/client.js +1 -1
- package/package.json +4 -3
- package/src/compat.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,13 @@ All notable changes to this project are documented here. The format follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.2.3]
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Verified against DeepSeek Harness 0.2.1-alpha.4 (install smoke test and the 24-check browser E2E pass with no code changes). It is now in `TESTED_DSH_VERSIONS`.
|
|
14
|
+
- Redesigned both READMEs with animated SVG illustrations (hero, agent routing, widget streaming, security model), a highlights grid, badges, a compatibility table and collapsible sections. `npm run docs:art` regenerates the illustrations.
|
|
15
|
+
|
|
9
16
|
## [0.2.2]
|
|
10
17
|
|
|
11
18
|
### Fixed
|
|
@@ -57,6 +64,7 @@ All notable changes to this project are documented here. The format follows
|
|
|
57
64
|
- The declarative component catalog (`ui_render`) and sandboxed streaming HTML widgets (`ui_render_widget`).
|
|
58
65
|
- The `/ui` command and the guidance system-prompt section.
|
|
59
66
|
|
|
60
|
-
[Unreleased]: https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/compare/v0.2.
|
|
67
|
+
[Unreleased]: https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/compare/v0.2.3...HEAD
|
|
68
|
+
[0.2.3]: https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/compare/v0.2.2...v0.2.3
|
|
61
69
|
[0.2.2]: https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/compare/v0.2.1...v0.2.2
|
|
62
70
|
[0.2.1]: https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/releases/tag/v0.2.1
|
package/README.md
CHANGED
|
@@ -1,22 +1,81 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<img src="https://raw.githubusercontent.com/dreamfarer-space/deepseek-harness-intelligent-ui/main/docs/assets/readme/hero.svg" alt="DeepSeek Harness Intelligent UI: generative, interactive UI for DeepSeek Harness" width="100%">
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**English** · [中文](README.zh-CN.md)
|
|
6
|
+
|
|
7
|
+
[](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/actions/workflows/ci.yml)
|
|
8
|
+
[](https://www.npmjs.com/package/deepseek-harness-intelligent-ui)
|
|
9
|
+
[](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/main/docs/compatibility.md)
|
|
10
|
+
[](https://nodejs.org)
|
|
11
|
+
[](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/main/docs/compatibility.md)
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
|
|
14
|
+
[Demo](#-demo) · [Quick start](#-quick-start) · [How it decides](#-how-the-agent-decides) · [Widgets](#-sandboxed-widgets-ui_render_widget) · [Security](#-security-model) · [Configuration](#%EF%B8%8F-configuration) · [Develop](#-develop-and-verify)
|
|
15
|
+
|
|
16
|
+
</div>
|
|
6
17
|
|
|
7
18
|
Generative, interactive UI for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH). Ask in plain language and the agent decides on its own whether to answer with text, with native components (dashboards, tables, charts, timelines, live function plots, KaTeX math, Mermaid diagrams, forms), or with a fully custom **sandboxed live widget** (Three.js scenes, canvas simulations, mini-apps). The UI renders progressively in the chat while the answer streams. Sliders, rotation, zoom, sorting and tabs respond instantly in the browser. Only explicit actions (a button, a form, `Bridge.sendPrompt`) go back to the agent.
|
|
8
19
|
|
|
9
20
|
It ports the ideas of CopilotKit's [OpenIntelligentUI](https://github.com/CopilotKit/OpenIntelligentUI) (Open Generative UI + A2UI-style declarative components) onto DSH's own extension points. It needs no CopilotKit, LangGraph, or external router.
|
|
10
21
|
|
|
11
|
-
##
|
|
22
|
+
## ✨ Highlights
|
|
23
|
+
|
|
24
|
+
<table>
|
|
25
|
+
<tr>
|
|
26
|
+
<td width="33%" valign="top">
|
|
27
|
+
|
|
28
|
+
### 🧠 Decides by itself
|
|
29
|
+
No command needed. Each turn the agent picks text, native components or a live widget, guided by a system-prompt section.
|
|
30
|
+
|
|
31
|
+
</td>
|
|
32
|
+
<td width="33%" valign="top">
|
|
33
|
+
|
|
34
|
+
### ⚡ Streams progressively
|
|
35
|
+
Components appear while the JSON streams. Widgets morph into **one** iframe and finalize in place: no rebuild, no flash.
|
|
36
|
+
|
|
37
|
+
</td>
|
|
38
|
+
<td width="33%" valign="top">
|
|
39
|
+
|
|
40
|
+
### 🖱️ Local first
|
|
41
|
+
Sliders, rotate, zoom, sort, tabs and hover tooltips run in the browser and never call the model.
|
|
42
|
+
|
|
43
|
+
</td>
|
|
44
|
+
</tr>
|
|
45
|
+
<tr>
|
|
46
|
+
<td valign="top">
|
|
47
|
+
|
|
48
|
+
### 🧩 20-component catalog
|
|
49
|
+
Cards, grids, tabs, tables, charts, timelines, `Plot`, KaTeX `Math`, `Mermaid`, forms. Validated before it renders.
|
|
50
|
+
|
|
51
|
+
</td>
|
|
52
|
+
<td valign="top">
|
|
53
|
+
|
|
54
|
+
### 🔒 Sandboxed by default
|
|
55
|
+
Opaque-origin iframe, strict CSP, token-checked messages and a rate-limited bridge, all verified in a real browser.
|
|
56
|
+
|
|
57
|
+
</td>
|
|
58
|
+
<td valign="top">
|
|
59
|
+
|
|
60
|
+
### 💾 State that survives
|
|
61
|
+
Open tabs, sort order, form values, sliders and `UI.state` survive turn folding, page reloads and stopped generations.
|
|
62
|
+
|
|
63
|
+
</td>
|
|
64
|
+
</tr>
|
|
65
|
+
</table>
|
|
66
|
+
|
|
67
|
+
## 🎬 Demo
|
|
12
68
|
|
|
13
69
|

|
|
14
70
|
|
|
15
71
|
🎥 **Full-quality video (H.264, ~2 min):** [docs/assets/demo.mp4](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/v0.2.1/docs/assets/demo.mp4)
|
|
16
72
|
|
|
73
|
+
> [!NOTE]
|
|
17
74
|
> The recording comes from the real DSH Web 0.2.0-rc.1 with this plugin installed, driven by `npm run e2e:all -- --record`. The model behind it is the **scripted mock** in `scripts/e2e/` (no API key was available), so the answers are canned. Everything you see (streaming, rendering, interaction, the round trips, persistence, isolation) is the real plugin running in DSH.
|
|
18
|
-
|
|
19
|
-
>
|
|
75
|
+
|
|
76
|
+
<details>
|
|
77
|
+
<summary><b>📸 Screenshot gallery</b> (dashboard, Three.js, math, forms, streaming, dark mode, phone, reload)</summary>
|
|
78
|
+
<br>
|
|
20
79
|
|
|
21
80
|
| Dashboard streams in, then settles | Three.js widget: R slider, rotate, zoom |
|
|
22
81
|
|:---:|:---:|
|
|
@@ -36,7 +95,61 @@ It ports the ideas of CopilotKit's [OpenIntelligentUI](https://github.com/Copilo
|
|
|
36
95
|
|:---:|:---:|:---:|
|
|
37
96
|
|  |  |  |
|
|
38
97
|
|
|
39
|
-
|
|
98
|
+
To get an inline player on GitHub, drag `docs/assets/demo.mp4` into a GitHub comment or release editor and paste the resulting `https://github.com/user-attachments/assets/…` URL on its own line here. GitHub only renders inline video for uploaded attachments, not for repository files.
|
|
99
|
+
|
|
100
|
+
</details>
|
|
101
|
+
|
|
102
|
+
## 🚀 Quick start
|
|
103
|
+
|
|
104
|
+
You need [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) **0.1.7 – 0.2.x** (`>=0.1.7-rc.1 <0.3.0`) and Node.js ≥ 22.13, on Windows, Linux or macOS. Nothing is compiled during install. The package ships its prebuilt browser bundle and declares no install scripts.
|
|
105
|
+
|
|
106
|
+
```sh
|
|
107
|
+
dsh plugin --profile web add deepseek-harness-intelligent-ui
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Then restart DSH Web (`dsh web`) and ask for something visual, for example *"compare Q1–Q4 revenue by channel"* or *"let me explore x²+y²+z²=2Rz in 3D"*.
|
|
111
|
+
|
|
112
|
+
To have your environment checked first, use the guided installer instead. It verifies Node, the `dsh` version, pnpm and the profile, then runs the same `dsh plugin add`:
|
|
113
|
+
|
|
114
|
+
```sh
|
|
115
|
+
npx deepseek-harness-intelligent-ui install # --profile <name>, --dsh <path>, --dry-run
|
|
116
|
+
npx deepseek-harness-intelligent-ui doctor # diagnose only
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
| Task | Command |
|
|
120
|
+
|---|---|
|
|
121
|
+
| Upgrade | `dsh plugin --profile web add deepseek-harness-intelligent-ui@latest` |
|
|
122
|
+
| Try a prerelease (only when the `next` dist-tag exists) | `dsh plugin --profile web add deepseek-harness-intelligent-ui@next` |
|
|
123
|
+
| Pin a version | `dsh plugin --profile web add deepseek-harness-intelligent-ui@0.2.3` |
|
|
124
|
+
| Uninstall | `dsh plugin --profile web remove deepseek-harness-intelligent-ui` (or `npx deepseek-harness-intelligent-ui uninstall`) |
|
|
125
|
+
| From a checkout | `dsh plugin --profile web add file:/path/to/deepseek-harness-intelligent-ui` |
|
|
126
|
+
|
|
127
|
+
<details>
|
|
128
|
+
<summary><b>🩺 Troubleshooting</b></summary>
|
|
129
|
+
<br>
|
|
130
|
+
|
|
131
|
+
- *`pnpm was not found`*: DSH installs plugins with pnpm. Run `corepack enable` (it ships with Node) or `npm i -g pnpm`.
|
|
132
|
+
- *`… is incompatible with dsh X`*: your DSH is outside the supported range. Upgrade DSH (`npm i -g @deepseek-ai/dsh@latest`) or check [compatibility](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/main/docs/compatibility.md) for a plugin release that supports it.
|
|
133
|
+
- *Upgrading from 0.1.x (`dsh-intelligent-ui` via `file:`)*: run `dsh plugin --profile web remove dsh-intelligent-ui` first. Both packages insert the same `intelligent-ui` row, and `doctor` reports the conflict.
|
|
134
|
+
- *The UI does not appear*: restart DSH Web after installing, and make sure you started the profile you installed into (`dsh web`).
|
|
135
|
+
|
|
136
|
+
</details>
|
|
137
|
+
|
|
138
|
+
### Compatibility
|
|
139
|
+
|
|
140
|
+
| DeepSeek Harness | Install smoke test | Browser E2E (24 checks) |
|
|
141
|
+
|---|:---:|:---:|
|
|
142
|
+
| `0.1.7-rc.2` | ✅ | ✅ |
|
|
143
|
+
| `0.2.0-rc.1` | ✅ | ✅ |
|
|
144
|
+
| `0.2.0-rc.2` (`latest`) | ✅ | ✅ |
|
|
145
|
+
| `0.2.1-alpha.2` | ✅ | ✅ |
|
|
146
|
+
| `0.2.1-alpha.4` (`alpha`) | ✅ | ✅ |
|
|
147
|
+
|
|
148
|
+
CI runs the matrix on Windows, Linux and macOS, nightly too, so new DSH releases are caught early. Details: [docs/compatibility.md](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/main/docs/compatibility.md).
|
|
149
|
+
|
|
150
|
+
## 🧠 How the agent decides
|
|
151
|
+
|
|
152
|
+
<img src="https://raw.githubusercontent.com/dreamfarer-space/deepseek-harness-intelligent-ui/main/docs/assets/readme/routing.svg" alt="The agent routes each prompt to plain text, ui_render or ui_render_widget; local interactions never call the model, explicit actions go back to the agent" width="100%">
|
|
40
153
|
|
|
41
154
|
The plugin injects a system-prompt section (`src/guidance.js`) that makes the model route each turn itself. There is no command and no external router:
|
|
42
155
|
|
|
@@ -47,33 +160,44 @@ The plugin injects a system-prompt section (`src/guidance.js`) that makes the mo
|
|
|
47
160
|
|
|
48
161
|
`/ui <request>` still exists to force a UI answer.
|
|
49
162
|
|
|
50
|
-
## Tools
|
|
51
|
-
|
|
52
163
|
| Tool | Use it for | Rendering |
|
|
53
164
|
|---|---|---|
|
|
54
165
|
| `ui_render` | Structured answers | Native React components from a fixed catalog, rendered progressively as the JSON streams |
|
|
55
166
|
| `ui_render_widget` | Custom visuals, 3D, simulations, mini-apps | HTML/CSS/JS in an opaque-origin sandboxed iframe: CSS first, HTML morphed in live, JS last, all in **one** iframe |
|
|
56
167
|
|
|
57
|
-
|
|
168
|
+
## 🧩 Component catalog (`ui_render`)
|
|
58
169
|
|
|
59
|
-
|
|
170
|
+
| Category | Components |
|
|
171
|
+
|---|---|
|
|
172
|
+
| Layout | `Card`, `Stack`, `Grid`, `Tabs` (keyboard navigable) |
|
|
173
|
+
| Text & callouts | `Text` (markdown subset), `Code`, `Alert`, `Badge`, `Divider` |
|
|
174
|
+
| Data | `Stat`, `Progress`, `List`, `Table` (sortable), `Timeline` |
|
|
175
|
+
| Charts | `Chart`: bar / line / area / pie, stacked, hover tooltip, toggleable legend |
|
|
176
|
+
| Math & diagrams | **`Plot`** (y = f(x) with parameter sliders that redraw instantly; expressions run in a safe compiler, never `eval`), **`Math`** (KaTeX), **`Mermaid`** (flowchart, sequence, class, state, ER, gantt, mindmap…) |
|
|
177
|
+
| Interaction | `Button` (sends a prompt), `Form` (text, number, **range slider**, select, checkbox, date, textarea; submits the values as a message) |
|
|
60
178
|
|
|
61
179
|
A UI travels as a **flat node list with id references**, because DSH's tool-schema subset has no recursion. The Host validates it before acknowledging: unknown types or props, dangling or duplicate ids, cycles, two parents, chart length mismatches, `Plot` expressions that do not compile, slider defaults out of range, and so on. Problems come back as `ok:false` with paths, so the model can fix them and retry.
|
|
62
180
|
|
|
63
181
|
`Math` and `Mermaid` render inside the same sandbox as widgets, loading KaTeX or Mermaid from the CDN allowlist. No third-party code runs in the DSH page and the host bundle stays small (~127 KB). If the CDN is unreachable, the source text is shown instead.
|
|
64
182
|
|
|
65
|
-
|
|
183
|
+
## 🪟 Sandboxed widgets (`ui_render_widget`)
|
|
184
|
+
|
|
185
|
+
<img src="https://raw.githubusercontent.com/dreamfarer-space/deepseek-harness-intelligent-ui/main/docs/assets/readme/widget-streaming.svg" alt="Widget fields stream in order: placeholder, then a live preview with morphed HTML, then the same iframe is finalized and the code runs" width="100%">
|
|
66
186
|
|
|
67
187
|
Fields follow the OpenIntelligentUI streaming contract, **in this order**: `title`, `initialHeight`, `placeholderMessages`, `css`, `html`, `jsFunctions`, `jsExpressions`.
|
|
68
188
|
|
|
69
189
|
- **Streaming:** placeholder lines show until `css` is complete. Then a preview frame opens and the cleaned partial `html` is morphed in ([idiomorph](https://github.com/bigskysoftware/idiomorph)). When the arguments are complete, the **same frame is finalized in place**: the final HTML is morphed and the code runs. There is no rebuild, blank flash or height jump.
|
|
70
190
|
- **Runtime helpers** (global `UI`):
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
191
|
+
|
|
192
|
+
| Helper | What it does |
|
|
193
|
+
|---|---|
|
|
194
|
+
| `UI.three(el, { camera, target, autoRotate })` | Renderer, scene, lights and OrbitControls (drag rotates, wheel/pinch zooms); renders on demand and handles resize |
|
|
195
|
+
| `UI.canvas(el, draw)` | HiDPI 2D canvas, redrawn on resize and theme change |
|
|
196
|
+
| `UI.state` / `UI.setState()` | Persisted state; inputs with an `id` are persisted and restored automatically |
|
|
197
|
+
| `UI.color('accent')` / `UI.css()` | Opaque theme color for three.js/canvas / raw CSS value |
|
|
198
|
+
| `UI.onTheme(cb)`, `UI.scheme`, `UI.reducedMotion` | React to theme and motion preferences |
|
|
199
|
+
| `.ui-row`, `.ui-control`, `.ui-card`, `.ui-stage` | Helper classes |
|
|
200
|
+
|
|
77
201
|
- **Bridge:** `Bridge.sendPrompt({ text })` disables the clicked control until the host answers, so double clicks cannot queue duplicates. `Bridge.openLink({ url })` opens links, and `Websandbox.connection.remote.*` is kept for OpenIntelligentUI compatibility.
|
|
78
202
|
- **Libraries:** an importmap maps `three`, `three/addons/…`, `d3`, `chart.js/auto`, `gsap` and `canvas-confetti` to esm.sh.
|
|
79
203
|
- **Recovery:** script errors show a count with **Reload** and **Ask to fix** (the latter sends the errors to the agent).
|
|
@@ -87,56 +211,20 @@ Fields follow the OpenIntelligentUI streaming contract, **in this order**: `titl
|
|
|
87
211
|
- If the call already reached DSH, the view keeps the finished part (a static widget preview or the completed components) with a notice and a **Regenerate** button.
|
|
88
212
|
- If the user stops while the arguments are still streaming, DSH drops the call entirely. The plugin stashes what was streamed and shows it beneath the stopped turn the same way.
|
|
89
213
|
|
|
90
|
-
## Security model
|
|
214
|
+
## 🔒 Security model
|
|
215
|
+
|
|
216
|
+
<img src="https://raw.githubusercontent.com/dreamfarer-space/deepseek-harness-intelligent-ui/main/docs/assets/readme/security.svg" alt="Widgets run in an opaque-origin sandboxed iframe under a strict CSP; access to the host page is blocked and only token-checked postMessage calls reach the rate-limited bridge" width="100%">
|
|
91
217
|
|
|
92
218
|
- **Widget isolation:** widgets run in `<iframe sandbox="allow-scripts allow-forms">` with `srcdoc` and **no** `allow-same-origin`. They cannot reach the DSH page, its cookies or storage, or its API. The E2E checks this in the browser: `parent.document`, `localStorage` and `document.cookie` all throw `SecurityError`, `fetch` is blocked, and `window.origin === "null"`.
|
|
93
|
-
- **CSP:**
|
|
94
|
-
- `default-src 'none'`.
|
|
95
|
-
- Scripts, styles, fonts and images load only from `cdnAllowlist`.
|
|
96
|
-
- `connect-src 'none'` unless `allowNetwork` is on.
|
|
97
|
-
- `form-action 'none'` and `base-uri 'none'`.
|
|
219
|
+
- **CSP:** `default-src 'none'`; scripts, styles, fonts and images load only from `cdnAllowlist`; `connect-src 'none'` unless `allowNetwork` is on; `form-action 'none'` and `base-uri 'none'`.
|
|
98
220
|
- **Messages from the frame:** they are accepted only from that frame's `contentWindow`, must carry a per-frame random token, and are shape-checked. Persisted widget state is size-limited JSON. The E2E checks that forged messages from the page or the frame are dropped.
|
|
99
|
-
- **`sendPrompt` limits:**
|
|
100
|
-
- It is refused during the first second after mount.
|
|
101
|
-
- At most one send every 2 seconds.
|
|
102
|
-
- Text is capped at `sendPromptMaxChars`.
|
|
103
|
-
- The message is queued as a normal user message.
|
|
221
|
+
- **`sendPrompt` limits:** refused during the first second after mount; at most one send every 2 seconds; text capped at `sendPromptMaxChars`; queued as a normal user message.
|
|
104
222
|
- **`openLink`:** https only, optionally restricted to `openLinkAllowedOrigins`.
|
|
105
223
|
- **Catalog:** text renders as React elements, never raw HTML. `Plot` expressions are compiled by a tokenizer/parser over a fixed math function table, with no `eval`, `Function`, or property access.
|
|
106
224
|
|
|
107
|
-
##
|
|
108
|
-
|
|
109
|
-
You need [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) **0.1.7 – 0.2.x** (`>=0.1.7-rc.1 <0.3.0`) and Node.js ≥ 22.13, on Windows, Linux or macOS. Nothing is compiled during install. The package ships its prebuilt browser bundle and declares no install scripts.
|
|
225
|
+
## ⚙️ Configuration
|
|
110
226
|
|
|
111
|
-
|
|
112
|
-
dsh plugin --profile web add deepseek-harness-intelligent-ui
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
To have your environment checked first, use the guided installer instead. It verifies Node, the `dsh` version, pnpm and the profile, then runs the same `dsh plugin add`:
|
|
116
|
-
|
|
117
|
-
```sh
|
|
118
|
-
npx deepseek-harness-intelligent-ui install # --profile <name>, --dsh <path>, --dry-run
|
|
119
|
-
npx deepseek-harness-intelligent-ui doctor # diagnose only
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
| Task | Command |
|
|
123
|
-
|---|---|
|
|
124
|
-
| Upgrade | `dsh plugin --profile web add deepseek-harness-intelligent-ui@latest` |
|
|
125
|
-
| Try a prerelease (only when the `next` dist-tag exists) | `dsh plugin --profile web add deepseek-harness-intelligent-ui@next` |
|
|
126
|
-
| Pin a version | `dsh plugin --profile web add deepseek-harness-intelligent-ui@0.2.2` |
|
|
127
|
-
| Uninstall | `dsh plugin --profile web remove deepseek-harness-intelligent-ui` (or `npx deepseek-harness-intelligent-ui uninstall`) |
|
|
128
|
-
| From a checkout | `dsh plugin --profile web add file:/path/to/deepseek-harness-intelligent-ui` |
|
|
129
|
-
|
|
130
|
-
Supported DSH versions and the CI matrix are in [docs/compatibility.md](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/v0.2.2/docs/compatibility.md).
|
|
131
|
-
|
|
132
|
-
**Troubleshooting**
|
|
133
|
-
|
|
134
|
-
- *`pnpm was not found`*: DSH installs plugins with pnpm. Run `corepack enable` (it ships with Node) or `npm i -g pnpm`.
|
|
135
|
-
- *`… is incompatible with dsh X`*: your DSH is outside the supported range. Upgrade DSH (`npm i -g @deepseek-ai/dsh@latest`) or check [compatibility](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/v0.2.2/docs/compatibility.md) for a plugin release that supports it.
|
|
136
|
-
- *Upgrading from 0.1.x (`dsh-intelligent-ui` via `file:`)*: run `dsh plugin --profile web remove dsh-intelligent-ui` first. Both packages insert the same `intelligent-ui` row, and `doctor` reports the conflict.
|
|
137
|
-
- *The UI does not appear*: restart DSH Web after installing, and make sure you started the profile you installed into (`dsh web`).
|
|
138
|
-
|
|
139
|
-
Restart DSH Web afterwards. The bundle patch inserts the plugin row automatically. To change settings, add to your profile's `cordis.patch.yml`:
|
|
227
|
+
The bundle patch inserts the plugin row automatically. To change settings, add to your profile's `cordis.patch.yml`:
|
|
140
228
|
|
|
141
229
|
```yaml
|
|
142
230
|
- id: intelligent-ui
|
|
@@ -157,7 +245,7 @@ Restart DSH Web afterwards. The bundle patch inserts the plugin row automaticall
|
|
|
157
245
|
| `sendPromptMaxChars` | `4000` | Longest message a widget, button or form may send |
|
|
158
246
|
| `openLinkAllowedOrigins` | `[]` | If non-empty, the only origins `openLink` may open |
|
|
159
247
|
|
|
160
|
-
## Develop and verify
|
|
248
|
+
## 🛠 Develop and verify
|
|
161
249
|
|
|
162
250
|
```sh
|
|
163
251
|
npm install
|
|
@@ -168,11 +256,42 @@ npm run e2e:all # build → install into a temp DSH home → mock model + re
|
|
|
168
256
|
npm run e2e:all -- --record # also re-records docs/assets/demo.mp4 / demo.gif (needs ffmpeg)
|
|
169
257
|
npm run e2e:all -- --spec ./deepseek-harness-intelligent-ui-<v>.tgz # E2E the packed tarball instead of the checkout
|
|
170
258
|
npm run smoke -- --spec ./deepseek-harness-intelligent-ui-<v>.tgz # install smoke test (no browser): version gate, bundle row, DSH Web boot
|
|
259
|
+
npm run docs:art # regenerate the animated README illustrations in docs/assets/readme/
|
|
171
260
|
```
|
|
172
261
|
|
|
173
|
-
The E2E runs on Windows, Linux and macOS. It finds Chrome per platform (set `CHROME_PATH` to override) and uses `DSH_BIN` to test another `dsh` binary. CI runs everything on all three OSes against every supported DSH line ([compatibility](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/
|
|
262
|
+
The E2E runs on Windows, Linux and macOS. It finds Chrome per platform (set `CHROME_PATH` to override) and uses `DSH_BIN` to test another `dsh` binary. CI runs everything on all three OSes against every supported DSH line ([compatibility](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/main/docs/compatibility.md)).
|
|
174
263
|
|
|
175
|
-
**
|
|
264
|
+
- **Layout:** `src/` is the Host half (plain ESM, no build). `client-src/` is the browser half (TSX, bundled with esbuild). `client/client.js` is committed and published so npm, `file:` and git installs need no build step. CI fails if it is stale. Never add a `prepare`/`postinstall` script, because DSH's pnpm blocks plugin build scripts.
|
|
265
|
+
- Requires Chrome (`CHROME_PATH`), `dsh` on PATH and, for `--record`, `ffmpeg`. Headless Chrome uses SwiftShader for WebGL.
|
|
266
|
+
|
|
267
|
+
<details>
|
|
268
|
+
<summary><b>✅ What the browser E2E checks</b> (<code>scripts/e2e/browser.mjs</code>)</summary>
|
|
269
|
+
<br>
|
|
270
|
+
|
|
271
|
+
Report: [`docs/e2e-report.json`](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/v0.2.1/docs/e2e-report.json).
|
|
272
|
+
|
|
273
|
+
- Plain Q&A stays text.
|
|
274
|
+
- The dashboard streams progressively.
|
|
275
|
+
- Chart hover, table sort and tabs are local.
|
|
276
|
+
- A form round-trip returns a new UI.
|
|
277
|
+
- The preview iframe is finalized in place.
|
|
278
|
+
- The Three.js scene renders, and the R slider, drag-rotate and wheel-zoom work.
|
|
279
|
+
- The `Bridge.sendPrompt` round trip works.
|
|
280
|
+
- KaTeX and Mermaid render.
|
|
281
|
+
- Plot sliders work.
|
|
282
|
+
- Earlier UIs keep their state.
|
|
283
|
+
- Stop → static preview → Regenerate works.
|
|
284
|
+
- The sandbox is isolated and forged messages are ignored.
|
|
285
|
+
- Dark theme reaches cards and widgets.
|
|
286
|
+
- Phone width has no overflow.
|
|
287
|
+
- A reload restores the UIs and their state.
|
|
288
|
+
- No plugin console errors appear.
|
|
289
|
+
|
|
290
|
+
</details>
|
|
291
|
+
|
|
292
|
+
<details>
|
|
293
|
+
<summary><b>📦 Releasing</b> (maintainers)</summary>
|
|
294
|
+
<br>
|
|
176
295
|
|
|
177
296
|
See [release security and OIDC setup](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/main/docs/releasing.md).
|
|
178
297
|
|
|
@@ -185,27 +304,11 @@ See [release security and OIDC setup](https://github.com/dreamfarer-space/deepse
|
|
|
185
304
|
- creates the GitHub Release with the changelog section and the tarball.
|
|
186
305
|
4. Run `npm run release:check` to perform the same preflight locally.
|
|
187
306
|
|
|
188
|
-
|
|
189
|
-
- **What the E2E checks** (`scripts/e2e/browser.mjs`, report in [`docs/e2e-report.json`](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/v0.2.1/docs/e2e-report.json)):
|
|
190
|
-
- Plain Q&A stays text.
|
|
191
|
-
- The dashboard streams progressively.
|
|
192
|
-
- Chart hover, table sort and tabs are local.
|
|
193
|
-
- A form round-trip returns a new UI.
|
|
194
|
-
- The preview iframe is finalized in place.
|
|
195
|
-
- The Three.js scene renders, and the R slider, drag-rotate and wheel-zoom work.
|
|
196
|
-
- The `Bridge.sendPrompt` round trip works.
|
|
197
|
-
- KaTeX and Mermaid render.
|
|
198
|
-
- Plot sliders work.
|
|
199
|
-
- Earlier UIs keep their state.
|
|
200
|
-
- Stop → static preview → Regenerate works.
|
|
201
|
-
- The sandbox is isolated and forged messages are ignored.
|
|
202
|
-
- Dark theme reaches cards and widgets.
|
|
203
|
-
- Phone width has no overflow.
|
|
204
|
-
- A reload restores the UIs and their state.
|
|
205
|
-
- No plugin console errors appear.
|
|
206
|
-
- Requires Chrome (`CHROME_PATH`), `dsh` on PATH and, for `--record`, `ffmpeg`. Headless Chrome uses SwiftShader for WebGL.
|
|
307
|
+
</details>
|
|
207
308
|
|
|
208
|
-
|
|
309
|
+
<details>
|
|
310
|
+
<summary><b>🤖 Real-model evaluation</b></summary>
|
|
311
|
+
<br>
|
|
209
312
|
|
|
210
313
|
The API suite checks model routing, tool-argument schemas, and selected requested components or data across 15 prompts. It does **not** execute model-generated widgets in a browser or verify factual data, visual quality, physics, or interaction behavior. The separate browser E2E uses scripted model responses.
|
|
211
314
|
|
|
@@ -227,6 +330,8 @@ node scripts/run-real-model-suite.mjs all
|
|
|
227
330
|
|
|
228
331
|
Each invocation writes only that run's cases to `docs/real-model-eval-report.json`. A partial run does not merge older cases into a new timestamp. Failed assertions/API calls exit with code 1; an invalid category or missing key fails before changing the report. Keep keys out of git.
|
|
229
332
|
|
|
333
|
+
</details>
|
|
334
|
+
|
|
230
335
|
## Limitations
|
|
231
336
|
|
|
232
337
|
- Widgets, Math and Mermaid need the CDN allowlist to be reachable. Offline, Math/Mermaid fall back to source text and `UI.three` reports a script error.
|
package/README.zh-CN.md
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<img src="https://raw.githubusercontent.com/dreamfarer-space/deepseek-harness-intelligent-ui/main/docs/assets/readme/hero.zh.svg" alt="DeepSeek Harness Intelligent UI:为 DeepSeek Harness 带来生成式、可交互的界面" width="100%">
|
|
4
4
|
|
|
5
|
-
[
|
|
5
|
+
[English](README.md) · **中文**
|
|
6
|
+
|
|
7
|
+
[](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/actions/workflows/ci.yml)
|
|
8
|
+
[](https://www.npmjs.com/package/deepseek-harness-intelligent-ui)
|
|
9
|
+
[](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/main/docs/compatibility.md)
|
|
10
|
+
[](https://nodejs.org)
|
|
11
|
+
[](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/main/docs/compatibility.md)
|
|
12
|
+
[](LICENSE)
|
|
13
|
+
|
|
14
|
+
[演示](#-演示) · [快速开始](#-快速开始) · [如何选择](#-agent-如何选择呈现方式) · [沙箱组件](#-沙箱组件ui_render_widget) · [安全](#-安全模型) · [配置](#%EF%B8%8F-配置) · [开发](#-开发与验证)
|
|
15
|
+
|
|
16
|
+
</div>
|
|
6
17
|
|
|
7
18
|
为 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)提供**生成式、可交互的 UI**。用户用自然语言提问,Agent 自行决定怎样作答:
|
|
8
19
|
|
|
@@ -14,17 +25,63 @@
|
|
|
14
25
|
|
|
15
26
|
本插件把 CopilotKit [OpenIntelligentUI](https://github.com/CopilotKit/OpenIntelligentUI) 的思路(Open Generative UI + A2UI 风格声明式组件)移植到 DSH 自带的扩展点上,不依赖 CopilotKit、LangGraph 或外部路由服务。
|
|
16
27
|
|
|
17
|
-
##
|
|
28
|
+
## ✨ 亮点
|
|
29
|
+
|
|
30
|
+
<table>
|
|
31
|
+
<tr>
|
|
32
|
+
<td width="33%" valign="top">
|
|
33
|
+
|
|
34
|
+
### 🧠 自主决策
|
|
35
|
+
无需任何命令。每一轮由 Agent 依据系统提示,自行选择文本、原生组件或实时组件。
|
|
36
|
+
|
|
37
|
+
</td>
|
|
38
|
+
<td width="33%" valign="top">
|
|
39
|
+
|
|
40
|
+
### ⚡ 流式渐进
|
|
41
|
+
JSON 还在生成,组件就已出现。实时组件在**同一个** iframe 中 morph 并原地定稿,不重建、不闪烁。
|
|
42
|
+
|
|
43
|
+
</td>
|
|
44
|
+
<td width="33%" valign="top">
|
|
45
|
+
|
|
46
|
+
### 🖱️ 本地优先
|
|
47
|
+
滑块、旋转、缩放、排序、标签页、悬停提示都在浏览器内完成,不调用模型。
|
|
48
|
+
|
|
49
|
+
</td>
|
|
50
|
+
</tr>
|
|
51
|
+
<tr>
|
|
52
|
+
<td valign="top">
|
|
53
|
+
|
|
54
|
+
### 🧩 20 种组件
|
|
55
|
+
卡片、栅格、标签页、表格、图表、时间线、`Plot`、KaTeX `Math`、`Mermaid`、表单,渲染前先校验。
|
|
56
|
+
|
|
57
|
+
</td>
|
|
58
|
+
<td valign="top">
|
|
59
|
+
|
|
60
|
+
### 🔒 默认沙箱隔离
|
|
61
|
+
不透明源 iframe、严格 CSP、带 token 的消息校验、限流的 Bridge,全部在真实浏览器中实测。
|
|
62
|
+
|
|
63
|
+
</td>
|
|
64
|
+
<td valign="top">
|
|
65
|
+
|
|
66
|
+
### 💾 状态不丢失
|
|
67
|
+
标签页、排序、表单值、滑块和 `UI.state` 在回合折叠、页面刷新、中途停止后都能恢复。
|
|
68
|
+
|
|
69
|
+
</td>
|
|
70
|
+
</tr>
|
|
71
|
+
</table>
|
|
72
|
+
|
|
73
|
+
## 🎬 演示
|
|
18
74
|
|
|
19
75
|

|
|
20
76
|
|
|
21
77
|
🎥 **高清视频(H.264,约 2 分钟):** [docs/assets/demo.mp4](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/v0.2.1/docs/assets/demo.mp4)
|
|
22
78
|
|
|
23
|
-
>
|
|
24
|
-
>
|
|
25
|
-
|
|
26
|
-
>
|
|
27
|
-
|
|
79
|
+
> [!NOTE]
|
|
80
|
+
> 演示视频录自真实的 DSH Web 0.2.0-rc.1,装好本插件后由 `npm run e2e:all -- --record` 自动驱动。背后的模型是 `scripts/e2e/` 中的**脚本化 mock**(当时没有 API Key),回答内容是预设的。画面中的流式渲染、交互、双向通信、持久化和隔离,都是插件在 DSH 中真实运行的结果。
|
|
81
|
+
|
|
82
|
+
<details>
|
|
83
|
+
<summary><b>📸 截图集</b>(看板、Three.js、公式、表单、流式预览、深色主题、手机、刷新)</summary>
|
|
84
|
+
<br>
|
|
28
85
|
|
|
29
86
|
| 看板流式出现并定稿 | Three.js 组件:R 滑块、旋转、缩放 |
|
|
30
87
|
|:---:|:---:|
|
|
@@ -43,7 +100,61 @@
|
|
|
43
100
|
|:---:|:---:|:---:|
|
|
44
101
|
|  |  |  |
|
|
45
102
|
|
|
46
|
-
|
|
103
|
+
**在 GitHub 内联播放:** 把 `docs/assets/demo.mp4` 拖进 GitHub 的评论或 Release 编辑框,再把生成的 `https://github.com/user-attachments/assets/…` 链接单独一行粘贴到这里。GitHub 只对上传的附件内联播放视频,不支持仓库内的文件。
|
|
104
|
+
|
|
105
|
+
</details>
|
|
106
|
+
|
|
107
|
+
## 🚀 快速开始
|
|
108
|
+
|
|
109
|
+
需要 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) **0.1.7 – 0.2.x**(`>=0.1.7-rc.1 <0.3.0`)和 Node.js ≥ 22.13,Windows、Linux、macOS 均可。安装过程不需要编译:npm 包自带预构建的浏览器端 bundle,也没有任何安装脚本。
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
dsh plugin --profile web add deepseek-harness-intelligent-ui
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
然后重启 DSH Web(`dsh web`),试着提一个需要可视化的问题,例如 *“按渠道对比 Q1–Q4 营收”* 或 *“让我在 3D 里探索 x²+y²+z²=2Rz”*。
|
|
116
|
+
|
|
117
|
+
也可以用引导式安装器。它会先检查 Node、`dsh` 版本、pnpm 和 profile,检查通过后执行同样的 `dsh plugin add`:
|
|
118
|
+
|
|
119
|
+
```sh
|
|
120
|
+
npx deepseek-harness-intelligent-ui install # 可选 --profile <名称>、--dsh <路径>、--dry-run
|
|
121
|
+
npx deepseek-harness-intelligent-ui doctor # 只诊断,不做修改
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
| 操作 | 命令 |
|
|
125
|
+
|---|---|
|
|
126
|
+
| 升级 | `dsh plugin --profile web add deepseek-harness-intelligent-ui@latest` |
|
|
127
|
+
| 试用预发布版(仅在存在 `next` 标签时) | `dsh plugin --profile web add deepseek-harness-intelligent-ui@next` |
|
|
128
|
+
| 固定版本 | `dsh plugin --profile web add deepseek-harness-intelligent-ui@0.2.3` |
|
|
129
|
+
| 卸载 | `dsh plugin --profile web remove deepseek-harness-intelligent-ui`(或 `npx deepseek-harness-intelligent-ui uninstall`) |
|
|
130
|
+
| 从源码目录安装 | `dsh plugin --profile web add file:/path/to/deepseek-harness-intelligent-ui` |
|
|
131
|
+
|
|
132
|
+
<details>
|
|
133
|
+
<summary><b>🩺 常见问题</b></summary>
|
|
134
|
+
<br>
|
|
135
|
+
|
|
136
|
+
- *提示 `pnpm was not found`*:DSH 用 pnpm 安装插件。运行 `corepack enable`(Node 自带)或 `npm i -g pnpm`。
|
|
137
|
+
- *提示 `… is incompatible with dsh X`*:当前 DSH 版本不在支持范围内。可以升级 DSH(`npm i -g @deepseek-ai/dsh@latest`),或在[兼容性文档](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/main/docs/compatibility.md)里找支持该版本的插件发行版。
|
|
138
|
+
- *从 0.1.x 升级(以前用 `file:` 安装的 `dsh-intelligent-ui`)*:先运行 `dsh plugin --profile web remove dsh-intelligent-ui`。新旧两个包会插入同一个 `intelligent-ui` 行,`doctor` 能检测到这种冲突。
|
|
139
|
+
- *界面没有出现*:安装后要重启 DSH Web,并确认启动的是安装插件时指定的 profile(`dsh web`)。
|
|
140
|
+
|
|
141
|
+
</details>
|
|
142
|
+
|
|
143
|
+
### 兼容性
|
|
144
|
+
|
|
145
|
+
| DeepSeek Harness | 安装冒烟测试 | 浏览器 E2E(24 项) |
|
|
146
|
+
|---|:---:|:---:|
|
|
147
|
+
| `0.1.7-rc.2` | ✅ | ✅ |
|
|
148
|
+
| `0.2.0-rc.1` | ✅ | ✅ |
|
|
149
|
+
| `0.2.0-rc.2`(`latest`) | ✅ | ✅ |
|
|
150
|
+
| `0.2.1-alpha.2` | ✅ | ✅ |
|
|
151
|
+
| `0.2.1-alpha.4`(`alpha`) | ✅ | ✅ |
|
|
152
|
+
|
|
153
|
+
CI 每天定时在 Windows、Linux、macOS 上跑完整矩阵,DSH 一发新版就能发现问题。详见 [docs/compatibility.md](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/main/docs/compatibility.md)。
|
|
154
|
+
|
|
155
|
+
## 🧠 Agent 如何选择呈现方式
|
|
156
|
+
|
|
157
|
+
<img src="https://raw.githubusercontent.com/dreamfarer-space/deepseek-harness-intelligent-ui/main/docs/assets/readme/routing.zh.svg" alt="Agent 把每次提问路由到纯文本、ui_render 或 ui_render_widget;本地交互不调用模型,显式操作才回到 Agent" width="100%">
|
|
47
158
|
|
|
48
159
|
插件注入一段系统提示(`src/guidance.js`),让模型每一轮自行选择,用户无需输入任何命令:
|
|
49
160
|
|
|
@@ -54,7 +165,12 @@
|
|
|
54
165
|
|
|
55
166
|
`/ui <需求>` 命令仍然保留,用于强制以 UI 作答。
|
|
56
167
|
|
|
57
|
-
|
|
168
|
+
| 工具 | 适用场景 | 渲染方式 |
|
|
169
|
+
|---|---|---|
|
|
170
|
+
| `ui_render` | 结构化回答 | 固定目录中的原生 React 组件,随 JSON 流式渐进渲染 |
|
|
171
|
+
| `ui_render_widget` | 自定义可视化、三维、模拟、小应用 | 不透明源沙箱 iframe 中的 HTML/CSS/JS:先 CSS,再实时 morph HTML,最后执行 JS,全程**一个** iframe |
|
|
172
|
+
|
|
173
|
+
## 🧩 组件目录(`ui_render`)
|
|
58
174
|
|
|
59
175
|
| 类别 | 组件 |
|
|
60
176
|
|---|---|
|
|
@@ -69,33 +185,31 @@
|
|
|
69
185
|
- **`Form`**:字段类型有文本、数字、**范围滑块**、下拉、勾选、日期、多行文本。
|
|
70
186
|
- **`Button` 与 `Form`**:点击或提交后,内容作为下一条用户消息发给 Agent。
|
|
71
187
|
|
|
72
|
-
**传输与校验:** DSH 的工具 schema 不支持递归,所以界面以**扁平节点列表加 id 引用**的形式传输。Host
|
|
73
|
-
|
|
74
|
-
- 未知类型或属性;
|
|
75
|
-
- id 悬空、重复或成环;
|
|
76
|
-
- 一个节点有多个父节点;
|
|
77
|
-
- 图表数据长度不一致;
|
|
78
|
-
- `Plot` 表达式无法编译、参数默认值越界等。
|
|
79
|
-
|
|
80
|
-
发现问题时返回 `ok:false` 并附带出错路径,模型据此修正后重试。
|
|
188
|
+
**传输与校验:** DSH 的工具 schema 不支持递归,所以界面以**扁平节点列表加 id 引用**的形式传输。Host 先校验再确认,检查项包括未知类型或属性;id 悬空、重复或成环;一个节点有多个父节点;图表数据长度不一致;`Plot` 表达式无法编译、参数默认值越界等。发现问题时返回 `ok:false` 并附带出错路径,模型据此修正后重试。
|
|
81
189
|
|
|
82
190
|
**`Math` 与 `Mermaid` 的渲染:** 两者在与组件相同的沙箱中,从 CDN 白名单加载 KaTeX 或 Mermaid。第三方代码不在 DSH 页面中运行,宿主包体积保持在约 127 KB。CDN 不可用时,显示源码文本。
|
|
83
191
|
|
|
84
|
-
## 沙箱组件(`ui_render_widget`)
|
|
192
|
+
## 🪟 沙箱组件(`ui_render_widget`)
|
|
193
|
+
|
|
194
|
+
<img src="https://raw.githubusercontent.com/dreamfarer-space/deepseek-harness-intelligent-ui/main/docs/assets/readme/widget-streaming.zh.svg" alt="组件字段按顺序流式到达:先显示占位,再实时 morph 预览,最后在同一个 iframe 中定稿并执行代码" width="100%">
|
|
85
195
|
|
|
86
196
|
字段顺序固定:`title`、`initialHeight`、`placeholderMessages`、`css`、`html`、`jsFunctions`、`jsExpressions`。
|
|
87
197
|
|
|
88
198
|
- **流式过程:**
|
|
89
199
|
1. `css` 完成前,显示占位文字。
|
|
90
|
-
2. `css` 完成后打开预览 iframe,把清洗过的部分 HTML 实时 morph
|
|
200
|
+
2. `css` 完成后打开预览 iframe,把清洗过的部分 HTML 实时 morph 进去([idiomorph](https://github.com/bigskysoftware/idiomorph))。
|
|
91
201
|
3. 参数完整后,在**同一个 iframe 内原地定稿**:morph 最终 HTML,然后执行代码。iframe 不重建,没有白屏闪烁,高度也不跳动。
|
|
92
202
|
- **运行时辅助(全局 `UI`):**
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
203
|
+
|
|
204
|
+
| 辅助方法 | 作用 |
|
|
205
|
+
|---|---|
|
|
206
|
+
| `UI.three(el, opts)` | 返回 renderer、场景、灯光和 OrbitControls(拖动旋转,滚轮或双指缩放),按需渲染并自适应尺寸 |
|
|
207
|
+
| `UI.canvas(el, draw)` | 高清 2D 画布,尺寸或主题变化时自动重绘 |
|
|
208
|
+
| `UI.state` / `UI.setState()` | 持久化状态;带 `id` 的输入控件会自动保存并恢复 |
|
|
209
|
+
| `UI.color('accent')` / `UI.css()` | 不透明主题色(可直接用于 three.js 和 Canvas)/ 原始 CSS 值 |
|
|
210
|
+
| `UI.onTheme(cb)`、`UI.scheme`、`UI.reducedMotion` | 响应主题变化与减少动效偏好 |
|
|
211
|
+
| `.ui-row`、`.ui-control`、`.ui-card`、`.ui-stage` | 辅助样式类 |
|
|
212
|
+
|
|
99
213
|
- **Bridge:**
|
|
100
214
|
- `Bridge.sendPrompt({ text })`:在宿主应答前,自动禁用触发它的按钮,防止重复提交。
|
|
101
215
|
- `Bridge.openLink({ url })`:打开链接。
|
|
@@ -103,7 +217,7 @@
|
|
|
103
217
|
- **依赖库:** 通过 importmap 从 esm.sh 引入 `three`、`three/addons/…`、`d3`、`chart.js/auto`、`gsap`、`canvas-confetti`。
|
|
104
218
|
- **错误恢复:** 出现脚本错误时显示错误数量,并提供“重新加载”和“让模型修复”两个按钮。后者会把错误信息发给 Agent。
|
|
105
219
|
|
|
106
|
-
|
|
220
|
+
### 显示位置与状态保持
|
|
107
221
|
|
|
108
222
|
- **显示位置:**
|
|
109
223
|
- 回合进行中,UI 在工具调用处内联显示。从准备、执行到结果,始终是同一个组件实例,交互状态不会丢。
|
|
@@ -113,61 +227,41 @@
|
|
|
113
227
|
- 已进入会话日志的调用:保留已完成的部分(组件的静态预览,或已生成的组件),并显示提示和“重新生成”按钮。
|
|
114
228
|
- 参数仍在流式输出时就被停止的调用:DSH 会整体丢弃它。插件会暂存已生成的内容,同样在被停止的回合下方显示。
|
|
115
229
|
|
|
116
|
-
## 安全模型
|
|
117
|
-
|
|
118
|
-
- **隔离:**
|
|
119
|
-
- iframe 设置 `sandbox="allow-scripts allow-forms"` 并使用 `srcdoc`,**不加** `allow-same-origin`。
|
|
120
|
-
- E2E 在浏览器中实测:访问 `parent.document`、`localStorage`、`cookie` 均抛出 `SecurityError`,`fetch` 被拦截,`window.origin` 为 `"null"`。
|
|
121
|
-
- **CSP:**
|
|
122
|
-
- `default-src 'none'`;
|
|
123
|
-
- 脚本、样式、字体、图片只能来自 `cdnAllowlist`;
|
|
124
|
-
- 默认 `connect-src 'none'`;
|
|
125
|
-
- `form-action 'none'`、`base-uri 'none'`。
|
|
126
|
-
- **消息校验:**
|
|
127
|
-
- 宿主只接受来自该 iframe 的 `contentWindow`、带随机 token、且格式合法的消息。
|
|
128
|
-
- 持久化的组件状态是有大小上限的 JSON。
|
|
129
|
-
- E2E 实测,从页面或 iframe 伪造的消息都会被丢弃。
|
|
130
|
-
- **sendPrompt 限制:**
|
|
131
|
-
- 挂载后 1 秒内拒绝发送;
|
|
132
|
-
- 2 秒内最多发送一次;
|
|
133
|
-
- 长度受 `sendPromptMaxChars` 限制;
|
|
134
|
-
- 以普通的排队用户消息发送。
|
|
135
|
-
- **openLink:** 只允许 https,可用白名单进一步限制。
|
|
136
|
-
- **Plot 表达式:** 由分词器和解析器编译,只能调用固定的数学函数表,无法使用 `eval`、`Function` 或访问属性。
|
|
230
|
+
## 🔒 安全模型
|
|
137
231
|
|
|
138
|
-
|
|
232
|
+
<img src="https://raw.githubusercontent.com/dreamfarer-space/deepseek-harness-intelligent-ui/main/docs/assets/readme/security.zh.svg" alt="组件运行在不透明源沙箱 iframe 中并受严格 CSP 约束;访问宿主页面会被拦截,只有通过 token 校验的 postMessage 才能到达限流的 Bridge" width="100%">
|
|
139
233
|
|
|
140
|
-
|
|
234
|
+
- **隔离:** iframe 设置 `sandbox="allow-scripts allow-forms"` 并使用 `srcdoc`,**不加** `allow-same-origin`。E2E 在浏览器中实测:访问 `parent.document`、`localStorage`、`cookie` 均抛出 `SecurityError`,`fetch` 被拦截,`window.origin` 为 `"null"`。
|
|
235
|
+
- **CSP:** `default-src 'none'`;脚本、样式、字体、图片只能来自 `cdnAllowlist`;默认 `connect-src 'none'`;`form-action 'none'`、`base-uri 'none'`。
|
|
236
|
+
- **消息校验:** 宿主只接受来自该 iframe 的 `contentWindow`、带随机 token、且格式合法的消息。持久化的组件状态是有大小上限的 JSON。E2E 实测,从页面或 iframe 伪造的消息都会被丢弃。
|
|
237
|
+
- **sendPrompt 限制:** 挂载后 1 秒内拒绝发送;2 秒内最多发送一次;长度受 `sendPromptMaxChars` 限制;以普通的排队用户消息发送。
|
|
238
|
+
- **openLink:** 只允许 https,可用 `openLinkAllowedOrigins` 白名单进一步限制。
|
|
239
|
+
- **Plot 表达式:** 由分词器和解析器编译,只能调用固定的数学函数表,无法使用 `eval`、`Function` 或访问属性。
|
|
141
240
|
|
|
142
|
-
|
|
143
|
-
dsh plugin --profile web add deepseek-harness-intelligent-ui
|
|
144
|
-
```
|
|
241
|
+
## ⚙️ 配置
|
|
145
242
|
|
|
146
|
-
|
|
243
|
+
安装后 bundle patch 会自动插入 `intelligent-ui` 这一行。要修改配置,在 profile 的 `cordis.patch.yml` 中添加:
|
|
147
244
|
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
|
|
245
|
+
```yaml
|
|
246
|
+
- id: intelligent-ui
|
|
247
|
+
config:
|
|
248
|
+
allowNetwork: true
|
|
249
|
+
cdnAllowlist: [https://esm.sh, https://cdn.jsdelivr.net]
|
|
151
250
|
```
|
|
152
251
|
|
|
153
|
-
|
|
|
154
|
-
|
|
155
|
-
|
|
|
156
|
-
|
|
|
157
|
-
|
|
|
158
|
-
|
|
|
159
|
-
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
- *提示 `pnpm was not found`*:DSH 用 pnpm 安装插件。运行 `corepack enable`(Node 自带)或 `npm i -g pnpm`。
|
|
166
|
-
- *提示 `… is incompatible with dsh X`*:当前 DSH 版本不在支持范围内。可以升级 DSH(`npm i -g @deepseek-ai/dsh@latest`),或在[兼容性文档](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/v0.2.2/docs/compatibility.md)里找支持该版本的插件发行版。
|
|
167
|
-
- *从 0.1.x 升级(以前用 `file:` 安装的 `dsh-intelligent-ui`)*:先运行 `dsh plugin --profile web remove dsh-intelligent-ui`。新旧两个包会插入同一个 `intelligent-ui` 行,`doctor` 能检测到这种冲突。
|
|
168
|
-
- *界面没有出现*:安装后要重启 DSH Web,并确认启动的是安装插件时指定的 profile(`dsh web`)。
|
|
252
|
+
| 配置项 | 默认值 | 含义 |
|
|
253
|
+
|---|---|---|
|
|
254
|
+
| `enableCatalog` | `true` | 注册 `ui_render` |
|
|
255
|
+
| `enableWidget` | `true` | 注册 `ui_render_widget` |
|
|
256
|
+
| `injectGuidance` | `true` | 注入“何时使用 UI”的系统提示 |
|
|
257
|
+
| `cdnAllowlist` | esm.sh、jsdelivr、unpkg | 组件(以及 Math/Mermaid)可加载资源的来源 |
|
|
258
|
+
| `allowNetwork` | `false` | 允许组件对上述来源发起 `fetch` 和 WebSocket |
|
|
259
|
+
| `maxWidgetHeight` | `2400` | iframe 最大高度(px) |
|
|
260
|
+
| `maxWidgetBytes` | `400000` | 超过此大小的组件会被拒绝 |
|
|
261
|
+
| `sendPromptMaxChars` | `4000` | 组件、按钮、表单单条消息的最大长度 |
|
|
262
|
+
| `openLinkAllowedOrigins` | `[]` | 非空时,`openLink` 只能打开这些来源 |
|
|
169
263
|
|
|
170
|
-
## 开发与验证
|
|
264
|
+
## 🛠 开发与验证
|
|
171
265
|
|
|
172
266
|
```sh
|
|
173
267
|
npm install
|
|
@@ -178,13 +272,16 @@ npm run e2e:all # 构建 → 安装到临时 DSH 目录 → mock
|
|
|
178
272
|
npm run e2e:all -- --record # 同时重新录制 docs/assets/demo.mp4 / demo.gif(需要 ffmpeg)
|
|
179
273
|
npm run e2e:all -- --spec ./deepseek-harness-intelligent-ui-<版本>.tgz # 改为对 npm pack 打出的包做 E2E
|
|
180
274
|
npm run smoke -- --spec ./deepseek-harness-intelligent-ui-<版本>.tgz # 安装冒烟测试(不需要浏览器)
|
|
275
|
+
npm run docs:art # 重新生成 docs/assets/readme/ 下的 README 动画插图
|
|
181
276
|
```
|
|
182
277
|
|
|
183
278
|
E2E 可以在 Windows、Linux、macOS 上运行。它会按平台自动查找 Chrome(可用 `CHROME_PATH` 指定),`DSH_BIN` 可指定其他 `dsh` 可执行文件。检查项见 `scripts/e2e/browser.mjs`,最近一次报告在 [`docs/e2e-report.json`](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/v0.2.1/docs/e2e-report.json)。GitHub Actions 会在三个系统上,针对每个受支持的 DSH 版本跑完全部测试。
|
|
184
279
|
|
|
185
280
|
`client/client.js` 已提交到仓库并随包发布,所以 npm、`file:` 和 git 安装都不需要构建。不要添加 `prepare` 或 `postinstall` 脚本,因为 DSH 使用的 pnpm 会拦截插件的构建脚本。
|
|
186
281
|
|
|
187
|
-
|
|
282
|
+
<details>
|
|
283
|
+
<summary><b>📦 发布流程</b>(维护者)</summary>
|
|
284
|
+
<br>
|
|
188
285
|
|
|
189
286
|
发布安全与 OIDC 配置见[维护者说明](https://github.com/dreamfarer-space/deepseek-harness-intelligent-ui/blob/main/docs/releasing.md)。
|
|
190
287
|
|
|
@@ -197,7 +294,11 @@ E2E 可以在 Windows、Linux、macOS 上运行。它会按平台自动查找 Ch
|
|
|
197
294
|
- 用 CHANGELOG 的对应小节和 tarball 创建 GitHub Release。
|
|
198
295
|
4. 本地可以先运行 `npm run release:check` 做同样的预检。
|
|
199
296
|
|
|
200
|
-
|
|
297
|
+
</details>
|
|
298
|
+
|
|
299
|
+
<details>
|
|
300
|
+
<summary><b>🤖 真实模型评测</b></summary>
|
|
301
|
+
<br>
|
|
201
302
|
|
|
202
303
|
API 测试套件覆盖 15 个提示词,检查模型路由、工具参数格式,以及部分指定组件和数据。它**不会在浏览器中执行模型生成的组件**,也不验证数据事实、视觉质量、物理正确性或交互行为。独立浏览器 E2E 使用脚本化模型回复。
|
|
203
304
|
|
|
@@ -219,6 +320,8 @@ node scripts/run-real-model-suite.mjs all
|
|
|
219
320
|
|
|
220
321
|
每次仅将本次用例写入 `docs/real-model-eval-report.json`,分类运行不混入旧结果。断言或 API 请求失败时返回退出码 1;类别错误或密钥缺失会在改写报告前退出。请勿将密钥提交到 git。
|
|
221
322
|
|
|
323
|
+
</details>
|
|
324
|
+
|
|
222
325
|
## 已知限制
|
|
223
326
|
|
|
224
327
|
- 沙箱组件、`Math` 和 `Mermaid` 需要能访问 CDN 白名单。离线时,`Math` 和 `Mermaid` 退回显示源码,`UI.three` 会报告脚本错误。
|
package/client/client.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* deepseek-harness-intelligent-ui 0.2.
|
|
1
|
+
/* deepseek-harness-intelligent-ui 0.2.3 — generated by scripts/build-client.mjs; do not edit. */
|
|
2
2
|
window.__ModuleLoader__.load({ id: "deepseek-harness-intelligent-ui", factory: (require) => {
|
|
3
3
|
var module = { exports: {} }; var exports = module.exports;
|
|
4
4
|
"use strict";var Re=Object.defineProperty;var Dn=Object.getOwnPropertyDescriptor;var qn=Object.getOwnPropertyNames;var Hn=Object.prototype.hasOwnProperty;var Bn=(e,t,n)=>t in e?Re(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var Wn=(e,t)=>{for(var n in t)Re(e,n,{get:t[n],enumerable:!0})},Vn=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of qn(t))!Hn.call(e,i)&&i!==n&&Re(e,i,{get:()=>t[i],enumerable:!(r=Dn(t,i))||r.enumerable});return e};var Jn=e=>Vn(Re({},"__esModule",{value:!0}),e);var z=(e,t,n)=>Bn(e,typeof t!="symbol"?t+"":t,n);var Zr={};Wn(Zr,{apply:()=>Yr,inject:()=>Xr,promptSession:()=>zn});module.exports=Jn(Zr);var Ie=Object.freeze({sin:[1,Math.sin],cos:[1,Math.cos],tan:[1,Math.tan],asin:[1,Math.asin],acos:[1,Math.acos],atan:[1,Math.atan],atan2:[2,Math.atan2],sinh:[1,Math.sinh],cosh:[1,Math.cosh],tanh:[1,Math.tanh],exp:[1,Math.exp],ln:[1,Math.log],log:[1,Math.log10],log10:[1,Math.log10],log2:[1,Math.log2],sqrt:[1,Math.sqrt],cbrt:[1,Math.cbrt],abs:[1,Math.abs],sign:[1,Math.sign],floor:[1,Math.floor],ceil:[1,Math.ceil],round:[1,Math.round],min:[-1,Math.min],max:[-1,Math.max],pow:[2,Math.pow],hypot:[-1,Math.hypot]}),Lt=Object.freeze({pi:Math.PI,e:Math.E,tau:2*Math.PI}),_t=(e,t)=>Object.prototype.hasOwnProperty.call(e,t)?e[t]:void 0,Ut=500;function Kn(e){let t=[],n=0;for(;n<e.length;){let r=e[n];if(r===" "||r===" "||r===`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deepseek-harness-intelligent-ui",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "DeepSeek Harness Intelligent UI: generative, interactive UI in the chat (declarative component catalog + sandboxed streaming HTML widgets), inspired by CopilotKit OpenIntelligentUI.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"./package.json": "./package.json"
|
|
29
29
|
},
|
|
30
30
|
"bin": {
|
|
31
|
-
"deepseek-harness-intelligent-ui": "
|
|
31
|
+
"deepseek-harness-intelligent-ui": "bin/cli.mjs"
|
|
32
32
|
},
|
|
33
33
|
"files": [
|
|
34
34
|
"bin",
|
|
@@ -68,7 +68,8 @@
|
|
|
68
68
|
"version": "node scripts/build-client.mjs && git add client/client.js",
|
|
69
69
|
"prepublishOnly": "node scripts/build-client.mjs && git diff --exit-code -- client/client.js && vitest run",
|
|
70
70
|
"release:check": "node scripts/ci/release-check.mjs",
|
|
71
|
-
"smoke": "node scripts/ci/smoke.mjs"
|
|
71
|
+
"smoke": "node scripts/ci/smoke.mjs",
|
|
72
|
+
"docs:art": "node scripts/docs/readme-art.mjs"
|
|
72
73
|
},
|
|
73
74
|
"peerDependencies": {
|
|
74
75
|
"@deepseek-ai/cordis": "~4.0.4 || >=4.0.5-alpha.0 <4.1.0-0",
|
package/src/compat.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
export const SUPPORTED_DSH_RANGE = '>=0.1.7-rc.1 <0.3.0-0 || >=0.2.0-0 <0.2.0 || >=0.2.1-0 <0.2.1';
|
|
13
13
|
|
|
14
14
|
/** Versions the CI compatibility matrix installs the packed plugin into. */
|
|
15
|
-
export const TESTED_DSH_VERSIONS = Object.freeze(['0.1.7-rc.2', '0.2.0-rc.1', '0.2.0-rc.2', '0.2.1-alpha.2']);
|
|
15
|
+
export const TESTED_DSH_VERSIONS = Object.freeze(['0.1.7-rc.2', '0.2.0-rc.1', '0.2.0-rc.2', '0.2.1-alpha.2', '0.2.1-alpha.4']);
|
|
16
16
|
|
|
17
17
|
/** Lowest Node.js version DSH itself requires. */
|
|
18
18
|
export const MIN_NODE_VERSION = '22.13.0';
|