-
Notifications
You must be signed in to change notification settings - Fork 0
APIs e protocolo SSE
Última revisão: junho/2026 (alinhado a api/routes.py + engine/chat_provider.py).
| Método | Rota | Auth | Descrição |
|---|---|---|---|
GET |
/ |
— | UI (templates/index.html) |
POST |
/chat |
— | Chat SSE (e comandos /reload, /reset via message) |
GET |
/health/catalog |
Bearer |
Drift catálogo vs índice (CI / operadores) |
Não existe rota
POST /reloaddedicada./reloade/resetsão mensagens enviadas no corpo dePOST /chat(campomessage). Ver secção/reload.
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
message |
string | sim | Texto do utilizador (pergunta atual); vazio → 400 |
session_id |
string | não | ID da sessão (8–128 caracteres [A-Za-z0-9_-]); habilita pin e logs por sessão |
history |
array | não | Turnos anteriores { role, content } — ver abaixo |
discipline |
string | não | Filtro de silo (equivalente a comando /<disciplina>) |
session_idé opcional mas recomendado: sem ele, o servidor não fixa pin nem associa o turno a uma sessão (api/routes.py). Formato inválido → 400.
Lista opcional de mensagens anteriores à pergunta em message (engine/context.py::_normalize_conversation_history):
"history": [
{ "role": "user", "content": "..." },
{ "role": "assistant", "content": "..." }
]| Regra | Valor | Origem |
|---|---|---|
| Roles permitidos |
user, assistant
|
_VALID_HISTORY_ROLES |
role: system do cliente |
rejeitado (400) | reservado ao servidor |
| Máx. itens na entrada | 40 |
_MAX_HISTORY_ITEMS_RAW (acima → 400) |
| Máx. chars por item | 8192 (truncado server-side) | _MAX_HISTORY_CONTENT_LEN |
| Truncamento no prompt |
ACL_CHAT_HISTORY_MAX_TURNS (12), ACL_CHAT_HISTORY_MAX_CHARS (12000) |
core/config.py |
Ordem no prompt do LLM: system (RAG + grounding) → history truncado → user (mensagem atual).
POC: sem autenticação — o cliente pode forjar history; aceitável para demo local.
Persistência UI: localStorage chave acl_conversation_v1 (sobrevive a refresh / fechar aba).
Limpar: /reset ou /limpar (no message) limpa o pin no servidor; o botão «Nova conversa» no header limpa o storage + gera novo session_id + envia /reset.
Content-Type: text/event-stream- Linhas SSE no formato
data: <conteúdo>\n\n
Todo o stream sai como linhas data:. Não há tipos de evento nomeados (event:); o cliente distingue pelo prefixo do payload (engine/chat_provider.py):
| Linha | Quando | Formato |
|---|---|---|
| Meta | Início do stream (e opcional pós-geração) | data: [ACL_META]{json}\n\n |
| Texto | Durante a geração |
data: <fragmento>\n\n (quebras de linha escapadas como \n) |
| Fim | Sempre, no final | data: [DONE]\n\n |
O ACL_META inicial sai antes de qualquer texto. Um segundo [ACL_META] pode ser emitido pós-geração para override/advisory ou desambiguação (ver 06). O provider LLM pode ser Cursor SDK (default) ou OpenRouter (ACL_LLM_PROVIDER) — o contrato SSE é idêntico.
| Campo | Significado |
|---|---|
v |
Versão do contrato (3) |
label |
Rótulo do escopo (ex.: «Assistente geral», silo) |
sources |
Lista db:discipline/slug dos chunks usados |
decision |
answer | hard_stop
|
reason |
DecisionReason (ver 06) |
confidence |
high | medium | low
|
allow_generation |
true quando decision == answer
|
llm_called |
Se o LLM foi efetivamente chamado |
tokens_used |
Fragmentos/tokens acumulados |
mode |
Modo do trace |
pinned_active / pinned_display / pin_chunks_used
|
Estado do pin no turno |
| Campo | Quando aparece |
|---|---|
grounding_policy |
Sempre que há trace (strict | anchored | hybrid) |
scope_hint / suggested_scope_command
|
Pin diverge da disciplina inferida na query |
sources_note |
Busca atual traz fontes além do pin |
pinned_scope_key |
Pin com escopo definido |
catalog_match / payload
|
decision == hard_stop (ex.: index_gap, ambiguous_retrieval) |
disambiguation_options |
Resposta com opções estruturadas detetadas |
post_generation_advisory / post_generation_flags
|
Aviso suave (anchored/hybrid) |
post_generation_override / misalignment
|
Override destrutivo (strict) |
Construído em engine/chat_provider.py::_build_meta.
Quando allow_generation=false (ex.: provider_error, override strict):
- O stream pode conter apenas
[ACL_META]+ texto fixo de hard stop (sem chamada ao LLM nos casos operacionais). - A UI renderiza conforme
reason— ver Frontend e UI.
/reload reconstrói o índice BM25 a partir do MySQL. É enviado como message no POST /chat e exige Bearer:
| Aspecto | Valor |
|---|---|
| Como enviar |
POST /chat com {"message": "/reload"}
|
| Auth | Authorization: Bearer <ACL_RELOAD_BEARER_TOKEN> |
| Token ausente no servidor | 503 (reload token not configured) |
| Token inválido | 401 |
| Efeito |
SearchEngine.rebuild() + refresh_indexed_lesson_keys_state()
|
| Resposta | SSE com data: <status> + data: [DONE]
|
O alias legado KERNELBOT_RELOAD_TOKEN também é aceite como token (core/config.py). O workflow ISS sync-kernelbot-knowledge envia o mesmo valor.
curl -sS -N -X POST "http://127.0.0.1:8001/chat" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACL_RELOAD_BEARER_TOKEN" \
-d '{"message": "/reload"}'Protegido por Bearer (mesmo token de /reload). Resposta JSON (api/routes.py::health_catalog):
| Campo | Uso |
|---|---|
catalog_enabled |
Valor de ACL_CATALOG_ENABLED
|
indexed_lesson_keys_count |
Aulas no índice BM25 |
catalog_lesson_keys_count |
Aulas no catálogo ISS |
catalog_only_count |
Aulas no catálogo sem row no MySQL (drift) |
catalog_only_sample |
Até 10 chaves de exemplo do drift |
Consumido pelo workflow ISS de verificação de sync.
curl -sS -N -X POST "http://127.0.0.1:8001/chat" \
-H "Content-Type: application/json" \
-d '{
"message": "/python O que são variáveis?",
"session_id": "00000000-0000-4000-8000-000000000001",
"history": [
{"role": "user", "content": "Oi"},
{"role": "assistant", "content": "Olá! Em que posso ajudar?"}
]
}'Resposta (stream SSE, resumido):
data: [ACL_META]{"v":3,"label":"Python","decision":"answer","reason":"ok","allow_generation":true,"llm_called":true,"sources":["db:python/variaveis-tipos-estilo-python"], ...}
data: Variáveis em Python são nomes que apontam para valores...
data: [DONE]
| Função | Papel |
|---|---|
streamChat(message, opts) |
fetch + ReadableStream, parser SSE incremental |
Callbacks aceites (opts):
| Callback | Disparo |
|---|---|
onDelta(fullText) |
A cada fragmento de texto (texto acumulado) |
onMeta(payload) |
A cada linha [ACL_META]
|
onDone() |
No [DONE]
|
onError(err) |
Falha de rede/parse |
onInactivity() |
Sem dados por DEFAULT_STREAM_INACTIVITY_MS (45 s) |
KernelBot — tutor de estudo sobre o material das aulas.
Índice · Home · FAQ · Como contribuir · Visão geral · Backlog · Repositório