Zum Hauptinhalt springen

SSE-Protokollvertrag

POST /chat/control/stream antwortet mit Server-Sent Events (text/event-stream): einer langlebigen Verbindung, die den Antworttext während seiner Entstehung sowie strukturierte Ereignisse zu Orten, Kartenaktionen und Routen überträgt.

Diese Seite beschreibt den Vertrag für diesen Stream. Bei Verwendung von kaleidr.js liest das Chatfenster den Stream selbst; dann benötigen Sie diese Seite nicht. Lesen Sie sie, wenn Sie einen eigenen Client entwickeln. Funktionsfähige Clients für Node und Python finden Sie unter Stream lesen. Der Anfragekörper ist unter Endpunkte beschrieben.

/chat/summary/stream und /chat/button/stream verwenden dasselbe Frame-Format, jedoch mit weniger Ereignistypen. Sie werden am Ende dieser Seite beschrieben.

Vor dem Beginn des Streams​

Eine abgelehnte Anfrage wird nie zu einem Stream. Fehler bei Authentifizierung, Berechtigungen, Kontingent, Ratenbegrenzung, Validierung oder Größe ergeben eine reguläre HTTP-Antwort mit JSON-Körper und 4xx-Status (Fehler). Prüfen Sie zuerst den Status und interpretieren Sie den Körper nur bei 200 als SSE.

Die Anfrage unterliegt Größenbeschränkungen: maximal 400 Nachrichten, 64.000 Zeichen je Nachricht und insgesamt 200.000 Zeichen über alle Nachrichten hinweg. Bei Überschreitung folgt der Status 422 mit einem Code wie conversation_too_long; für einen Anfragekörper über 2 MiB gilt 413. Die vollständige Liste steht unter Endpunkte.

Eine erfolgreiche Antwort hat folgende Header:

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

Frame-Format​

Ein Frame besteht aus einer oder zwei Zeilen, gefolgt von einer Leerzeile. Jede Zeile endet mit \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

  • Ein benanntes Frame enthält eine event:-Zeile und danach eine data:-Zeile.
  • Ein Text-Frame enthält nur eine data:-Zeile und keine event:-Zeile.
  • Ein Kommentar beginnt mit einem Doppelpunkt. Kaleidr sendet : keep-alive als Lebenszeichen; es enthält keine Daten.
  • data: enthält immer ein vollständiges JSON-Objekt in genau einer Zeile. Der Text ist UTF-8-kodiert.

Netzwerkpakete stimmen nicht notwendigerweise mit Frame-Grenzen überein. Ein Lesevorgang kann ein halbes Frame oder mehrere Frames enthalten. Puffern Sie die empfangenen Daten, trennen Sie sie an Zeilenumbrüchen und verarbeiten Sie ein Frame erst, wenn seine abschließende Leerzeile vorliegt.

Kompatibilitätsregel​

Ignorieren Sie unbekannte Ereignisnamen und nicht verwendete Felder. Neue Ereignisse und Felder können ohne Versionswechsel zum Vertrag hinzukommen. Ein Client, der bei einem unbekannten Ereignis abbricht, wird dadurch unbrauchbar.

Stabile Ereignisse​

