a2ui-render-in-dsh 0.1.2 → 0.2.0

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/README.md CHANGED
@@ -28,6 +28,7 @@ a2ui-render-in-dsh (one npm package, a dsh bundle)
28
28
  ├─ x-card engine (A2UI command stream, data binding, action resolution)
29
29
  ├─ component catalog implementations (44 components, themed via --dsw-* tokens)
30
30
  ├─ streaming renderer (truncated-JSON repair → cards appear while the model types)
31
+ ├─ session navigator (tasks + full-chat locating, drafts, transcript rebuild)
31
32
  └─ ECharts 6 / Mermaid 11 / KaTeX (fonts inlined) / China geoJSON all bundled
32
33
  — zero external requests
33
34
  ```
@@ -36,7 +37,7 @@ a2ui-render-in-dsh (one npm package, a dsh bundle)
36
37
 
37
38
  **1. Proactive rendering, decided by the model — anchored on UI's purposes.** The tool contract frames the judgment as: would a card serve any of UI's four purposes better than prose? **Act** (the user must answer/choose/fill/adjust — render a form), **browse** (the user wants to see or scan data — statistics, rankings, distributions, trends get a chart/table/map, and uncertain data never cancels the card: chart the best known, label the period, caveat in prose), **understand** (structure or notation aids comprehension — math, code, flows, stepwise processes), or **feedback** (long multi-step work gets a progress card advanced via `a2ui_update`). None of the four → prose. Cards always **pair with prose**: the takeaway lives in 1–3 sentences of normal text, the structured content in the card, with no duplication. Grounded in HCI research (Norman's gulfs, the keyhole effect, external cognition) and verified with keyword-free prompts across all purposes plus prose negatives.
38
39
 
39
- **2. Skill-style context design (catalog on demand).** The full component catalog is NOT inlined in the tool description; it lives in a second tool, `a2ui_catalog`. Always-visible cost stays at ~220 tokens even as the catalog grew to 44 components. The model calls the catalog once before its first card in a conversation and reuses it for later cards; conversations that never draw a card pay nothing. The host validates component names and errors with a "call a2ui_catalog" hint, so the model can't silently guess wrong.
40
+ **2. Skill-style context design (catalog on demand).** The full component catalog is NOT inlined in the tool description; it lives in a second tool, `a2ui_catalog`. The always-visible tool description stays at ~350 tokens for 44 components (the on-demand catalog is ~2.5k, paid once per card-using conversation). The model calls the catalog once before its first card in a conversation and reuses it for later cards; conversations that never draw a card pay nothing. The host validates component names and errors with a "call a2ui_catalog" hint, so the model can't silently guess wrong.
40
41
 
41
42
  **3. Non-blocking answers over the native message path.** Submissions need no custom server channel: the client sends the submission through dsh's own `session.prompt` RPC as an ordinary user message. Messages are **plain language** (button label + chosen values, multi-line for forms) — readable for humans, parseable for the model, no raw JSON in the conversation:
42
43
 
@@ -56,10 +57,15 @@ Tracks: Backend, Data Analysis
56
57
 
57
58
  **8. Answers beyond text.** `Upload` (photos) and `Signature` (hand-drawn canvas) send images back through dsh's native prompt channel as real image parts — the model sees the picture, not a placeholder. `Suggestions` renders tappable follow-up chips that send themselves as the next user message. Voice recording is deliberately excluded: dsh's prompt channel carries text + images only.
58
59
 
60
+ **9. State that outlives the browser.** Drafts auto-save as you type (reload-safe); submissions lock cards with persisted records; and when even localStorage is gone, the client reconstructs submitted-state from the session transcript itself — render calls carry ids, submission messages match back by button label, errored calls excluded. The session navigator surfaces all of it: to-submit/submitted task groups and a full, clickable map of every user message.
61
+
59
62
  ## Highlights
60
63
 
61
64
  - 🎯 **Adaptive**: the model chooses text vs. card; verified reliable in both directions
62
- - 🪶 **Context-friendly**: skill-style catalog design, ~220 tokens always-visible for 44 components
65
+ - 🪶 **Context-friendly**: skill-style catalog design, ~350 tokens always-visible for 44 components
66
+ - ✅ **Form validation**: `required: true` on any input blocks submission and highlights what's missing
67
+ - 🧭 **Session navigator**: a right-edge drawer with Tasks (to-submit / submitted groups, fill counts, previews, dismissable) and All (every user message in full, click-to-locate with auto "load earlier", live-refreshing); drafts survive reloads and submitted-state survives cache clears (rebuilt from the transcript)
68
+ - 🗜️ **Upload compression**: photos are downscaled client-side (≤1568px, JPEG) before flowing into the prompt
63
69
  - 💬 **Elegant answers**: plain-language submissions, not raw JSON strings; photos & signatures return as real images
64
70
  - 🔒 **Submit-once locking**: forms can't double-submit, records persist, a "refill" button reopens them; query buttons unaffected
65
71
  - ⚡ **Streaming render**: cards appear progressively while the model is still writing the JSON
@@ -97,7 +103,7 @@ Tracks: Backend, Data Analysis
97
103
  | `Card` | `children, title?` | Bordered group |
98
104
  | `List` | `children, direction?` | List container |
99
105
  | `Divider` | — | Separator |
100
- | `Text` | `text, variant?: h1\|h2\|h3\|body\|caption\|strong` | Text |
106
+ | `Text` | `text, variant?: h1\|h2\|h3\|body\|caption\|strong` | Text; fenced ``` content auto-upgrades to a formatted code block; inline `` `code` `` renders as code chips |
101
107
  | `Markdown` | `text` | **Rich long-form**: headings, bold/italic, links, lists, quotes, fenced code, `$...$` math; copy-source button |
