dddk — A2UI Renderer

dddk 跟 webagent 共用 A2UI renderer,dddk 多了 palette 整合 + 觸發 + skill 用法。

跟 webagent A2UI 的關係

  • webagent A2UI:agent 在執行任務中需要結構化輸入時呼叫 render_a2ui_surface action
  • 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 } });