event:NutzdatenBedeutung
(unbenannt){ text }Nächster Teil des Antworttextes. Hängen Sie ihn an den bestehenden Text an. Kann [[Name]]-Markierungen um Ortsnamen enthalten.
phase{ type: "phase", phase: "thinking", session_id }Die Anfrage wurde angenommen und die Verarbeitung hat begonnen. phase ist immer "thinking".
start{ type: "start", session_id, purpose: "control" }Der Antworttext wird gleich übertragen.
place{ name, coordinates?: { lat, lng }, address?, category?, icon?, source?, id?, unverified? }Ein Ort aus der Antwort. Führen Sie Einträge nach name zusammen; die ersten für einen Namen empfangenen Koordinaten sind endgültig. source: "vendor" kennzeichnet einen Ort aus Organisationsdaten, source: "map" einen Ort, den die veröffentlichte Karte bereits zeigt.
place_linkedOrtsfelder sowie is_update?Zusätzliche Details zu einem bereits gesendeten Ort. Führen Sie sie mit dem Datensatz desselben name zusammen; ignorieren Sie sie, wenn der Ort noch nicht bekannt ist.
early_actions{ type: "early_actions", actions: [ { type, payload } ], places_count, is_partial: true }Kartenaktionen, die schon vor dem Ende der Antwort anwendbar sind; werden gesendet, sobald mindestens zwei Orte Koordinaten besitzen.
prompt_options{ type: "prompt_options", schema_version, kind, question, allow_free_text, options: [ { label, send_text } ] }Auswahlfrage bei einer mehrdeutigen Anfrage. Zeigen Sie die Optionen an und senden Sie den gewählten Wert send_text als nächste Nutzernachricht.
route_clear{}Entfernen Sie die gezeichneten Routen. Neue Routen folgen.
route{ type: "route", schema_version, id?, profile, origin, destination, primary, alternatives[], comparison[], stops?, color?, label?, transit?, attribution? }Berechnete Route. Bei Wegbeschreibungen kommt sie vor dem Antworttext, damit die Karte während der Textübertragung zeichnen kann.
end{ type: "end", full_text, places[], actions[], question_type, response_time, total_tokens?, dropped_places? }Die Antwort ist vollständig. Dies ist das maßgebliche Ergebnis.
error{ type: "error", message, code?, partial_text }Die Antwort ist fehlgeschlagen. Wird statt end gesendet.
quota{ type: "quota", product, meter, tier, used, limit, reset_at, period } mit Serverschlüssel; { type: "quota", meter, reset_at } mit SitzungstokenKI-Guthabenverbrauch der Organisation nach Abrechnung dieses Aufrufs. Letztes Streamereignis nach end oder error. Siehe quota.
: keep-aliveKommentarzeileLebenszeichen nach zehn Sekunden ohne Ausgabe. Ignorieren Sie den Inhalt, aber behandeln Sie ihn als Aktivität.

Entfernt: grounding (2026-09-05). Es wird nicht mehr gesendet.

Live-Datenkarten und Ebenen​

Eine Frage nach aktuellen oder gemessenen Fakten kann zusätzliche Ereignisse dieser Art auslösen. Eine Karte trifft vor dem Antworttext ein, eine Ebene währenddessen oder danach. Die Ereignisse sind ergänzend: Stellen Sie unterstützte Inhalte dar und ignorieren Sie den Rest. Weitere Felder können später hinzukommen.

event:NutzdatenZweck
weather_cardObjekt mit lat, lng, name, Temperaturen (temp_c, temp_f), conditions, optional forecast[]Aktuelles Wetter an einem Ort.
weather_layerObjekt mit layer, tile_path_template, tile_size, max_zoom, scope, attributionTemperaturüberlagerung für eine Region.
satellite_cardObjekt mit name, norad_id, lat, lng, altitude_km, velocity_kms, observed_atPosition eines benannten Satelliten.
constellation_layerObjekt mit group, features[] aus { name, norad_id, lat, lng }, optional trackSatelliten in der Umgebung des Satelliten auf der Karte.
building_cardObjekt mit lat, lng, optional name, height_m, num_floorsAngaben zu einem Gebäude.
trees_cardObjekt mit lat, lng, count, radius_mErfasste Bäume um einen Punkt.
heritage_cardObjekt mit lat, lng, count, sites[]Denkmäler und Kulturstätten um einen Punkt.
rail_cardObjekt mit lat, lng, lines[], optional nearest_stationBahnlinien um einen Punkt.
arrivals_cardObjekt mit lat, lng, stop, departures[], alerts[], attributionÖPNV-Abfahrten an einer Haltestelle.
vehicles_layerObjekt mit operator, vehicles[], shapes[], attributionPositionen von ÖPNV-Fahrzeugen an der Haltestelle oder Linie der Karte.
streetview_cardObjekt mit lat, lng, image_id, image_lat, image_lngStraßenansichten in der Nähe eines Ortes.

end wiederholt bei deren Auftreten fünf dieser Elemente unter demselben Namen, damit ein Client sie auch nach einem verpassten Ereignis noch lesen kann: weather_card, satellite_card, constellation_layer, weather_layer und vehicles_layer (beispielsweise end.weather_card). Andere Karten werden in end nicht wiederholt. Live-Veranstaltungslisten stehen nicht über die Plattform-API bereit; siehe Datenlizenzen.

Diagnose und experimentelle Ereignisse (nicht vertraglich)​

Diese Ereignisse können im Datenstrom erscheinen. Sie gehören nicht zum Vertrag; verlassen Sie sich nicht darauf.