102
108
  | `Image` | `url, alt?, width?, height?` | Images (incl. GIF), built-in fullscreen zoom |
103
109
  | `Tag` | `text, color?: blue\|green\|red\|orange\|gray` | Tag/badge |
@@ -110,7 +116,7 @@ Tracks: Backend, Data Analysis
110
116
  | `Anim` | `frames, interval?, height?, autoplay?, labels?` | **Algorithm animation**: bars, grid/matrix, and graph/tree (BFS/DFS, auto circle layout) forms auto-detected; auto-plays once per card per tab, ↻ replay / pause / step / reset / progress / legend |
111
117
  | `Button` | `label, variant?, submit?, action: {event: {name, context?}}` | Sends the submission; `submit` explicitly controls card locking |
112
118
  | `MultipleChoice` | `options, bind, maxAllowedSelections?, disabled?` | Flat multi/single select (`maxAllowedSelections: 1` = single), per-option disable |
113
- | `Select` | `options, bind, label?, placeholder?, multiple?, maxAllowedSelections?, disabled?` | **Dropdown**: single stores a value, multi stores an array; option descriptions/disabling |
119
+ | `Select` | `options, bind, label?, placeholder?, multiple?, maxAllowedSelections?, disabled?` | **Dropdown**: single stores a value, multi stores an array; auto search box on long lists |
114
120
  | `CheckBox` | `label, bind, disabled?` | Boolean toggle |
115
121
  | `Slider` | `bind, label?, min?, max?, step?, unit?` | Numeric slider; pairs with Chart `params` for live parameter exploration |
116
122
  | `Rate` | `bind, label?, max?` | Star rating |
@@ -122,15 +128,15 @@ Tracks: Backend, Data Analysis
122
128
  | `Steps` | `items` | Step list (done/current/pending) |
123
129
  | `Progress` | `value, max?, label?` | Progress bar |
124
130
  | `Timeline` | `items` | Timeline (history / event review) |
