Aller au contenu principal

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:PayloadMeaning
(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_linkedplace 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-alivecomment lineKeep-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:PayloadNotes
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.