SpyBara
Go Premium

agent-sdk/session-storage.md 2026-06-16 21:57 UTC to 2026-06-17 17:02 UTC

2 added, 0 removed.

2026
Wed 24 22:02 Tue 23 22:00 Mon 22 23:59 Fri 19 22:58 Thu 18 22:00 Wed 17 17:02 Tue 16 21:57 Mon 15 23:02 Sat 13 21:59 Fri 12 22:00 Thu 11 23:01 Wed 10 23:57 Tue 9 06:34 Mon 8 06:52 Sat 6 06:24 Fri 5 06:45 Thu 4 06:52 Wed 3 06:53 Tue 2 06:51

Persistir sessões em armazenamento externo

Espelhe transcrições de sessão para S3, Redis ou seu próprio backend para que qualquer host possa retomá-las.

Por padrão, o SDK escreve transcrições de sessão em arquivos JSONL em ~/.claude/projects/ no sistema de arquivos local. Um adaptador SessionStore permite que você espelhe essas transcrições para seu próprio backend, como S3, Redis ou um banco de dados, para que uma sessão criada em um host possa ser retomada em outro.

Razões comuns para usar um session store:

  • Implantações multi-host. Funções serverless, workers com autoscaling e runners de CI não compartilham um sistema de arquivos. Um store compartilhado permite que qualquer réplica retome qualquer sessão.
  • Durabilidade. Contêineres locais são efêmeros. Um store apoiado por S3 ou um banco de dados sobrevive a reinicializações e redeploys.
  • Conformidade e auditoria. Mantenha transcrições em armazenamento que você já governa, com suas próprias regras de retenção, criptografia e controles de acesso.

A interface `SessionStore`

Um SessionStore é um objeto com dois métodos obrigatórios, append e load, e três métodos opcionais. O SDK chama append para escrever entradas de transcrição durante uma consulta e load para lê-las novamente para retomada.

// Exported from @anthropic-ai/claude-agent-sdk as
// SessionStore, SessionKey, SessionStoreEntry.

type SessionKey = {
projectKey: string;
sessionId: string;
subpath?: string;
};

type SessionStore = {
// Required
append(key: SessionKey, entries: SessionStoreEntry[]): Promise<void>;
load(key: SessionKey): Promise<SessionStoreEntry[] | null>;

// Optional
listSessions?(
projectKey: string,
): Promise<Array<{ sessionId: string; mtime: number }>>;
delete?(key: SessionKey): Promise<void>;
listSubkeys?(key: {
projectKey: string;
sessionId: string;
}): Promise<string[]>;
};

SessionKey endereça uma transcrição. projectKey é uma codificação estável e segura para sistema de arquivos do diretório de trabalho, sessionId é o UUID da sessão, e subpath é definido quando a entrada pertence a uma transcrição de subagente ou arquivo sidecar em vez da conversa principal. Trate subpath como um sufixo de chave opaco; ele segue o layout em disco, por exemplo subagents/agent-<id>. Quando subpath é indefinido, a chave se refere à transcrição principal.

Método Obrigatório Chamado quando
append Sim Após cada lote de entradas de transcrição ser escrito localmente. As entradas são objetos seguros para JSON, um por linha no JSONL local.
load Sim Uma vez antes do subprocess ser gerado, quando resume é definido. Retorne null se a sessão for desconhecida.
listSessions Não Por listSessions({ sessionStore }) e por query()/startup() com continue: true. Se indefinido, essas chamadas lançam.
delete Não Por deleteSession({ sessionStore }). Deletar a chave principal (sem subpath) deve cascatear para todas as subchaves dessa sessão. Se indefinido, a exclusão é uma no-op, o que é adequado para backends append-only.
listSubkeys Não Durante retomada, para descobrir transcrições de subagentes. Se indefinido, apenas a transcrição principal é restaurada.

Início rápido

O SDK fornece um InMemorySessionStore para desenvolvimento e testes. O exemplo abaixo executa uma consulta com o store anexado, captura o ID da sessão da mensagem de resultado e depois retoma do store em uma segunda chamada query(). A segunda chamada passa a mesma instância de store mais resume, para que o SDK carregue a transcrição do store em vez do sistema de arquivos local:

import { query, InMemorySessionStore } from "@anthropic-ai/claude-agent-sdk";

const store = new InMemorySessionStore();

let sessionId: string | undefined;
for await (const message of query({
prompt: "List the TypeScript files under src/",
options: { sessionStore: store },
})) {
if (message.type === "result") {
sessionId = message.session_id;
}
}

// Resume from the store. The agent has full context from the first call.
for await (const message of query({
prompt: "Summarize what those files do",
options: { sessionStore: store, resume: sessionId },
})) {
if (message.type === "result" && message.subtype === "success") {
console.log(message.result);
}
}

A segunda consulta imprime um resumo dos arquivos da primeira consulta, o que mostra que o agente retomou com contexto completo do store.

Escreva seu próprio adaptador

Implemente append e load contra seu backend. Adicione listSessions, delete e listSubkeys se você quiser que listSessions(), deleteSession() e retomada de subagentes funcionem contra o store.