125
- | `CodeBlock` | `code, language?, title?` | Code with line numbers, light highlighting, copy button |
131
+ | `CodeBlock` | `code, language?, title?` | Code with line numbers, light highlighting, copy button — quiz stems included (never inline code in Text) |
126
132
  | `Icon` | `name, size?, color?` | 32 built-in stroke icons |
127
133
  | `Audio` | `url, title?` | Audio player |
128
134
  | `Flashcard` | `front, back` | Tap-to-flip card (vocabulary / recall) |
129
135
  | `Countdown` | `to?/seconds?, label?` | Live countdown |
130
136
  | `TextField` | `label?, placeholder?, multiline?, bind, disabled?` | Text input |
131
137
  | `Wizard` | `steps, children, submitLabel?` | **Multi-step form**: one pane per step, prev/next + progress built in, final submit sends all collected fields |
132
- | `Calendar` | `bind, label?, min?, max?` | Month-view date picker with range limits |
133
- | `RankList` | `items, bind, label?` | Reorder options by priority; submits the ordered list |
138
+ | `Calendar` | `bind, label?, min?, max?, range?` | Month-view date picker; `range: true` picks a start + end date |
139
+ | `RankList` | `items, bind, label?` | Drag (or tap ↑↓) to reorder by priority; submits the ordered list |
134
140
  | `EditableTable` | `columns, rows, bind, label?` | User edits cells inline; the whole grid submits |
135
141
  | `Upload` | `bind?, label?, max?` | Image picker — chosen photos are sent back to the model as **real images** |
136
142
  | `Signature` | `label?` | Handwritten signature pad; the drawing returns as an image |
@@ -138,7 +144,7 @@ Tracks: Backend, Data Analysis
138
144
 
139
145
  **Inline math**: every text position (Text, option labels, table cells, steps, flashcards, animation captions) may embed KaTeX with `$...$` — math-quiz OPTIONS can be formulas. **Reactive bindings**: inputs write the data model and every `{"path"}` binding updates live — slider→curve (Chart `params`), choice→follow-up (When), input→computed result (Calc→Stat), switcher→dataset (Tabs / Table dictionary binding).
140
146
 
141
- Common to inputs: **preselect** by seeding `dataModel` at the bind path; **disable** via component-level `disabled: true` or per-option `disabled`. Data binding: `bind` is a write path WITHOUT a leading slash; display props read live values with `{"path": "/x"}` (WITH a slash).
147
+ Common to inputs: **preselect** by seeding `dataModel` at the bind path; **disable** via component-level `disabled: true` or per-option `disabled`; **require** via `required: true` (submission blocks and highlights until filled). `a2ui_update` dataModel changes re-sync bound inputs in place. Data binding: `bind` is a write path WITHOUT a leading slash; display props read live values with `{"path": "/x"}` (WITH a slash).
142
148
 
143
149
  ## Installation
144
150
 
@@ -147,6 +153,8 @@ Common to inputs: **preselect** by seeding `dataModel` at the bind path; **disab
147
153
  | Requirement | Notes |
148
154
  |---|---|
149
155
  | dsh | `@deepseek-ai/dsh` ≥ 0.1.1-rc.1 with an initialized web profile (run `dsh web` once before installing) |
156
+
157
+ Development: `npm test` runs the jsdom interaction suite (host validation + full component/interaction coverage, ~70 assertions).
150
158
  | Node.js | ≥ 20 (with npm) |
151
159
 
152
160
  ### Option A · From npm (recommended)
package/README.zh.md CHANGED
@@ -27,6 +27,7 @@ a2ui-render-in-dsh (一个 npm 包,dsh bundle)
27
27
  ├─ x-card 引擎(A2UI 命令流、数据绑定、action 解析)
28
28
  ├─ 组件目录实现(44 个组件,跟随 --dsw-* 主题令牌)
29
29
  ├─ 流式渲染器(截断 JSON 修复 → 模型边写卡片边出现)
