Aller au contenu principal

Contrat du protocole SSE

POST /chat/control/stream répond au moyen des événements envoyés par le serveur (text/event-stream) : une réponse persistante qui transmet le texte au fur et à mesure de sa rédaction, ainsi que des événements structurés représentant les lieux, les actions cartographiques et les itinéraires.

Cette page définit le contrat de ce flux. Si vous utilisez kaleidr.js, le panneau de discussion lit le flux à votre place et vous n’avez pas besoin de cette page. Consultez-la lorsque vous créez votre propre client. Des clients opérationnels en Node et Python figurent dans Lecture du flux ; le corps de la requête est décrit dans Points de terminaison.

/chat/summary/stream et /chat/button/stream utilisent le même format de trame, avec un ensemble réduit d’événements. Ils sont décrits à la fin de cette page.

Avant le début du flux​

Une requête refusée ne devient jamais un flux. Les échecs d’authentification, de portée d’accès, de quota, de limitation de débit, de validation ou de taille produisent une réponse HTTP ordinaire avec un corps JSON et un statut 4xx (Erreurs). Vérifiez d’abord le statut et interprétez le corps comme du SSE uniquement lorsqu’il vaut 200.

La requête est limitée à 400 messages, 64 000 caractères par message et 200 000 caractères pour l’ensemble des messages. Le dépassement de l’une de ces limites renvoie un code 422, par exemple conversation_too_long, tandis qu’un corps de plus de 2 Mio renvoie un 413. La liste complète figure dans Points de terminaison.

Une réponse réussie contient ces en-têtes :

HTTP/1.1 200 OK
Content-Type: text/event-stream; charset=utf-8
Cache-Control: no-cache, no-transform

Format des trames​

Une trame comporte une ou deux lignes, suivies d’une ligne vide. Les lignes se terminent par \n.

event: place
data: {"name": "Louvre Museum", "coordinates": {"lat": 48.8606, "lng": 2.3376}}

data: {"text": "The Louvre sits on the right bank"}

: keep-alive

  • Une trame nommée comporte une ligne event: suivie d’une ligne data:.
  • Une trame de texte comporte uniquement une ligne data: et aucune ligne event:.
  • Un commentaire commence par deux-points. Kaleidr envoie : keep-alive comme signal de maintien de connexion. Il ne contient pas de données.
  • data: contient toujours un objet JSON complet sur une seule ligne. Le texte est encodé en UTF-8.

Les fragments réseau ne correspondent pas nécessairement aux trames. Une seule lecture peut recevoir une demi-trame ou plusieurs. Mettez en mémoire tampon les données reçues, séparez-les aux sauts de ligne et ne traitez une trame qu’après avoir atteint sa ligne vide.

Règle de compatibilité​

Ignorez les noms d’événements inconnus et les champs que vous n’utilisez pas. De nouveaux événements et champs peuvent être ajoutés sans changement de version. Un client qui échoue à la réception d’un événement inconnu ne fonctionnera plus.

Événements stables​

