Contrato del protocolo SSE
POST /chat/control/stream responde mediante eventos enviados por el servidor (text/event-stream): una respuesta de larga duración que entrega el texto a medida que se genera, además de eventos estructurados sobre lugares, acciones en el mapa y rutas.
Esta página define el contrato de ese flujo. Si usas kaleidr.js, el panel de chat lo interpreta por ti y no necesitas esta página. Consúltala al crear tu propio cliente. Encontrarás clientes funcionales en Node y Python en Lectura del flujo; el cuerpo de la solicitud se describe en Endpoints.
/chat/summary/stream y /chat/button/stream emplean el mismo formato de tramas, pero con menos tipos de eventos. Se describen al final de esta página.
Antes de iniciar el flujo
Una solicitud rechazada nunca se convierte en un flujo. Los fallos de autenticación, permisos, cuota, límite de velocidad, validación o tamaño devuelven una respuesta HTTP normal con un cuerpo JSON y un estado 4xx (Errores). Comprueba primero el estado y analiza el cuerpo como SSE solo cuando sea 200.
La solicitud tiene límites de tamaño: un máximo de 400 mensajes, 64 000 caracteres por mensaje y 200 000 caracteres sumando todos los mensajes. Superar uno de estos límites devuelve un 422 con un código como conversation_too_long; un cuerpo superior a 2 MiB devuelve un 413. La lista completa está en Endpoints.
Una respuesta correcta incluye estas cabeceras:
HTTP/1.1 200 OK
Content-Type: text/event-stream; charset=utf-8
Cache-Control: no-cache, no-transform
Formato de las tramas
Una trama tiene una o dos líneas seguidas de una línea en blanco. Las líneas terminan con \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
- Una trama con nombre contiene una línea
event:seguida de una líneadata:. - Una trama de texto contiene únicamente una línea
data:y no tiene líneaevent:. - Un comentario comienza con dos puntos. Kaleidr envía
: keep-alivecomo señal periódica; no contiene datos. data:siempre contiene un objeto JSON completo en una sola línea. El texto está codificado en UTF-8.
Los fragmentos recibidos por la red no coinciden necesariamente con las tramas. Una lectura puede contener media trama o varias. Acumula el contenido recibido, sepáralo por saltos de línea y procesa cada trama solamente cuando llegues a su línea en blanco.
Regla de compatibilidad
Ignora los nombres de eventos que no reconozcas y los campos que no utilices. Este contrato puede recibir eventos y campos nuevos sin cambiar de versión. Un cliente que falle ante un evento desconocido dejará de funcionar.
Eventos estables
event: | Datos | Significado |
|---|---|---|
| (sin nombre) | { text } | El siguiente fragmento de texto de la respuesta. Añádelo al texto existente. Puede contener marcadores [[Name]] alrededor de nombres de lugares. |
phase | { type: "phase", phase: "thinking", session_id } | Se aceptó la solicitud y comenzó el trabajo. phase siempre vale "thinking". |
start | { type: "start", session_id, purpose: "control" } | El texto está a punto de comenzar a transmitirse. |
place | { name, coordinates?: { lat, lng }, address?, category?, icon?, source?, id?, unverified? } | Un lugar de la respuesta. Combina los registros por name; las primeras coordenadas recibidas para un nombre son definitivas. source: "vendor" identifica un lugar de los datos de tu organización; source: "map" identifica uno que ya muestra el mapa publicado. |
place_linked | campos del lugar más is_update? | Más detalles de un lugar enviado previamente. Incorpóralos al lugar con el mismo name; ignóralos si no lo has recibido. |
early_actions | { type: "early_actions", actions: [ { type, payload } ], places_count, is_partial: true } | Acciones del mapa que puedes aplicar antes de terminar la respuesta; se envían cuando al menos dos lugares tienen coordenadas. |
prompt_options | { type: "prompt_options", schema_version, kind, question, allow_free_text, options: [ { label, send_text } ] } | Una pregunta con opciones, enviada cuando la solicitud era ambigua. Muestra las opciones y envía el send_text elegido como siguiente mensaje del usuario. |
route_clear | {} | Borra las rutas dibujadas. Después llegan otras nuevas. |
route | { type: "route", schema_version, id?, profile, origin, destination, primary, alternatives[], comparison[], stops?, color?, label?, transit?, attribution? } | Una ruta calculada. Llega antes del texto en una pregunta sobre indicaciones, para que el mapa se dibuje mientras se genera la respuesta. |
end | { type: "end", full_text, places[], actions[], question_type, response_time, total_tokens?, dropped_places? } | La respuesta está completa. Es el resultado definitivo. |
error | { type: "error", message, code?, partial_text } | La respuesta falló. Se envía en lugar de end. |
quota | { type: "quota", product, meter, tier, used, limit, reset_at, period } con clave de servidor; { type: "quota", meter, reset_at } con token de sesión | Consumo de créditos de IA de tu organización después de facturar la llamada. Es el último evento del flujo, posterior a end o error. Consulta quota. |
: keep-alive | línea de comentario | Señal periódica enviada tras 10 segundos de silencio. Ignórala, pero cuenta como actividad. |
Eliminado: grounding (2026-09-05). Ya no se envía.
Tarjetas y capas de datos en vivo
Una pregunta sobre datos en vivo o medidos puede incorporar uno de estos eventos. Una tarjeta llega antes del texto; una capa puede llegar durante o después. Son elementos adicionales: representa los que admitas e ignora los demás. Los conjuntos de campos pueden ampliarse.
event: | Datos | Se envía para |
|---|---|---|
weather_card | objeto con lat, lng, name, temperaturas (temp_c, temp_f), conditions y forecast[] opcional | El tiempo actual de un lugar. |
weather_layer | objeto con layer, tile_path_template, tile_size, max_zoom, scope, attribution | Una superposición de temperaturas para una región. |
satellite_card | objeto con name, norad_id, lat, lng, altitude_km, velocity_kms, observed_at | La posición de un satélite identificado por su nombre. |
constellation_layer | objeto con group, features[] de { name, norad_id, lat, lng } y track opcional | Los satélites alrededor del indicado en la tarjeta. |
building_card | objeto con lat, lng, name opcional, height_m, num_floors | Datos sobre un edificio. |
trees_card | objeto con lat, lng, count, radius_m | Árboles inventariados alrededor de un punto. |
heritage_card | objeto con lat, lng, count, sites[] | Lugares patrimoniales alrededor de un punto. |
rail_card | objeto con lat, lng, lines[], nearest_station opcional | Líneas ferroviarias cerca de un punto. |
arrivals_card | objeto con lat, lng, stop, departures[], alerts[], attribution | Próximas salidas del transporte público en una parada. |
vehicles_layer | objeto con operator, vehicles[], shapes[], attribution | Posiciones de vehículos de transporte público en la parada o línea de la tarjeta. |
streetview_card | objeto con lat, lng, image_id, image_lat, image_lng | Imágenes a pie de calle cerca de un lugar. |
Cuando se han enviado, end repite cinco de estos elementos con el mismo nombre, para que un cliente que haya perdido el evento aún pueda leerlos: weather_card, satellite_card, constellation_layer, weather_layer y vehicles_layer (por ejemplo, end.weather_card). Las demás tarjetas no se repiten en end. Los listados de eventos en vivo no se ofrecen mediante la API de la plataforma; consulta Licencias de datos.
Diagnóstico y experimentación (fuera del contrato)
Pueden aparecer en el flujo de datos. No forman parte del contrato: no dependas de ellos.
event: | Datos | Notas |
|---|---|---|
debug | { scope, … } | Diagnóstico interno. No se envía en solicitudes normales. |
place_name_found | { name, is_early } | Aviso temprano de que se ha mencionado el nombre de un lugar. Debes utilizar el evento place que llegue después. |
Orden de los eventos
Un flujo pasa por estas etapas. Las marcadas como opcionales no aparecen en todos los flujos.
- Opcional. Eventos
placeconsource: "vendor": hasta tres lugares procedentes de los datos de tu organización, cuando la clave tiene el permisovendor. Se envían primero para que el mapa pueda mostrarlos inmediatamente. phase. Siempre es el primer evento de la propia respuesta.- Opcional. Comentarios
: keep-alivemientras se prepara la respuesta. - Opcional. Eventos anteriores al texto:
prompt_options, oroute_clearseguido deroute, y una tarjeta. start.- Tramas de texto intercaladas con
place,place_linked,early_actionsy, a veces,route_clear,routey eventos de capas. Las señales de mantenimiento cubren los períodos sin actividad. - Opcional. Eventos tardíos de
place,place_linked, capas y rutas una vez terminado el texto. endoerror.- Opcional.
quota. - El servidor cierra la conexión.
Esto tiene dos consecuencias para el cliente:
endno es el último evento. Sigue leyendo hasta que se cierre el cuerpo o perderásquota.- Un flujo puede cerrarse sin
endnierror, por ejemplo, debido a una interrupción de la red. Considera fallido cualquier flujo cerrado sin evento final.
Detalles de los datos
Texto y marcadores
Las tramas de texto solo contienen texto. Los datos estructurados nunca llegan dentro del texto. El contenido puede incluir marcadores de doble corchete alrededor de nombres de lugares, como near [[Louvre Museum]], que el panel de chat transforma en enlaces a marcadores del mapa. Para mostrar texto sin formato, elimina los corchetes y conserva el nombre.
place
| Campo | Tipo | Notas |
|---|---|---|
| name | string | Clave utilizada para combinar los registros. |
| coordinates | object { lat, lng } | Grados decimales. Puede no estar presente. Si no se pudo localizar un lugar mencionado, se envía sin coordenadas y con unverified: true. No dibujes un marcador. |
| address | string | Opcional. |
| category | string | Opcional. |
| icon | string | Opcional. Un emoji para el lugar. |
| source | string | Opcional. "vendor" indica un lugar de los datos de tu organización. "map" indica un lugar que ya muestra el mapa publicado que ve el visitante: el chat no añade otro marcador porque el mapa ya lo dibuja. |
| id | string | Opcional. Presente en los lugares de tus propios datos. |
| unverified | boolean | Opcional. true si el lugar no tiene una ubicación confirmada. |
Un lugar puede incluir otros campos. Ignora los que no utilices.
Un mismo nombre puede llegar varias veces: primero con coordenadas y después con más detalles. Mantén un solo registro por nombre, no muevas un marcador una vez que tenga coordenadas y permite que los eventos posteriores completen los demás campos.
Acciones
early_actions.actions y end.actions son listas de { type, payload }.
| Tipo de acción | Datos | Qué hacer |
|---|---|---|
| map.fitBounds | { coordinates: [[lng, lat], …], padding, maxZoom, duration } | Ajusta la cámara para abarcar las coordenadas. |
| places.highlight | { places: [ { name, lat, lng } ], options } | Destaca esos lugares. |
| map.showRoute | { id, label, profile, coordinates: [[lng, lat], …], distance_m, duration_s, turn_by_turn[], transit?, attribution? } | Dibuja la línea y muestra su attribution. |
| route.clear | { id? } | Borra la ruta con ese id, o todas las rutas si no hay id. |
Pueden aparecer otros tipos de acciones; omite los que no sepas procesar. Ten presentes los dos formatos de coordenadas: un lugar lleva coordinates: { lat, lng }, mientras que una línea es una lista de pares [lng, lat].
route
primary contiene la línea que debe dibujarse: { coordinates: [[lng, lat], …], distance_m, duration_s, turn_by_turn[] }. Cada paso de turn_by_turn tiene text y puede incluir direction_type, distance_m, duration_s, lat y lng. origin y destination tienen cada uno un label. alternatives[] contiene otras líneas con un route_id, y comparison[] indica el delta_duration_s de cada alternativa respecto de la ruta principal. Cuando existe, stops[] contiene puntos ordenados { lat, lng, name } de una ruta con varias paradas.
Una ruta por carretera incluye attribution: { text, url, license }. Muestra text con un enlace a url siempre que dibujes la ruta. En una ruta de transporte público, el crédito del operador se encuentra dentro de transit.
Cada evento route contiene un id. Si dibujas una ruta con un id ya existente, sustituyes esa ruta.
end
| Campo | Tipo | Notas |
|---|---|---|
| full_text | string | La respuesta completa. Prefiérela a las tramas de texto concatenadas. |
| places | array | Lista definitiva de lugares, en orden. Combínala por nombre con los lugares recogidos. |
| actions | array | Acciones definitivas del mapa. Aplícalas; sustituyen a early_actions. |
| dropped_places | array of strings | Opcional. Nombres enviados anteriormente que ya no forman parte de la respuesta final. Elimina sus marcadores. |
| question_type | string | Etiqueta que describe el tipo de pregunta. Solo informativa. |
| response_time | number | Segundos empleados para generar la respuesta. |
| total_tokens | number | Opcional. Número de tokens utilizados, que determina el cargo. |
error
event: error
data: {"type": "error", "code": "upstream_stall", "message": "The AI service stopped responding. Please try again.", "partial_text": "The Louvre sits"}
message puede mostrarse con seguridad al usuario. partial_text es el texto generado antes del fallo. code solo aparece en un caso:
| Caso | code | Qué hacer |
|---|---|---|
| La respuesta dejó de avanzar o el flujo alcanzó su longitud máxima | "upstream_stall" | Ofrece volver a intentarlo. |
| Cualquier otro fallo durante la respuesta | ausente | Muestra message; un nuevo intento podría funcionar. |
Después de error no hay end. Aún puede llegar un evento quota.
quota
Los campos dependen de la credencial utilizada para abrir el flujo.
| Campo | Tipo | Clave de servidor o antigua | Token de sesión |
|---|---|---|---|
| type | cadena, "quota" | Sí | Sí |
| meter | cadena | Sí | Sí |
| reset_at | cadena, ISO 8601 con zona horaria | Sí | Sí |
| product | cadena | Sí | No |
| period | cadena | Sí | No |
| tier | cadena | Sí | No |
| used | número | Sí | No |
| limit | número | Sí | No |
El token de sesión es lo que emplean los visitantes de una página: uno obtenido mediante una clave publicable o una sesión de visitante de un mapa publicado. Su evento quota indica cuándo se reinicia el período, sin revelar el plan, el consumo ni el límite de la organización. Un cliente de navegador no debe esperar los campos used o limit. La misma regla rige para el cuerpo de respuesta 429 quota_exceeded: consulta Cuotas y límites de velocidad.
Señales de mantenimiento y tiempos de espera
| Comportamiento | Valor | Qué debe hacer el cliente |
|---|---|---|
| Señal periódica del flujo de chat | Un comentario : keep-alive tras 10 segundos sin otra salida | Reinicia el temporizador de inactividad al recibir cualquier byte, incluidos los comentarios. |
| Conexión inactiva | Una conexión sin actividad durante aproximadamente un minuto puede cerrarse durante el transporte | Configura un tiempo de espera de inactividad (lectura) de 30 a 60 segundos. No establezcas un tiempo máximo total demasiado corto. |
| Tiempo hasta recibir el primer texto | Puede tardar decenas de segundos si la pregunta es difícil | Muestra el progreso desde phase; no interpretes la espera como un fallo. |
| Duración máxima del flujo | Aproximadamente 10 minutos, tras los cuales el servidor envía error con upstream_stall | Establece como protección adicional un tiempo máximo total algo superior a 10 minutos. |
Interrupción de flujos y facturación
Cierra la conexión para interrumpir el flujo. El servidor lo detecta en unos diez segundos y detiene la respuesta.
- Un flujo que finaliza correctamente se factura por los tokens utilizados, indicados en
end.total_tokens. - Si un flujo se interrumpe o falla antes de terminar, se factura una estimación. Esta equivale, como mínimo, al tamaño de la conversación incluida en la solicitud y, en otros casos, depende del texto ya transmitido. Por ello, puede superar la reserva inicial efectuada al admitir la solicitud: cerrar la conexión al recibir la primera trama no hace que una conversación larga sea gratuita.
- Los lugares procedentes de tus propios datos (
source: "vendor") no se incluyen en el cargo.
Un nuevo intento es otra solicitud y vuelve a generar un cargo. Consulta Cuotas y límites de velocidad.
Flujos de resúmenes y botones
Estos dos endpoints respaldan la ficha de lugar de Kaleidr Chat. Utilizan el mismo formato de tramas, las mismas tramas de texto sin nombre y el mismo evento final quota. Se diferencian del flujo de chat en tres aspectos: no envían el evento phase, ni eventos de lugares o acciones, y no envían señales de mantenimiento. Usa un tiempo de espera de inactividad de 60 segundos.
Ambos rechazan antes de comenzar los campos demasiado largos con 422 field_too_long e ignoran los campos no indicados: consulta Endpoints. Si uno de estos flujos se interrumpe o falla, el cargo es una estimación del texto ya transmitido y nunca supera la reserva inicial.
POST /chat/summary/stream, para un lugar:
- Opcional.
addresscon los datos{ type: "address", address, source } startcon los datos{ type: "start", poi_type }- Opcional, puede repetirse.
urlcon los datos{ type: "url", website, source } - Tramas de texto con los datos
{ text } endcon los datos{ type: "end", full_text, summary, poi_type, category, city, country, sources[], website?, total_tokens? }, oerrorcon los datos{ type: "error", message, partial_text }- Opcional.
quota
POST /chat/summary/stream, para un edificio (type: "building"):
startcon los datos{ type: "start", address }- Tramas de texto
endcon los datos{ type: "end", full_text, parsed, total_tokens? }, oerror- Opcional.
quota
POST /chat/button/stream:
startcon los datos{ type: "start", query_type }- Tramas de texto
endcon los datos{ type: "end", full_text, reply, query_type, first_token_ms, total_ms, total_tokens? }- Opcional.
quota
El flujo de botones no tiene evento error. Si falla después de empezar, la conexión se cierra sin end. Un fallo anterior al inicio devuelve HTTP 500 con {"detail": "Button chat stream error"}.
POST /spot/overview/stream envía las tramas del resumen de lugar descritas antes, precedidas de una trama place con los datos { type: "place", name }: el nombre completo del lugar o la región que se describe, como "Springfield, Ohio, United States of America", para etiquetarlo o copiarlo. Llega antes que cualquier otra trama y puede faltar. No es el evento place del flujo de chat y no incluye coordenadas. Si no puede describir un ref, envía una sola trama error con los datos { type: "error", message, ref } en lugar del resumen. Consulta Endpoints.
Páginas relacionadas
- Lectura del flujo: clientes completos para Node y Python.
- Endpoints: cuerpos de solicitud de cada flujo.
- Errores: fallos anteriores y posteriores al inicio del flujo.
- Cuotas y límites de velocidad: el evento
quotay su facturación.