Contrato wire SSE
Os endpoints de chat AI transmitem Server-Sent Events (text/event-stream).
Esta página documenta o contrato control-stream usado por
POST /chat/control/stream. A fonte de verdade é o parser + types em
@kaleidr/inference-ui (packages/inference-ui/src/control/sse.ts e
types.ts). Se você usa kaleidr.js, o bundle de chat faz o parse para você —
você só precisa desta página para criar um cliente personalizado.
/chat/summary/stream e /chat/button/stream usam contratos SSE
diferentes e não são abordados aqui. Não reutilize o parser control-stream
nesses endpoints.
Regra de compatibilidade
Clientes devem ignorar nomes de eventos desconhecidos. Novos eventos podem ser adicionados ao contrato estável sem alteração de versão. Eventos downstream documentados na tabela "diagnostic / experimental" abaixo não fazem parte do contrato — o cliente oficial os ignora e eles podem desaparecer.
Eventos estáveis
Os payloads correspondem ao que o control parser pressupõe. start não possui campo phase
(ele aparece apenas em eventos phase).
event: | Payload | Meaning |
|---|---|---|
| (unnamed) | { text } | Token incremental de texto. Pode conter marcadores [[Place]]. |
phase | { type: "phase", phase, session_id } | Ciclo de vida pré-stream. |
start | { type: "start", session_id, purpose? } | Stream aberto. |
place | { name, coordinates: { lat, lng }, address?, category?, source?, id? } | Local resolvido (merge-by-name → pin no mapa). source: "vendor" identifica um local vindo dos dados enviados pela organização. |
place_linked | place fields + is_update? | Enriquece um local já emitido. |
early_actions | { type: "early_actions", actions: [ { type, payload } ], places_count?, is_partial? } | Ações de mapa (fitBounds / route / highlight) antes da resposta completa. |
prompt_options | { type: "prompt_options", schema_version, kind, question, allow_free_text, options: [ { label, send_text } ] } | Opções de desambiguação — renderize como opções clic áveis e envie o send_text da opção como a próxima mensagem do usuário. |
route_clear | {} | Limpa todos os overlays antes da chegada de novas routes. Stable. |
route | { type: "route", schema_version, id?, profile, origin, destination, primary, alternatives[], comparison[], stops?, connectors?, color?, label? } | Turno formulado como trajeto — route calculada pelo engine, emitida antes do texto para que o mapa possa desenhar enquanto a resposta é transmitida. |
quota | { type: "quota", product, meter, tier, used, limit, reset_at, period } | Medidor durante o stream — exiba o orçamento restante. |
end | { type: "end", full_text, places[], actions[], question_type, response_time, total_tokens? } | Envelope terminal — resultado completo. |
error | { type: "error", message, code?, partial_text? } | Erro terminal. |
: keep-alive | comment line | Keep-alive do proxy (~10s). Ignore. |
Removido: grounding (2026-09-05). Grounding continua influenciando a resposta, mas
não coloca mais nenhum frame no wire.
Diagnóstico / experimental (fora do contrato)
Estes são detalhes de implementação emitidos. O cliente oficial os ignora; não dependa deles.
event: | Payload | Notes |
|---|---|---|
debug | { scope, … } | Diagnóstico interno. Pode mudar ou desaparecer. |
place_name_found | { name, is_early? } | Fora do contrato; o cliente oficial ignora. |
Tokens e dados estruturados
Eventos sem nome transmitem texto simples. Eles podem conter marcadores inline [[Place]]
onde um local é referenciado (por exemplo, …cafes near [[Louvre]]…) —
remova-os para uma exibição limpa, ou ignore completamente o texto e controle sua
UI pelos eventos estruturados.
Dados estruturados chegam como eventos, nunca inline no texto. Locais resolvidos
são transmitidos em place (e place_linked para metadata posterior) enquanto são
geocodificados; ações do mapa chegam em early_actions; routes chegam em route
após route_clear; o payload final autoritativo é o evento end.
Um cliente típico renderiza pins a partir de eventos place conforme chegam e
trata end como fonte de verdade.
Cliente mínimo
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).
Consulte Endpoints para request bodies e Errors para tratamento de falhas.