event:Charge utileSignification
(sans nom){ text }Prochain fragment du texte de la réponse. Ajoutez-le au texte existant. Peut contenir des marqueurs [[Name]] autour des noms de lieux.
phase{ type: "phase", phase: "thinking", session_id }La requête est acceptée et le traitement a commencé. phase vaut toujours "thinking".
start{ type: "start", session_id, purpose: "control" }La transmission du texte va commencer.
place{ name, coordinates?: { lat, lng }, address?, category?, icon?, source?, id?, unverified? }Un lieu mentionné dans la réponse. Regroupez par name ; les premières coordonnées reçues pour un nom sont définitives. source: "vendor" désigne un lieu issu des données de votre organisation et source: "map" un lieu déjà visible sur la carte publiée.
place_linkedchamps du lieu avec is_update?Détails supplémentaires d’un lieu déjà envoyé. Fusionnez-les avec le lieu portant le même name ; ignorez-les si vous ne l’avez pas reçu.
early_actions{ type: "early_actions", actions: [ { type, payload } ], places_count, is_partial: true }Actions cartographiques applicables avant la fin de la réponse, envoyées dès qu’au moins deux lieux ont des coordonnées.
prompt_options{ type: "prompt_options", schema_version, kind, question, allow_free_text, options: [ { label, send_text } ] }Question à choix envoyée lorsque la requête est ambiguë. Affichez les options et envoyez le send_text choisi comme prochain message utilisateur.
route_clear{}Effacez les itinéraires tracés. De nouveaux itinéraires suivent.
route{ type: "route", schema_version, id?, profile, origin, destination, primary, alternatives[], comparison[], stops?, color?, label?, transit?, attribution? }Itinéraire calculé, envoyé avant le texte lors d’une question de guidage pour que la carte puisse se dessiner pendant la transmission.
end{ type: "end", full_text, places[], actions[], question_type, response_time, total_tokens?, dropped_places? }La réponse est terminée. Ce résultat fait autorité.
error{ type: "error", message, code?, partial_text }La réponse a échoué. Envoyé à la place de end.
quota{ type: "quota", product, meter, tier, used, limit, reset_at, period } avec une clé de serveur ; { type: "quota", meter, reset_at } avec un jeton de sessionConsommation de crédits IA de votre organisation après facturation de cet appel. Dernier événement du flux, après end ou error. Voir quota.
: keep-aliveligne de commentaireSignal envoyé après 10 secondes de silence. Ignorez-le, mais comptabilisez-le comme une activité.

Supprimé : grounding (2026-09-05). Il n’est plus envoyé.

Fiches et couches de données en direct​

Une question portant sur des faits mesurés ou en direct peut ajouter l’un de ces événements. Une fiche arrive avant le texte ; une couche peut arriver pendant ou après. Ils sont complémentaires : affichez ceux que vous prenez en charge et ignorez les autres. D’autres champs pourront être ajoutés.

event:Charge utileUtilisation
weather_cardobjet contenant lat, lng, name, les températures (temp_c, temp_f), conditions et éventuellement forecast[]Météo actuelle en un lieu.
weather_layerobjet contenant layer, tile_path_template, tile_size, max_zoom, scope, attributionCouche de température couvrant une région.
satellite_cardobjet contenant name, norad_id, lat, lng, altitude_km, velocity_kms, observed_atPosition d’un satellite nommé.
constellation_layerobjet contenant group, features[] de { name, norad_id, lat, lng } et éventuellement trackSatellites voisins de celui présenté sur la fiche.
building_cardobjet contenant lat, lng, éventuellement name, height_m, num_floorsDonnées sur un bâtiment.
trees_cardobjet contenant lat, lng, count, radius_mArbres recensés autour d’un point.
heritage_cardobjet contenant lat, lng, count, sites[]Sites patrimoniaux autour d’un point.
rail_cardobjet contenant lat, lng, lines[] et éventuellement nearest_stationLignes ferroviaires proches d’un point.
arrivals_cardobjet contenant lat, lng, stop, departures[], alerts[], attributionProchains départs des transports en commun à un arrêt.
vehicles_layerobjet contenant operator, vehicles[], shapes[], attributionPositions des véhicules de transport en commun pour l’arrêt ou la ligne de la fiche.
streetview_cardobjet contenant lat, lng, image_id, image_lat, image_lngImages au niveau de la rue près d’un lieu.

Lorsqu’ils sont envoyés, end reprend cinq de ces éléments sous le même nom, afin qu’un client ayant manqué l’événement puisse toujours les lire : weather_card, satellite_card, constellation_layer, weather_layer et vehicles_layer (par exemple end.weather_card). Les autres fiches ne sont pas reprises dans end. Les listes d’événements en direct ne sont pas disponibles via l’API de la plateforme : voir Licences des données.

