Tool Errors 與 Timeouts
Tool failure 可能發生在多個 layer。應區分 expected application-domain result、SDK handler failure、serialization/transport failure 與 runtime timeout。
TOOL_HANDLER_NOT_FOUND 是 browser-side:SDK 找不到 handler,會將 error result 回給 agent。TOOL_NOT_FOUND 則表示 Core ToolRegistry 找不到 requested tool;TOOL_ARGS_INVALID 表示 agent args 不是 object 或不符合 schema;TOOL_TIMEOUT 表示 Core 等待 result 超時。Recovery 詳見 Error Codes。
預期內 domain errors
Section titled “預期內 domain errors”Tool 正常執行,但 action 無法完成時回傳 structured error:
return { error: { code: "NO_ACTIVE_SELECTION", message: "Select text before using replace_selection.", details: { documentId: activeDocument.id, }, retryable: true, },};這是 normal result,SDK 會送給 agent,不會因此自動呼叫 session.onError()。
適合用於:
- resource missing;
- current UI state invalid;
- permission denial;
- user cancellation;
- version conflict;
- validation failure。
TOOL_HANDLER_NOT_FOUND
Section titled “TOOL_HANDLER_NOT_FOUND”沒有 named、inline 或 generic handler 時,SDK 產生包含 TOOL_HANDLER_NOT_FOUND 的 error result 並送給 agent。通常是 integration bug:
- tool 在
skills.tools但未實作; - definition 與 registration name 不一致;
- resumed page 未 restore handlers;
- component cleanup 太早;
- handler 註冊在另一個 session object。
TOOL_HANDLER_ERROR
Section titled “TOOL_HANDLER_ERROR”Selected handler throw/reject 時,SDK catch 並轉成 TOOL_HANDLER_ERROR result。
session.onTool("save", async () => { throw new Error("Database unavailable");});Raw exception 不會讓 SDK event listener crash,agent 會收到 normalized failure。
需要 stack trace 或更完整 diagnostics 時,請在 handler 內先 application log,因 serialized error result 會保持精簡。
SUBMIT_TOOL_RESULT_FAILED
Section titled “SUBMIT_TOOL_RESULT_FAILED”取得 result 後,SDK 會呼叫 bridge submit_tool_result。Request 失敗時 session emit SDK error:
session.onError((error) => { if (error.code === "SUBMIT_TOOL_RESULT_FAILED") { showToolTransportFailure(); }});可能原因:
- Extension/native/Core disconnect;
- handler pending 時 session ended;
- Core 已 timeout 該 request;
- result 無法 clone/serialize;
- runtime 拒絕 request ID。
Agent 可能無法繼續。不要盲目 retry 有 side effect 的 handler,因 operation 可能已完成,只是 result delivery 失敗。
Timeout
Section titled “Timeout”timeoutMs: 60_000省略時 Core 目前預設 60 秒。Timeout 控制 runtime 等 result 的時間,不會強制停止 page JavaScript。
Handler late resolve 時:
- application side effect 可能已完成;
- Core 可能已 fail 或繼續 turn;
- result submission 可能失敗;
- session 可能 emit
SUBMIT_TOOL_RESULT_FAILED或 runtime session error。
Handler 應在 deadline 前 settle,並自行實作 cancellation/cleanup。
Provider command timeout 與 App Tool formal timeout
Section titled “Provider command timeout 與 App Tool formal timeout”Provider 的 shell 或 terminal 可能在 Core 的 timeoutMs deadline 前停止等待 pedelec-cli --thread-id <pedelec_thread_id> tool-call。這是 ambiguous transport failure,不代表 App Tool 已失敗。若 Agent 沒有收到完整 structured Pedelec response,可以用完全相同的 tool name 與語意完全相同的 arguments exact retry;Core 會 join 仍在執行的 invocation,或 replay 最近完成但尚未確認 delivery 的 result。不要改 arguments,也不要無限 retry。
Core 到達 App Tool 的 timeoutMs 時,會回傳正式的 TOOL_TIMEOUT structured error。收到 TOOL_TIMEOUT 代表原 invocation 已結束,不是繼續同一 invocation 的 in-flight retry 指示。只有 IPC delivery 未確認的 result 可能在短時間內 replay;成功 delivery 的 result 不會作為一般 deduplication cache 保留。
Serialization failures
Section titled “Serialization failures”請回傳 plain JSON-compatible values。問題範例:
return document.body; // DOM nodereturn () => 1; // functionreturn { value: 1n }; // BigIntreturn cyclicObject; // cyclereturn new Map(); // 意圖結構會丟失return new File(...); // browser object,不是 compact JSON轉換:
return { html: document.body.innerHTML, entries: [...map.entries()], size: file.size, name: file.name,};也要留意 payload size。Large result 增加 bridge cost,也可能超過 local IPC/message limit。大型 artifact 應只回傳 application-owned ID。
Validation errors
Section titled “Validation errors”Schema 改善 agent output,但不會讓 args 變可信。Routine bad input 應回 domain error,不要 throw:
function validateMoveArgs(raw: unknown) { if (!raw || typeof raw !== "object") return null; const value = raw as Record<string, unknown>; if (typeof value.shapeId !== "string") return null; if (typeof value.x !== "number" || !Number.isFinite(value.x)) return null; if (typeof value.y !== "number" || !Number.isFinite(value.y)) return null; return { shapeId: value.shapeId, x: value.x, y: value.y };}
session.onTool("move_shape", (raw) => { const args = validateMoveArgs(raw); if (!args) { return { error: { code: "INVALID_TOOL_ARGS", message: "shapeId, x, and y are required.", }, }; } return scene.move(args);});Retry policy
Section titled “Retry policy”| Failure | 適合 automatic retry? |
|---|---|
| Read-only tool 在 execution 前 transport failed | Connection recovery 後有時可以 |
| Domain validation error | 不可;需改 input |
| User cancelled | 除非使用者重新要求,否則不可 |
| Handler 在 side effect 前 throw | Operation 已知 idempotent 時可能可以 |
| Mutation 後 result submission failed | 通常不可;先 reconcile state |
| 收到完整 Pedelec response 前的 ambiguous provider command/transport timeout | 可以 exact retry;Core 會 join 或 replay 同一 logical invocation |
已收到正式 TOOL_TIMEOUT |
不要當成 in-flight retry;先 reconcile 可能的 side effect |
| Stale UI lifecycle | 不可;agent 應先讀 current state |
需要安全 retry 的 tool 可加入 idempotency key 或 expected-version field。
Logging
Section titled “Logging”記錄足以診斷但不洩漏 secret 的 correlation data:
console.error("tool failed", { sessionId: ctx.sessionId, turnId: ctx.turnId, toolRequestId: ctx.toolRequestId, tool: ctx.tool, code: error.code,});Tool args 可能包含 private page/user data,不要預設完整 logging。
精確型別與 signature 請看 Tools API Reference。