- Início
- Documentation
- Configuração
- Arquitetura de armazenamento de blobs e artefatos
Arquitetura de armazenamento de blobs e artefatos
Este documento descreve como o coding-agent armazena payloads grandes/binários fora do JSONL de sessão, como a saída truncada de ferramentas é persistida e como as URLs internas (artifact://, agent://) resolvem de volta para os dados armazenados.
Por que dois sistemas de armazenamento existem
Seção intitulada “Por que dois sistemas de armazenamento existem”O runtime utiliza dois mecanismos de persistência diferentes para diferentes formatos de dados:
- Blobs endereçados por conteúdo (
blob:sha256:<hash>): armazenamento global orientado a binários, usado para externalizar payloads base64 de imagens grandes das entradas de sessão persistidas. - Artefatos com escopo de sessão (arquivos sob
<arquivoDeSessão-sem-.jsonl>/): arquivos de texto por sessão usados para saídas completas de ferramentas e saídas de subagentes.
Eles são intencionalmente separados:
- o armazenamento de blobs otimiza a deduplicação e referências estáveis por hash de conteúdo,
- o armazenamento de artefatos otimiza ferramentas de sessão append-only e recuperação por humanos/ferramentas através de IDs locais.
Limites de armazenamento e layout em disco
Seção intitulada “Limites de armazenamento e layout em disco”Limite do armazenamento de blobs (global)
Seção intitulada “Limite do armazenamento de blobs (global)”SessionManager constrói BlobStore(getBlobsDir()), então os arquivos de blob ficam em um diretório global compartilhado de blobs (não em uma pasta de sessão).
Nomenclatura de arquivos de blob:
- caminho do arquivo:
<blobsDir>/<sha256-hex> - sem extensão
- string de referência armazenada nas entradas:
blob:sha256:<sha256-hex>
Implicações:
- o mesmo conteúdo binário entre sessões resolve para o mesmo hash/caminho,
- escritas são idempotentes no nível do conteúdo,
- blobs podem sobreviver a qualquer arquivo de sessão individual.
Limite de artefatos (local à sessão)
Seção intitulada “Limite de artefatos (local à sessão)”ArtifactManager deriva o diretório de artefatos a partir do caminho do arquivo de sessão:
- arquivo de sessão:
.../<timestamp>_<sessionId>.jsonl - diretório de artefatos:
.../<timestamp>_<sessionId>/(remove.jsonl)
Os tipos de artefatos compartilham este diretório:
- arquivos de saída de ferramenta truncada:
<numericId>.<toolType>.log(paraartifact://) - arquivos de saída de subagente:
<outputId>.md(paraagent://)
Esquemas de alocação de IDs e nomes
Seção intitulada “Esquemas de alocação de IDs e nomes”IDs de blob: hash de conteúdo
Seção intitulada “IDs de blob: hash de conteúdo”BlobStore.put() computa SHA-256 sobre os bytes binários brutos e retorna:
hash: digest hexadecimal,path:<blobsDir>/<hash>,ref:blob:sha256:<hash>.
Nenhum contador local de sessão é utilizado.
IDs de artefato: inteiro monotônico local à sessão
Seção intitulada “IDs de artefato: inteiro monotônico local à sessão”ArtifactManager escaneia os arquivos de artefato *.log existentes no primeiro uso para encontrar o ID numérico máximo existente e define nextId = max + 1.
Comportamento de alocação:
- formato do arquivo:
{id}.{toolType}.log - IDs são strings sequenciais (
"0","1", …) - a retomada não sobrescreve artefatos existentes porque o escaneamento acontece antes da alocação.
Se o diretório de artefatos estiver ausente, o escaneamento retorna lista vazia e a alocação começa do 0.
IDs de saída de agente (agent://)
Seção intitulada “IDs de saída de agente (agent://)”AgentOutputManager aloca IDs para saídas de subagentes como <index>-<requestedId> (opcionalmente aninhado sob prefixo pai, por exemplo, 0-Parent.1-Child). Ele escaneia arquivos .md existentes na inicialização para continuar a partir do próximo índice na retomada.
Fluxo de dados de persistência
Seção intitulada “Fluxo de dados de persistência”1) Caminho de reescrita na persistência de entradas de sessão
Seção intitulada “1) Caminho de reescrita na persistência de entradas de sessão”Antes que as entradas de sessão sejam escritas (#rewriteFile / persistência incremental), SessionManager chama prepareEntryForPersistence() (via truncateForPersistence).
Comportamentos-chave:
- Truncamento de strings grandes: strings superdimensionadas são cortadas e sufixadas com
"[Session persistence truncated large content]". - Remoção de campos transientes:
partialJsonejsonlEventssão removidos das entradas persistidas. - Externalização de imagens para blobs:
- aplica-se apenas a blocos de imagem em arrays
content, - apenas quando
datanão é já uma referência de blob, - apenas quando o comprimento do base64 é pelo menos o limite (
BLOB_EXTERNALIZE_THRESHOLD = 1024), - substitui base64 inline por
blob:sha256:<hash>.
- aplica-se apenas a blocos de imagem em arrays
Isso mantém o JSONL de sessão compacto enquanto preserva a recuperabilidade.
2) Caminho de reidratação no carregamento de sessão
Seção intitulada “2) Caminho de reidratação no carregamento de sessão”Ao abrir uma sessão (setSessionFile), após as migrações, SessionManager executa resolveBlobRefsInEntries().
Para cada bloco de imagem de message/custom-message com blob:sha256:<hash>:
- lê os bytes do blob a partir do armazenamento de blobs,
- converte os bytes de volta para base64,
- modifica a entrada em memória para inline base64 para consumidores em tempo de execução.
Se o blob estiver ausente:
resolveImageData()registra um aviso,- retorna a string de referência original sem alteração,
- o carregamento continua (sem crash).
3) Caminho de despejo/truncamento de saída de ferramenta
Seção intitulada “3) Caminho de despejo/truncamento de saída de ferramenta”OutputSink alimenta a saída em streaming no bash/python/ssh e executores relacionados.
Comportamento:
- Cada chunk é sanitizado e adicionado ao buffer de cauda em memória.
- Quando os bytes em memória excedem o limite de despejo (
DEFAULT_MAX_BYTES, 50KB), o sink marca a saída como truncada. - Se um caminho de artefato está disponível, o sink abre um escritor de arquivo e escreve:
- o conteúdo já em buffer uma vez,
- todos os chunks subsequentes.
- O buffer em memória é sempre aparado para a janela de cauda para exibição.
dump()retorna um resumo incluindoartifactIdapenas quando o file sink foi criado com sucesso.
Efeito prático:
- UI/retorno de ferramenta mostra a cauda truncada,
- a saída completa é preservada no arquivo de artefato e referenciada como
artifact://<id>.
Se a criação do file sink falhar (erro de I/O, caminho ausente, etc.), o sink silenciosamente faz fallback para truncamento somente em memória; a saída completa não é persistida.
Modelo de acesso por URL
Seção intitulada “Modelo de acesso por URL”Referências blob:
Seção intitulada “Referências blob:”blob:sha256:<hash> é uma referência de persistência dentro dos payloads de entradas de sessão, não um esquema de URL interno tratado pelo roteador. A resolução é feita pelo SessionManager durante o carregamento da sessão.
artifact://<id>
Seção intitulada “artifact://<id>”Tratado pelo ArtifactProtocolHandler:
- requer diretório de artefatos de sessão ativo,
- o ID deve ser numérico,
- resolve por correspondência do prefixo do nome de arquivo
<id>., - retorna texto bruto (
text/plain) do arquivo.logcorrespondente, - quando ausente, o erro inclui lista de IDs de artefatos disponíveis.
Comportamento com diretório ausente:
- se o diretório de artefatos não existir, lança
No artifacts directory found.
agent://<id>
Seção intitulada “agent://<id>”Tratado pelo AgentProtocolHandler sobre <artifactsDir>/<id>.md:
- a forma simples retorna texto markdown,
- as formas
/pathou?q=realizam extração JSON, - extração por path e query não podem ser combinadas,
- se extração é solicitada, o conteúdo do arquivo deve ser parseado como JSON.
Comportamento com diretório ausente:
- lança
No artifacts directory found.
Comportamento com saída ausente:
- lança
Not found: <id>com IDs disponíveis dos arquivos.mdexistentes.
Integração com a ferramenta read:
readsuporta paginação com offset/limit para leituras de URL interna sem extração,- rejeita
offset/limitquando extraçãoagent://é utilizada.
Semânticas de retomada, fork e movimentação
Seção intitulada “Semânticas de retomada, fork e movimentação”Retomada
Seção intitulada “Retomada”ArtifactManagerescaneia arquivos{id}.*.logexistentes na primeira alocação e continua a numeração.AgentOutputManagerescaneia IDs de saída.mdexistentes e continua a numeração.SessionManagerreidrata referências de blob para base64 no carregamento.
SessionManager.fork() cria um novo arquivo de sessão com novo ID de sessão e link parentSession, então retorna os caminhos de arquivo antigo/novo. A cópia de artefatos é tratada pelo AgentSession.fork():
- tenta cópia recursiva do diretório de artefatos antigo para o novo diretório de artefatos,
- diretório antigo ausente é tolerado,
- erros de cópia que não são ENOENT são registrados como avisos e o fork ainda é concluído.
Implicações de ID após o fork:
- se a cópia foi bem-sucedida, os contadores de artefatos na nova sessão continuam após o ID máximo copiado,
- se a cópia falhou/foi ignorada, os IDs de artefatos da nova sessão começam do
0.
Implicações de blob após o fork:
- blobs são globais e endereçados por conteúdo, então nenhuma cópia de diretório de blobs é necessária.
Mover para novo cwd
Seção intitulada “Mover para novo cwd”SessionManager.moveTo() renomeia tanto o arquivo de sessão quanto o diretório de artefatos para o novo diretório de sessão padrão, com lógica de rollback se uma etapa posterior falhar. Isso preserva a identidade dos artefatos enquanto realoca o escopo da sessão.
Tratamento de falhas e caminhos de fallback
Seção intitulada “Tratamento de falhas e caminhos de fallback”| Caso | Comportamento |
|---|---|
| Arquivo de blob ausente durante reidratação | Avisa e mantém a string de referência blob:sha256: em memória |
Blob read ENOENT via BlobStore.get | Retorna null |
Diretório de artefatos ausente (ArtifactManager.listFiles) | Retorna lista vazia (alocação pode começar do zero) |
Diretório de artefatos ausente (artifact:// / agent://) | Lança explicitamente No artifacts directory found |
| ID de artefato não encontrado | Lança com listagem de IDs disponíveis |
| Falha na inicialização do escritor de artefato do OutputSink | Continua com truncamento somente de cauda (sem artefato de saída completa) |
| Sem arquivo de sessão (alguns caminhos de tarefa) | Ferramenta Task faz fallback para diretório de artefatos temporário para saídas de subagente |
Externalização de blob binário vs artefatos de saída de texto
Seção intitulada “Externalização de blob binário vs artefatos de saída de texto”- Externalização de blob é para payloads de imagens binárias dentro do conteúdo de entradas de sessão persistidas; substitui base64 inline no JSONL por referências de conteúdo estáveis.
- Artefatos são arquivos de texto simples para saída de execução e saída de subagente; são endereçáveis por IDs locais à sessão através de URLs internas.
Os dois sistemas se intersectam apenas indiretamente (ambos reduzem o inchaço do JSONL de sessão) mas possuem caminhos diferentes de identidade, tempo de vida e recuperação.
Arquivos de implementação
Seção intitulada “Arquivos de implementação”src/session/blob-store.ts— formato de referência de blob, hashing, put/get, helpers de externalização/resolução.src/session/artifacts.ts— modelo de diretório de artefatos de sessão e alocação de ID numérico de artefato.src/session/streaming-output.ts— comportamento de truncamento/despejo-para-arquivo doOutputSinke metadados de resumo.src/session/session-manager.ts— transformações de persistência, reidratação de blob no carregamento, interações de fork/movimentação de sessão.src/session/agent-session.ts— cópia de diretório de artefatos durante fork interativo.src/tools/output-utils.ts— bootstrap do gerenciador de artefatos de ferramentas e alocação de caminho de artefato por ferramenta.src/internal-urls/artifact-protocol.ts— resolver deartifact://.src/internal-urls/agent-protocol.ts— resolver deagent://+ extração JSON.src/sdk.ts— wiring do roteador de URLs internas e resolver de diretório de artefatos.src/task/output-manager.ts— alocação de ID de saída de agente com escopo de sessão paraagent://.src/task/executor.ts— escritas de artefatos de saída de subagente (<id>.md) e fallback para diretório de artefatos temporário.