event:NutzdatenHinweise
debug{ scope, … }Interne Diagnose. Bei normalen Anfragen nicht vorhanden.
place_name_found{ name, is_early }Früher Hinweis, dass ein Ortsname erwähnt wurde. Verwenden Sie das danach folgende place-Ereignis.

Ereignisreihenfolge​

Ein Stream durchläuft die folgenden Phasen. Als optional markierte Phasen treten nicht in jedem Stream auf.

  1. Optional. place-Ereignisse mit source: "vendor": bis zu drei Orte aus den eigenen Daten Ihrer Organisation, wenn der Schlüssel die Berechtigung vendor besitzt. Sie werden zuerst gesendet, damit die Karte sie sofort darstellen kann.
  2. phase. Immer das erste Ereignis der eigentlichen Antwort.
  3. Optional. : keep-alive-Kommentare während der Antwortvorbereitung.
  4. Optional. Ereignisse vor dem Text: prompt_options oder route_clear, gefolgt von route und einer Karte.
  5. start.
  6. Text-Frames, durchsetzt mit place, place_linked, early_actions und mitunter route_clear, route sowie Ebenenereignissen. Keepalives überbrücken stille Zeiträume.
  7. Optional. Späte place-, place_linked-, Ebenen- und Routenereignisse nach Abschluss des Textes.
  8. end oder error.
  9. Optional. quota.
  10. Der Server schließt die Verbindung.

Für Clients hat dies zwei Konsequenzen:

  • end ist nicht das letzte Ereignis. Lesen Sie bis zum Schließen des Antwortkörpers weiter, sonst verpassen Sie quota.
  • Ein Stream kann ohne end und ohne error schließen, zum Beispiel bei einem Netzwerkausfall. Behandeln Sie einen solchen Stream ohne Abschlussereignis als fehlgeschlagen.

Einzelheiten der Nutzdaten​

Text und Markierungen​

Text-Frames enthalten ausschließlich Text; strukturierte Daten kommen nicht innerhalb des Fließtextes an. Der Text kann Ortsnamen in doppelten eckigen Klammern markieren, beispielsweise near [[Louvre Museum]]. Das Chatfenster wandelt diese Markierungen in Links zu Kartenmarkern um. Entfernen Sie für die Klartextanzeige die Klammern, nicht aber den Namen.

place​

FeldTypHinweise
namestringSchlüssel für die Zusammenführung.
coordinatesobject { lat, lng }Dezimalgrad. Kann fehlen. Ein nicht lokalisierbarer Ort wird ohne Koordinaten mit unverified: true gesendet. Zeichnen Sie dann keinen Marker.
addressstringOptional.
categorystringOptional.
iconstringOptional. Ein Emoji für den Ort.
sourcestringOptional. "vendor" steht für Orte aus eigenen Organisationsdaten. "map" bezeichnet einen Ort, den die gerade betrachtete veröffentlichte Karte schon zeigt; das Chatfenster fügt deshalb keinen eigenen Marker hinzu.
idstringOptional. Bei Orten aus eigenen Daten vorhanden.
unverifiedbooleanOptional. true, wenn die Position nicht bestätigt ist.

Ein Ort kann weitere Felder enthalten. Ignorieren Sie nicht benötigte Felder.

Derselbe Name kann mehrfach eintreffen: erst mit Koordinaten, später mit weiteren Details. Führen Sie pro Namen einen Datensatz, verschieben Sie einen Marker nach Erhalt seiner Koordinaten nicht mehr und ergänzen Sie anhand späterer Ereignisse die übrigen Felder.

Aktionen​

early_actions.actions und end.actions sind Listen aus { type, payload }.

AktionstypNutzdatenVerarbeitung
map.fitBounds{ coordinates: [[lng, lat], …], padding, maxZoom, duration }Passen Sie die Kartenansicht an die Koordinaten an.
places.highlight{ places: [ { name, lat, lng } ], options }Heben Sie diese Orte hervor.
map.showRoute{ id, label, profile, coordinates: [[lng, lat], …], distance_m, duration_s, turn_by_turn[], transit?, attribution? }Zeichnen Sie die Linie und zeigen Sie attribution an.
route.clear{ id? }Entfernen Sie die Route mit dieser id oder alle Routen, wenn keine id angegeben ist.

