dddk — Skills SDK
Skill = 可註冊的「dddk 行為單元」。四種類型涵蓋從純文字 prompt 到視覺導覽到 A2UI form。
四種 Skill 類型
1. ScriptSkill — 一連串視覺步驟
最適合 onboarding 導覽 / 教學 / 復演。
import type { ScriptSkill } from '@perhapxin/dddk';
const introduce: ScriptSkill = {
id: 'introduce',
type: 'script',
name: '導覽我們的功能',
description: '5 分鐘看完所有重點',
steps: [
{
page: '/',
subtitle: '歡迎!這是首頁。',
action: (tools) => tools.spotlight('.hero'),
},
{
page: '/pricing',
subtitle: '這是我們的方案。',
action: (tools) => tools.highlight('.plans', undefined, '看這裡'),
},
{
page: '/dashboard',
subtitle: '進來之後會看到儀表板。可以按 ctrl+k 隨時叫我。',
waitForUser: true, // 等用戶按 space 才往下
},
],
};
每個 step:
page(optional)— 換頁subtitle(optional)— 字幕條給用戶看action(optional)— 視覺操作(highlight / spotlight / border / inject)waitForUser(預設 true)— 等用戶按 space 才下一步
2. PromptSkill — 客製 agent system prompt
最適合「同一種任務反覆做」。
const translate: PromptSkill = {
id: 'translate',
type: 'prompt',
name: '翻譯這頁',
prompt: '使用 immersive_translate action 把這頁翻譯成 {{language}}。完成後 show_subtitle 告訴用戶完成。',
};
{{variable}} 從用戶輸入抽。
用戶在 palette 輸入 /translate 英文 → variable language = '英文' → 整段 prompt 套進 agent system prompt → agent 跑。
3. ActionSkill — 純 action,不必走 agent
最適合「立即執行、不需要 LLM 判斷」。
const clipboardHistory: ActionSkill = {
id: 'clipboard-history',
type: 'action',
name: '剪貼簿歷史',
handler: (ctx) => {
const items = ctx.storage.get('clipboard') ?? [];
ctx.palette.replace(items.map(i => ({
id: i.id,
name: i.text.slice(0, 50),
handler: () => navigator.clipboard.writeText(i.text),
})));
},
};
handler 拿一個 context,可以:
ctx.palette— 操作 palettectx.subtitle— 顯示字幕ctx.storage— 讀 / 存ctx.llm— 需要時叫 LLMctx.agent— 需要時叫 agent
4. A2UISkill — 開出一份 A2UI surface
最適合「需要結構化輸入 / 顯示結構化結果」。
const orderStatus: A2UISkill = {
id: 'order-status',
type: 'a2ui',
name: '查訂單狀態',
build: async (ctx) => {
return {
version: 'v0.10',
updateComponents: {
surfaceId: 'order-status',
catalogId: 'basic',
components: [
{ id: 'root', component: 'Card', children: ['title', 'input', 'btn'] },
{ id: 'title', component: 'Heading', text: '查詢訂單' },
{ id: 'input', component: 'TextField', label: '訂單編號', bind: '/orderId' },
{ id: 'btn', component: 'Button', text: '查詢', action: 'submit' },
],
},
};
},
onSubmit: async ({ orderId }, ctx) => {
const order = await fetch(`/api/orders/${orderId}`).then(r => r.json());
return {
// 第二個 surface 顯示結果
version: 'v0.10',
updateComponents: { ... },
};
},
};
build 產初始 surface,onSubmit 收用戶輸入 → 可以回新 surface(多步表單)或關閉。
SkillRegistry
class SkillRegistry {
register(skill: Skill): void;
unregister(id: string): void;
get(id: string): Skill | undefined;
list(): Skill[];
match(command: string): Skill | undefined; // "/introduce" → skill "introduce"
}
SkillRegistry 是 dddk 內建的,host 透過 config 傳 skills:
new DotDotDuck({
skills: [introduce, translate, orderStatus, clipboardHistory],
});
或之後動態加:
dddk.skills.register(newSkill);
SkillTools(給 ScriptSkill 用)
interface SkillTools {
navigate(path: string): void;
highlight(selector: string, color?: string, label?: string): string; // 回 overlay id
border(selector: string, color?: string, label?: string): string;
spotlight(selector: string): string;
inject(selector: string, text: string, position?: 'before' | 'after'): string;
subtitle(text: string): void;
clearOverlays(): void;
ask(question: string): Promise<string>; // ask user 純文字
wait(ms: number): Promise<void>;
llm(prompt: string): Promise<string>; // 一次性 LLM 呼叫
}
Skill ID 與 palette 整合
Skill id 開頭通常用斜線,因為 palette 把以斜線開頭的輸入當 skill:
用戶在 palette 打 "/introduce"
→ registry.match("/introduce") → 找到 introduce skill
→ dispatch(introduce, args)
不以斜線開頭也行(純 name 搜尋),習慣上 ScriptSkill / PromptSkill 用斜線,ActionSkill / A2UISkill 用 name。
套件附帶哪些 skill?— 零個
dddk 不附任何內建 skill。所有 skill 由企業 / 開發者自己寫,自己 register。
理由:
- skill 是業務行為,沒有 universal 的「合適預設」
- 一附帶就要負責維護、文件、i18n
- 用戶會把它當「應該保留」的東西改不掉
需要寫範例 skill 時,看 10-cookbook-enterprise-skills.md(cookbook 是 doc,不是 export 出去的程式碼)。
多 skill 組合
ScriptSkill 步驟內可以呼叫其他 skill:
{
page: '/dashboard',
action: async (tools) => {
await tools.runSkill('translate', { language: 'zh-TW' });
tools.subtitle('翻譯完成,繼續導覽');
},
}
PromptSkill 在 prompt 內也可以引用其他 skill:「先用 /clipboard-history 找最近複製的內容,再 ...」。