Diagnostic et expérimentation (hors contrat)​

Ces éléments peuvent apparaître dans le flux. Ils ne font pas partie du contrat : ne vous appuyez pas dessus.

event:Charge utileRemarques
debug{ scope, … }Diagnostic interne. Absent des requêtes normales.
place_name_found{ name, is_early }Indice précoce indiquant qu’un nom de lieu a été mentionné. Utilisez l’événement place qui suit.

Ordre des événements​

Un flux passe par les étapes suivantes. Les étapes marquées facultatives ne figurent pas dans tous les flux.

  1. Facultatif. Événements place avec source: "vendor" : jusqu’à trois lieux provenant des données de votre organisation lorsque la clé dispose de la portée vendor. Ils sont envoyés en premier pour permettre à la carte de les afficher immédiatement.
  2. phase. Toujours le premier événement de la réponse elle-même.
  3. Facultatif. Commentaires : keep-alive pendant la préparation de la réponse.
  4. Facultatif. Événements précédant le texte : prompt_options, ou route_clear suivi de route, ainsi qu’une fiche.
  5. start.
  6. Trames de texte entrecoupées de place, place_linked, early_actions et parfois de route_clear, route et d’événements de couches. Les signaux de maintien de connexion couvrent les périodes de silence.
  7. Facultatif. Événements tardifs place, place_linked, de couches et d’itinéraires une fois le texte terminé.
  8. end ou error.
  9. Facultatif. quota.
  10. Le serveur ferme la connexion.

Deux conséquences pour votre client :

  • end n’est pas le dernier événement. Continuez la lecture jusqu’à la fermeture du corps de réponse, sinon vous manquerez quota.
  • Un flux peut se fermer sans end ni error, notamment en cas de rupture réseau. Considérez comme ayant échoué tout flux fermé sans événement terminal.

Détails des charges utiles​

Texte et marqueurs​

Les trames de texte ne contiennent que du texte ; les données structurées ne se trouvent jamais dans le texte. Celui-ci peut contenir des marqueurs à doubles crochets autour des noms de lieux, par exemple near [[Louvre Museum]], que le panneau de discussion transforme en liens vers les repères. Pour un affichage simple, retirez les crochets et conservez le nom.

place​

ChampTypeRemarques
namestringClé utilisée pour fusionner les données.
coordinatesobject { lat, lng }Degrés décimaux. Peut être absent. Un lieu nommé mais non localisé est envoyé sans coordonnées avec unverified: true. Ne placez aucun repère.
addressstringFacultatif.
categorystringFacultatif.
iconstringFacultatif. Un émoji représentant le lieu.
sourcestringFacultatif. "vendor" indique un lieu tiré des données de votre organisation. "map" désigne un lieu déjà représenté sur la carte publiée : le panneau ne crée pas de repère supplémentaire, puisque la carte le fait déjà.
idstringFacultatif. Présent pour les lieux issus de vos données.
unverifiedbooleanFacultatif. true si l’emplacement du lieu n’a pas été confirmé.

Un lieu peut comporter d’autres champs. Ignorez ceux que vous n’utilisez pas.

Le même nom peut être envoyé plusieurs fois : d’abord avec des coordonnées, puis avec davantage de détails. Conservez une seule entrée par nom, ne déplacez jamais un repère dès lors qu’il possède des coordonnées et laissez les événements suivants compléter les autres champs.

Actions​

early_actions.actions et end.actions sont des listes de { type, payload }.

Type d’actionCharge utileAction à effectuer
map.fitBounds{ coordinates: [[lng, lat], …], padding, maxZoom, duration }Cadrez la caméra sur les coordonnées.
places.highlight{ places: [ { name, lat, lng } ], options }Mettez ces lieux en évidence.
map.showRoute{ id, label, profile, coordinates: [[lng, lat], …], distance_m, duration_s, turn_by_turn[], transit?, attribution? }Tracez la ligne et affichez son attribution.
route.clear{ id? }Supprimez l’itinéraire avec cet id, ou tous les itinéraires si aucun id n’est donné.

