dddk — A2UI Renderer
dddk 跟 webagent 共用 A2UI renderer,dddk 多了 palette 整合 + 觸發 + skill 用法。
跟 webagent A2UI 的關係
- webagent A2UI:agent 在執行任務中需要結構化輸入時呼叫
render_a2ui_surfaceaction - dddk A2UI:除了上述還有
- A2UISkill — 用戶從 palette 主動觸發開出 surface
- Inline 渲染 — 字幕條上方塞短表單 / 單選
- Dock 渲染 — 右側持續面板(進度表 / 工作清單)
兩者共用同一個 A2UIRenderer class,只是 dddk 多包了 hook。
三種 placement
┌──────────────────────────────────────────┐
│ │
│ ┌──────────────┐ ┌─────────┐│
│ │ │ │ ││
│ │ CENTER │ │ DOCK ││
│ │ (modal) │ │ (右側) ││
│ │ │ │ ││
│ └──────────────┘ │ ││
│ │ ││
│ ┌────────────────────────┐ │ ││
│ │ INLINE (字幕條上方) │ │ ││
│ └────────────────────────┘ └─────────┘│
└──────────────────────────────────────────┘
| Placement | 用途 | 是否搶焦 |
|---|---|---|
center |
完整 form / 大型卡片 | backdrop + click outside 取消 |
inline |
字幕條上方短互動(單選、確認) | 不搶焦,繼續看 page |
dock |
持續性面板(進度表、聊天) | 不搶焦,持續顯示 |
API
import { A2UIRenderer } from '@perhapxin/dddk/ui';
const renderer = new A2UIRenderer({
catalog: 'basic', // 或自訂 catalog
defaultPlacement: 'center',
});
renderer.mount(surface, {
placement?: 'center' | 'inline' | 'dock',
onSubmit?: (data: any) => void,
onCancel?: () => void,
onAction?: (action: string, data: any) => void,
});
renderer.unmount(surfaceId);
renderer.unmountAll();
跟 dddk 主類別的整合
const dddk = new DotDotDuck({
llm,
webAgent: () => new WebAgent({ llm }),
a2ui: {
catalog: 'basic', // 或自訂
defaultPlacement: 'center',
},
skills: [orderStatus], // 含 A2UISkill
});
dddk.mount();
// dddk 內部已掛 a2ui_surface event handler
A2UISkill 完整生命週期
用戶在 palette 打 "/order-status" ↵
↓
SkillRegistry.match("/order-status") → A2UISkill
↓
skill.build(ctx) → 回 surface JSON
↓
A2UIRenderer.mount(surface, { placement: 'center' })
↓
用戶填表單 → 按 submit
↓
skill.onSubmit(data, ctx) → 可以:
- 回新 surface(多步表單)
- 回 null / undefined(結束)
- throw(錯誤訊息顯示)
Inline 用法範例
agent 跑到一半要簡單確認 → 不開大 modal,inline 就好:
{
"name": "render_a2ui_surface",
"arguments": {
"placement": "inline",
"surface": {
"version": "v0.10",
"updateComponents": {
"surfaceId": "confirm-delete",
"components": [
{ "id": "root", "component": "Row", "children": ["q", "yes", "no"] },
{ "id": "q", "component": "Text", "text": "確定刪除這筆?" },
{ "id": "yes", "component": "Button", "text": "確定", "action": "confirm" },
{ "id": "no", "component": "Button", "text": "取消", "action": "cancel" }
]
}
}
}
}
Dock 用法範例
長任務的進度追蹤面板:
const surface = {
version: 'v0.10',
updateComponents: {
surfaceId: 'progress',
components: [
{ id: 'root', component: 'Card', children: ['title', 'list'] },
{ id: 'title', component: 'Heading', text: '匯入進度' },
{ id: 'list', component: 'List', bind: '/steps' },
],
},
updateDataModel: {
data: { steps: [
{ name: '讀檔', status: 'done' },
{ name: '解析', status: 'in_progress' },
{ name: '寫入', status: 'pending' },
]},
},
};
renderer.mount(surface, { placement: 'dock' });
// 持續 update
setInterval(() => {
renderer.update('progress', {
updateDataModel: { data: { steps: currentSteps } },
});
}, 1000);
內建 catalog
跟 webagent 共用 basic catalog(見 webagent 06-a2ui-surface.md),多 3 個 dddk-specific:
| Component | 用途 |
|---|---|
Spinner |
loading indicator |
ProgressBar |
進度條 |
Toast |
短暫訊息(auto-hide) |
主題化
A2UI renderer 完全吃 dddk 主題 CSS 變數(見 11-theming.md):
[data-dddk-a2ui-surface] {
background: var(--dddk-bg);
color: var(--dddk-text);
border-radius: var(--dddk-radius);
/* ... */
}
不會跟 host page 樣式打架(Shadow DOM optional)。
Custom catalog
詳見 webagent 06-a2ui-surface.md,用法一致:
import { defineCatalog } from '@perhapxin/dddk/ui';
const myCatalog = defineCatalog('my-corp', {
EmployeeCard: { schema, render },
OrgChart: { schema, render },
});
new DotDotDuck({ a2ui: { catalog: myCatalog } });