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 +16 -8
- package/README.zh.md +16 -8
- package/lib/client.js +458 -395
- package/lib/index.js +24 -16
- package/package.json +6 -4
package/lib/index.js
CHANGED
|
@@ -5919,7 +5919,7 @@ var KNOWN_COMPONENTS = /* @__PURE__ */ new Set([
|
|
|
5919
5919
|
]);
|
|
5920
5920
|
var CATALOG_DOC = `# a2ui_render authoring guide
|
|
5921
5921
|
|
|
5922
|
-
Forms: each question = one field; options -> MultipleChoice/Select; free answers -> TextField (multiline for long); offering suggestions? ALSO add a TextField for a custom answer; several questions = ONE card, ONE submit Button labeled with the action ("\u63D0\u4EA4", "\u786E\u8BA4\u5EFA\u6863"). Multiple items or several charts = ONE call with a Grid. Display-only cards (no Button) are fine.
|
|
5922
|
+
Forms: each question = one field; options -> MultipleChoice/Select; free answers -> TextField (multiline for long); offering suggestions? ALSO add a TextField for a custom answer; several questions = ONE card, ONE submit Button labeled with the action ("\u63D0\u4EA4", "\u786E\u8BA4\u5EFA\u6863"). Multiple items or several charts = ONE call with a Grid. Display-only cards (no Button) are fine. Pair every card with 1-3 sentences of prose (takeaway/caveats) \u2014 never restate its data in text.
|
|
5923
5923
|
|
|
5924
5924
|
## Components (adjacency list; MUST include id "root"; only these names render)
|
|
5925
5925
|
Layout:
|
|
@@ -5928,20 +5928,20 @@ Layout:
|
|
|
5928
5928
|
- Card {children, title?} \xB7 List {children, direction?} \xB7 Divider {}
|
|
5929
5929
|
- Tabs {tabs: ["\u540D"\u2026], children, bind?} \u2014 one child per tab; dataset switching / grouping
|
|
5930
5930
|
- When {value: {"path": "/x"}, equals?, includes?, notEmpty?, children} \u2014 children render only when the bound value matches; use for follow-up fields (e.g. reason box when choice includes "\u5176\u4ED6")
|
|
5931
|
-
- Wizard {steps: ["\u6B65\u9AA4\u540D"\u2026], children, submitLabel?} \u2014 multi-step form: one child (
|
|
5931
|
+
- Wizard {steps: ["\u6B65\u9AA4\u540D"\u2026], children, submitLabel?} \u2014 multi-step form: one child (Column of fields) per step, built-in prev/next/progress, last step submits ALL fields; use for 5+ questions
|
|
5932
5932
|
Content (Chart/Mermaid/Image auto-get fullscreen zoom; don't oversize):
|
|
5933
5933
|
- Text {text, variant?: "h1"|"h2"|"h3"|"body"|"caption"|"strong"}
|
|
5934
|
-
- Markdown {text} \u2014 rich long-form
|
|
5934
|
+
- Markdown {text} \u2014 rich long-form (headings, bold/italic, links, lists, quotes, fenced code, $...$ math); use for any multi-paragraph text instead of stacked Texts
|
|
5935
5935
|
- Image {url, alt?, width?, height?} \xB7 Tag {text, color?: "blue"|"green"|"red"|"orange"|"gray"}
|
|
5936
5936
|
- Icon {name, size?, color?} \u2014 check x plus minus warning info star heart calendar clock location user search settings mail phone home file link download upload play music image cart tag gift trophy fire bolt sun moon cloud thumbs-up
|
|
5937
5937
|
- Math {tex, block?} \u2014 KaTeX. ALL math notation goes here, matrices included: never raw arrays like [[2,1],[0,3]] in Text \u2014 write {"tex": "\\\\begin{pmatrix}2&1\\\\\\\\0&3\\\\end{pmatrix}", "block": true} (row sep \\\\\\\\). Equation above its Anim when animating.
|
|
5938
5938
|
- Mermaid {code, caption?} \u2014 flowchart ("graph TD; A[\u5F00\u59CB]-->B{\u5224\u65AD}"), mindmap, sequenceDiagram, gantt, pie, stateDiagram
|
|
5939
5939
|
- Chart {option, height?, functions?, params?, xMin?, xMax?, yClip?} \u2014 ECharts (viewers get a PNG-download button). Data mode: standard option verbatim. Function mode: functions=[{"expr":"tan(x)","name"?}], xMin/xMax (\xB110), yClip (10); sampled automatically, asymptotes break \u2014 NEVER hand-enumerate curve points. Ops: + - * / ^ %, sin cos tan cot sec csc asin acos atan sinh cosh tanh sqrt cbrt abs exp ln log2 log10 floor ceil round sign min max pow atan2, pi/e, x. params: {"mu":{"path":"/mu"}} injects bound values as constants \u2014 pair with Slider for live curves.
|
|
5940
|
-
- Table {columns, rows, caption?, sortable?, filter?, pageSize?} \u2014 any 2+ item
|
|
5940
|
+
- Table {columns, rows, caption?, sortable?, filter?, pageSize?} \u2014 for any 2+ item comparison; sort/filter/pagination/copy/CSV are automatic. Dict binding: rows={"source":{"k1":[[\u2026]],\u2026},"pick":{"path":"/k"}} + a Select/Tabs on that path switches datasets live.
|
|
5941
5941
|
- Stat {label, value, unit?, trend?, hint?} \u2014 KPI tile ("+12%" green / "-3%" red); several in a Grid
|
|
5942
5942
|
- Steps {items: [{title, description?, status?: "done"|"current"|"pending"}]} \u2014 linear procedures; Mermaid flowchart only when it BRANCHES
|
|
5943
5943
|
- Progress {value, max?, label?} \xB7 Timeline {items: [{time?, title, description?}]} (past events; Steps = to-dos)
|
|
5944
|
-
- CodeBlock {code, language?, title?} \u2014
|
|
5944
|
+
- CodeBlock {code, language?, title?} \u2014 ALWAYS for code, including quiz/form stems: compose Text(\u9898\u5E72) + CodeBlock(\u4EE3\u7801) + inputs; NEVER inline code in a Text prop
|
|
5945
5945
|
- Video {url, poster?\u2026} \xB7 Audio {url, title?} \xB7 Flashcard {front, back} \xB7 Countdown {to?: "2026-09-01 10:00", seconds?, label?}
|
|
5946
5946
|
- Map {data: [{name: "\u5E7F\u4E1C", value: 100}\u2026], title?, unit?, height?} \u2014 China province choropleth (regional sales/distribution); province names in Chinese
|
|
5947
5947
|
- ImageCompare {before, after} \u2014 drag-divider image comparison (before/after, A/B)
|
|
@@ -5955,15 +5955,15 @@ Interaction:
|
|
|
5955
5955
|
- Select {options, bind, label?, placeholder?, multiple?, maxAllowedSelections?, disabled?} \u2014 dropdown; single stores value, multiple stores array
|
|
5956
5956
|
- Rate {bind, label?, max?, disabled?} \u2014 stars 1..max (5)
|
|
5957
5957
|
- Slider {bind, label?, min?, max?, step?, unit?, disabled?} \u2014 numbers in a range; parameter exploration with Chart params
|
|
5958
|
-
- Calc {expr, inputs: {name: {"path": "/x"}\u2026}, out, digits?} \u2014 invisible derived number written at out; chainable
|
|
5958
|
+
- Calc {expr, inputs: {name: {"path": "/x"}\u2026}, out, digits?} \u2014 invisible derived number written at out; chainable. digits rounds display only \u2014 omit on intermediates to keep precision
|
|
5959
5959
|
- CheckBox {label, bind, disabled?} \xB7 TextField {label?, placeholder?, multiline?, kind?: "text"|"number"|"date"|"time", bind, disabled?}
|
|
5960
|
-
- Upload {bind?, label?, max?} \u2014 image picker; chosen images are SENT TO YOU with the submission (
|
|
5961
|
-
- Calendar {bind, label?, min?, max?} \u2014 month-view date picker
|
|
5960
|
+
- Upload {bind?, label?, max?} \u2014 image picker; chosen images are SENT TO YOU with the submission (use whenever seeing an image helps)
|
|
5961
|
+
- Calendar {bind, label?, min?, max?, range?} \u2014 month-view date picker; range: true picks start+end (value ["\u8D77","\u6B62"])
|
|
5962
5962
|
- RankList {items: ["\u9009\u9879"\u2026], bind, label?} \u2014 user reorders by priority; submits the ordered list
|
|
5963
5963
|
- Signature {label?} \u2014 handwritten signature pad; the drawing is sent to you as an image
|
|
5964
5964
|
- EditableTable {columns, rows, bind, label?} \u2014 user edits cells, the whole grid submits at bind
|
|
5965
|
-
- Suggestions {items: ["\u8FFD\u95EE1"
|
|
5966
|
-
Preselect by seeding dataModel at bind paths; disable via disabled on a control or
|
|
5965
|
+
- Suggestions {items: ["\u8FFD\u95EE1"\u2026]} \u2014 tappable follow-ups; a tap sends that question as the user's message. ADD 2-4 to display-only cards
|
|
5966
|
+
Preselect by seeding dataModel at bind paths; disable via disabled on a control or option. Any input takes required: true \u2014 submit is blocked (field highlighted) until filled; give required fields labels.
|
|
5967
5967
|
|
|
5968
5968
|
## Reactivity
|
|
5969
5969
|
Bindings are live: inputs write bind paths, every {"path"} display binding updates instantly.
|
|
@@ -5974,7 +5974,7 @@ Bindings are live: inputs write bind paths, every {"path"} display binding updat
|
|
|
5974
5974
|
Seed every bound path in dataModel.
|
|
5975
5975
|
|
|
5976
5976
|
## Scenario map
|
|
5977
|
-
Input collection -> form (TextField/kind date|time|number, MultipleChoice 2-7 options, Select for long lists, CheckBox, Rate). Decisions -> Grid Cards + Table; lone confirm Button gets submit:true. Data -> Chart (trend/rank/share) + Stat tiles + Table. Learning -> MultipleChoice quizzes (options may be formulas), Math, Chart functions (+Slider), Anim, mindmap, Flashcard
|
|
5977
|
+
Input collection -> form (TextField/kind date|time|number, MultipleChoice 2-7 options, Select for long lists, CheckBox, Rate). Decisions -> Grid Cards + Table; lone confirm Button gets submit:true. Data -> Chart (trend/rank/share) + Stat tiles + Table; regional -> Map. Learning -> MultipleChoice quizzes (options may be formulas), Math, Chart functions (+Slider), Anim, mindmap, Flashcard; \u8BFB\u4EE3\u7801\u9898 = Text(\u9898\u5E72) + CodeBlock(\u4EE3\u7801) + TextField. Procedures -> Steps (Timeline for history, Progress for completion, gantt/Table for schedules). Entertainment -> Grid recommendation cards, Rate, polls via MultipleChoice.
|
|
5978
5978
|
|
|
5979
5979
|
## Inline math
|
|
5980
5980
|
Any text prop (Text, option labels/descriptions, Table cells, Steps, Flashcard, Anim notes) embeds formulas with $...$, e.g. option {"label": "$\\\\frac{x^2}{2}+C$"}. Math component = display equations; $...$ = math inside sentences/choices. In math quizzes, option labels with fractions/roots/integrals/exponents SHOULD be $...$ formulas (e.g. {"label": "$3x^2$"}), not Unicode approximations.
|
|
@@ -5983,15 +5983,15 @@ Any text prop (Text, option labels/descriptions, Table cells, Steps, Flashcard,
|
|
|
5983
5983
|
"bind" = write path WITHOUT leading slash ("answer", "form/name"). Display reads use {"path": "/answer"} (WITH slash). Avoid literal string props starting with "/".
|
|
5984
5984
|
|
|
5985
5985
|
## Submission
|
|
5986
|
-
Button click sends a plain-language user message: button label + chosen values ("\u63D0\u4EA4\u7B54\u6848\uFF1AB\u3001C"; multi-line for forms); MultipleChoice arrives as option LABELS. action.event.context optional (touched fields auto-included); entries may be literals or {"path": "/x", "label": "\u540D"}. Locking (submitMode "once", default): cards WITH inputs lock after submit and stay recorded; input-less cards' buttons are query buttons, always clickable; per-Button submit: true|false overrides; "multi" never locks.
|
|
5986
|
+
Button click sends a plain-language user message: button label + chosen values ("\u63D0\u4EA4\u7B54\u6848\uFF1AB\u3001C"; multi-line for forms); MultipleChoice arrives as option LABELS. action.event.context optional (touched fields auto-included); entries may be literals or {"path": "/x", "label": "\u540D"}. Locking (submitMode "once", default): cards WITH inputs lock after submit and stay recorded; input-less cards' buttons are query buttons, always clickable; per-Button submit: true|false overrides; "multi" never locks. A plain typed reply also counts as the answer. Uploads/signatures arrive attached to the submission. \u91CD\u65B0\u586B\u5199 unlocks a locked card; corrections arrive prefixed \uFF08\u4FEE\u6B63\uFF09.
|
|
5987
5987
|
|
|
5988
5988
|
## Updating a rendered card
|
|
5989
|
-
a2ui_render returns a surfaceId. Call a2ui_update {surfaceId, components?, dataModel?} to change that card IN PLACE \u2014 replace/add components by id, overwrite dataModel keys. Use for long-task progress
|
|
5989
|
+
a2ui_render returns a surfaceId. Call a2ui_update {surfaceId, components?, dataModel?} to change that card IN PLACE \u2014 replace/add components by id, overwrite dataModel keys. Use for long-task progress, corrections, appended results \u2014 never render a duplicate card. Cards stream progressively; don't shrink them.
|
|
5990
5990
|
|
|
5991
5991
|
## Example (quiz)
|
|
5992
5992
|
components=[{"id":"root","component":"Column","children":["q","opts","btn"]},{"id":"q","component":"Text","variant":"h3","text":"\u2026\u9898\u76EE\u2026"},{"id":"opts","component":"MultipleChoice","bind":"answer","maxAllowedSelections":1,"options":[{"label":"A\u2026","value":"A"},{"label":"B\u2026","value":"B"}]},{"id":"btn","component":"Button","label":"\u63D0\u4EA4\u7B54\u6848","variant":"primary","action":{"event":{"name":"submit"}}}]
|
|
5993
5993
|
dataModel={"answer":[]}`;
|
|
5994
|
-
var RENDER_DESCRIPTION = "Render a UI card (A2UI) inline in the chat. Judge EVERY reply
|
|
5994
|
+
var RENDER_DESCRIPTION = "Render a UI card (A2UI) inline in the chat. Judge EVERY reply from user intent (they never say \u5361\u7247/\u56FE\u8868): would a card serve any of UI's FOUR purposes better than prose? ACT \u64CD\u4F5C: user must answer/choose/fill/adjust/confirm -> form card. BROWSE \u6D4F\u89C8: user wants to see/scan data or items \u2014 statistics, rankings, distributions, trends, comparisons, multi-item recommendations -> chart/table/map/Grid of item cards; \u770B/\u67E5/\u5BF9\u6BD4/\u63A8\u8350\u51E0\u4E2A IS a card ask, and dated or approximate data never cancels the card \u2014 chart the best known, label the period, caveat in prose. UNDERSTAND \u7406\u89E3: structure, notation or motion aids comprehension \u2014 math, code, flows, what-if exploration, and time-unfolding processes (algorithms, simulations) -> step animation. FEEDBACK \u53CD\u9988: before multi-step work (3+ tool steps), render a Progress/Steps card, a2ui_update it as steps complete, final results into the card (not markdown tables in prose). None of the four (opinions, narration, short answers, translations, chat) -> prose. Compose freely \u2014 one card can mix form/chart/table/formula parts. Cards PAIR with prose: 1-3 sentences of takeaway as normal text, structured content in the card, no duplication. Call a2ui_catalog BEFORE your first render in a conversation \u2014 never guess component names. After an interactive card, end your turn; the submission arrives as a plain-language user message.";
|
|
5995
5995
|
var CATALOG_DESCRIPTION = "Returns the full component catalog and authoring rules for a2ui_render. Call ONCE before your first render in a conversation; the result stays in context \u2014 call again only if it is no longer visible.";
|
|
5996
5996
|
function apply(ctx) {
|
|
5997
5997
|
ctx.tools.register(defineTool({
|
|
@@ -6045,13 +6045,21 @@ function apply(ctx) {
|
|
|
6045
6045
|
}
|
|
6046
6046
|
const byId = new Map(components.filter((n) => n !== null && typeof n === "object" && n.id !== void 0).map((n) => [n.id, n]));
|
|
6047
6047
|
const reachable = /* @__PURE__ */ new Set();
|
|
6048
|
+
const missing = /* @__PURE__ */ new Set();
|
|
6048
6049
|
const queue = ["root"];
|
|
6049
6050
|
while (queue.length > 0) {
|
|
6050
6051
|
const id = queue.pop();
|
|
6051
6052
|
if (reachable.has(id)) continue;
|
|
6052
6053
|
reachable.add(id);
|
|
6053
6054
|
const node = byId.get(id);
|
|
6054
|
-
|
|
6055
|
+
if (node === void 0) {
|
|
6056
|
+
missing.add(id);
|
|
6057
|
+
continue;
|
|
6058
|
+
}
|
|
6059
|
+
for (const child of Array.isArray(node.children) ? node.children : []) queue.push(child);
|
|
6060
|
+
}
|
|
6061
|
+
if (missing.size > 0) {
|
|
6062
|
+
throw new Error(`a2ui_render: children reference undefined component id(s) ${[...missing].map((id) => `"${id}"`).join(", ")} \u2014 define them or fix the reference.`);
|
|
6055
6063
|
}
|
|
6056
6064
|
const orphans = [...byId.keys()].filter((id) => !reachable.has(id));
|
|
6057
6065
|
if (orphans.length > 0) {
|
|
@@ -6070,7 +6078,7 @@ function apply(ctx) {
|
|
|
6070
6078
|
}));
|
|
6071
6079
|
ctx.tools.register(defineTool({
|
|
6072
6080
|
name: "a2ui_update",
|
|
6073
|
-
description: "Update a card
|
|
6081
|
+
description: "Update a rendered card IN PLACE by its surfaceId (from a2ui_render): components replace/add by id, dataModel overwrites keys. For progress, corrections, appended results \u2014 never render a duplicate card.",
|
|
6074
6082
|
parameters: {
|
|
6075
6083
|
surfaceId: { type: "string", required: true, description: "The surfaceId returned by the a2ui_render call to update." },
|
|
6076
6084
|
components: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "a2ui-render-in-dsh",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A2UI interactive cards for the dsh web UI: the agent renders clickable interfaces (quizzes, forms, product cards) via @ant-design/x-card, and user interactions flow back to the agent as answers.",
|
|
5
5
|
"author": "sondge <fengshangjie@lilybearing.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -52,15 +52,18 @@
|
|
|
52
52
|
"scripts": {
|
|
53
53
|
"build": "node scripts/build.mjs",
|
|
54
54
|
"watch": "node scripts/build.mjs --watch",
|
|
55
|
-
"prepublishOnly": "npm run build"
|
|
55
|
+
"prepublishOnly": "npm run build",
|
|
56
|
+
"test": "node test/run.mjs"
|
|
56
57
|
},
|
|
57
58
|
"devDependencies": {
|
|
58
59
|
"@ant-design/x-card": "^2.9.0",
|
|
59
60
|
"@deepseek-ai/dsh-tools": "^0.1.1-rc.2",
|
|
60
61
|
"echarts": "^6.1.0",
|
|
61
62
|
"esbuild": "^0.25.0",
|
|
63
|
+
"jsdom": "^30.0.1",
|
|
62
64
|
"katex": "^0.18.4",
|
|
63
65
|
"mermaid": "^11.17.0",
|
|
66
|
+
"playwright": "^1.62.1",
|
|
64
67
|
"react": "^18.2.0",
|
|
65
68
|
"react-dom": "^18.2.0"
|
|
66
69
|
},
|
|
@@ -75,6 +78,5 @@
|
|
|
75
78
|
"publishConfig": {
|
|
76
79
|
"registry": "https://registry.npmjs.org/",
|
|
77
80
|
"access": "public"
|
|
78
|
-
}
|
|
79
|
-
"dependencies": {}
|
|
81
|
+
}
|
|
80
82
|
}
|