D’autres types d’actions peuvent apparaître. Ignorez ceux que vous ne gérez pas. Notez les deux formats de coordonnées : un lieu possède coordinates: { lat, lng }, tandis qu’une ligne est une liste de paires [lng, lat].

route​

primary contient la ligne à tracer : { coordinates: [[lng, lat], …], distance_m, duration_s, turn_by_turn[] }. Chaque étape de turn_by_turn possède text et peut aussi contenir direction_type, distance_m, duration_s, lat et lng. origin et destination possèdent chacun un label. alternatives[] contient d’autres lignes avec un route_id et comparison[] indique le delta_duration_s de chaque alternative par rapport à l’itinéraire principal. Lorsqu’il est présent, stops[] contient des points ordonnés { lat, lng, name } d’un itinéraire à plusieurs arrêts.

Un itinéraire routier comporte attribution: { text, url, license }. Affichez text sous forme de lien vers url partout où vous tracez l’itinéraire. Pour les transports en commun, la mention de l’opérateur se trouve plutôt dans transit.

Chaque événement route possède un id. Tracer un itinéraire avec un id déjà existant remplace cet itinéraire.

end​

ChampTypeRemarques
full_textstringRéponse intégrale. Préférez-la aux trames de texte concaténées.
placesarrayListe définitive et ordonnée des lieux. Fusionnez-la par nom avec les lieux collectés.
actionsarrayActions finales sur la carte. Appliquez-les : elles remplacent early_actions.
dropped_placesarray of stringsFacultatif. Noms envoyés plus tôt mais exclus de la réponse finale. Supprimez leurs repères.
question_typestringÉtiquette indiquant le type de question, à titre informatif.
response_timenumberDurée de la réponse en secondes.
total_tokensnumberFacultatif. Nombre de jetons utilisés, servant au calcul de la facturation.

error​

event: error
data: {"type": "error", "code": "upstream_stall", "message": "The AI service stopped responding. Please try again.", "partial_text": "The Louvre sits"}

message peut être présenté à l’utilisateur. partial_text correspond au texte généré avant l’échec. code n’apparaît que dans un seul cas :

CascodeAction à effectuer
La réponse a cessé de progresser ou le flux a atteint sa taille maximale"upstream_stall"Proposez une nouvelle tentative.
Tout autre échec pendant la réponseabsentAffichez message ; une nouvelle tentative peut réussir.

Après error, aucun événement end n’est envoyé. Un événement quota peut encore suivre.

quota​

Les champs dépendent du type d’identifiant ayant ouvert le flux.

ChampTypeClé de serveur ou ancienne cléJeton de session
typechaîne, "quota"OuiOui
meterchaîneOuiOui
reset_atchaîne, ISO 8601 avec décalageOuiOui
productchaîneOuiNon
periodchaîneOuiNon
tierchaîneOuiNon
usednombreOuiNon
limitnombreOuiNon

Le jeton de session est utilisé par les visiteurs d’une page : il est obtenu à partir d’une clé publiable ou d’une session de visiteur pour une carte publiée. Son événement quota indique la date de réinitialisation de la période sans révéler le forfait, l’utilisation ni la limite de l’organisation. Un client navigateur ne doit pas s’attendre à recevoir used ou limit. La même règle s’applique au corps de la réponse 429 quota_exceeded : voir Quotas et limites de débit.

Maintien de connexion et délais d’expiration​