30
+ ├─ 会话导航(任务分组 + 全会话定位 + 草稿 + 会话记录重建)
30
31
  └─ ECharts 6 / Mermaid 11 / KaTeX(字体内联)/ 中国省份 geoJSON
31
32
  全部打入 bundle,零外部请求
32
33
  ```
@@ -35,7 +36,7 @@ a2ui-render-in-dsh (一个 npm 包,dsh bundle)
35
36
 
36
37
  **1. 主动式渲染,由模型判断——锚定 UI 的目的。** 工具契约把判断框定为:卡片能否在 UI 的四个目的之一上胜过纯文本?**方便操作**(用户要回答/选择/填写/调节——渲染表单)、**方便浏览**(用户想看/扫数据——统计、排名、分布、趋势出图表/表格/地图,数据不确定也不取消卡片:画已知最好的数据、标注时间口径、正文说明局限)、**增强理解**(结构或记号帮助理解——数学、代码、流程、分步过程)、**状态反馈**(长/多步任务先出进度卡,`a2ui_update` 原地推进)。四者都不沾 → 纯文本。卡片始终**与文案搭配**:结论/看点用 1–3 句正文说,结构化内容进卡片,两边不重复。判断框架有 HCI 理论依据(Norman 双鸿沟、钥匙孔效应、外部认知),并用无关键词的自然语言提示词对各目的 + 纯文本反例实测。
37
38
 
38
- **2. skill 式上下文设计(目录按需加载)。** 完整组件目录不内联在工具描述里,而是放进 `a2ui_catalog` 工具:组件扩到 44 个,常驻上下文仍稳定在 ~220 token;模型首次画卡前调用一次目录,同会话后续卡片直接复用;不画卡的会话零目录开销。服务端校验未知组件名并报错引导查目录,防止模型跳过目录瞎猜。
39
+ **2. skill 式上下文设计(目录按需加载)。** 完整组件目录不内联在工具描述里,而是放进 `a2ui_catalog` 工具:44 个组件的常驻工具描述约 ~350 token(按需目录约 2.5k,每个用卡会话只付一次);模型首次画卡前调用一次目录,同会话后续卡片直接复用;不画卡的会话零目录开销。服务端校验未知组件名并报错引导查目录,防止模型跳过目录瞎猜。
39
40
 
40
41
  **3. 非阻塞回传,复用原生消息通路。** 卡片提交不需要自定义 server 通道:客户端通过 dsh 自身的 `session.prompt` RPC 把提交内容作为普通用户消息发回会话。消息是**自然语言**(按钮文案 + 所选内容,多字段换行列出),对人可读、对模型可解析,不污染对话观感:
41
42
 
@@ -55,10 +56,15 @@ a2ui-render-in-dsh (一个 npm 包,dsh bundle)
55
56
 
56
57
  **8. 回答不止于文字。** `Upload`(拍照/截图)和 `Signature`(手写画板)走 dsh 原生消息通路把**真实图片**发回给模型——模型看到的是图,不是占位符。`Suggestions` 渲染可点的追问 chips,点一下即作为下一条用户消息发出。录音回传刻意不做:dsh 的 prompt 通道只支持文本 + 图片。
57
58
 
59
+ **9. 比浏览器更长寿的状态。** 草稿边填边存(刷新不丢);提交锁卡并持久化记录;即使 localStorage 全清,客户端也能从**会话记录本身**重建已提交状态——渲染调用带 id、提交消息按按钮文案回配、失败调用被排除。会话导航把这一切摆到明面:待提交/已提交任务分组 + 每条用户消息的可点击地图。
60
+
58
61
  ## 亮点
59
62
 
60
63
  - 🎯 **自适应**:模型自行判断"文本还是卡片",双向实测可靠
61
- - 🪶 **上下文友好**:skill 式目录设计,44 个组件常驻开销仅 ~220 token
64
+ - 🪶 **上下文友好**:skill 式目录设计,44 个组件常驻开销约 ~350 token
65
+ - ✅ **表单校验**:任意输入组件可设 `required: true`——提交被拦截并高亮缺失项
66
+ - 🧭 **会话导航**:右缘抽屉——「任务」页签分组待提交/已提交任务(已填计数、内容预览、可标记无需填写),「全部」页签完整列出每条用户消息并点击定位(自动加载更早、实时同步);草稿刷新不丢,已提交状态清缓存后仍可从会话记录重建
67
+ - 🗜️ **上传压缩**:照片在客户端先压到 ≤1568px JPEG 再进消息,手机原图不再撑爆对话
62
68
  - 💬 **优雅回传**:自然语言提交消息,非 JSON 裸串;照片、签名以真实图片回传
63
69
  - 🔒 **提交即锁定**:表单防重复提交,记录持久化,"重新填写"可解锁;查询按钮不受影响
64
70
  - ⚡ **流式渲染**:模型边写 JSON,卡片边逐块出现
@@ -96,7 +102,7 @@ a2ui-render-in-dsh (一个 npm 包,dsh bundle)
96
102
  | `Card` | `children, title?` | 带边框分组 |
97
103
  | `List` | `children, direction?` | 列表容器 |
98
104
  | `Divider` | — | 分隔线 |
99
- | `Text` | `text, variant?: h1\|h2\|h3\|body\|caption\|strong` | 文本 |
105
+ | `Text` | `text, variant?: h1\|h2\|h3\|body\|caption\|strong` | 文本;含 ``` 围栏时自动升级为格式化代码块;行内 `` `code` `` 渲染为代码片 |
100
106
  | `Markdown` | `text` | **富文本长文**:标题、加粗/斜体、链接、列表、引用、代码块、`$...$` 公式;带复制原文按钮 |
