Skip to main content

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.
tokenunnamed eventdata: { "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_linkedpartial place fieldsMetadata 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.