ComportementValeurAction du client
Signal de maintien du flux de discussionUn commentaire : keep-alive après 10 secondes sans autre sortieRéinitialisez le compteur d’inactivité dès la réception d’octets, y compris les commentaires.
Connexion inactiveUne connexion silencieuse pendant environ une minute peut être fermée pendant le transportFixez un délai d’inactivité (lecture) de 30 à 60 secondes. Évitez un délai global trop court.
Délai avant le premier textePeut prendre plusieurs dizaines de secondes pour une question difficileAffichez la progression dès phase ; ne considérez pas l’attente comme un échec.
Durée maximale du fluxEnviron 10 minutes, puis le serveur envoie error avec upstream_stallFixez un délai global légèrement supérieur à 10 minutes en dernier recours.

Interruption d’un flux et facturation​

Fermez la connexion pour interrompre le flux. Le serveur le détecte en une dizaine de secondes et arrête la réponse.

  • Un flux qui se termine normalement est facturé selon le nombre de jetons utilisés, indiqué dans end.total_tokens.
  • Un flux interrompu ou en échec avant la fin est facturé sur une estimation, au moins égale à la taille de la conversation envoyée dans la requête, ou calculée d’après le texte déjà transmis. De ce fait, le montant peut dépasser la réservation effectuée à l’admission : fermer la connexion dès la première trame ne rend pas gratuite une longue conversation.
  • Les lieux issus de vos propres données (source: "vendor") n’entrent pas dans le calcul.

Une nouvelle tentative constitue une nouvelle requête, facturée à nouveau. Voir Quotas et limites de débit.

Flux de résumés et de boutons​

Ces deux points de terminaison alimentent la fiche d’un lieu dans Kaleidr Chat. Ils utilisent le même format de trame, les mêmes trames de texte sans nom et le même événement quota final. Ils diffèrent du flux de discussion sur trois points : aucun événement phase, aucun événement de lieu ou d’action, et aucun signal de maintien de connexion. Utilisez un délai d’inactivité de 60 secondes.

Les deux points de terminaison refusent un champ trop long avant le début du flux avec le statut 422 et le code field_too_long, et ignorent les champs non répertoriés : voir Points de terminaison. Si l’un de ces flux est interrompu ou échoue, sa facturation repose sur une estimation du texte déjà transmis et ne dépasse jamais le montant réservé.

POST /chat/summary/stream, pour un lieu :

  1. Facultatif. address avec la charge utile { type: "address", address, source }
  2. start avec la charge utile { type: "start", poi_type }
  3. Facultatif, parfois répété. url avec la charge utile { type: "url", website, source }
  4. Trames de texte avec la charge utile { text }
  5. end avec la charge utile { type: "end", full_text, summary, poi_type, category, city, country, sources[], website?, total_tokens? }, ou error avec la charge utile { type: "error", message, partial_text }
  6. Facultatif. quota

POST /chat/summary/stream, pour un bâtiment (type: "building") :

  1. start avec la charge utile { type: "start", address }
  2. Trames de texte
  3. end avec la charge utile { type: "end", full_text, parsed, total_tokens? }, ou error
  4. Facultatif. quota

POST /chat/button/stream:

  1. start avec la charge utile { type: "start", query_type }
  2. Trames de texte
  3. end avec la charge utile { type: "end", full_text, reply, query_type, first_token_ms, total_ms, total_tokens? }
  4. Facultatif. quota

Le flux des boutons ne possède pas d’événement error. S’il échoue après avoir commencé, la connexion se ferme sans end. Un échec survenant avant son démarrage renvoie un statut HTTP 500 avec {"detail": "Button chat stream error"}.

POST /spot/overview/stream envoie les trames du résumé de lieu décrit ci-dessus, précédées d’une trame place contenant { type: "place", name } : le nom complet du lieu ou de la région décrits, par exemple "Springfield, Ohio, United States of America", pour l’étiqueter ou le copier. Elle arrive avant toute autre trame et peut être absente. Ce n’est pas l’événement place du flux de chat et elle ne porte aucune coordonnée. Si un ref ne peut être décrit, une seule trame error contenant { type: "error", message, ref } remplace le résumé. Voir Points de terminaison.

Voir aussi​