101
107
  | `Image` | `url, alt?, width?, height?` | 图片(含 GIF),自带全屏放大 |
102
108
  | `Tag` | `text, color?: blue\|green\|red\|orange\|gray` | 标签 |
@@ -109,7 +115,7 @@ a2ui-render-in-dsh (一个 npm 包,dsh bundle)
109
115
  | `Anim` | `frames, interval?, height?, autoplay?, labels?` | **算法动画**:数组/柱状、网格/矩阵、图/树(BFS/DFS,自动圆形布局)三形态自动识别;每卡每页签只自动播一遍,↻ 重播/暂停/单步/重置/进度条/图例 |
110
116
  | `Button` | `label, variant?, submit?, action: {event: {name, context?}}` | 触发回传;`submit` 显式控制是否锁卡 |
111
117
  | `MultipleChoice` | `options, bind, maxAllowedSelections?, disabled?` | 平铺多选/单选(`maxAllowedSelections: 1` 单选),选项级禁用 |
112
- | `Select` | `options, bind, label?, placeholder?, multiple?, maxAllowedSelections?, disabled?` | **下拉选择**:单选存值、多选存数组,选项描述/禁用 |
118
+ | `Select` | `options, bind, label?, placeholder?, multiple?, maxAllowedSelections?, disabled?` | **下拉选择**:单选存值、多选存数组;长列表自动带搜索框 |
113
119
  | `CheckBox` | `label, bind, disabled?` | 布尔勾选 |
114
120
  | `Slider` | `bind, label?, min?, max?, step?, unit?` | 数值滑杆;配合 Chart `params` 做参数探索联动 |
115
121
  | `Rate` | `bind, label?, max?` | 星级评分 |
@@ -121,15 +127,15 @@ a2ui-render-in-dsh (一个 npm 包,dsh bundle)
121
127
  | `Steps` | `items` | 步骤条(done/current/pending) |
122
128
  | `Progress` | `value, max?, label?` | 进度条 |
123
129
  | `Timeline` | `items` | 时间轴(历程/事件回顾) |
