Documentação oficial desta página · v0.20.6
Compressão e cache de contexto
O Hermes Agent usa um sistema de compressão dupla e o cache de prompt da Anthropic para administrar com eficiência o uso da janela de contexto em conversas longas.
Arquivos de origem: agent/context_engine.py (ABC), agent/context_compressor.py (motor padrão),
agent/prompt_caching.py, gateway/run.py (higiene de sessão), run_agent.py (procure por _compress_context)
Motor de contexto plugável
O gerenciamento de contexto é construído sobre a ABC ContextEngine (agent/context_engine.py). O ContextCompressor embutido é a implementação padrão, mas plugins podem trocá-lo por motores alternativos (por exemplo, o Lossless Context Management).
context:
engine: "compressor" # padrão — sumarização com perdas, embutida
engine: "lcm" # exemplo — plugin que fornece contexto sem perdas
O motor é responsável por:
- Decidir quando a compactação deve disparar (
should_compress()) - Executar a compactação (
compress()) - Opcionalmente, expor ferramentas que o agente pode chamar (por exemplo,
lcm_grep) - Acompanhar o uso de tokens a partir das respostas da API
A escolha vem da configuração, pela chave context.engine no config.yaml. A ordem de resolução:
- Procura o diretório
plugins/context_engine/<name>/ - Procura no sistema geral de plugins (
register_context_engine()) - Recai no
ContextCompressorembutido
Motores de plugin nunca são ativados sozinhos — o usuário precisa definir explicitamente o context.engine com o nome do plugin. O padrão "compressor" sempre usa o embutido.
Configure em hermes plugins → Provider Plugins → Context Engine, ou edite o config.yaml direto.
Para construir um plugin de motor de contexto, veja Plugins de motor de contexto.
Sistema de compressão dupla
O Hermes tem duas camadas separadas de compressão, que operam de forma independente:
┌───────────────────────────────┐
Mensagem chegando │ Higiene de sessão do gateway │ Dispara em 85% do contexto
─────────────────► │ (antes do agente, estimativa)│ Rede de segurança p/ sessões grandes
└───────────────┬───────────────┘
│
▼
┌───────────────────────────────┐
│ ContextCompressor do agente │ Dispara em 50% do contexto (padrão)
│ (no laço, tokens reais) │ Gerenciamento normal de contexto
└───────────────────────────────┘
1. Higiene de sessão do gateway (limiar de 85%)
Fica em gateway/run.py (procure por Session hygiene: auto-compress). É uma rede de segurança que
roda antes de o agente processar uma mensagem. Ela evita falhas de API quando as sessões
crescem demais entre turnos (por exemplo, acúmulo de uma noite inteira no Telegram/Discord).
- Limiar: fixo em 85% do comprimento de contexto do modelo
- Fonte dos tokens: prefere os tokens reais informados pela API no último turno; recai
numa estimativa grosseira baseada em caracteres (
estimate_messages_tokens_rough) - Dispara: só quando
len(history) >= 4e a compressão está ligada - Objetivo: pegar as sessões que escaparam do compressor do próprio agente
O limiar da higiene do gateway é propositalmente mais alto que o do compressor do agente. Deixá-lo em 50% (igual ao do agente) causava compressão prematura em todo turno nas sessões longas de gateway.
2. ContextCompressor do agente (limiar de 50%, configurável)
Fica em agent/context_compressor.py. É o sistema principal de compressão,
que roda dentro do laço de ferramentas do agente, com acesso a contagens de token
precisas, informadas pela API.
Configuração
Todas as opções de compressão são lidas do config.yaml, sob a chave compression:
compression:
enabled: true # Liga/desliga a compressão (padrão: true)
threshold: 0.50 # Fração da janela de contexto (padrão: 0.50 = 50%)
# model_thresholds: # Limiar por modelo (casamento por substring,
# "glm-5.2": 0.40 # a chave mais longa vence). Veja "Limiar por
# "claude-sonnet": 0.35 # modelo" abaixo.
target_ratio: 0.20 # Quanto do limiar manter como cauda (padrão: 0.20)
tail_mode: lean # Política de retenção da cauda: lean | legacy (padrão: lean)
protect_last_n: 20 # Mínimo de mensagens protegidas na cauda (padrão: 20)
min_tail_user_messages: 1 # Mensagens reais do usuário garantidas na cauda (padrão: 1)
codex_gpt55_autoraise: true # gpt-5.5 no OAuth do Codex: sobe o gatilho para 85% (padrão: true)
codex_gpt55_autoraise_notice: true # Mostra o aviso único do autoraise (padrão: true)
codex_app_server_auto: native # native|hermes|off para compactação de thread no Codex app-server
codex_responses_native: false # gpt-5.6 na OpenAI direta/Codex: compactação no servidor (opt-in)
codex_responses_compact_threshold: 200000 # Gatilho da compactação no servidor (tokens de entrada)
in_place: true # Compacta no mesmo id de sessão, sem rotação (padrão: true)
# Modelo/provedor de sumarização configurados em auxiliary:
auxiliary:
compression:
model: null # Sobrescreve o modelo dos resumos (padrão: detecção automática)
provider: auto # Provedor: "auto", "openrouter", "nous", "main" etc.
base_url: null # Endpoint personalizado compatível com OpenAI
Detalhes dos parâmetros
| Parâmetro | Padrão | Faixa | Descrição |
|---|---|---|---|
threshold | 0.50 | 0.0-1.0 | A compressão dispara quando os tokens do prompt ficam ≥ threshold × context_length |
model_thresholds | {} | mapa | Sobrescreve o threshold por modelo. As chaves são casadas por substring contra o nome do modelo (a correspondência mais longa vence). O piso de contexto pequeno continua valendo por cima (veja abaixo) |
target_ratio | 0.20 | 0.10-0.80 | Controla o orçamento de tokens da proteção de cauda: threshold_tokens × target_ratio (só no modo legacy — o lean usa o próprio limite) |
tail_mode | lean | lean, legacy | Política de retenção da cauda. O legacy mantém uma cauda literal do tamanho de target_ratio (~100 mil tokens ou mais em modelos de janela grande). O lean mantém uma cauda limitada a 2.5% × janela de contexto (piso de 10 mil, teto de 25 mil) e, em vez disso, carrega a continuidade no resumo: digests em pedaços que preservam identificadores da região compactada, um índice de âncoras extraído mecanicamente (números de PR, SHAs, caminhos, strings de erro — por regex, nunca parafraseados), toda mensagem real do usuário citada literalmente (orçamento da mais nova para a mais velha) e um ponteiro de recuperação por session_search, para o agente reacessar qualquer coisa que virou resumo. Resultado em sessões reais de 500 mil tokens: ~49 mil retidos contra ~162 mil, com recall maior quando combinado com a recuperação (veja evals/compaction/results/). Custa algumas chamadas extras ao sumarizador na fronteira da compactação. Resultados de ferramenta antigos dentro da cauda lean são rebaixados a esqueletos de uma linha com um ponteiro de recuperação |
protect_last_n | 20 | ≥1 | Número mínimo de mensagens recentes sempre preservadas |
min_tail_user_messages | 1 | ≥1 | Número mínimo de mensagens REAIS (acionáveis) do usuário garantidas na cauda não comprimida. 1 = a âncora única de último usuário que já existia (padrão que preserva o comportamento). Suba para 3, por exemplo, para manter os 3 últimos turnos reais do usuário na íntegra, mesmo quando saídas volumosas de ferramenta enchem o orçamento de tokens da cauda. Ecos vazios de plataforma, repasses de compactação e linhas sintéticas de continuação nunca contam para o N. A garantia vence o orçamento de tokens da cauda — a cauda pode passar do orçamento quando a âncora puxa o corte para trás |
protect_first_n | 3 | (fixo no código) | Prompt de sistema + primeira troca sempre preservados |
idle_compact_after_seconds | 0 | ≥0 segundos | Opcional: compacta logo de cara quando uma sessão é retomada depois desse tanto de segundos ociosa (0 = desligado). Pula quando o contexto está ≤ threshold × target_ratio; respeita as travas de cooldown, de anti-thrash e de bloqueio |
codex_gpt55_autoraise | true | bool | Sobe o gatilho para 85% no gpt-5.5 pela rota OAuth do ChatGPT Codex (veja abaixo). Coloque false para manter o threshold global |
codex_gpt55_autoraise_notice | true | bool | Mostra o aviso único de autoraise do gpt-5.5 no Codex. Coloque false para manter o autoraise de 85% mas suprimir o banner |
codex_app_server_auto | native | native, hermes, off | Modo de compactação de thread para sessões do Codex app-server (veja abaixo) |
codex_responses_native | false | bool | Adere à compactação no lado do servidor da OpenAI, na Responses API. Só entra em ação para modelos da família gpt-5.6 na API direta da OpenAI ou numa assinatura do ChatGPT Codex (veja abaixo) |
codex_responses_compact_threshold | 200000 | ≥1 tokens | Gatilho da compactação no servidor, em tokens de entrada. É limitado abaixo do limiar local de compressão no momento da requisição, para o servidor compactar primeiro |
in_place | true | bool | Compacta no mesmo id de sessão, em vez de rotacionar para um novo (veja abaixo) |
Compactação no lugar (um id de sessão estável)
Com compression.in_place: true (o padrão), uma compactação reescreve a lista viva de mensagens no mesmo id de sessão: o prompt de sistema é remontado, o meio resumido entra no lugar e os turnos anteriores à compactação são arquivados de forma leve sob o mesmo id (active=0, compacted=1 no armazenamento de sessões) — continuam pesquisáveis pelo session_search e recuperáveis, nunca apagados. Não existe cadeia de parent_session_id nem renumeração de name #N; uma conversa mantém um id durável a vida inteira. Isso eliminou o grupo de bugs da rotação de sessão (estado de /goal perdido, sessões órfãs, buracos de busca nas fronteiras).
Quem consome observa o modo em vez de comparar ids de sessão:
- O evento
session:compresscarregain_place: true/falseeold_session_id(string vazia no modo no lugar, já que não existe id antigo). - O gateway refaz a linha de base do tratamento da transcrição a partir da flag
_last_compaction_in_placedo agente, que independe de rotação, e não de uma comparação de mudança de id.
Coloque in_place: false para voltar ao caminho antigo, com rotação, em que cada compactação registra um novo id de sessão ligado ao anterior por parent_session_id.
Limiar por modelo
O compression.model_thresholds deixa você disparar a compactação em pontos diferentes
conforme o modelo ativo — útil quando você alterna entre modelos de janelas de contexto
muito diferentes (por exemplo, um modelo de 1M de contexto pode comprimir mais tarde,
enquanto um de 128K deveria comprimir mais cedo):
compression:
threshold: 0.50
model_thresholds:
"glm-5.2": 0.40
"glm-5.2-1M": 0.25
"claude-sonnet": 0.35
Regras de resolução:
- As chaves são casadas por substring contra o nome do modelo; a chave que casa e é
mais longa vence (
glm-5.2-1Mganha deglm-5.2para o modeloglm-5.2-1M). - Quando nenhuma chave casa (ou o mapa está vazio), vale o
thresholdglobal. - A sobrescrita é resolvida de novo a cada troca por
/model; trocar para um modelo sem chave correspondente volta aothresholdglobal. - O piso de contexto pequeno continua valendo por cima das sobrescritas (só para cima):
modelos com janela de contexto abaixo de 512K têm piso de
0.75, então uma sobrescrita abaixo do piso é elevada a0.75, enquanto uma acima dele (por exemplo,0.80) vence.
Motores de contexto de plugin podem reaproveitar a mesma lógica de resolução com
from agent.context_compressor import resolve_model_threshold; motores que
sobrescrevem o update_model() são donos da própria política de compactação e podem ignorar
o mapa.
Autoraise do limiar no gpt-5.5 do Codex
O backend OAuth do ChatGPT Codex limita o gpt-5.5 a uma janela de contexto de 272K
(o mesmo slug expõe 1,05M na API direta da OpenAI e no OpenRouter, e 400K no
GitHub Copilot). No gatilho padrão de 50%, a compactação dispararia em ~136K —
metade da janela que o modelo realmente pode usar. Quando a rota ativa é o
OAuth do Codex (provider: openai-codex) e o modelo é o gpt-5.5, o Hermes sobe o
gatilho para 85% (~231K) e mostra um aviso com o comando para desativar. O
aviso aparece uma vez por perfil — um marcador em $HERMES_HOME
(.codex_gpt55_autoraise_notice) registra que ele já rodou, então inicializações repetidas
de agente/sessão (por exemplo, a cada mensagem que chega no gateway) não o emitem de novo; se o
limiar elevado mudar depois, ele avisa mais uma vez. Só essa rota exata é afetada;
o gpt-5.5 em qualquer outro provedor mantém o seu threshold global. Para voltar ao
valor global:
hermes config set compression.codex_gpt55_autoraise false
Para manter o autoraise de 85% e esconder só o aviso único:
hermes config set compression.codex_gpt55_autoraise_notice false
Variantes -900k de contexto grande no Codex (opt-in)
O backend do ChatGPT Codex anuncia uma janela de 272K para as famílias gpt-5.4 e gpt-5.6 (Sol/Terra/Luna), mas na prática aceita ~911 mil tokens de entrada em contas com assinatura do ChatGPT (verificado ao vivo em ago/2026). O Hermes mantém os 272K anunciados como padrão para os slugs base — uma janela maior significa mais tokens por requisição e um consumo bem mais rápido da assinatura, então a janela grande é estritamente opt-in.
Para usar a janela grande, escolha a variante explícita -900k no /model (por exemplo,
gpt-5.6-sol-900k, gpt-5.6-terra-900k, gpt-5.6-luna-900k,
gpt-5.4-900k). Elas são apelidos do lado do Hermes: o sufixo é removido antes de
o id do modelo ser mandado ao backend, e a contabilidade de preço/uso trata as variantes
como o modelo base. Slugs que de fato impõem 272K (gpt-5.5, gpt-5.4-mini)
não têm variante -900k.
Os limiares de compactação seguem a janela: os slugs base (272K) recebem o autoraise
de 85% descrito acima, enquanto as variantes -900k mantêm o seu
compression.threshold global (padrão de 50%, ~450K) — o autoraise existe para parar de
desperdiçar uma janela pequena, coisa de que uma janela de 900K não precisa.
Compactação de thread no Codex app-server
Sessões do Codex app-server (api_mode: codex_app_server — o runtime do agente/CLI
do codex) são diferentes de todas as outras rotas: o agente do codex é o dono do
contexto da thread por trás, então o sumarizador auxiliar do Hermes não consegue encolhê-lo —
reescrever o espelho local da transcrição deixa a thread real crescendo sem limite até um
reset duro de contexto. Nesse runtime, a compactação passa pelo mecanismo do próprio
app-server:
- A compactação manual (
/compress) pede ao app-server que compacte a thread (thread/compact/start) e espera o turno de compactação terminar. - A compactação automática é controlada pelo
compression.codex_app_server_auto: o padrãonativedeixa o app-server decidir quando compactar, e o Hermes registra os eventos de compactação resultantes (contadores de compressão, eventos de sessão). Coloquehermespara deixar o limiar de compressão do Hermes iniciar a compactação do app-server, ouoffpara desligar por completo a compactação automática iniciada pelo Hermes (o codex ainda pode compactar de forma nativa).
A transcrição local do Hermes nunca é reescrita nesse runtime — o state.db registra a fronteira de compactação enquanto a transcrição visível fica intacta. Todas as outras rotas (incluindo as sessões de chat por OAuth do Codex) mantêm o compressor de resumo do Hermes.
Compactação nativa da Responses (gpt-5.6 na OpenAI direta / assinatura do Codex)
A Responses API da OpenAI aceita compactação no lado do servidor: quando uma requisição inclui
context_management: [{type: "compaction", compact_threshold: N}] e a
entrada renderizada passa de N tokens, o servidor poda o contexto mais antigo num item de saída
compaction opaco e criptografado. O Hermes captura esse item no sidecar de replay que já
existe na mensagem do assistente e o manda de volta nos turnos seguintes, no lugar do
histórico podado — recuperação de longo alcance sem uma passada de resumo no cliente,
e compatível com ZDR (store: false, sem
previous_response_id).
Adira com compression.codex_responses_native: true. A liberação é propositalmente
estreita e reavaliada a cada requisição:
- Modelos: só a família gpt-5.6. Os outros modelos falham no servidor quando o campo está presente (o gpt-5.1/5.2 devolve HTTP 500 ou trava o fluxo — não existe rejeição estruturada para servir de gatilho de rebaixamento, verificado ao vivo em ago/2026).
- Rotas: só
api.openai.com(chave de API da OpenAI) ou o backend do ChatGPT Codex (OAuth da assinatura do Codex). A xAI, o GitHub/Copilot, o OpenRouter, relays e servidores locais nunca veem o campo.
Todo o resto da compressão fica igual: o compressor local segue armado como o dono da alternativa (o limiar nativo é limitado a ~8 mil tokens abaixo do gatilho local, para o servidor compactar primeiro), e uma rejeição estruturada do campo pelo provedor desliga a compactação nativa naquela sessão e repete a requisição sem ela. Trocar a sessão para um modelo ou rota não elegível simplesmente faz o campo parar de ser enviado — os checkpoints capturados são descartados do replay pela proteção de troca de emissor que já existe, quando o endpoint muda.
Valores calculados (para um modelo de 200K de contexto, nos padrões)
context_length = 200.000
threshold_tokens = 200.000 × 0,50 = 100.000
tail_token_budget = 100.000 × 0,20 = 20.000
max_summary_tokens = min(200.000 × 0,05, 12.000) = 10.000
O threshold_tokens é sempre threshold × context_length, em que context_length
é a janela de contexto do modelo principal do agente — nunca a do modelo
auxiliar/de resumo. Num modelo de 262.144 tokens, no padrão 0.50, o limiar é
262.144 × 0,50 = 131.072. Esse número ficar perto de um "contexto de 128K" comum
é coincidência da porcentagem, não sinal de que a janela do modelo auxiliar
seja o gatilho. A janela de contexto do modelo auxiliar é outro assunto — veja
o aviso "Comprimento de contexto do modelo de resumo" abaixo para entender como ela afeta se
um resumo consegue ser produzido, e não quando a compressão dispara.
Algoritmo de compressão
O método ContextCompressor.compress() segue um algoritmo de 4 fases:
Fase 1: podar resultados antigos de ferramenta (barato, sem chamada de LLM)
Resultados antigos de ferramenta (>200 caracteres) fora da cauda protegida são trocados por:
[Old tool output cleared to save context space]
Essa é uma passada prévia barata, que economiza bastante token das saídas prolixas de ferramenta (conteúdo de arquivos, saída de terminal, resultados de busca).
Fase 2: determinar as fronteiras
┌───────────────────────────────────────────────────────────────┐
│ Lista de mensagens │
│ │
│ [0..2] ← protect_first_n (sistema + primeira troca) │
│ [3..N] ← turnos do meio → RESUMIDOS │
│ [N..fim] ← cauda (por orçamento de tokens OU protect_last_n) │
│ │
└───────────────────────────────────────────────────────────────┘
A proteção da cauda é baseada em orçamento de tokens: ela caminha do fim para trás,
acumulando tokens até esgotar o orçamento. Recai na contagem fixa de
protect_last_n se o orçamento protegesse menos mensagens.
As fronteiras são alinhadas para não partir grupos de tool_call/tool_result.
O método _align_boundary_backward() anda por cima de resultados de ferramenta consecutivos
até achar a mensagem de assistente que os originou, mantendo os grupos inteiros.
Fase 3: gerar o resumo estruturado
O modelo de resumo precisa ter uma janela de contexto pelo menos tão grande quanto a do modelo principal do agente. A seção do meio inteira é mandada ao modelo de resumo numa única chamada de call_llm(task="compression"). Se o contexto do modelo de resumo for menor, a API devolve um erro de comprimento de contexto — o _generate_summary() captura o erro, registra um aviso e devolve None. O compressor então descarta os turnos do meio sem resumo, perdendo em silêncio o contexto da conversa. Essa é a causa mais comum de queda na qualidade da compactação.
Os turnos do meio são resumidos com o LLM auxiliar, usando um modelo estruturado:
## Goal
[What the user is trying to accomplish]
## Constraints & Preferences
[User preferences, coding style, constraints, important decisions]
## Progress
### Done
[Completed work — specific file paths, commands run, results]
### In Progress
[Work currently underway]
### Blocked
[Any blockers or issues encountered]
## Key Decisions
[Important technical decisions and why]
## Relevant Files
[Files read, modified, or created — with brief note on each]
## Next Steps
[What needs to happen next]
## Critical Context
[Specific values, error messages, configuration details]
O orçamento do resumo escala com a quantidade de conteúdo que está sendo comprimido:
- Fórmula:
content_tokens × 0.20(a constante_SUMMARY_RATIO) - Mínimo: 2.000 tokens
- Máximo:
min(context_length × 0.05, 12,000)tokens
Fase 4: montar as mensagens comprimidas
A lista comprimida de mensagens é:
- As mensagens de cabeça (com uma nota acrescentada ao prompt de sistema na primeira compressão)
- A mensagem de resumo (com o papel escolhido para não violar a regra de papéis iguais consecutivos)
- As mensagens de cauda (sem alteração)
Pares órfãos de tool_call/tool_result são limpos pelo _sanitize_tool_pairs():
- Resultados de ferramenta que apontam para chamadas removidas → removidos
- Chamadas de ferramenta cujos resultados foram removidos → recebem um resultado de esqueleto
Recompressão iterativa
Nas compressões seguintes, o resumo anterior é passado ao LLM com instruções para atualizá-lo em vez de resumir do zero. Isso preserva a informação ao longo de várias compactações — itens saem de "In Progress" para "Done", o novo progresso é acrescentado e a informação obsoleta é removida.
O campo _previous_summary da instância do compressor guarda o texto do último resumo
para isso.
Exemplo de antes/depois
Antes da compressão (45 mensagens, ~95 mil tokens)
[0] system: "Você é um assistente prestativo..." (prompt de sistema)
[1] user: "Me ajude a montar um projeto FastAPI"
[2] assistant: <tool_call> terminal: mkdir projeto </tool_call>
[3] tool: "diretório criado"
[4] assistant: <tool_call> write_file: main.py </tool_call>
[5] tool: "arquivo escrito (2,3KB)"
... mais 30 turnos de edição de arquivo, testes, depuração ...
[38] assistant: <tool_call> terminal: pytest </tool_call>
[39] tool: "8 passed, 2 failed\n..." (saída de 5KB)
[40] user: "Conserte os testes que falharam"
[41] assistant: <tool_call> read_file: tests/test_api.py </tool_call>
[42] tool: "import pytest\n..." (3KB)
[43] assistant: "Vi qual é o problema com as fixtures de teste..."
[44] user: "Ótimo, e acrescente tratamento de erro"
Depois da compressão (25 mensagens, ~45 mil tokens)
[0] system: "Você é um assistente prestativo...
[Nota: alguns turnos anteriores da conversa foram compactados...]"
[1] user: "Me ajude a montar um projeto FastAPI"
[2] assistant: "[CONTEXT COMPACTION] Turnos anteriores foram compactados...
## Goal
Montar um projeto FastAPI com testes e tratamento de erro
## Progress
### Done
- Estrutura do projeto criada: main.py, tests/, requirements.txt
- 5 endpoints de API implementados em main.py
- 10 casos de teste escritos em tests/test_api.py
- 8/10 testes passando
### In Progress
- Consertando 2 testes que falham (test_create_user, test_delete_user)
## Relevant Files
- main.py — app FastAPI com 5 endpoints
- tests/test_api.py — 10 casos de teste
- requirements.txt — fastapi, pytest, httpx
## Next Steps
- Consertar as fixtures dos testes que falham
- Acrescentar tratamento de erro"
[3] user: "Conserte os testes que falharam"
[4] assistant: <tool_call> read_file: tests/test_api.py </tool_call>
[5] tool: "import pytest\n..."
[6] assistant: "Vi qual é o problema com as fixtures de teste..."
[7] user: "Ótimo, e acrescente tratamento de erro"
Cache de prompt (Anthropic)
Origem: agent/prompt_caching.py
Reduz em cerca de 75% o custo dos tokens de entrada em conversas de vários turnos, ao cachear
o prefixo da conversa. Usa os pontos de corte de cache_control da Anthropic.
Estratégia: system_and_3
A Anthropic permite no máximo 4 pontos de corte de cache_control por requisição. O Hermes
usa a estratégia "system_and_3":
Ponto de corte 1: prompt de sistema (estável em todos os turnos)
Ponto de corte 2: antepenúltima mensagem não-sistema ─┐
Ponto de corte 3: penúltima mensagem não-sistema ├─ Janela deslizante
Ponto de corte 4: última mensagem não-sistema ─┘
Como funciona
O apply_anthropic_cache_control() faz uma cópia profunda das mensagens e injeta
marcadores de cache_control:
# Formato do marcador de cache
marker = {"type": "ephemeral"}
# Ou, para TTL de 1 hora:
marker = {"type": "ephemeral", "ttl": "1h"}
O marcador é aplicado de formas diferentes conforme o tipo de conteúdo:
| Tipo de conteúdo | Onde o marcador vai |
|---|---|
| Conteúdo em string | Convertido para [{"type": "text", "text": ..., "cache_control": ...}] |
| Conteúdo em lista | Acrescentado ao dicionário do último elemento |
| None/vazio | Acrescentado como msg["cache_control"] |
| Mensagens de ferramenta | Acrescentado como msg["cache_control"] (só na Anthropic nativa) |
Padrões de projeto conscientes do cache
-
Prompt de sistema estável: o prompt de sistema é o ponto de corte 1 e fica em cache em todos os turnos. Evite alterá-lo no meio da conversa (a compressão acrescenta uma nota só na primeira compactação).
-
A ordem das mensagens importa: acertar o cache exige casamento de prefixo. Acrescentar ou remover mensagens no meio invalida o cache de tudo que vem depois.
-
Interação entre compressão e cache: depois da compressão, o cache é invalidado na região comprimida, mas o cache do prompt de sistema sobrevive. A janela deslizante de 3 mensagens restabelece o cache em 1 ou 2 turnos.
-
Escolha do TTL: o padrão é
5m(5 minutos). Use1hem sessões de longa duração, nas quais o usuário dá pausas entre os turnos. -
A identidade do modelo faz parte da chave de cache: os caches do lado do provedor têm escopo por modelo (e por conta/chave de API) que atende a requisição. Qualquer troca de modelo no meio da conversa — uma troca explícita por
/model, uma queda para o modelo de reserva, ou uma rotação de pool de credenciais para outra conta — significa que a próxima requisição não acerta nada no cache e relê a conversa inteira pelo preço de entrada sem desconto. Isso é inerente ao funcionamento dos caches de provedor, não algo que o Hermes possa evitar; a documentação de/model, de provedores de reserva e de pools de credenciais traz avisos de custo justamente por isso. Não crie recursos que troquem o modelo ou as credenciais em silêncio no meio da sessão.
Ligar o cache de prompt
O cache de prompt é ligado automaticamente quando:
- O modelo é um Claude da Anthropic (detectado pelo nome do modelo)
- O provedor aceita
cache_control(API nativa da Anthropic ou OpenRouter)
# config.yaml — o TTL é configurável (precisa ser "5m" ou "1h")
prompt_caching:
cache_ttl: "5m"
A CLI mostra o status do cache na inicialização:
💾 Prompt caching: ENABLED (Claude via OpenRouter, 5m TTL)
Avisos de pressão de contexto
Os avisos intermediários de pressão de contexto foram removidos (veja o bloco de orçamento de iterações em run_agent.py, que anota: "No intermediate pressure warnings — they caused models to 'give up' prematurely on complex tasks"). A compressão dispara quando os tokens do prompt chegam ao compression.threshold configurado (padrão de 50%), sem nenhum passo de aviso antes; a higiene de sessão do gateway dispara como rede de segurança secundária em 85% da janela de contexto do modelo.