Es können weitere Aktionstypen auftreten. Überspringen Sie Typen, die Sie nicht verarbeiten. Beachten Sie die zwei Koordinatenformate: Ein Ort enthält coordinates: { lat, lng }, eine Linie besteht dagegen aus [lng, lat]-Paaren.

route​

primary enthält die zu zeichnende Linie: { coordinates: [[lng, lat], …], distance_m, duration_s, turn_by_turn[] }. Jeder Schritt in turn_by_turn enthält text und gegebenenfalls direction_type, distance_m, duration_s, lat und lng. origin und destination haben jeweils ein label. alternatives[] enthält weitere Linien mit route_id; comparison[] nennt für jede Alternative deren delta_duration_s gegenüber der Hauptroute. Falls vorhanden, enthält stops[] geordnete Punkte { lat, lng, name } einer Route mit mehreren Zwischenstopps.

Eine Straßenroute enthält attribution: { text, url, license }. Zeigen Sie beim Zeichnen der Route text mit einem Link zu url an. Bei einer ÖPNV-Route steht der Hinweis auf den Betreiber dagegen unter transit.

Jedes route-Ereignis besitzt eine id. Wird eine Route mit einer bereits vorhandenen id gezeichnet, ersetzt sie die bisherige Route.

end​

FeldTypHinweise
full_textstringVollständige Antwort. Verwenden Sie sie bevorzugt statt aneinandergereihter Text-Frames.
placesarrayEndgültige Ortsliste in Reihenfolge. Führen Sie sie nach Namen mit den gesammelten Orten zusammen.
actionsarrayEndgültige Kartenaktionen. Wenden Sie sie an; sie ersetzen early_actions.
dropped_placesarray of stringsOptional. Früher gesendete Namen, die nicht mehr zur finalen Antwort gehören. Entfernen Sie die zugehörigen Marker.
question_typestringBeschreibende Kennzeichnung des Fragetyps. Rein informativ.
response_timenumberAntwortdauer in Sekunden.
total_tokensnumberOptional. Anzahl verwendeter Tokens, nach der abgerechnet wird.

error​

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

message kann den Nutzern direkt angezeigt werden. partial_text ist der Text, der vor dem Fehler entstand. code wird nur in einem Fall übermittelt:

FallcodeVorgehen
Die Antwort kam nicht weiter oder der Stream erreichte seine maximale Länge"upstream_stall"Bieten Sie einen erneuten Versuch an.
Sonstiger Fehler während der Antwortnicht vorhandenZeigen Sie message an; ein erneuter Versuch kann erfolgreich sein.

Nach error folgt kein end; ein quota-Ereignis kann jedoch noch eintreffen.

quota​

Die Felder hängen von den Zugangsdaten ab, mit denen der Stream geöffnet wurde.

FeldTypServerschlüssel oder älterer SchlüsselSitzungstoken
typeZeichenfolge, "quota"JaJa
meterZeichenfolgeJaJa
reset_atZeichenfolge, ISO 8601 mit ZeitzonenoffsetJaJa
productZeichenfolgeJaNein
periodZeichenfolgeJaNein
tierZeichenfolgeJaNein
usedZahlJaNein
limitZahlJaNein

Ein Sitzungstoken wird von Besuchern einer Webseite verwendet: entweder aus einem öffentlichen Schlüssel ausgetauscht oder aus einer Besuchersitzung für eine veröffentlichte Karte. Sein quota-Ereignis gibt nur den Zeitpunkt der nächsten Periodenrücksetzung an, nicht aber Tarif, Verbrauch oder Limit der Organisation. Browserclients dürfen nicht mit used oder limit rechnen. Dieselbe Regel gilt für den Antwortkörper bei 429 quota_exceeded; siehe Kontingente und Ratenbegrenzungen.

Keepalives und Zeitlimits​

VerhaltenWertMaßnahme des Clients
Lebenszeichen des ChatstreamsEin : keep-alive-Kommentar nach zehn Sekunden ohne andere AusgabeSetzen Sie den Inaktivitätstimer bei jedem empfangenen Byte zurück, auch bei Kommentaren.
Inaktive VerbindungEine rund eine Minute stille Verbindung kann auf dem Transportweg geschlossen werdenVerwenden Sie einen Leerlauf-/Lesetimeout von 30 bis 60 Sekunden. Setzen Sie kein kurzes Gesamtzeitlimit.
Zeit bis zum ersten TextBei schwierigen Fragen können mehrere Dutzend Sekunden vergehenZeigen Sie ab phase einen Fortschritt an und werten Sie die Wartezeit nicht als Fehler.
Maximale StreamdauerUngefähr zehn Minuten, danach sendet der Server error mit upstream_stallWählen Sie zur Absicherung ein Gesamtzeitlimit von etwas mehr als zehn Minuten.

Abbruch eines Streams und Abrechnung​

Schließen Sie die Verbindung, um einen Stream abzubrechen. Der Server erkennt den Abbruch innerhalb von ungefähr zehn Sekunden und stoppt die Antwort.

  • Ein Stream, der vollständig abgeschlossen wird, wird nach den verwendeten Tokens abgerechnet, wie in end.total_tokens ausgewiesen.
  • Wird ein Stream vorher abgebrochen oder schlägt er fehl, erfolgt eine Schätzung. Mindestens wird die Größe des in der Anfrage gesendeten Gesprächs angesetzt; ansonsten richtet sich der Betrag nach dem bereits übertragenen Text. Daher kann der Betrag höher als die Reservierung sein, die bei Annahme der Anfrage vorgenommen wurde: Das Schließen der Verbindung nach dem ersten Frame macht ein langes Gespräch nicht kostenlos.
  • Orte aus Ihren eigenen Daten (source: "vendor") zählen bei der Berechnung nicht mit.

Ein erneuter Versuch ist eine neue Anfrage und wird erneut abgerechnet. Siehe Kontingente und Ratenbegrenzungen.

Streams für Zusammenfassungen und Schaltflächen​

Diese zwei Endpunkte versorgen die Ortskarte in Kaleidr Chat. Sie verwenden dasselbe Frame-Format, dieselben unbenannten Text-Frames und dasselbe abschließende quota-Ereignis. Vom Chatstream unterscheiden sie sich in drei Punkten: kein phase-Ereignis, keine Orts- oder Aktionsereignisse und keine Keepalives. Verwenden Sie ein Inaktivitätslimit von 60 Sekunden.

Beide Endpunkte lehnen überlange Felder vor Streambeginn mit 422 field_too_long ab und ignorieren nicht aufgeführte Felder; siehe Endpunkte. Bei Abbruch oder Fehler beruht die Abrechnung auf einer Schätzung des bereits übertragenen Textes und überschreitet nie den reservierten Betrag.

POST /chat/summary/stream für einen Ort:

  1. Optional. address mit Nutzdaten { type: "address", address, source }
  2. start mit Nutzdaten { type: "start", poi_type }
  3. Optional, gegebenenfalls mehrfach. url mit Nutzdaten { type: "url", website, source }
  4. Text-Frames mit Nutzdaten { text }
  5. end mit Nutzdaten { type: "end", full_text, summary, poi_type, category, city, country, sources[], website?, total_tokens? } oder error mit Nutzdaten { type: "error", message, partial_text }
  6. Optional. quota

POST /chat/summary/stream für ein Gebäude (type: "building"):

  1. start mit Nutzdaten { type: "start", address }
  2. Text-Frames
  3. end mit Nutzdaten { type: "end", full_text, parsed, total_tokens? } oder error
  4. Optional. quota

POST /chat/button/stream:

  1. start mit Nutzdaten { type: "start", query_type }
  2. Text-Frames
  3. end mit Nutzdaten { type: "end", full_text, reply, query_type, first_token_ms, total_ms, total_tokens? }
  4. Optional. quota

Der Schaltflächenstream besitzt kein error-Ereignis. Bei einem Fehler nach Beginn schließt die Verbindung ohne end. Ein Fehler vor dem Start wird als HTTP 500 mit {"detail": "Button chat stream error"} beantwortet.

POST /spot/overview/stream sendet die oben beschriebenen Frames einer Ortszusammenfassung, davor ein place-Frame mit { type: "place", name }: dem vollständigen Namen des beschriebenen Orts oder der Region, etwa "Springfield, Ohio, United States of America", zum Beschriften oder Kopieren. Er kommt vor allen anderen Frames und kann fehlen. Er ist nicht das place-Ereignis des Chat-Streams und enthält keine Koordinaten. Kann eine ref nicht beschrieben werden, folgt statt der Zusammenfassung ein einzelnes error-Frame mit { type: "error", message, ref }. Siehe Endpunkte.

Verwandte Seiten​