跳到主要内容

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