Contrato do protocolo SSE
POST /chat/control/stream responde com Server-Sent Events (text/event-stream): uma resposta de longa duração que entrega o texto à medida que ele é gerado, além de eventos estruturados sobre lugares, ações no mapa e rotas.
Esta página define o contrato desse fluxo. Se você usar kaleidr.js, o painel de chat interpreta o fluxo automaticamente, sem precisar desta página. Consulte-a ao criar seu próprio cliente. Há clientes funcionais em Node e Python em Como ler o fluxo; o corpo da requisição está em Endpoints.
/chat/summary/stream e /chat/button/stream usam o mesmo formato de quadro com menos tipos de eventos. Eles são descritos no final desta página.
Antes de o fluxo começar
Uma requisição rejeitada nunca se transforma em fluxo. Falhas de autenticação, escopo, cota, limite de requisições, validação ou tamanho retornam uma resposta HTTP comum com corpo JSON e status 4xx (Erros). Confira o status primeiro e interprete o corpo como SSE somente quando ele for 200.
A requisição tem limites de tamanho: no máximo 400 mensagens, 64.000 caracteres por mensagem e 200.000 caracteres somados em todas as mensagens. Ultrapassar algum limite retorna 422 com um código como conversation_too_long; um corpo acima de 2 MiB retorna 413. A lista completa está em Endpoints.
Uma resposta bem-sucedida contém estes cabeçalhos:
HTTP/1.1 200 OK
Content-Type: text/event-stream; charset=utf-8
Cache-Control: no-cache, no-transform
Formato dos quadros
Um quadro tem uma ou duas linhas seguidas de uma linha em branco. As linhas terminam com \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
- Um quadro identificado contém uma linha
event:seguida de uma linhadata:. - Um quadro de texto contém somente uma linha
data:e nenhuma linhaevent:. - Um comentário começa com dois-pontos. O Kaleidr envia
: keep-alivecomo sinal de atividade; ele não contém dados. data:sempre contém um objeto JSON completo em uma única linha. O texto usa UTF-8.
Os blocos recebidos pela rede não correspondem necessariamente aos quadros. Uma leitura pode conter metade de um quadro ou vários. Armazene o que receber em buffer, separe pelas quebras de linha e só processe um quadro quando chegar à linha em branco que o encerra.
Regra de compatibilidade
Ignore nomes de eventos desconhecidos e campos que você não utiliza. Eventos e campos podem ser adicionados a este contrato sem mudança de versão. Um cliente que falhe ao receber um evento desconhecido deixará de funcionar.
Eventos estáveis
event: | Dados | Significado |
|---|---|---|
| (sem nome) | { text } | Próximo trecho do texto da resposta. Acrescente ao texto existente. Pode conter marcadores [[Name]] ao redor de nomes de lugares. |
phase | { type: "phase", phase: "thinking", session_id } | A requisição foi aceita e o processamento começou. phase sempre é "thinking". |
start | { type: "start", session_id, purpose: "control" } | O texto está prestes a começar a ser enviado. |
place | { name, coordinates?: { lat, lng }, address?, category?, icon?, source?, id?, unverified? } | Um lugar da resposta. Agrupe pelo name; as primeiras coordenadas recebidas para cada nome são definitivas. source: "vendor" identifica um lugar dos dados da organização e source: "map" um lugar já mostrado no mapa publicado. |
place_linked | campos do lugar mais is_update? | Mais detalhes de um lugar já enviado. Incorpore ao lugar com o mesmo name; ignore se ainda não o recebeu. |
early_actions | { type: "early_actions", actions: [ { type, payload } ], places_count, is_partial: true } | Ações de mapa aplicáveis antes de a resposta terminar, enviadas assim que dois ou mais lugares têm coordenadas. |
prompt_options | { type: "prompt_options", schema_version, kind, question, allow_free_text, options: [ { label, send_text } ] } | Pergunta com escolhas quando a requisição é ambígua. Mostre as opções e envie o send_text escolhido como próxima mensagem do usuário. |
route_clear | {} | Remova as rotas desenhadas. Novas rotas serão enviadas. |
route | { type: "route", schema_version, id?, profile, origin, destination, primary, alternatives[], comparison[], stops?, color?, label?, transit?, attribution? } | Rota calculada. Em perguntas de direções, chega antes do texto para que o mapa seja desenhado durante a geração da resposta. |
end | { type: "end", full_text, places[], actions[], question_type, response_time, total_tokens?, dropped_places? } | A resposta está completa. Este é o resultado definitivo. |
error | { type: "error", message, code?, partial_text } | A resposta falhou. Enviado no lugar de end. |
quota | { type: "quota", product, meter, tier, used, limit, reset_at, period } com chave de servidor; { type: "quota", meter, reset_at } com token de sessão | Uso dos créditos de IA da organização após a cobrança da chamada. Último evento do fluxo, depois de end ou error. Consulte quota. |
: keep-alive | linha de comentário | Sinal de atividade após dez segundos de silêncio. Ignore-o, mas conte-o como atividade. |
Removido: grounding (2026-09-05). Ele não é mais enviado.
Cartões e camadas de dados em tempo real
Perguntas sobre fatos em tempo real ou medidos podem acrescentar um destes eventos. Um cartão chega antes do texto; uma camada pode chegar durante ou depois. Eles são adicionais: renderize os que forem compatíveis e ignore os demais. Novos campos podem ser adicionados.
event: | Dados | Enviado para |
|---|---|---|
weather_card | objeto com lat, lng, name, temperaturas (temp_c, temp_f), conditions, forecast[] opcional | Condições meteorológicas atuais em um lugar. |
weather_layer | objeto com layer, tile_path_template, tile_size, max_zoom, scope, attribution | Sobreposição de temperatura em uma região. |
satellite_card | objeto com name, norad_id, lat, lng, altitude_km, velocity_kms, observed_at | Posição de um satélite identificado pelo nome. |
constellation_layer | objeto com group, features[] de { name, norad_id, lat, lng } e track opcional | Satélites próximos ao apresentado no cartão. |
building_card | objeto com lat, lng, name opcional, height_m, num_floors | Informações sobre um edifício. |
trees_card | objeto com lat, lng, count, radius_m | Árvores inventariadas ao redor de um ponto. |
heritage_card | objeto com lat, lng, count, sites[] | Locais históricos ao redor de um ponto. |
rail_card | objeto com lat, lng, lines[] e nearest_station opcional | Linhas ferroviárias próximas a um ponto. |
arrivals_card | objeto com lat, lng, stop, departures[], alerts[], attribution | Partidas de transporte público em uma parada. |
vehicles_layer | objeto com operator, vehicles[], shapes[], attribution | Posições dos veículos de transporte público para a parada ou linha do cartão. |
streetview_card | objeto com lat, lng, image_id, image_lat, image_lng | Imagens ao nível da rua perto de um lugar. |
Quando enviados, cinco destes elementos são repetidos em end com o mesmo nome, permitindo que um cliente que perdeu o evento ainda os leia: weather_card, satellite_card, constellation_layer, weather_layer e vehicles_layer (por exemplo, end.weather_card). Os outros cartões não são repetidos em end. Listagens de eventos ao vivo não são disponibilizadas pela API da plataforma: consulte Licenças de dados.
Diagnóstico e experimental (fora do contrato)
Estes eventos podem aparecer no fluxo, mas não fazem parte do contrato. Não dependa deles.
event: | Dados | Observações |
|---|---|---|
debug | { scope, … } | Diagnóstico interno. Não enviado em requisições normais. |
place_name_found | { name, is_early } | Aviso antecipado de que um nome de lugar foi mencionado. Use o evento place que chega em seguida. |
Ordem dos eventos
O fluxo passa por estas etapas. As etapas marcadas como opcionais não aparecem em todos os fluxos.
- Opcional. Eventos
placecomsource: "vendor": até três lugares dos dados da sua organização quando a chave tem o escopovendor. Eles são enviados primeiro para que o mapa possa desenhá-los imediatamente. phase. Sempre o primeiro evento da própria resposta.- Opcional. Comentários
: keep-aliveenquanto a resposta é preparada. - Opcional. Eventos antes do texto:
prompt_optionsouroute_clear, seguido deroute, e um cartão. start.- Quadros de texto intercalados com
place,place_linked,early_actionse, às vezes,route_clear,routee eventos de camadas. Sinais de atividade preenchem os períodos de silêncio. - Opcional. Eventos tardios de
place,place_linked, camadas e rotas após o texto terminar. endouerror.- Opcional.
quota. - O servidor fecha a conexão.
Duas consequências para o cliente:
endnão é o último evento. Continue lendo até o corpo ser encerrado, ou perderáquota.- Um fluxo pode fechar sem
ende semerror, por exemplo, quando a rede cai. Considere como falha qualquer fluxo encerrado sem evento terminal.
Detalhes dos dados
Texto e marcadores
Os quadros de texto contêm somente texto, nunca dados estruturados. O texto pode incluir marcadores de colchetes duplos em nomes de lugares, como near [[Louvre Museum]], que o painel de chat transforma em links para os pinos do mapa. Para mostrar texto simples, remova os colchetes e mantenha o nome.
place
| Campo | Tipo | Observações |
|---|---|---|
| name | string | Chave usada na combinação de registros. |
| coordinates | object { lat, lng } | Graus decimais. Pode estar ausente. Um lugar mencionado mas não localizado é enviado sem coordenadas e com unverified: true. Não desenhe um pino. |
| address | string | Opcional. |
| category | string | Opcional. |
| icon | string | Opcional. Um emoji do lugar. |
| source | string | Opcional. "vendor" para um lugar dos dados da sua organização. "map" para um lugar já exibido no mapa publicado: o painel não adiciona outro pino porque o mapa já o desenha. |
| id | string | Opcional. Presente nos lugares provenientes dos seus dados. |
| unverified | boolean | Opcional. true quando a localização não foi confirmada. |
Um lugar pode conter outros campos. Ignore os que você não usa.
O mesmo nome pode aparecer várias vezes: primeiro com coordenadas e depois com outros detalhes. Mantenha um único registro por nome, nunca mova um pino depois de receber as coordenadas e deixe os eventos posteriores preencherem os outros campos.
Ações
early_actions.actions e end.actions são listas de { type, payload }.
| Tipo de ação | Dados | O que fazer |
|---|---|---|
| map.fitBounds | { coordinates: [[lng, lat], …], padding, maxZoom, duration } | Ajuste a câmera para abranger as coordenadas. |
| places.highlight | { places: [ { name, lat, lng } ], options } | Destaque esses lugares. |
| map.showRoute | { id, label, profile, coordinates: [[lng, lat], …], distance_m, duration_s, turn_by_turn[], transit?, attribution? } | Desenhe a linha e mostre sua attribution. |
| route.clear | { id? } | Remova a rota com esse id, ou todas se não houver id. |
Outros tipos de ação podem aparecer. Ignore os que você não reconhece. Observe os dois formatos de coordenadas: um lugar possui coordinates: { lat, lng }, enquanto uma linha é uma lista de pares [lng, lat].
route
primary contém a linha a ser desenhada: { coordinates: [[lng, lat], …], distance_m, duration_s, turn_by_turn[] }. Cada etapa de turn_by_turn contém text e pode ter direction_type, distance_m, duration_s, lat e lng. origin e destination têm um label cada. alternatives[] contém outras linhas com um route_id, e comparison[] informa o delta_duration_s de cada alternativa em relação à rota principal. Se presente, stops[] contém pontos { lat, lng, name } ordenados de uma rota com várias paradas.
Uma rota rodoviária contém attribution: { text, url, license }. Mostre text com link para url sempre que desenhar a rota. Uma viagem por transporte público traz o crédito da operadora dentro de transit.
Cada evento route tem um id. Desenhar uma rota com um id existente substitui essa rota.
end
| Campo | Tipo | Observações |
|---|---|---|
| full_text | string | Resposta completa. Prefira-a à concatenação dos quadros de texto. |
| places | array | Lista final ordenada de lugares. Combine-a pelo nome com os lugares já coletados. |
| actions | array | Ações finais de mapa. Aplique-as; elas substituem early_actions. |
| dropped_places | array of strings | Opcional. Nomes enviados antes que não fazem parte da resposta final. Remova seus pinos. |
| question_type | string | Rótulo que indica o tipo de pergunta. Apenas informativo. |
| response_time | number | Tempo da resposta em segundos. |
| total_tokens | number | Opcional. Quantidade de tokens usados, que define o valor cobrado. |
error
event: error
data: {"type": "error", "code": "upstream_stall", "message": "The AI service stopped responding. Please try again.", "partial_text": "The Louvre sits"}
message pode ser exibido ao usuário. partial_text é o texto produzido antes da falha. code aparece em apenas um caso:
| Caso | code | O que fazer |
|---|---|---|
| A resposta parou de progredir ou o fluxo atingiu o comprimento máximo | "upstream_stall" | Ofereça uma nova tentativa. |
| Qualquer outra falha durante a resposta | ausente | Mostre message; tentar novamente pode funcionar. |
Depois de error, não há end. Ainda pode ocorrer um evento quota.
quota
Os campos dependem da credencial usada para abrir o fluxo.
| Campo | Tipo | Chave de servidor ou chave legada | Token de sessão |
|---|---|---|---|
| type | texto, "quota" | Sim | Sim |
| meter | texto | Sim | Sim |
| reset_at | texto, ISO 8601 com deslocamento | Sim | Sim |
| product | texto | Sim | Não |
| period | texto | Sim | Não |
| tier | texto | Sim | Não |
| used | número | Sim | Não |
| limit | número | Sim | Não |
Um token de sessão é usado pelos visitantes de uma página: pode ser obtido de uma chave publicável ou de uma sessão de visitante de um mapa publicado. O evento quota informa quando o período será reiniciado, sem revelar plano, uso nem limite da organização. Um cliente no navegador não deve esperar used ou limit. A mesma regra se aplica ao corpo da resposta 429 quota_exceeded; consulte Cotas e limites de requisições.
Sinais de atividade e tempos limite
| Comportamento | Valor | O que o cliente deve fazer |
|---|---|---|
| Sinal de atividade do fluxo de chat | Um comentário : keep-alive após dez segundos sem outra saída | Reinicie o temporizador de inatividade ao receber quaisquer bytes, inclusive comentários. |
| Conexão inativa | Uma conexão sem dados por cerca de um minuto pode ser fechada durante o transporte | Defina um tempo limite de inatividade (leitura) de 30 a 60 segundos. Não use um tempo limite total curto. |
| Tempo até o primeiro texto | Pode levar dezenas de segundos em perguntas difíceis | Mostre o progresso a partir de phase; não interprete a espera como falha. |
| Duração máxima do fluxo | Cerca de dez minutos, quando o servidor envia error com upstream_stall | Defina um tempo limite total um pouco maior que dez minutos como proteção. |
Interrupção de fluxos e cobrança
Feche a conexão para interromper o fluxo. O servidor percebe isso em cerca de dez segundos e para de gerar a resposta.
- Um fluxo concluído é cobrado pelos tokens usados na resposta, informados em
end.total_tokens. - Um fluxo interrompido ou com falha antes de terminar é cobrado por uma estimativa. Ela corresponde, no mínimo, ao tamanho da conversa enviada na requisição ou é calculada a partir do texto já transmitido. Por isso, pode superar a reserva inicial feita quando a requisição foi aceita: encerrar a conexão no primeiro quadro não torna gratuita uma conversa longa.
- Lugares dos seus próprios dados (
source: "vendor") não entram na cobrança.
Uma nova tentativa é outra requisição e será cobrada novamente. Consulte Cotas e limites de requisições.
Fluxos de resumos e botões
Esses dois endpoints alimentam o cartão de lugar no Kaleidr Chat. Eles usam o mesmo formato de quadro, os mesmos quadros de texto sem identificação e o mesmo evento quota final. Diferem do fluxo de chat em três pontos: não enviam phase, não enviam eventos de lugar ou ação e não enviam sinais de atividade. Use tempo limite de inatividade de 60 segundos.
Ambos rejeitam campos longos demais antes de iniciar com 422 field_too_long e ignoram campos que não listam: consulte Endpoints. Se um deles for interrompido ou falhar, o custo será estimado com base no texto já enviado e nunca será maior que a reserva inicial.
POST /chat/summary/stream, para um lugar:
- Opcional.
addresscom dados{ type: "address", address, source } startcom dados{ type: "start", poi_type }- Opcional, podendo se repetir.
urlcom dados{ type: "url", website, source } - Quadros de texto com dados
{ text } endcom dados{ type: "end", full_text, summary, poi_type, category, city, country, sources[], website?, total_tokens? }, ouerrorcom dados{ type: "error", message, partial_text }- Opcional.
quota
POST /chat/summary/stream, para um edifício (type: "building"):
startcom dados{ type: "start", address }- Quadros de texto
endcom dados{ type: "end", full_text, parsed, total_tokens? }, ouerror- Opcional.
quota
POST /chat/button/stream:
startcom dados{ type: "start", query_type }- Quadros de texto
endcom dados{ type: "end", full_text, reply, query_type, first_token_ms, total_ms, total_tokens? }- Opcional.
quota
O fluxo de botões não tem evento error. Se falhar depois de começar, a conexão fecha sem end. Uma falha antes de começar retorna HTTP 500 com {"detail": "Button chat stream error"}.
POST /spot/overview/stream envia os quadros de resumo de lugar descritos acima, precedidos de um quadro place com dados { type: "place", name }: o nome completo do local ou região descrito, como "Springfield, Ohio, United States of America", para rotulá-lo ou copiá-lo. Ele chega antes de qualquer outro quadro e pode estar ausente. Não é o evento place do stream de chat e não traz coordenadas. Para um ref que não pode descrever, envia um único quadro error com dados { type: "error", message, ref } em vez do resumo. Consulte Endpoints.
Páginas relacionadas
- Como ler o fluxo: clientes completos para Node e Python.
- Endpoints: corpos de requisição de cada fluxo.
- Erros: falhas antes e durante um fluxo.
- Cotas e limites de requisições: evento
quotae cobrança.