串流回應
Pedelec 將 assistant output 分成兩個 callback:session.onChat() 接收完成的 logical assistant message;session.onChatDelta() 則在 Provider 提供真實增量串流時接收 best-effort incremental text。
不要把 delta 當成權威的完成回應。Provider 可能只提供完成訊息,也可能對同一份 logical output 同時提供 deltas 與 completed message。
Signature
Section titled “Signature”const offChat = session.onChat((text, ctx) => { // text 是一個完整的 logical assistant message // ctx.type === "chat_message"});
const offChatDelta = session.onChatDelta((delta, ctx) => { // delta 是一個 incremental fragment // ctx.type === "chat_delta"});type ChatEventContext = PedelecEventContext & { type: "chat_message"; turnId: string; turnStartedAt: number; eventReceivedAt: number;};
type ChatDeltaEventContext = PedelecEventContext & { type: "chat_delta"; turnId: string; turnStartedAt: number; eventReceivedAt: number;};Delta 可能只有幾個字元、標點、一個詞或更大的 chunk。Chunk boundary 沒有語意。Pedelec 會保留 Provider 傳來的 delta,不會因為後續 completed message 多了文字,就自行補出缺少的 suffix delta。
累積一個即時 response
Section titled “累積一個即時 response”如果 UI 要在 Provider 還在生成時就更新畫面,使用 onChatDelta():
let assistantText = "";
const offChatDelta = session.onChatDelta((delta) => { assistantText += delta; renderAssistantMessage(assistantText);});
await session.sendText("Explain this screen.");offChatDelta();不要每個 delta 都建立一個 message bubble。
// 錯誤:會產生大量極短訊息。session.onChatDelta((delta) => { messages.push({ role: "assistant", text: delta });});每個 turn 建立一個 live assistant message,再 append delta。
以完成訊息作為權威結果
Section titled “以完成訊息作為權威結果”如果應用程式需要 Provider 的完成語意輸出,直接訂閱 onChat():
session.onChat((text) => { saveCompletedAssistantMessage(text);});Delta delivery 是 best-effort,而且依 Provider 能力而定。不要把 completed message 與已累積 delta 的差異視為「漏掉、應該補發」的 delta。
依 turn 分組
Section titled “依 turn 分組”type AssistantMessage = { id: string; sessionId: string; turnId: string; text: string;};
const messages = new Map<string, AssistantMessage>();
session.onChatDelta((delta, ctx) => { const key = `${ctx.sessionId}:${ctx.turnId}`; const current = messages.get(key) ?? { id: key, sessionId: ctx.sessionId, turnId: ctx.turnId, text: "", };
current.text += delta; messages.set(key, current); renderMessages([...messages.values()]);});turnId 由 SDK 為一次已接受的 sendText() 或 prepare() lifecycle 產生;chat delta 只會顯示 user turn。請當 opaque ID:
- 不要解析其中 timestamp;
- 不要依賴 prefix;
- 不要當成 provider resume ID;
- 不要期待 page reload 後保留。
多 sessions
Section titled “多 sessions”即使 handler 已附著在特定 session,每個 callback 仍包含 ctx.sessionId,方便 generic store 與 logging。
session.onChatDelta((delta, ctx) => { transcriptStore.append(ctx.sessionId, ctx.turnId, delta);});
session.onChat((text, ctx) => { transcriptStore.commit(ctx.sessionId, ctx.turnId, text);});UI 切換 active session 時,仍要正確記錄非目前可見 session 的 delta,不要誤加到 selected transcript。
Timing fields
Section titled “Timing fields”sessionCreatedAt:browser-side session object 建立時間。turnStartedAt:SDK 接受 local turn 的時間。eventReceivedAt:SDK 從 Extension 收到 Core event 的時間。eventEmittedAt:SDK 建立 callback context 並送出 handler 的時間。
可用於 diagnostics 與 UI metrics,但只是 browser clock,不是 distributed tracing guarantee。
Rendering performance
Section titled “Rendering performance”Delta 很頻繁時可能造成過多 framework render。先確保 correctness,再視需要 batch:
let buffer = "";let scheduled = false;
session.onChatDelta((delta) => { buffer += delta; if (scheduled) return;
scheduled = true; requestAnimationFrame(() => { scheduled = false; renderAssistantMessage(buffer); });});如果 Provider 提供 completed message,onChat() 是校正最終 rendered text 的權威來源。sendText() completion 由相符的內部 operation completion 驅動,不由任一 chat callback 或單獨的 idle status 決定。
Unsubscribe 與 component cleanup
Section titled “Unsubscribe 與 component cleanup”每個 registration 都回傳 cleanup function:
const offChat = session.onChat(handleCompletedMessage);const offChatDelta = session.onChatDelta(handleDelta);
onComponentCleanup(() => { offChat(); offChatDelta();});Unsubscribe 只停止該 handler 的 callback,不會停止 provider turn 或 end session。
Component 重複 mount 卻不 cleanup,會造成 duplicate append 與 memory growth。
Error 與 completion boundary
Section titled “Error 與 completion boundary”onChat() 是 completed-message callback,但不會決定 sendText() 是否 resolve。Turn completion 依相符的 operation ID;status 與 error event 是可觀察狀態/diagnostic,operation_completed 才是語意 terminal。
失敗 turn 仍可能已輸出 partial deltas。產品需決定保留、標記 interrupted 或丟棄這份 live partial response。SDK contract 不會從 deltas 合成 completed message。
HTML 與 Markdown safety
Section titled “HTML 與 Markdown safety”Assistant messages 與 deltas 都是 provider 產生的 plain text。若將內容 render 成 Markdown 或 HTML,必須使用和其他 untrusted model output 相同的 sanitization 與 CSP。不要未經可信 sanitizer 直接放進 innerHTML。
下一頁:Session 狀態與 Events。