124
- | `CodeBlock` | `code, language?, title?` | 代码块:行号 + 轻量高亮 + 复制按钮 |
130
+ | `CodeBlock` | `code, language?, title?` | 代码块:行号 + 轻量高亮 + 复制——读代码题的题干代码也走这里(不许塞进 Text) |
125
131
  | `Icon` | `name, size?, color?` | 内置 32 个常用线条图标 |
126
132
  | `Audio` | `url, title?` | 音频播放器 |
127
133
  | `Flashcard` | `front, back` | 点击翻面闪卡(背单词/问答记忆) |
128
134
  | `Countdown` | `to?/seconds?, label?` | 实时倒计时 |
129
135
  | `TextField` | `label?, placeholder?, multiline?, bind, disabled?` | 文本输入 |
130
136
  | `Wizard` | `steps, children, submitLabel?` | **分步表单**:每步一个面板,内置上一步/下一步 + 进度,最后一步提交全部字段 |
131
- | `Calendar` | `bind, label?, min?, max?` | 月视图日期选择,支持范围限制 |
132
- | `RankList` | `items, bind, label?` | 用户按优先级排序选项,提交排好的列表 |
137
+ | `Calendar` | `bind, label?, min?, max?, range?` | 月视图日期选择;`range: true` 选起止两天 |
138
+ | `RankList` | `items, bind, label?` | 拖拽(或点 ↑↓)按优先级排序,提交排好的列表 |
133
139
  | `EditableTable` | `columns, rows, bind, label?` | 用户直接改单元格,整表提交 |
134
140
  | `Upload` | `bind?, label?, max?` | 图片选择器——所选照片以**真实图片**回传给模型 |
135
141
  | `Signature` | `label?` | 手写签名画板,笔迹以图片回传 |
@@ -137,7 +143,7 @@ a2ui-render-in-dsh (一个 npm 包,dsh bundle)
137
143
 
138
144
  **内联公式**:所有文本位置(Text、选项、表格单元格、步骤、闪卡、动画解说)支持 `$...$` 内嵌 KaTeX——数学选择题的选项可以直接是公式。**响应式联动**:输入组件写数据模型,所有 `{"path"}` 绑定即时更新——滑杆→曲线(Chart `params`)、选择→追问(When)、输入→计算结果(Calc→Stat)、切换→换表(Tabs/Table 字典绑定)。
139
145
 
140
- 输入组件通用:**预选中**在 `dataModel` 给 bind 路径设初值;**禁用**用组件级 `disabled: true` 或选项级 `disabled`。数据绑定:`bind` 为不带前导斜杠的写入路径;展示属性用 `{"path": "/x"}`(带斜杠)读实时值。
146
+ 输入组件通用:**预选中**在 `dataModel` 给 bind 路径设初值;**禁用**用组件级 `disabled: true` 或选项级 `disabled`;**必填**用 `required: true`(未填完提交被拦截并高亮)。`a2ui_update` 改写 dataModel 后,绑定的输入组件会原地同步。数据绑定:`bind` 为不带前导斜杠的写入路径;展示属性用 `{"path": "/x"}`(带斜杠)读实时值。
141
147
 
142
148
  ## 安装
143
149
 
@@ -146,6 +152,8 @@ a2ui-render-in-dsh (一个 npm 包,dsh bundle)
146
152
  | 要求 | 说明 |
147
153
  |---|---|
148
154
  | dsh | `@deepseek-ai/dsh` ≥ 0.1.1-rc.1,且 web profile 已初始化(装插件前先运行过一次 `dsh web`) |
155
+
156
+ 开发:`npm test` 运行 jsdom 交互测试套件(宿主校验 + 组件/交互全覆盖,约 70 条断言)。
149
157
  | Node.js | ≥ 20(含 npm) |
150
158
 
151
159
  ### 方式 A · npm 安装(推荐)