As entradas passadas para append são digitadas como SessionStoreEntry (um objeto { type: string; ... }). Trate-as como valores JSON-safe opacos: persista-as em ordem e retorne-as de load na mesma ordem. load deve retornar entradas que sejam deep-equal ao que foi anexado; serialização byte-equal não é necessária, então backends como Postgres jsonb que reordenam chaves de objeto são adequados.

Implementações de referência

O repositório do SDK TypeScript inclui adaptadores de referência executáveis para S3, Redis e Postgres em examples/session-stores/. Eles não são publicados no npm; copie o arquivo src/ que você precisa para seu projeto e instale o cliente backend correspondente.

Adaptador Cliente backend Modelo de armazenamento
S3SessionStore @aws-sdk/client-s3 Um arquivo de parte JSONL por append(); load() lista, ordena e concatena.
RedisSessionStore ioredis Lista RPUSH/LRANGE por transcrição, mais um índice de conjunto ordenado de sessão.
PostgresSessionStore pg Uma linha por entrada em uma tabela jsonb, ordenada por BIGSERIAL.

Cada adaptador recebe uma instância de cliente pré-configurada, para que você controle credenciais, TLS, região e pooling. Por exemplo, com S3:

import { query } from "@anthropic-ai/claude-agent-sdk";
import { S3Client } from "@aws-sdk/client-s3";
import { S3SessionStore } from "./S3SessionStore"; // copied from examples/session-stores/s3

const store = new S3SessionStore({
  bucket: "my-claude-sessions",
  prefix: "transcripts",
  client: new S3Client({ region: "us-east-1" }),
});

for await (const message of query({
  prompt: "Hello!",
  options: { sessionStore: store },
})) {
  if (message.type === "result" && message.subtype === "success") {
    console.log(message.result);
  }
}

// Later, possibly on a different host:
for await (const message of query({
  prompt: "Continue where we left off",
  options: { sessionStore: store, resume: "previous-session-id" },
})) {
  // ...
}

Valide seu adaptador

Ambos os SDKs fornecem um conjunto de conformidade que afirma o contrato comportamental que append, load e os métodos opcionais devem satisfazer. Testes para métodos opcionais pulam automaticamente quando esses métodos não são implementados.

Em TypeScript, copie shared/conformance.ts do diretório de exemplos para seu conjunto de testes. Em Python, o conjunto é fornecido no pacote:

import pytest
from claude_agent_sdk.testing import run_session_store_conformance


@pytest.mark.asyncio
async def test_my_store_conformance():
    await run_session_store_conformance(MyRedisStore)

Notas de comportamento

Arquitetura de escrita dupla

O store é um espelho, não uma substituição. O subprocess Claude Code sempre escreve no disco local primeiro; o SDK então encaminha cada lote para append(). Se você quiser que a cópia local seja efêmera, aponte CLAUDE_CONFIG_DIR para um diretório temporário em options.env. Como o espelho depende de escritas locais, sessionStore não pode ser combinado com persistSession: false; o SDK lança se você definir ambos. Também lança se combinado com enableFileCheckpointing, já que blobs de backup de histórico de arquivo são escritos diretamente no disco local e não são espelhados para o store.

Escritas de espelho são best-effort

Se append() rejeita ou expira, o erro é registrado, uma mensagem { type: "system", subtype: "mirror_error" } é emitida para o iterador, e a consulta continua. A transcrição local já é durável no disco, então uma interrupção de store não interrompe o agente ou perde dados localmente. Lotes que falham não são retentados, então monitore mirror_error se você precisar detectar perda de dados de store.

`getSessionMessages` retorna a cadeia pós-compactação

getSessionMessages({ sessionStore }) retorna a cadeia de mensagens vinculada que o agente veria ao retomar. Após auto-compactação, turnos anteriores são substituídos por um resumo, então uma sessão cujo store contém 503 entradas brutas pode retornar 18 mensagens de getSessionMessages. Para o histórico bruto completo, incluindo turnos pré-compactação e entradas de metadados, chame store.load(key) diretamente.

`forkSession` não é uma cópia byte

forkSession({ sessionStore }) lê as entradas de origem, reescreve cada campo sessionId e remapeia UUIDs de mensagem, depois anexa as entradas transformadas sob uma nova chave. Uma cópia em nível de adaptador ou atalho CopyObject produziria uma transcrição que ainda referencia o ID de sessão antigo, então o SDK não usa um.

Transcrições de subagentes

Transcrições de subagentes são espelhadas em subpath: "subagents/agent-<id>". listSubagents({ sessionStore }) requer que o adaptador implemente listSubkeys; getSubagentMessages({ sessionStore }) o usa quando disponível, mas volta para o subpath direto quando é indefinido. Retomada também chama listSubkeys para restaurar arquivos de subagentes; sem ele, apenas a transcrição principal é materializada.

Retenção

O SDK nunca deleta de seu store por conta própria. Retenção é responsabilidade do adaptador: implemente TTLs, políticas de ciclo de vida S3 ou limpeza agendada de acordo com seus requisitos de conformidade. Transcrições locais em CLAUDE_CONFIG_DIR são limpas independentemente pela configuração cleanupPeriodDays.

Suportado em

As seguintes funções do SDK aceitam uma opção sessionStore e operam contra o store em vez do sistema de arquivos local quando fornecido: