Phase 14 - Lesson 34
Memória do Repositório e Estado Durável
O histórico do chat é volátil. O repositório é durável. A workbench armazena o estado do agente em arquivos versionados para que a próxima sessão, o próximo agente e o próximo revisor leiam todos da mesma fonte da verdade.
Tipo: Build
Linguagens: Python (stdlib + jsonschema opcional)
Pré-requisitos: Fase 14 · 32 (Minimal Workbench)
Tempo: ~60 minutos
Objetivos de Aprendizagem
- Definir o que pertence à memória do repositório e o que pertence ao histórico do chat.
- Criar JSON Schemas para
agent_state.jsonetask_board.json. - Construir um gerenciador de estado que carrega, valida, modifica e persiste o estado de forma atômica.
- Usar o schema para rejeitar gravações inválidas antes que corrompam a workbench.
O Problema
O agente finaliza uma sessão. O chat é fechado. A próxima sessão é aberta e pergunta por onde começar. O modelo diz "deixe-me verificar os arquivos", lê notas desatualizadas e refaz o trabalho que já estava concluído. Ou pior, ele reescreve um arquivo finalizado porque ninguém lhe disse que o arquivo estava pronto.
A solução da workbench é a memória do repositório: o estado reside em arquivos JSON no repositório, escritos sob um schema, persistidos de forma atômica e fáceis de visualizar diferenças (diff-friendly) em revisões de código. O chat é um fluxo transitório; o repositório é o sistema de registro.
O Conceito
flowchart LR
Agent[Loop do Agente] --> Manager[StateManager]
Manager --> Schema[agent_state.schema.json]
Schema --> Validate{válido?}
Validate -- sim --> Write[agent_state.json]
Validate -- não --> Reject[rejeitar + lançar erro]
Write --> Manager
O que pertence à memória do repositório
| Pertence | Não pertence |
|---|---|
| ID da tarefa ativa | Transcrições brutas de chat |
| Arquivos modificados nesta sessão | Rastreamento de raciocínio a nível de token |
| Suposições que o agente fez | "O usuário parecia frustrado" |
| Bloqueios em aberto | Amostras de conclusões (completions) |
| Próxima ação | IDs de modelos específicos do provedor |
O teste é a durabilidade: isso seria útil daqui a três meses em uma execução de CI? Se sim, vai para o repositório. Se não, é telemetria.
Estado schema-first
O JSON Schema é o contrato. Sem ele, cada agente inventa novos campos, cada revisor precisa aprender um novo formato e cada script de CI tem que tratar versões anteriores como casos especiais. Com ele, uma gravação ruim é uma gravação recusada.
O schema cobre:
- Chaves obrigatórias.
- Valores de
statuspermitidos. - Valores proibidos (por exemplo,
nullpara arrays). - Restrições de padrão (IDs de tarefas correspondendo a
T-\d{3,}). - Campo de versão para migrações.
Gravações atômicas
As gravações de estado precisam sobreviver a falhas parciais: gravar em um arquivo temporário, realizar fsync e renomear substituindo o destino. O arquivo de estado é a fonte da verdade; um arquivo gravado pela metade é pior do que nenhum arquivo.
Migrações
Quando o schema mudar, envie um script de migração junto com a atualização do schema. O arquivo de estado carrega um campo schema_version; o gerenciador se recusa a carregar um arquivo de uma versão que não pode migrar.
Construa
code/main.py implementa:
agent_state.schema.jsonetask_board.schema.json.- Um validador que usa apenas a stdlib (subconjunto do JSON Schema: required, type, enum, pattern, items).
StateManager.load,StateManager.update,StateManager.commitcom gravações atômicas do tipo cria-temporário-e-renomeia (temp-and-rename).- Uma demonstração que modifica o estado, persiste, recarrega e prova o ciclo completo (round-trip).
Execute:
python3 code/main.py
O script grava workdir/agent_state.json e workdir/task_board.json, modifica-os ao longo de dois turnos e imprime o estado validado em cada etapa.
Padrões de produção na prática
Quatro padrões transformam o mínimo desta lição em algo que um monorepo multiagente consegue suportar.
Gravação atômica com temporário e renomeação não é opcional. Um relatório de bug do projeto Hive de março de 2026 documenta claramente o modo de falha: state.json era gravado via write_text() e as exceções eram capturadas e silenciadas. Gravações parciais faziam com que as sessões fossem retomadas com estados corrompidos sem qualquer sinal de alerta. A correção é sempre: tempfile.mkstemp no mesmo diretório do destino, escrever, fsync, os.replace (renomeação atômica em POSIX e Windows). O atomic_write desta lição faz exatamente isso.
Chaves de idempotência em cada chamada de ferramenta não idempotente. Se um agente falhar após chamar uma ferramenta, mas antes de salvar o ponto de verificação (checkpoint) do resultado, a recuperação repetirá a chamada da ferramenta. Isso é seguro para leituras, mas perigoso para e-mails, inserções no banco de dados e uploads de arquivos. O padrão: registrar cada ID de chamada de ferramenta em um pending_calls.jsonl antes da execução. Na tentativa de repetição, verificar o ID; se estiver presente, pular a chamada e usar o resultado em cache. A Anthropic e o LangChain destacam isso em suas diretrizes de 2026; o checkpointer do LangGraph persiste as gravações pendentes pelo mesmo motivo.
Separe artefatos grandes do estado. Não armazene arquivos CSV, transcrições longas ou arquivos gerados em agent_state.json. Salve o artefato como um arquivo separado (ou faça o upload para um armazenamento de objetos) e mantenha apenas o caminho no estado. Os checkpoints continuam pequenos e rápidos; os artefatos crescem de forma independente.
Event sourcing para auditoria, snapshots para retomar. Adicione a um log de eventos (state.events.jsonl) a cada modificação; faça snapshots periódicos para state.json. A retomada lê o snapshot e, em seguida, reproduz todos os eventos após o carimbo de data/hora (timestamp) do snapshot. Isso custa mais espaço em disco, mas permite reproduzir as decisões do agente exatamente como ocorreram — essencial ao depurar execuções de longo prazo (long-horizon). É o mesmo formato que o Postgres usa internamente para WAL.
Migrações de schema ou recusa de carregamento. O número inteiro schema_version é o contrato. Quando o gerenciador carrega um arquivo com uma versão desconhecida, ele se recusa a ler. Envie um script de migração junto com a atualização do schema; o tools/migrate_state.py é executado de forma idempotente a cada inicialização.
Uso
Em produção:
- Checkpointers do LangGraph. Mesma ideia, armazenamento diferente. O checkpointer persiste o estado do grafo no SQLite, Postgres ou em um backend customizado. O schema ensinado nesta lição é o que você usará quando o checkpointer falhar e você precisar ler o estado manualmente.
- Blocos de memória do Letta. Blocos persistentes com schemas estruturados (Fase 14 · 08). A mesma disciplina voltada para personas de longa execução.
- OpenAI Agents SDK session store. Backends plugáveis, cientes do schema. O arquivo de estado nesta lição é o backend de arquivo local.
Implementação
outputs/skill-state-schema.md gera um par de JSON Schema específico para o projeto (estado + painel/board), um StateManager em Python conectado a gravações atômicas e uma estrutura de migração para que a próxima atualização de schema não quebre a workbench.
Exercícios
- Adicione um carimbo de data/hora (timestamp)
last_human_touch. Recuse qualquer gravação do agente dentro de cinco segundos após uma edição humana. - Estenda o validador para suportar
oneOfpara que uma tarefa possa ser uma tarefa de build ou uma tarefa de revisão com diferentes campos obrigatórios. - Adicione um campo
schema_versione escreva a migração de v1 para v2 (renomeieblockerspararisks). - Mova o backend de armazenamento de um arquivo local para o SQLite. Mantenha a API do
StateManageridêntica. - Execute dois agentes contra o mesmo arquivo de estado com uma corrida de gravação (write race) de 50 ms. O que dá errado e como a renomeação atômica protege você?
Termos-Chave
| Termo | O que as pessoas dizem | O que realmente significa |
|---|---|---|
| Memória do repositório (Repo memory) | "Arquivo de notas" | Estado armazenado em arquivos rastreados no repositório, sob um schema |
| Schema-first | "Validar entradas" | Definir o contrato antes de quem escreve, rejeitando desvios |
| Gravação atômica | "Apenas renomeie" | Gravar em arquivo temporário, realizar fsync e renomear, para que falhas parciais não corrompam os dados |
| Migração | "Atualização de schema" | Um script que transforma o estado vN em estado v(N+1) |
| Sistema de registro (System of record) | "Fonte da verdade" | O artefato que a workbench trata como autoritativo |
Leituras Adicionais
- Especificação do JSON Schema
- Checkpointers do LangGraph
- Blocos de memória do Letta
- Fast.io, AI Agent State Checkpointing: A Practical Guide — checkpointing com foco no schema (schema-first) e idempotência
- Fast.io, AI Agent Workflow State Persistence: Best Practices 2026 — controle de concorrência, TTL, event sourcing
- Hive Issue #6263 — non-atomic state.json writes silently ignored — o modo de falha em um projeto real
- eunomia, Checkpoint/Restore Systems: Evolution, Techniques, Applications — primitivas de CR da história dos SOs aplicadas a agentes
- Indium, 7 State Persistence Strategies for Long-Running AI Agents in 2026
- Microsoft Agent Framework, Compaction
- Fase 14 · 08 — blocos de memória e computação em tempo de suspensão (sleep-time compute)
- Fase 14 · 32 — o mínimo de três arquivos que esta lição esquematiza
- Fase 14 · 40 — pacotes de handoff lidos a partir do mesmo schema