跳至主要内容

SSE wire contract

AI chat endpoint 會串流傳送 Server-Sent Eventstext/event-stream)。 本頁記錄 POST /chat/control/stream 使用的 control-stream contract。 source of truth 是 @kaleidr/inference-ui 中的 parser + types (packages/inference-ui/src/control/sse.tstypes.ts)。 如果使用 kaleidr.js,chat bundle 會為您完成解析 — 只有建立 custom client 時 才需要此頁面。

/chat/summary/stream/chat/button/stream 使用不同的 SSE contract,本頁不涵蓋它們。不要在這些 endpoint 上重複使用 control-stream parser。

相容性規則

Client 必須忽略未知 event name。stable contract 中可以在不進行 version bump 的情況下加入新 event。下方 "diagnostic / experimental" 表中的 downstream event 不屬於 contract — official client 會忽略它們,而且它們可能消失。

穩定 events

Payload 是 control parser 所假設的格式。start 沒有 phase field (該欄位只出現在 phase event 中)。

event:PayloadMeaning
(unnamed){ text }增量 prose token。可能包含 [[Place]] marker。
phase{ type: "phase", phase, session_id }stream 前 lifecycle。
start{ type: "start", session_id, purpose? }Stream 已開啟。
place{ name, coordinates: { lat, lng }, address?, category?, source?, id? }已解析 place(merge-by-name → map pin)。source: "vendor" 表示此 place 來自 org 上傳的資料。
place_linkedplace fields + is_update?為已 emit 的 place 補充資訊。
early_actions{ type: "early_actions", actions: [ { type, payload } ], places_count?, is_partial? }完整 reply 前的 map action(fitBounds / route / highlight)。
prompt_options{ type: "prompt_options", schema_version, kind, question, allow_free_text, options: [ { label, send_text } ] }消歧選項 — 呈現為可點擊選項,並將對應的 send_text 作為下一則 user message 提交。
route_clear{}新 route 到達前清除所有 overlay。Stable.
route{ type: "route", schema_version, id?, profile, origin, destination, primary, alternatives[], comparison[], stops?, connectors?, color?, label? }以 journey 形式表達的 turn — engine-computed route,在 prose 前 emit,讓地圖能在回答 streaming 時繪製。
quota{ type: "quota", product, meter, tier, used, limit, reset_at, period }stream 中 meter — 顯示 remaining budget。
end{ type: "end", full_text, places[], actions[], question_type, response_time, total_tokens? }Terminal envelope — 完整結果。
error{ type: "error", message, code?, partial_text? }Terminal error。
: keep-alivecomment lineProxy keep-alive(~10s)。忽略。

已移除:grounding(2026-09-05)。Grounding 仍會影響回答,但 不會在 wire 上傳送 frame。

Diagnostic / experimental(non-contract)

這些是 emit 的 implementation detail。official client 會 忽略它們;不要依賴。

event:PayloadNotes
debug{ scope, … }內部 diagnostic。可能變更或消失。
place_name_found{ name, is_early? }Non-contract;official client 會忽略。

Tokens 與 structured data

Unnamed event 會 stream 一般 prose。當引用 place 時,可能包含 inline [[Place]] marker(例如 …cafes near [[Louvre]]…)— 可以移除以取得乾淨顯示,也可以完全忽略 prose,並使用 structured event 驅動 UI。

Structured data 以 event 形式到達,絕不內嵌在 prose 中。 Resolved place 會在 geocode 過程中透過 place(以及用於 late metadata 的 place_linked)stream; map action 透過 early_actions 到達;route 會在 route_clear 後透過 route 到達; authoritative final payload 是 end event。 典型 client 會在 place event 到達時呈現 pin,並將 end 視為 source of truth。

最小 client

const res = await fetch(`${API}/inference-api/b2b/v1/chat/control/stream`, {
method: 'POST',
headers: { 'X-Api-Key': key, 'Content-Type': 'application/json', Accept: 'text/event-stream' },
body: JSON.stringify({ messages: [{ role: 'user', content: 'cafes near the Louvre' }] }),
});
const reader = res.body.getReader();
// …decode chunks, split on \n\n, parse `event:` + `data:` lines
// IMPORTANT: ignore any unknown event name (forward-compat rule above).

request body 請參閱 Endpoints,failure handling 請參閱 Errors