@perhapxin/dddk
v0.2.3
Published
Command palette + voice + Dwell + inline AI + DOM-grounded agent SDK for any web app
Maintainers
Readme
https://github.com/user-attachments/assets/18d797df-4952-421a-a2b3-16aef1ebcb34
01 · 命令面板 — 所有功能,住進同一塊面板
- Ctrl/⌘+K 打開。註冊的指令跟 Ask AI 並排在同一張清單 — 切主題、切語言、找客戶,全部用同一個入口。
- 內嵌掛載或彈窗,同一份 item。
palette.mountInline(host)把 palette 常駐嵌進 sidebar / drawer / 對話框。Ctrl/⌘+K 會把 modal 疊在上面,關掉時還原 inline。 - 多行 row + 縮圖。Item 支援
lines: string[](多行 metadata)跟image(縮圖 URL)。書封、商品照、客戶頭像免寫 custom renderer。 - 前綴路由 —
/command、@entity、order:、#tag。一個入口讓使用者不管當下卡在哪都找得到答案。 - 多層客製 — CSS 變數換主題、Skill SDK(Script / Prompt / Action / Surface / Panel)寫劇本、或把現有功能直接掛成 palette item。
- 零內建指令。Palette 顯示什麼完全由你決定。SDK 提供基礎建設,詞彙交給你。
02 · WebAgent — 直接操作頁面,不是側邊 chatbot
- DOM-grounded 自主迴圈。讀目前可見頁面,一次選一個 tool,跑之前先把步驟唸到字幕條給使用者看。
- 加入制的 action bundle。預設只裝
coreActions(5 個:narrate · navigate · click · border · scroll_to)。要formActions(input / drag / hold_key / double_click / long_press)、flowActions(wait / pause / ask_user)或extraActions(highlight / track_intent / escalate_to_human)就 opt-in。也可以加自己的,LLM 自己選用哪一個。 - 每個動作都有滑鼠。
cursorTrail: true打開後,動作執行之前合成游標滑到目標 — click / fill_input / border / scroll_to / narrate-with-about。內含執行前停頓、抵達脈動、reduced-motion fallback。 - 每一步靠 Space 把關。單擊接受、雙擊拒絕、Esc 取消。使用者在事情發生之前就看得到。
- 不確定時主動問。
ask_user_choice給 2-4 個選項,ask_user接自由文字。不偷偷做決定。 - 自帶 key。LLM 走 OpenAI、Google AI Studio、或 server 端的
ProxyProvider。Per-role routing 把便宜模型留給後處理、旗艦留給 agent 迴圈。STT 預設用瀏覽器 Web Speech,要換用transcribe(audio)callback。
03 · Inline Agent — 反白文字,AI 不用離開輸入框
- 反白任何文字,只要在
<input>/<textarea>/[contenteditable]裡都行,選取下方就會浮出小工具列。選一個 action,結果直接串流回填到原本反白的位置。 - 預設一組 action 直接能用 — 翻譯、潤稿、修文法、縮短、延長、改成正式語氣、解釋。可以全部換掉、加自家的(
/translate-with-glossary、/rewrite-as-email)。 - 雙欄 layout 給編輯器類型的 host 用 — 一邊
Format、一邊AI。也可以掛快捷鍵(例如Ctrl+Shift+R不開選單直接改寫)。
04 · 直覺操作 — 把現有手勢轉成 context
多種把 context 餵進 dddk 的方式,沒有新的詞彙要學。
A · 長按 Space — 語音輸入
- 焦點在輸入框內 → 轉錄回填到輸入框;其他地方 → 直接送進 agent。
- 可選 LLM 後處理 — 一次解決贅詞跟標點。
- STT 可替換 — 預設用瀏覽器內建的 Web Speech(沒 SLA、Firefox 不支援)。一個
VoiceConfig.transcribecallback 就能換成 Whisper 或任何廠商。
B · 長按任何元素 — Dwell
- 長按頁面任何元素約 1 秒 → 框架釘住它。
- 下一次按
Ctrl+K開 palette 時,這個元素就會帶進去當 context。 - 視覺類元素(圖表、圖片)順手附上自動截圖。
C · 拖框截圖
- 點 palette 右側的相機 → 在頁面上拖一個矩形。
- 截到的區域會夾在下一次 Ask AI / agent 的 context 裡。
- 圖表、儀表板、地圖 — 直接給 AI 看,不必用文字描述。
D · /introduce — 導覽
- 宣告式 tour — 由
page+subtitle+action(tools)步驟組成的清單。 - Space 前進 · Esc / 雙擊 Space 退出。使用者用自己的節奏看。
- onboarding 或 feature tour 寫一份,任何時候播 — palette 指令、proactive 提示、或程式直接呼叫都行。
05 · 行動裝置 — FAB + 自家按鈕
- 浮動操作按鈕(FAB)。手機 breakpoint 上自動出現 — 點一下開 palette、長按變語音對 agent 講話。
- 觸控手勢。桌面用的 Space-hold / long-press / multi-choice 全部對應到觸控 — 點 → palette、長按 → 語音、按數字鍵 → 選項。
- 換你自家的按鈕。FAB 可以換成 host 的任何元素,傳 selector 或
HTMLElement,dddk 把開啟 / 對話 handler 自動掛上去 — 按鈕想擺在 header、側欄、品牌 logo 都行。 - 響應式 chrome。字幕條會自動避開螢幕鍵盤;640px 以下 palette 自動全寬;觸控目標符合 44×44 規範。
06 · Proactive — 讀懂訊號、問對問題
- Agent 訂閱頁面訊號 — scroll 深度、Dwell 時間、停留時長、上次互動 — 條件對上時,把一個提議浮到字幕條。
- Yes / no 用 Space 解決。單擊接受、雙擊拒絕。沒有 popup、不會 layout shift — 整段對話都在字幕條完成。
- 多選用 1-9 數字鍵,最後一格永遠是 Other 接自由文字。選項有蓋到的話使用者不打字就解決,沒蓋到也還是能填。
- 每個回答都發一個有型別的 intent(
agent_answered帶值、confirm_action等),你可以直接量哪些有效。不是 big-data 撈魚 — 直接問、直接記。 - 客服場景開箱即用 — 訂單剛出貨 → 「要幫你查物流嗎?」;使用者停在退貨頁太久 → 列三個常見動作。
07 · Intent stream — 每一個 yes / no 都是訊號,儀表板自然會浮現
- 每一次互動都發一個有型別的 event。Palette 開啟、語音轉錄、agent 回答、接受 / 拒絕手勢、Dwell 選取、多選挑選、甚至每一個 LLM call 的串流效能 — 全部走同一條結構化訊號流。
- Event 種類:
palette_activated·voice_captured·agent_asked/agent_answered(帶latencyMs)·agent_run_started/completed/stopped·agent_pause_decision·agent_llm_call(TTFT、tokens/sec、model)·confirm_action·selection_used·skill_started/finished·agent_feedback。要加自家的也走同一個通道。 - 乾淨的行為訊號,不用在資料海裡撈魚。你從使用者實際問了什麼、答了什麼學到他要什麼,不是從 clickstream 反推。
- 內建 dashboard route 直接把訊號跑成圖表 — yes-rate 時間序列、按模型分組的 TTFT / tok-per-sec、agent run 完成率、熱門 palette 指令、地理分布 — 或在程式裡訂閱 stream 自己接 Mixpanel / Amplitude / 自家 BI。
為什麼採用 — 八個實際劇本
大部分的客服票,其實在頁面上就解得掉。「我要怎麼 X」/「Y 在哪裡」/「查物流」/「換方案」 — 答案早就在你網站裡,差的是被找到。DOM-grounded agent 直接操作頁面就把這個 gap 接起來。在客服進到真人佇列之前,先處理掉好打的 70%。
Proactive 提議的轉換率夠看。盯著 scroll、Dwell、停留時長、上次互動,agent 就能在使用者想到之前主動問「要幫你查物流嗎?」/「要不要照你正在看的東西推薦一下?」。字幕條 yes / no 一鍵解決 — 物理上能做到的最低摩擦。同一個介面也吃得下 cross-sell 跟 upsell。
Palette 是個 UI 介面,不是純文字列表。每列的詳細區(以及 palette 內的 PanelSkill)可以 render 任何 Pieces 樹 — 圖表、表格、表單、迷你儀表板。Palette 變成真正的生產力介面,不只是 launcher:
- 金融 — 在 palette 打
AAPL,旁邊跑出即時報價卡 + sparkline。 - 客服 — 打一個問題,palette 直接顯示對應 FAQ 條目的格式化答案,不是給你一個連結再讓你點。
- 工具型 SaaS — 把工具(regex tester、JSON formatter、單位換算、內部查詢)全部塞進 palette,使用者完全不用切 tab。同樣的
Ctrl+K,每個產品有自己的動詞。
- 金融 — 在 palette 打
長按勝過「截圖再描述」。Dwell 讓使用者長按一個元素,agent 一個手勢就同時拿到 selector + 自動截圖 — 圖表、儀表板區、表格列、都行。使用者不用再中斷自己去截圖、貼進對話框、寫一段話解釋。意圖從手指直接流到 LLM。
一個 palette 指令打破語言牆。內建的 immersive translate 把當前頁面每一個段落雙語並排 render — 一個按鍵就把你英文-only 的文件 / KB / 產品文案變成中 / 日 / 韓 / 西語讀者看得懂的介面。每頁批次成幾個 LLM call(200 段的文章大概 7 個 call)。對跨境 SaaS、內容平台、或服務多區域的產品,roadmap 上就少一個翻譯工程專案。
一個 SDK 取代縫六個廠商。Palette + agent + inline AI + 語音 + Dwell + proactive + analytics + immersive translate 一次裝好。傳統作法是 Algolia 做搜尋、Intercom 做 chat、Mixpanel 做分析、Whisper 做語音,加上中間那些脆的膠水 code。dddk 一個 dependency、一套主題系統、一條 intent stream。
Yes / no / 多選 = 免費的 RL 標籤。每一個 Space-接受、雙擊-拒絕都是一筆乾淨、刻意的訊號 — 使用者真的想要什麼 vs 不想要什麼,本人說的、跟原始 prompt 一起記下來。不用再從 clickstream 雜訊反推。下一次要 fine-tune 或 eval 用的訓練集,順手就收完了。
語音不只用在瀏覽器。同一套
Voice+utilityLLM 角色撐得起 IoT 面板、kiosk 終端、服務機台、銀髮 / 不想打字使用者的無障礙介面。所有有麥克風的裝置共用一個心智模型。
v0.2.2 — 最新
疊在 v0.2.1 上的 patch。無破壞性改動。完整 release notes:release-notes.zh-TW.md。
- Prompt registry — SDK 內建的每一支 LLM system prompt(webagent narrator、planner、InlineAgent、markdown-edit、翻譯、STT 清理、Dwell 分類器)現在都可以從單一 API 依 locale 覆蓋。
dddk.prompts.override('inline-edit.system', 'ja', () => …)。完整介紹:prompts.zh-TW.md。 autoInstall()一行安裝 — 新的工廠函式回傳完全構造好的DotDotDuck,內建 locale 自動偵測、demo LLM stub、鴨子精靈預設。import { autoInstall } from '@perhapxin/dddk'; const dddk = autoInstall();— 就這樣。完整合約:auto-install.zh-TW.md。- 7 張鴨子精靈內建 — SDK
dist/duck/出貨neutral / swim-side / hero-greet / chill-shades / swim-cycle / logo / cursor七張 PNG,tokens.css用--dddk-*-url綁好預設。基本安裝就有鴨子——不用自己 host PNG。想換自家品牌角色就覆蓋對應的變數。 - HERO 打招呼膠囊 — 第一次造訪時圓形 FAB 展開成橫向黃色半透明膠囊,鴨子在右邊、招呼文字填滿左邊。12+ 個視覺屬性都是
--dddk-fab-hero-*變數。 - 8 條吉祥物動畫用 CSS 變數調速 — 想放慢配合品牌節奏、加速做玩心、或壓低給 reduced-motion 都改一個變數。詳見 mascot.zh-TW.md。
- 新 WebAgent cursor 精靈 — 原本 SVG 箭頭鴨頭換成 bitmap:一隻鴨子騎在紙飛機上,尖角朝左上作為點擊起點。透過
--dddk-cursor-url換掉整張。 - Palette footer 收尾 — 右邊 brand mark(用
--dddk-brand-mark-url);左邊 hint 依輸入模式切換(鍵盤環境顯 kbd hint,(hover: none) and (pointer: coarse)觸控環境顯觸控 hint)。修好「觸控筆電上 footer 整條消失」的 bug。
v0.2.1
疊在 v0.2.0 上的 patch。無破壞性改動。完整 release notes:release-notes.zh-TW.md。
- InlineAgent inline-diff UX — 每個內建 action(improve / fix / shorter / longer / tone / translate)都會用「刪除線舊文 / 新文」預覽 + accept / reject / 插入下方 / 複製 + 後續對話。要回到直接 splice 就
defaultDisplayAs: 'replace'。 - 新 UI primitive —
mountProcessingLine、mountInlineDiff、InlineChatSession在@perhapxin/dddk/ui,host 自己驅動 editor surface 也能用。 - Cursor 錨在目標上 — RAF loop 讓合成游標即時跟著元素過 scroll / resize / layout shift。每個 terminal event 也都會 hide cursor + 重置位置狀態。
- Planner 語意收緊 —
finish是結束(不是問題),ask只給真擋路的決策用。資訊類 task 走navigate → narrate → finish,不插後續 ask。 - Palette 鍵盤導航 — 高 row 上下移動時標題不會被切掉。
v0.2.0 — 已出貨
webagent 核心架構重寫。一個破壞性改動(預設只裝 coreActions,不是全部 12 個 builtin action)。
成本驗證 — 完成。 gpt-5.4-nano 跑完整單檔 webagent loop,任務成功率跟 gpt-5.4-mini 同等,成本約低一個量級。dddk.perhapxin.com 的 webagent + plan 兩個角色已換 nano 作預設。
亮點:
- ✅ TaskAgent — 第三種 agent class(跟 WebAgent / InlineAgent 平行)。對話 + host 自定 tool calling、不讀 DOM、純 plain protocol。
ask()/streamAsk()。AgentSession共用,多個 TaskAgent 注入同一個 session 就能共享對話歷史。 - ✅ WebAgent 多 instance + 共享 session —
dddk.sessions命名 session registry +dddk.agents命名 instance registry。把同一個AgentSession注入到不同 WebAgent,route 改變時dddk.agents.setActive(name)。 - ✅ 加入制 action bundle — 預設只裝
coreActions(5 個:narrate / navigate / click / border / scroll_to)。要formActions/flowActions/extraActions就customActionsopt-in。builtinActions聯集留下向後相容。(破壞性改動。) - ✅ 新動作 —
hold_key、double_click、long_press、drag,press_key加modifiers。narrate從 CoT-only primitive 升級成 registry 裡的 first-class action。 - ✅ 每個動作都有游標 —
cursorTrail: true涵蓋 click / border / highlight / fill_input / scroll_to / narrate-with-about。scroll_to中間會切成滑鼠滾輪圖示。新 API:moveCursorTo(el)、cursorPulse()、setCursorMode('pointer' | 'scroll' | 'reading')。 - ✅ Planner 讀 DOM — planning 呼叫會把當前頁面快照塞進
hostContext,planner 可以看到 sidebar / nav link 即使 sitemap 設定漏列。plannerDomMaxLength控制上限(預設 8000)。 - ✅ Navigate 路徑驗證 —
navigatereject 不在 sitemap 裡的 path,把 valid path list 回 LLM 重試。Loop 不會再追 hallucinate 出來的路徑跑進 404。 - ✅ Streaming envelope parser — scanner-based 漸進式 JSON parser。每個 action 在自己的 tool-args
{ }一閉合就 dispatch,不用等外層 envelope 結束。在DotDotDuckconfig 加enableStreamingEnvelope: true。 - ✅ Live registry —
webagent.registerTool(def) → ToolHandle跟webagent.registerContextProvider(role, fn) → ContextProviderHandle。handle.remove() 退掉註冊;context provider 的 remove() 會恢復 SDK 預設而不是清空 slot。 - ✅ Context providers 拆分 — 六個 slot(
url/page_summary/dom/screenshot/history/selection),預設 provider 在 WebAgent constructor 自動裝好。 - ✅ InlineAgent scoping —
inlineAgent.attachScope(selector, config)給每個區域自己的 action set。Innermost-wins;CSS selector 表達不了的 case 用setScopeResolver(callback)fallback。 - ✅
onLoopEndhook —silent/text/feedback(Space 接受 · 雙擊拒絕 · Esc 跳過)/ask_user(收尾多選問題)。 - ✅
agent_tool_failedintent event — tool handler 回{ ok: false }或 throw 就 fire。 - ✅ Inline palette + 多元 row —
dddk.palette.mountInline(host, opts?)把 palette 常駐嵌進 host 元素(無 backdrop)。Ctrl/⌘+K 會把 modal 疊上來,關掉時還原 inline。新增PaletteItem.lines: string[]+image: string+submitButton: boolean。 - ✅ 自架分析層(
@perhapxin/dddk/analytics) — IndexedDB-backedEventStore+toCSV/toNDJSON/toSQL匯出 + function-basedSqlSchemaMapper。canonicaldddk_eventsDDL 出貨 SQLite / Postgres / MySQL。 - ✅ 內建迷你 dashboard(
@perhapxin/dddk/analytics/dashboard) —renderDashboard(container, store)掛六張 vanilla SVG 圖。EN / zh-TW labels,可選自動刷新。 - ✅ Session lifecycle 強化 — 硬重整(F5 / Ctrl+R / Ctrl+Shift+R)永遠清 session,不管
sessionContinuityMs;預設sessionContinuityMs從5 * 60 * 1000改成0(每次 ask 都是獨立 session 除非 host opt-in)。 - ✅ 字幕條點擊 / 觸控 = Space — 點字幕條 = 按 Space;雙擊 = 雙按 Space。滑鼠 / 觸控 / pen 都吃。
v0.3 roadmap
從 v0.2 延後的項目:
- 跨類型 session 完整再序列化 — TaskAgent 讀 WebAgent 的 session 已經會了(CoT
agent_stepturn 直接跳過);反過來 WebAgent 讀 TaskAgent 的 plain-chat turn 並重新包成 CoT envelope 比較費工。 - 多 agent delegation — TaskAgent 透過 tool 呼叫 WebAgent(或反過來)。可行但 orchestrator routing 複雜度需要實際 use case 驗證。
- buildMessages 全面走 provider registry —
url/page_summary/history/selection/screenshot都改走 provider;dom因為currentIndexMap跟 selector resolution 綁死還是 inline。 - TaskAgent tool-args 逐字 streaming —
streamAsk已經 stream text delta + toolCallStart / toolCallEnd marker;tool 參數的逐字 stream 排在 roadmap。 - TaskAgent 跨 tab session 共享 — WebAgent 已 crosstab;TaskAgent 目前還沒。
v0.1.x 的 bug fix 會繼續在 v0.1.x branch 出。
狀態 — 早期階段,評估前先看
dotdotduck 仍在積極開發中。能跑,但會有粗糙的邊角。先講幾件事:
- 要認真評估的話,請 clone repo。內建的文件當地圖好用,但原始碼才是真相。
git clone https://github.com/PerhapxinLab/dotdotduck進你的專案目錄,搭配線上文件一起讀 — 這是搞清楚實際實作的最佳路徑。 - 文件是 AI 撰寫的。用 Claude Code 寫跟維護。慣例上盡量貼著程式碼,但如果看起來不對勁,grep repo 比相信文件可靠。
- 遇到 bug 或行為不清楚? 到 github.com/PerhapxinLab/dotdotduck/issues 開 issue — 一兩句話的描述就能影響 roadmap。
線上 demo 跑什麼(不綁定在 package 裡)
dddk.perhapxin.com 同時是 dotdotduck 的官方介紹頁,也是 package 的實際測試站 — 每次發版先上這個站、端對端壓過一輪,才會 tag。我們給自己的長期挑戰:用還能用的最小模型在每個角色把這個 demo 服務好,這樣別的團隊在成本壓力下採用 dddk 也照樣 work。下面列的模型選擇預期會持續換 — 小一點的 checkpoint 追上來就會換。
目前的 stack:
- 4-axis LLM router(
webagent/vision/utility/plan)— host 一個 role 配一個 model;展示站目前用 OpenAIgpt-5.4-nano跑主 agent 迴圈 + planner,用gpt-5.4-mini跑 InlineAgent + 語音後處理。 - 語音辨識 → 瀏覽器內建的 Web Speech API(SDK 預設;demo 沒問題、沒 SLA — 正式環境的 host 自己接
transcribe走 Whisper / Deepgram 等等)
這些都不是 @perhapxin/dddk 寫死的。Package 本身只 ship LLM provider adapter(OpenAI / Google / proxy,加上任何 OpenAI-compatible 廠商透過 baseURL — 例如 DEepSeek、Qwen、OpenRouter)跟一個 transcribe(audio) 擴充點。Key、模型、ASR 廠商都自己帶 — SDK 不綁你。
文件
v0.2.1 有什麼新東西 → release notes · migration guide
完整文件 → dddk.perhapxin.com/docs
Agent(DOM-grounded 迴圈 + InlineAgent + sitemap + Memory)→ /dddk/agent
LLM provider + router + adapter registry → /dddk/llm
Skills 系統 + evals → /dddk/skills
Modules(voice / Dwell / inline / immersive translate / proactive / analytics)→ /dddk/modules
Toolbox(search + recommend)→ /dddk/toolbox
Theming → /dddk/theming
安裝
pnpm add @perhapxin/dddk
# 或:npm i @perhapxin/dddk一行看到跑起來(v0.2.2+)— locale 自動偵測、合理預設全上、內建 demo LLM stub 讓 agent 功能不會沒接 LLM 就靜默 no-op:
import { autoInstall } from '@perhapxin/dddk';
import '@perhapxin/dddk/styles.css';
const dddk = autoInstall();按 Ctrl/⌘+K — palette 打開、鴨鴨 FAB 在右下角、首訪的招呼膠囊會展開。要接真 LLM + 自家指令就傳 overrides:
import { autoInstall, OpenAIProvider } from '@perhapxin/dddk';
import '@perhapxin/dddk/styles.css';
const dddk = autoInstall({
llm: new OpenAIProvider({
apiKey: import.meta.env.VITE_OPENAI_KEY,
model: 'gpt-5.4-mini',
}),
siteName: 'YourSaaS',
skills: [
{
id: 'introduce',
type: 'script',
name: 'Tour the app',
steps: [
{ subtitle: '歡迎!', action: (t) => t.spotlight('.hero') },
{ subtitle: '這是價格區。', action: (t) => t.highlight('.pricing'), waitForUser: true },
],
},
],
});比較喜歡明確 constructor 那條路?new DotDotDuck({ ... }) 從 v0.2.1 到 v0.2.2 完全不動 — autoInstall(overrides) 跟 new DotDotDuck({ ...defaults, ...overrides }) 功能等價。完整的安裝指南 有 React / Vue / Svelte / Solid 的整合說明,auto-install.zh-TW.md 是完整 API 合約。
主題
所有視覺都讀 CSS 自訂變數 — --dddk-bg、--dddk-accent、--dddk-radius、--dddk-font 等等。在 :root 蓋掉,或裹在任何 wrapper 內 scope。
:root {
--dddk-accent: #6366f1; /* 你的品牌色 */
--dddk-radius: 10px;
--dddk-font: 'Inter', system-ui, sans-serif;
}暗色模式自動切:樹上任何位置設 [data-theme="dark"],或者 @media (prefers-color-scheme: dark) — 哪個先 match 就用哪個。要做自家風格(sepia、高對比、品牌主題)就在新的 selector 下覆寫同樣那組變數。
授權
AGPL-3.0-or-later。完整條款看 LICENSE。
