SSE wire contract
The AI chat endpoints stream Server-Sent Events (text/event-stream). This
page is the event reference; the source of truth is the parser + types in
@kaleidr/inference-ui (packages/inference-ui/src/control/sse.ts and
types.ts). If you use kaleidr.js, the chat bundle parses this for you — you
only need this page to build a custom client.
Events
event: | Payload (shape) | When |
|---|---|---|
start / phase | { type, phase, session_id } | Lifecycle — thinking / waiting phases. |
token | unnamed event — data: { "text": "…" } | Prose, streamed incrementally. May contain [[Place]] markers. |
place | { name, coordinates: { lat, lng }, address?, category?, … } | A resolved place (merge-by-name → a map pin). |
place_linked | partial place fields | Metadata enrichment of an already-emitted place. |
early_actions | { actions: [ { type, payload } ] } | Map actions (fitBounds / route / highlight) before the full reply. |
quota | { used, limit, tier, reset_at } | Mid-stream meter — surface remaining budget. |
grounding | { sources: [ { title, url, tier } ] } | Sources for a grounded answer (grounded turns only). |
end | { full_text, places: [], actions: [], … } | Terminal envelope — the complete result. |
error | { message } | Terminal error. |
A keep-alive comment line (: keep-alive) arrives every ~10s to hold the
connection open through proxies — ignore it.
Tokens and structured data
token events stream plain prose. They may carry inline [[Place]] markers
where a place is referenced (e.g. …cafes near [[Louvre]]…) — strip them for clean
display, or ignore the prose entirely and drive your UI from the structured events.
Structured data arrives as events, never inline in the prose. Resolved places
stream on place (and place_linked for late metadata) as they geocode; map actions
arrive on early_actions; the authoritative final payload is the end event
({ full_text, places, actions }). A typical client renders pins from place events
as they arrive and treats end as the source of truth.
Minimal 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…
See Endpoints for the request bodies, and Errors for failure handling.