網站核准與連線狀態
Pedelec 不允許任意網站自動建立本機 agent session 或開啟原生 directory picker。Chrome Extension 會辨識 page origin,並在該 origin 第一次呼叫 createSession()、resumeSession() 或 workspaceFolderPicker() 前要求使用者核准。
讀取 approval status
Section titled “讀取 approval status”const status = await pedelec.getApprovalStatus();type ApprovalStatus = { installed: boolean; approved: boolean; origin: string | null; appConnected: boolean;};installed
Section titled “installed”true 表示 SDK 已連到 Pedelec Extension,並收到有效的 approval-status response。
false 表示目前 page 無法使用 Extension,可能原因包括:
- 尚未安裝 Extension;
- Extension 被停用或安裝在另一個 browser profile;
- page origin 不符合 external connection 規則;
- Extension service worker 或 SDK port 已中斷;
- SDK 在 browser page 以外建立。
因為多種原因都會得到同一結果,UI 建議顯示「Pedelec Extension 目前無法使用」,不要直接顯示「尚未安裝」。
approved
Section titled “approved”true 表示目前 origin 已記錄在 Extension local storage 的核准清單。
Approval 以 origin 為單位,origin 包含 scheme、hostname 與 port。開發 port 改變時可能需要重新核准。
origin
Section titled “origin”目前 page 的 normalized origin,例如 https://app.example.com 或 http://localhost:5173。
無法驗證 HTTP/HTTPS origin 時可能是 null。
檢查完整可用性
Section titled “檢查完整可用性”appConnected
Section titled “appConnected”此欄位來自專用且非敏感的 Core ping;它不代表 origin 已 approval 或 provider ready。它不會開啟 approval popup,但 ping 可能使用 Desktop auto-launch fallback。
需要在建立 session 前檢查完整 readiness 時,使用 checkAvailability():
const availability = await pedelec.checkAvailability();它回傳 Extension、approval、Desktop 與可選的 normalized error。未 approval 時不開 popup,但 approval-status ping 仍可能 probe Desktop;已 approval 時還會用 getSettings() 做 protocol probe。launchAttempted 只表示 ping 或 settings probe 已送出,並不確認 Desktop 已啟動。
什麼操作會開啟 approval popup
Section titled “什麼操作會開啟 approval popup”getApprovalStatus() 只讀取狀態並 ping Core,不會主動提出核准要求。getSettings()、listProviders() 與 workspaceFolderPicker() 是敏感 Desktop API,需 origin approval 且可能開啟 popup;它們只回傳 defaults、provider summary,或使用者明確選取的 folder observation。請用 appConnected,不要再以 listProviders() 作為 connectivity probe。
尚未核准時,第一個建立/resume session 或開啟 directory picker 的操作才會觸發:
await pedelec.createSession({ provider: "codex" });// 或await pedelec.resumeSession(savedSessionId);// 或const folder = await pedelec.workspaceFolderPicker();Extension 會暫存 request、開啟 popup,等待使用者 approve 或 reject。核准後,原本等待的操作會自動繼續。
Approval request 有 timeout。Popup 被關閉但沒有完成操作,也會被視為拒絕或未完成。
建議的 connect button state machine
Section titled “建議的 connect button state machine”Extension、runtime 與 provider readiness 應分開檢查。Approval status 無法證明 Desktop App 正在執行。
| UI 狀態 | 條件 | 建議操作 |
|---|---|---|
| Checking | Status request pending | Disable button 並顯示進度 |
| Extension unavailable | installed === false |
引導安裝或啟用 Extension |
| Ready to approve | 已安裝但 approved === false |
Button 顯示「Connect Pedelec」 |
| Connecting | createSession() pending |
保留 popup 操作提示 |
| Runtime unavailable | Native/Core request 失敗 | 引導啟動或修復 Desktop App |
| No provider | 沒有 ProviderInfo.available === true |
顯示 provider setup |
| Connected | Session 建立成功 | 顯示 provider、effort level 與 session status |
| Disconnected | Active SDK port 中斷 | Disable send;下一個新的 client operation 會 retry port,需繼續的 session 請明確 resume |
async function connectPedelec() { setConnectionState("checking");
const approval = await pedelec.getApprovalStatus(); if (!approval.installed) { setConnectionState("extension-unavailable"); return; }
setConnectionState(approval.approved ? "connecting" : "awaiting-approval");
try { const providers = await pedelec.listProviders(); const provider = providers.find((item) => item.available); if (!provider) { setConnectionState("no-provider"); return; }
const session = await pedelec.createSession({ provider: provider.code, });
registerSession(session); setConnectionState("connected"); } catch (error) { routeConnectionError(error); }}Approval 相關錯誤
Section titled “Approval 相關錯誤”| Code | 意義 | UI 處理 |
|---|---|---|
CREATE_SESSION_NOT_APPROVED |
無法驗證 origin,或另一個 origin 正在等待核准 | 說明 origin conflict,稍後重試 |
APPROVAL_REJECTED |
使用者拒絕或關閉 approval flow | 回到 ready-to-approve |
APPROVAL_TIMEOUT |
使用者未在時限內完成 | 提供 retry,提醒保持 popup 開啟 |
OPEN_POPUP_FAILED |
Chrome 無法自動開啟 Extension popup | 請使用者手動點 Pedelec Extension icon |
SDK_ORIGIN_UNAVAILABLE |
無法判定或傳遞 SDK caller origin | 使用支援的 HTTP(S) page origin 並 reload |
THREAD_ACCESS_DENIED |
Resume 或操作的 session 屬於不同 origin | 回到 owner origin 或建立新 session;不要把 ID 當 bearer token |
STORAGE_ERROR |
Extension 無法讀寫 approved origins | 檢查 Extension,持續發生時考慮重裝 |
INVALID_ORIGIN |
Popup action 收到非 HTTP(S) origin | 使用支援的 page origin |
Connection 相關錯誤
Section titled “Connection 相關錯誤”| Code | 層級 | 常見處理 |
|---|---|---|
EXTENSION_UNAVAILABLE |
Page → Extension | 檢查安裝、browser profile 與 origin |
EXTENSION_DISCONNECTED |
Page → Extension | 停止受影響的 operation;下一個新的 client operation 會 retry,需要繼續的 session 請明確 resume |
NATIVE_HOST_UNAVAILABLE |
Extension → native host | 啟動或修復 Desktop App installation |
NATIVE_CONNECTION_CLOSED |
Extension → native host | 重啟 Desktop App,安全的 read 操作可重試 |
CORE_RUNTIME_UNAVAILABLE |
Native host → Core | Background launch 可能失敗;手動開啟 Desktop 或修復 installation/launch config |
IPC_UNAVAILABLE |
Local Core IPC | 重啟 Desktop App,查看 local runtime log |
SDK_BRIDGE_TIMEOUT |
SDK request timeout | 不要連續重送 write;先檢查下游元件 |
不要從單一訊號過度推論
Section titled “不要從單一訊號過度推論”installed: true不代表 Desktop App 正在執行。- Origin 已核准不代表 provider 可用。
ProviderInfo.available: true不代表任意 model id 都有效。- Ollama provider available 不代表 server 或 model 已準備好。
- 已 disconnected 的 client 會在下一個新的 operation lazy reconnect;舊 session handle 仍需要明確 resume。
穩健的 connection screen 應顯示失敗層級與具體修復方式,而不是只有一個「連線失敗」。
下一步閱讀建立 Client,了解 client lifetime 與 bridge timeout。