Contrat wire SSE
Les endpoints de chat AI diffusent des Server-Sent Events (text/event-stream).
Cette page documente le contrat control-stream utilisé par
POST /chat/control/stream. La source de vérité est le parser + les types dans
@kaleidr/inference-ui (packages/inference-ui/src/control/sse.ts et
types.ts). Si vous utilisez kaleidr.js, le bundle chat l’analyse pour vous —
vous n’avez besoin de cette page que pour créer un client personnalisé.
/chat/summary/stream et /chat/button/stream utilisent des contrats SSE
différents et ne sont pas couverts ici. Ne réutilisez pas le parser control-stream
sur ces endpoints.
Règle de compatibilité
Les clients doivent ignorer les noms d’événements inconnus. De nouveaux événements peuvent être ajoutés au contrat stable sans changement de version. Les événements downstream documentés dans le tableau "diagnostic / experimental" ci-dessous ne font pas partie du contrat — le client officiel les ignore et ils peuvent disparaître.
Événements stables
Les payloads correspondent aux hypothèses du control parser. start n’a pas de champ phase
(celui-ci n’apparaît que sur les événements phase).
event: | Payload | Meaning |
|---|---|---|
| (unnamed) | { text } | Token de texte incrémental. Peut contenir des marqueurs [[Place]]. |
phase | { type: "phase", phase, session_id } | Cycle de vie avant le stream. |
start | { type: "start", session_id, purpose? } | Stream ouvert. |
place | { name, coordinates: { lat, lng }, address?, category?, source?, id? } | Lieu résolu (merge-by-name → pin de carte). source: "vendor" indique un lieu provenant des données importées par l’organisation. |
place_linked | place fields + is_update? | Enrichit un lieu déjà émis. |
early_actions | { type: "early_actions", actions: [ { type, payload } ], places_count?, is_partial? } | Actions de carte (fitBounds / route / highlight) avant la réponse complète. |
prompt_options | { type: "prompt_options", schema_version, kind, question, allow_free_text, options: [ { label, send_text } ] } | Options de désambiguïsation — affichez-les comme options cliquables et envoyez le send_text de l’option comme prochain message utilisateur. |
route_clear | {} | Efface tous les overlays avant l’arrivée de nouvelles routes. Stable. |
route | { type: "route", schema_version, id?, profile, origin, destination, primary, alternatives[], comparison[], stops?, connectors?, color?, label? } | Tour formulé comme trajet — route calculée par le moteur, émise avant le texte afin que la carte puisse se dessiner pendant le streaming. |
quota | { type: "quota", product, meter, tier, used, limit, reset_at, period } | Compteur pendant le stream — affichez le budget restant. |
end | { type: "end", full_text, places[], actions[], question_type, response_time, total_tokens? } | Envelope terminal — résultat complet. |
error | { type: "error", message, code?, partial_text? } | Erreur terminale. |
: keep-alive | comment line | Keep-alive proxy (~10s). Ignorer. |
Supprimé : grounding (2026-09-05). Grounding continue d’influencer la réponse mais
ne place plus de frame sur le wire.
Diagnostic / expérimental (hors contrat)
Ce sont des détails d’implémentation émis. Le client officiel les ignore ; ne vous appuyez pas dessus.
event: | Payload | Notes |
|---|---|---|
debug | { scope, … } | Diagnostic interne. Peut changer ou disparaître. |
place_name_found | { name, is_early? } | Hors contrat ; le client officiel l’ignore. |
Tokens et données structurées
Les événements sans nom diffusent du texte simple. Ils peuvent contenir des marqueurs inline [[Place]]
lorsqu’un lieu est référencé (par ex. …cafes near [[Louvre]]…) —
supprimez-les pour un affichage propre, ou ignorez entièrement le texte et pilotez votre
UI depuis les événements structurés.
Les données structurées arrivent sous forme d’événements, jamais inline dans le texte. Les lieux
résolus sont diffusés sur place (et place_linked pour les métadonnées tardives) à mesure qu’ils
sont géocodés ; les actions de carte arrivent sur early_actions ; les routes sur route
après un route_clear ; le payload final faisant autorité est l’événement end.
Un client type affiche les pins à partir des événements place à mesure qu’ils arrivent et
traite end comme source de vérité.
Client minimal
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).
Consultez Endpoints pour les request bodies et Errors pour la gestion des échecs.