Gerenciamento de Sessões & Compactação (Análise aprofundada)
Este documento explica como o OpenClaw gerencia sessões de ponta a ponta:- Roteamento de sessão (como mensagens de entrada mapeiam para um
sessionKey) - Loja de sessão (
sessions.json) e o que ele controla - Persistência de transcrições (
*.jsonl) e sua estrutura - Higiene de transcrições (ajustes específicos do provedor antes das execuções)
- Limites de contexto (janela de contexto vs. tokens acompanhados)
- Compactação (manual + auto-compactação) e onde conectar trabalhos de pré-compactação
- Organização silenciosa (ex.: gravações de memória que não devem produzir saída visível ao usuário)
Fonte da verdade: o Gateway
O OpenClaw foi projetado em torno de um único processo Gateway que é o dono do estado das sessões.- UIs (app macOS, UI de Controle web, TUI) devem consultar o Gateway para listas de sessões e contagens de tokens.
- Em modo remoto, os arquivos de sessão ficam no host remoto; “verificar seus arquivos locais do Mac” não reflete o que o Gateway está usando.
Duas camadas de persistência
O OpenClaw persiste sessões em duas camadas:-
Armazenamento de sessões (
sessions.json)- Mapa chave/valor:
sessionKey -> SessionEntry - Pequeno, mutável, seguro para editar (ou excluir entradas)
- Acompanha metadados da sessão (id da sessão atual, última atividade, alternâncias, contadores de tokens etc.)
- Mapa chave/valor:
-
Transcrição (
<sessionId>.jsonl)- Transcrição apenas de acréscimo com estrutura em árvore (entradas têm
id+parentId) - Armazena a conversa real + chamadas de ferramentas + resumos de compactação
- Usada para reconstruir o contexto do modelo em turnos futuros
- Transcrição apenas de acréscimo com estrutura em árvore (entradas têm
Localizações em disco
Por agente, no host do Gateway:- Armazenamento:
~/.openclaw/agents/<agentId>/sessions/sessions.json - Transcrições:
~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl- Sessões de tópico do Telegram:
.../<sessionId>-topic-<threadId>.jsonl
- Sessões de tópico do Telegram:
src/config/sessions.ts.
Chaves de sessão (sessionKey)
Uma sessionKey identifica em qual bucket de conversa você está (roteamento + isolamento).
Padrões comuns:
- Chat principal/direto (por agente):
agent:<agentId>:<mainKey>(padrãomain) - Grupo:
agent:<agentId>:<channel>:group:<id> - Sala/canal (Discord/Slack):
agent:<agentId>:<channel>:channel:<id>ou...:room:<id> - Cron:
cron:<job.id> - Webhook:
hook:<uuid>(a menos que seja substituído)
IDs de sessão (sessionId)
Cada sessionKey aponta para um sessionId atual (o arquivo de transcrição que continua a conversa).
Regras gerais:
- Reset (
/new,/reset) cria um novosessionIdpara essasessionKey. - Reset diário (padrão 4:00 da manhã no horário local do host do gateway) cria um novo
sessionIdna próxima mensagem após o limite do reset. - Expiração por inatividade (
session.reset.idleMinutesou legadosession.idleMinutes) cria um novosessionIdquando uma mensagem chega após a janela de inatividade. Quando diário + inatividade estão ambos configurados, o que expirar primeiro prevalece.
initSessionState() em src/auto-reply/reply/session.ts.
Esquema do armazenamento de sessões (sessions.json)
O tipo de valor do armazenamento é SessionEntry em src/config/sessions.ts.
Campos principais (não exaustivo):
sessionId: id da transcrição atual (o nome do arquivo é derivado disso, a menos quesessionFileesteja definido)updatedAt: timestamp da última atividadesessionFile: substituição opcional explícita do caminho da transcriçãochatType:direct | group | room(ajuda UIs e a política de envio)provider,subject,room,space,displayName: metadados para rotulagem de grupo/canal- Alternâncias:
thinkingLevel,verboseLevel,reasoningLevel,elevatedLevelsendPolicy(substituição por sessão)
- Seleção de modelo:
providerOverride,modelOverride,authProfileOverride
- Contadores de tokens (melhor esforço / dependente do provedor):
inputTokens,outputTokens,totalTokens,contextTokens
compactionCount: com que frequência a auto-compactação foi concluída para esta chave de sessãomemoryFlushAt: timestamp do último despejo de memória pré-compactaçãomemoryFlushCompactionCount: contagem de compactações quando o último despejo foi executado
Estrutura da transcrição (*.jsonl)
As transcrições são gerenciadas pelo SessionManager do @mariozechner/pi-coding-agent.
O arquivo é JSONL:
- Primeira linha: cabeçalho da sessão (
type: "session", incluiid,cwd,timestamp, opcionalparentSession) - Em seguida: entradas da sessão com
id+parentId(árvore)
message: mensagens de usuário/assistente/toolResultcustom_message: mensagens injetadas por extensões que entram no contexto do modelo (podem ser ocultadas da UI)custom: estado de extensão que não entra no contexto do modelocompaction: resumo de compactação persistido comfirstKeptEntryIdetokensBeforebranch_summary: resumo persistido ao navegar por um ramo da árvore
SessionManager para lê-las/escrevê-las.
Janelas de contexto vs. tokens acompanhados
Dois conceitos diferentes importam:- Janela de contexto do modelo: limite rígido por modelo (tokens visíveis ao modelo)
- Contadores do armazenamento de sessões: estatísticas contínuas gravadas em
sessions.json(usadas para /status e dashboards)
- A janela de contexto vem do catálogo de modelos (e pode ser substituída via configuração).
contextTokensno armazenamento é um valor de estimativa/relato em tempo de execução; não o trate como uma garantia estrita.
Compactação: o que é
A compactação resume conversas mais antigas em uma entradacompaction persistida na transcrição e mantém mensagens recentes intactas.
Após a compactação, turnos futuros veem:
- O resumo de compactação
- Mensagens após
firstKeptEntryId
Quando a auto-compactação acontece (runtime do Pi)
No agente Pi incorporado, a auto-compactação é acionada em dois casos:- Recuperação de overflow: o modelo retorna um erro de overflow de contexto → compacta → tenta novamente.
- Manutenção por limiar: após um turno bem-sucedido, quando:
contextTokens > contextWindow - reserveTokens
Onde:
contextWindowé a janela de contexto do modeloreserveTokensé a folga reservada para prompts + a próxima saída do modelo
Configurações de compactação (reserveTokens, keepRecentTokens)
As configurações de compactação do Pi ficam nas configurações do Pi:
- Se
compaction.reserveTokens < reserveTokensFloor, o OpenClaw o aumenta. - O piso padrão é
20000tokens. - Defina
agents.defaults.compaction.reserveTokensFloor: 0para desativar o piso. - Se já estiver mais alto, o OpenClaw não altera.
ensurePiCompactionReserveTokens() em src/agents/pi-settings.ts
(chamado a partir de src/agents/pi-embedded-runner.ts).
Superfícies visíveis ao usuário
Você pode observar a compactação e o estado da sessão via:/status(em qualquer sessão de chat)openclaw status(CLI)openclaw sessions/sessions --json- Modo verboso:
🧹 Auto-compaction complete+ contagem de compactações
Organização silenciosa (NO_REPLY)
O OpenClaw suporta turnos “silenciosos” para tarefas em segundo plano nas quais o usuário não deve ver saída intermediária.
Convenção:
- O assistente inicia sua saída com
NO_REPLYpara indicar “não entregar uma resposta ao usuário”. - O OpenClaw remove/suprime isso na camada de entrega.
2026.1.10, o OpenClaw também suprime streaming de rascunho/digitação quando um trecho parcial começa com NO_REPLY, para que operações silenciosas não vazem saída parcial no meio do turno.
“Despejo de memória” pré-compactação (implementado)
Objetivo: antes que a auto-compactação aconteça, executar um turno agentivo silencioso que grave estado durável em disco (ex.:memory/YYYY-MM-DD.md no workspace do agente) para que a compactação não
apague contexto crítico.
O OpenClaw usa a abordagem de despejo pré-limiar:
- Monitorar o uso de contexto da sessão.
- Quando cruzar um “limiar suave” (abaixo do limiar de compactação do Pi), executar uma diretiva silenciosa de “gravar memória agora” para o agente.
- Usar
NO_REPLYpara que o usuário não veja nada.
agents.defaults.compaction.memoryFlush):
enabled(padrão:true)softThresholdTokens(padrão:4000)prompt(mensagem do usuário para o turno de despejo)systemPrompt(prompt de sistema extra anexado para o turno de despejo)
- O prompt padrão/prompt de sistema incluem uma dica
NO_REPLYpara suprimir a entrega. - O despejo é executado uma vez por ciclo de compactação (acompanhado em
sessions.json). - O despejo roda apenas para sessões Pi incorporadas (backends de CLI o ignoram).
- O despejo é ignorado quando o workspace da sessão é somente leitura (
workspaceAccess: "ro"ou"none"). - Veja Memory para o layout de arquivos do workspace e padrões de escrita.
session_before_compact na API de extensões, mas a lógica de despejo do OpenClaw
vive hoje no lado do Gateway.
Checklist de solução de problemas
- Chave de sessão errada? Comece por /concepts/session e confirme o
sessionKeyem/status. - Divergência entre store e transcrição? Confirme o host do Gateway e o caminho do store a partir de
openclaw status. - Spam de compactação? Verifique:
- janela de contexto do modelo (muito pequena)
- configurações de compactação (
reserveTokensmuito alto para a janela do modelo pode causar compactação mais cedo) - inchaço de resultados de ferramentas: habilite/ajuste a poda de sessões
- Turnos silenciosos vazando? Confirme que a resposta começa com
NO_REPLY(token exato) e que você está em um build que inclui a correção de supressão de streaming.