建立 Client
Pedelec 是 browser SDK 的入口。一個 instance 擁有一條連向 Pedelec Chrome Extension 的 external connection,並負責 request correlation、bridge timeout、event routing,以及透過這個 client 建立的 session objects。
Constructor
Section titled “Constructor”import { Pedelec } from "@kaoruisaac/pedelec";
const pedelec = new Pedelec();Constructor 會立刻嘗試連到設定好的 Pedelec Extension ID,不會等待 Desktop App 或 provider ready。
若執行時沒有 browser window,instance 就無法使用 browser bridge。若不存在 chrome.runtime.connect,或第一次 connection attempt 失敗,後續 bridge operation 仍會 retry;暫時性的啟動失敗不會永久 poison client。
Options
Section titled “Options”const pedelec = new Pedelec({ bridgeTimeoutMs: 30_000,});type PedelecOptions = { bridgeTimeoutMs?: number;};bridgeTimeoutMs
Section titled “bridgeTimeoutMs”SDK request 等待 Extension bridge response 的最長時間。
- 預設:
30_000ms。 - 小於
1的值會被 clamp 為1。 - 適用於
listProviders()、getSettings()、createSession()與 low-levelrequest<T>()等 bridge request。 - 和 tool 的
timeoutMs不同。 - 不限制
sendText()的整體 turn 時間;sendText()先等待 bridge request,再等待 active agent turn 結束。
workspaceFolderPicker() 是例外:原生 picker 開啟並等待使用者操作時,不套用 SDK bridge wall-clock timeout;Extension/native disconnect 或明確的 bridge error 仍會立即 reject。
Timeout 會 reject SDK_BRIDGE_TIMEOUT,並在 details 附上 request metadata。
try { await pedelec.listProviders();} catch (error) { if ((error as { code?: string }).code === "SDK_BRIDGE_TIMEOUT") { showConnectionHelp(); }}在本機啟動特別慢時可提高數值,但過大的 timeout 也會讓斷線 UI 長時間像是卡住。應搭配 visible loading state 與分層 troubleshooting。
建議 lifetime
Section titled “建議 lifetime”一個 browser page lifecycle 共用一個 client。
let pedelec: Pedelec | null = null;
export function getPedelec() { pedelec ??= new Pedelec(); return pedelec;}同一 client 可以建立並追蹤多個 PedelecSession。共用 client 能避免不必要的 Extension ports,也讓 SDK 集中路由 session events。
不要把 client 當成跨 page singleton。Page refresh 會建立新的 JavaScript environment,因此一定會有新的 client 與 Extension port。
Browser-only initialization
Section titled “Browser-only initialization”一般 browser application
Section titled “一般 browser application”if (typeof window !== "undefined") { const pedelec = new Pedelec(); startPedelecUI(pedelec);}Framework lifecycle
Section titled “Framework lifecycle”在 framework browser lifecycle 建立 client,不要放入 server serialized state。
// 概念範例onBrowserMount(() => { const pedelec = new Pedelec(); setPedelecClient(pedelec);});SSR module 中不要這樣做:
// 不要在 server renderer 會 import 的 module 中建立。export const pedelec = new Pedelec();這個 instance 在沒有 window 時就已建立,hydration 後仍然 unavailable。
Extension connection 行為
Section titled “Extension connection 行為”Client 會產生唯一 channelId 並開啟 external runtime port。每個 request 都包含 channel ID 與唯一 request ID;其他 channel 的 session event 會被忽略。
Port disconnect 時:
- 已透過該 port 送出的 request 會以
EXTENSION_DISCONNECTEDreject,且不會 replay; - 每個已註冊 session 收到 SDK-originated error callback,舊 handle 也會變成不可使用;
- parent client 仍可 reuse,下一個新的 operation 會 lazy 開啟一條 replacement port。
getApprovalStatus() 與 checkAvailability() 也會走這條 retry path。若 replacement connection attempt 失敗,當次 operation 會回報 unavailable error,之後的 operation 仍可再次嘗試。若要在 disconnect 後繼續 session,請明確呼叫 resumeSession(sessionId);舊的 PedelecSession handle 不會靜默移到 replacement route。
Client 與 session 的責任
Section titled “Client 與 session 的責任”Pedelec client |
PedelecSession |
|---|---|
| Extension transport | 單一 agent conversation/thread |
| Provider 與 settings query | Turn lifecycle |
| Create/resume request | Chat、status、tool、error callbacks |
| Request timeout | prepare()、sendText()、end() |
| 依 session ID 路由 event | Session status 與 handler registration |
Health checks
Section titled “Health checks”完整環境 readiness 可使用 checkAvailability():
const availability = await pedelec.checkAvailability();它不建立/resume session,也不開啟 approval。getApprovalStatus() 會做非敏感 ping,因此未 approval origin 也可 probe Desktop 而不開 popup;已 approval 時還會以 getSettings() 檢查。launchAttempted 僅表示 ping 或 settings probe 已送出,不能確認 Desktop 已啟動。
沒有單一 method 能證明所有 layer 都健康:
const approval = await pedelec.getApprovalStatus();const providers = approval.installed ? await pedelec.listProviders() : [];getApprovalStatus().appConnected是非敏感 Core connectivity 結果,不代表 approval 或 provider ready。getSettings()與listProviders()需要 origin approval 且可能開啟 popup,且只公開 defaults 與name/code/available/isDefault/error;為保持 forward compatibility,未知的 response 欄位會被忽略。- 建立 session 會更深入驗證 provider configuration。
- 傳送 turn 才真正驗證 provider execution。
請採 progressive checks,不要只維護一個永久 connected boolean。
多個 clients
Section titled “多個 clients”技術上可以建立多個 clients;每個都會開啟獨立 Extension port,只接收自己 channel 的 events。除非不同 application root 確實需要獨立 lifecycle,否則建議共用。
同一 session 需要多個 view 時,通常共用 client 與 application store 更簡單。Session 同時被多條 SDK connection 路由時,autoEndOnDisconnect 要等最後一條 route 消失才會 end。