Skip to main content
O ChatCLI implementa um sistema de recuperação automatica de contexto que lida com três tipos de falha comuns em sessões longas: overflow da janela de contexto do modelo (“prompt too long”), limites de payload de proxy/gateway corporativo (413/WAF 403/EOF silencioso), e limite de tokens de saída. Quando a API rejeita uma requisição por qualquer um desses motivos, o sistema aplica estratégias progressivamente mais agressivas para recuperar a sessão sem perder a conversa.

Recuperação de Context Overflow

Quando a API retorna um erro de “context too long”, o ChatCLI aplica até 3 niveis de recuperação antes de desistir:
Primeira tentativa: reduz os limites de orcamento pela metade e limpa desalinhamentos.Acoes:
  • Repara pareamento de tool results (remove orfaos, injeta sinteticos)
  • Reduz DefaultTurnBudgetChars e DefaultPerResultMaxChars para 50% dos valores originais
  • Aplica enforcement de orcamento com limites reduzidos
  • Trunca mensagens longas do assistente para 5.000 chars
Os limites originais sao restaurados após a aplicacao. Apenas o histórico atual e afetado pela reducao.

Detecção de Erro — overflow do modelo

O sistema reconhece múltiplas formas de erro de overflow:

Recuperação de proxy/gateway corporativo

Ambientes corporativos frequentemente rodam atrás de proxies ou gateways que impõem um teto de body size para POSTs — tipicamente 1-5 MB, totalmente independente da janela de contexto do modelo. Você pode estar dentro do limite do Anthropic (200K tokens / ~800 KB) e mesmo assim tomar uma rejeição misteriosa do proxy. Pior: muitos proxies não retornam um 413 limpo — alguns mandam 403 do WAF (Cloudflare, Akamai, mod_security), 431 (header too large), ou simplesmente dropam a conexão TCP no meio do POST, emergindo como EOF / connection reset no cliente. O ChatCLI detecta esses três padrões e aplica o mesmo fluxo de recuperação do context overflow.

Detecção de Erro — proxy/gateway

A detecção de WAF é conservadora — um 403 sem sinais de firewall continua sendo tratado como erro de autenticação (refresh OAuth + retry). Só quando o 403 carrega sinais específicos do proxy/WAF é que ele é reclassificado como falha recuperável de payload. Isso evita invalidar credenciais OAuth válidas quando o problema real está na rede.
O caso Bedrock corporativo: quando o proxy/WAF intercepta a requisição POST ao Bedrock Runtime e devolve uma página HTML de bloqueio com status 403, o AWS SDK tenta fazer parse do body como JSON e falha com "invalid character '<' looking for beginning of value" e RequestID vazio. Esse padrão é um fingerprint inequívoco de middlebox (um 403 real da AWS retorna JSON bem-formado) — o ChatCLI reclassifica para falha recuperável de payload e dispara a mesma ladder de recovery.
A detecção de EOF/connection-reset aplica um limiar de tamanho do histórico (500 KB) antes de suspeitar de payload. Requisições pequenas que sofrem EOF continuam sendo tratadas como falhas transitórias de rede (retry normal). Só quando o histórico já está suspeitosamente grande é que o EOF é reclassificado como possível body cap.

Pre-flight check

A cada turno do agente, o histórico é medido antes do request sair. Dois caminhos: Com CHATCLI_MAX_PAYLOAD configurado: Se o histórico passa de 85% do cap, o BudgetRatio é forçado para 0.40 antes de qualquer coisa — compactação agressiva preventiva. O usuário vê:
Sem cap configurado: Se o histórico passa de 2.5 MB, um aviso one-shot por sessão é emitido sugerindo configurar a env var. Não dispara de novo no mesmo run para evitar barulho.

Cap adaptativo aprendido

Os providers Bedrock anotam cada erro de transporte com o tamanho exato da requisição que o middlebox rejeitou. Quando uma rejeição de payload acontece, o ChatCLI deriva o limite da sessão diretamente dessa observação — ¾ do tamanho rejeitado — em vez de chutar:
Na prática isso muda tudo: gateways corporativos reais frequentemente limitam o corpo em torno de 128 KB, onde um chute de vários megabytes não mudaria nada. O cap aprendido só aperta — se CHATCLI_MAX_PAYLOAD já estiver abaixo dele, seu valor vence; uma rejeição menor posterior aperta ainda mais. Quando o tamanho rejeitado é desconhecido (providers sem anotação de tamanho), vale o comportamento anterior como fallback: assumir 4 MB para o resto da sessão.

Diagnóstico de piso — quando compactar não resolve

O system prompt (charter do agente, personas, skills, docs de ferramentas MCP) nunca é compactado. Quando ele sozinho atinge o tamanho que o gateway acabou de rejeitar, nenhuma compactação de histórico produz uma requisição aceitável — repetir payloads idênticos só queimaria tentativas de recovery. O ChatCLI detecta isso e falha rápido com uma mensagem acionável:
A ¾ do tamanho rejeitado dispara um aviso — a sessão continua, mas você está perto da borda:
Três features estruturais encolhem esse piso: as descrições de ferramentas MCP são limitadas a uma linha no índice do system prompt (schema completo via @tools describe), os corpos de skills injetadas respeitam CHATCLI_SKILL_INJECT_BUDGET mais seu cap de 2× por execução, e blocos de skill mid-loop envelhecem para stubs após CHATCLI_SKILL_AGE_TURNS turnos (recuperáveis via @recall). Veja Integração MCP e Skill Registry.

