Saltar al contenido principal

Contrato wire SSE

Los endpoints de chat AI transmiten Server-Sent Events (text/event-stream). Esta página documenta el contrato control-stream utilizado por POST /chat/control/stream. La fuente de verdad son el parser y los tipos de @kaleidr/inference-ui (packages/inference-ui/src/control/sse.ts y types.ts). Si utilizas kaleidr.js, el bundle de chat lo analiza por ti — solo necesitas esta página para crear un cliente personalizado.

/chat/summary/stream y /chat/button/stream utilizan contratos SSE diferentes y no están cubiertos aquí. No reutilices el parser de control-stream en esos endpoints.

Regla de compatibilidad

Los clientes deben ignorar nombres de eventos desconocidos. Se pueden añadir nuevos eventos al contrato estable sin aumentar la versión. Los eventos downstream documentados en la tabla "diagnostic / experimental" siguiente no forman parte del contrato — el cliente oficial los ignora y pueden desaparecer.

Eventos estables

Los payloads corresponden a lo que asume el control parser. start no tiene un campo phase (este solo aparece en eventos phase).

event:PayloadMeaning
(unnamed){ text }Token incremental de texto. Puede contener marcadores [[Place]].
phase{ type: "phase", phase, session_id }Ciclo de vida previo al stream.
start{ type: "start", session_id, purpose? }Stream abierto.
place{ name, coordinates: { lat, lng }, address?, category?, source?, id? }Lugar resuelto (merge-by-name → pin del mapa). source: "vendor" marca un lugar procedente de datos cargados por la organización.
place_linkedplace fields + is_update?Enriquece un lugar ya emitido.
early_actions{ type: "early_actions", actions: [ { type, payload } ], places_count?, is_partial? }Acciones de mapa (fitBounds / route / highlight) antes de la respuesta completa.
prompt_options{ type: "prompt_options", schema_version, kind, question, allow_free_text, options: [ { label, send_text } ] }Opciones de desambiguación — muéstralas como opciones pulsables y envía send_text de la opción como el siguiente mensaje del usuario.
route_clear{}Borra todos los overlays antes de que lleguen nuevas rutas. Stable.
route{ type: "route", schema_version, id?, profile, origin, destination, primary, alternatives[], comparison[], stops?, connectors?, color?, label? }Turno formulado como trayecto — ruta calculada por el engine, emitida antes del texto para que el mapa pueda dibujar mientras la respuesta se transmite.
quota{ type: "quota", product, meter, tier, used, limit, reset_at, period }Medidor durante el stream — muestra el presupuesto restante.
end{ type: "end", full_text, places[], actions[], question_type, response_time, total_tokens? }Envelope terminal — resultado completo.
error{ type: "error", message, code?, partial_text? }Error terminal.
: keep-alivecomment lineKeep-alive del proxy (~10s). Ignorar.

Eliminado: grounding (2026-09-05). Grounding sigue influyendo en la respuesta, pero ya no coloca un frame en el wire.

Diagnóstico / experimental (fuera de contrato)

Son detalles de implementación emitidos. El cliente oficial los ignora; no dependas de ellos.

event:PayloadNotes
debug{ scope, … }Diagnóstico interno. Puede cambiar o desaparecer.
place_name_found{ name, is_early? }Fuera de contrato; el cliente oficial lo ignora.

Tokens y datos estructurados

Los eventos sin nombre transmiten texto normal. Pueden incluir marcadores inline [[Place]] cuando se hace referencia a un lugar (p. ej. …cafes near [[Louvre]]…) — elimínalos para una presentación limpia, o ignora completamente el texto y controla tu UI mediante los eventos estructurados.

Los datos estructurados llegan como eventos, nunca inline en el texto. Los lugares resueltos se transmiten por place (y place_linked para metadata tardía) a medida que se geocodifican; las acciones del mapa llegan por early_actions; las rutas llegan por route después de route_clear; el payload final autoritativo es el evento end. Un cliente típico representa pins a partir de eventos place a medida que llegan y considera end la fuente de verdad.

Cliente mínimo

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).

Consulta Endpoints para los request bodies y Errors para la gestión de fallos.