Encolhimento de conteúdo — o Nível 3 que funciona de verdade

Dropar mensagens inteiras é no-op quando o histórico é curto — sessões de agente frequentemente têm só o system prompt e um punhado de tool results gigantes, e o MinKeepRecent mantém exatamente as mensagens que carregam o volume. A truncagem de emergência ganhou por isso um passe final: encolhe o conteúdo das mensagens não-system, da maior para a menor, até caber no budget de payload. Mensagens system nunca são tocadas. Com a camada de compressão ativa, cada mensagem é arquivada verbatim no store CCR antes do primeiro corte e o conteúdo encolhido carrega um marcador <<ccr:KEY>> — o modelo recupera o original a qualquer momento com @recall. A truncagem nuclear (nível 3 da escada de recovery) adicionalmente limita cada mensagem não-system mantida a 4.000 chars.

System notice injetado na história

Após um recovery disparado por payload limit, o ChatCLI injeta uma mensagem user antes do retry instruindo o modelo a fazer leituras menores no futuro. Isso quebra o loop do modelo de tentar re-ler o mesmo arquivo gigante que causou o 413 originalmente. O notice é injetado no máximo uma vez por sessão — o recovery detecta uma cópia existente em qualquer lugar do histórico (mesmo dobrada num summary de compactação) e nunca empilha uma segunda, já que cada byte extra trabalha contra o próprio limite sendo recuperado:
Este hint é injetado em inglês intencionalmente. A IA segue instruções em inglês com muito mais fidelidade mesmo quando o usuário está em pt-BR, e esta mensagem não é visível ao usuário — ela só entra no histórico enviado ao modelo.

Escalação de Max Output Tokens

Quando o modelo para de gerar por atingir o limite de max_tokens, o ChatCLI pode escalar automaticamente:

Mensagem de Continuacao

Quando o modelo e interrompido por limite de tokens, o ChatCLI injeta uma mensagem de continuacao:
A mensagem instrui o modelo a continuar de onde parou, evitando repeticao de conteúdo já gerado.

Configuração

Feedback visual durante a compactação

Desde esta versão, o histórico nunca mais “congela” o terminal durante uma compactação longa. O HistoryCompactor emite status em cada fase do pipeline via SetStatusCallback:
Cancelamento: a chamada LLM de summarização agora deriva do context do turno — Ctrl+C / ESC propaga corretamente e aborta a compactação sem corromper o histórico (retorna ctx.Err() em vez de cair para truncamento de emergência cego).

Microcompact (pré-budget)

A checagem de budget em si é honesta com o payload: pesa o texto das mensagens mais argumentos de tool calls nativas, payloads de imagem e excesso de system-parts, então históricos pesados em tools ou visão cruzam o limiar quando a requisição real cruza — não depois de um proxy já ter rejeitado. Antes do NeedsCompaction checar se o histórico excede o budget, o agent loop aplica ApplyMicrocompact — uma passada pure-Go, sem LLM, sem rede que progressivamente trunca/resume tool results antigos (2+ turnos atrás → head+tail preview; 4+ turnos atrás → one-line summary). Na maioria dos casos isso mantém o histórico dentro do budget sem disparar o Level 2 (caro). Com a camada de compressão ativa, o microcompact é sem perda: o tool result original é arquivado no store CCR antes do corte e o stub de preview/summary embute um marcador <<ccr:KEY>>. Os marcadores sobrevivem entre níveis — quando um preview truncado depois vira um summary de uma linha, o marcador permanece no summary — então o modelo sempre pode expandir o original com @recall.
Configurável via env:

Ratio de Orcamento Agressivo

No nivel 1, os limites de orcamento de tool results sao multiplicados por 0.5 (50%). Isso significa:

Fluxo de Recuperação

Após o truncamento nuclear (nível 3), o contexto de trabalho do modelo cai para as últimas 2 trocas. Com a camada de compressão ativa o conteúdo dropado permanece recuperável — os stubs carregam marcadores <<ccr:KEY>> que o modelo expande com @recall — mas o /compact proativo continua sendo a melhor experiência: um summary estruturado vale mais que uma pilha de marcadores de recall.

Interação com Outros Sistemas

A recuperação de contexto trabalha em conjunto com:

Tool Result Budget

O orcamento de resultados e a primeira linha de defesa. A recuperação ativa quando o orcamento não foi suficiente.

Microcompactacao

A compactação progressiva reduz o crescimento do contexto ao longo do tempo.

Controle de Conversa

O comando /compact e a forma proativa de prevenir overflow.

Cost Tracking

Monitore o uso de contexto para antecipar quando /compact sera necessário.