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

Persister les sessions dans un stockage externe

Miroir les transcriptions de session vers S3, Redis ou votre propre backend pour que n'importe quel hôte puisse les reprendre.

Par défaut, le SDK écrit les transcriptions de session dans des fichiers JSONL sous ~/.claude/projects/ sur le système de fichiers local. Un adaptateur SessionStore vous permet de mettre en miroir ces transcriptions vers votre propre backend, tel que S3, Redis ou une base de données, afin qu'une session créée sur un hôte puisse être reprise sur un autre.

Raisons courantes d'utiliser un magasin de sessions :

  • Déploiements multi-hôtes. Les fonctions serverless, les workers autoscalés et les exécuteurs CI ne partagent pas de système de fichiers. Un magasin partagé permet à n'importe quel réplica de reprendre n'importe quelle session.
  • Durabilité. Les conteneurs locaux sont éphémères. Un magasin sauvegardé par S3 ou une base de données survit aux redémarrages et aux redéploiements.
  • Conformité et audit. Conservez les transcriptions dans un stockage que vous gouvernez déjà, avec vos propres règles de rétention, chiffrement et contrôles d'accès.

L'interface `SessionStore`

Un SessionStore est un objet avec deux méthodes requises, append et load, et trois méthodes optionnelles. Le SDK appelle append pour écrire les entrées de transcription lors d'une requête et load pour les relire pour la reprise.

// 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 adresse une transcription. projectKey est un encodage stable et sûr pour le système de fichiers du répertoire de travail, sessionId est l'UUID de la session, et subpath est défini lorsque l'entrée appartient à une transcription de sous-agent ou à un fichier sidecar plutôt qu'à la conversation principale. Traitez subpath comme un suffixe de clé opaque ; il suit la disposition sur disque, par exemple subagents/agent-<id>. Lorsque subpath n'est pas défini, la clé fait référence à la transcription principale.

Méthode Requise Appelée quand
append Oui Après chaque lot d'entrées de transcription écrites localement. Les entrées sont des objets sûrs pour JSON, une par ligne dans le JSONL local.
load Oui Une fois avant le lancement du sous-processus, lorsque resume est défini. Retournez null si la session est inconnue.
listSessions Non Par listSessions({ sessionStore }) et par query()/startup() avec continue: true. Si non défini, ces appels lèvent une exception.
delete Non Par deleteSession({ sessionStore }). La suppression de la clé principale (pas de subpath) doit en cascade à toutes les sous-clés de cette session. Si non défini, la suppression est une no-op, ce qui convient aux backends append-only.
listSubkeys Non Pendant la reprise, pour découvrir les transcriptions de sous-agents. Si non défini, seule la transcription principale est restaurée.

Démarrage rapide

Le SDK expédie un InMemorySessionStore pour le développement et les tests. L'exemple ci-dessous exécute une requête avec le magasin attaché, capture l'ID de session du message de résultat, puis reprend à partir du magasin dans un deuxième appel query(). Le deuxième appel transmet la même instance de magasin plus resume, afin que le SDK charge la transcription à partir du magasin au lieu du système de fichiers 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);
}
}

La deuxième requête affiche un résumé des fichiers de la première requête, ce qui montre que l'agent a repris avec le contexte complet du magasin.

Écrivez votre propre adaptateur

Implémentez append et load par rapport à votre backend. Ajoutez listSessions, delete et listSubkeys si vous voulez que listSessions(), deleteSession() et la reprise de sous-agent fonctionnent par rapport au magasin.

Les entrées transmises à append sont typées comme SessionStoreEntry (un objet { type: string; ... }). Traitez-les comme des valeurs JSON-safe opaques : persistez-les dans l'ordre et retournez-les de load dans le même ordre. load doit retourner des entrées qui sont deep-equal à ce qui a été ajouté ; la sérialisation byte-equal n'est pas requise, donc les backends comme Postgres jsonb qui réorganisent les clés d'objet vont bien.

Implémentations de référence

Le référentiel TypeScript SDK inclut des adaptateurs de référence exécutables pour S3, Redis et Postgres sous examples/session-stores/. Ils ne sont pas publiés sur npm ; copiez le fichier src/ dont vous avez besoin dans votre projet et installez le client backend correspondant.

Adaptateur Client backend Modèle de stockage
S3SessionStore @aws-sdk/client-s3 Un fichier de partie JSONL par append() ; load() liste, trie et concatène.
RedisSessionStore ioredis Liste RPUSH/LRANGE par transcription, plus un index de sorted-set de session.
PostgresSessionStore pg Une ligne par entrée dans une table jsonb, ordonnée par BIGSERIAL.

Chaque adaptateur prend une instance de client préconfigurée, afin que vous contrôliez les identifiants, TLS, la région et le pooling. Par exemple, avec 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" },
})) {
  // ...
}

Validez votre adaptateur

Les deux SDK expédient une suite de conformité qui affirme le contrat comportemental que append, load et les méthodes optionnelles doivent satisfaire. Les tests pour les méthodes optionnelles ignorent automatiquement lorsque ces méthodes ne sont pas implémentées.

En TypeScript, copiez shared/conformance.ts du répertoire d'exemples dans votre suite de tests. En Python, la suite est expédiée dans le package :

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)

Notes de comportement

Architecture à double écriture

Le magasin est un miroir, pas un remplacement. Le sous-processus Claude Code écrit toujours d'abord sur le disque local ; le SDK transfère ensuite chaque lot à append(). Si vous voulez que la copie locale soit éphémère, pointez CLAUDE_CONFIG_DIR vers un répertoire temporaire dans options.env. Parce que le miroir dépend des écritures locales, sessionStore ne peut pas être combiné avec persistSession: false ; le SDK lève une exception si vous définissez les deux. Il lève également une exception s'il est combiné avec enableFileCheckpointing, car les blobs de sauvegarde de l'historique des fichiers sont écrits directement sur le disque local et ne sont pas mis en miroir vers le magasin.

Les écritures en miroir sont au mieux

Si append() rejette ou expire, l'erreur est enregistrée, un message { type: "system", subtype: "mirror_error" } est émis dans l'itérateur, et la requête continue. La transcription locale est déjà durable sur disque, donc une panne du magasin n'interrompt pas l'agent ou ne perd pas de données localement. Les lots qui échouent ne sont pas retentés, donc surveillez mirror_error si vous devez détecter une perte de données du magasin.

`getSessionMessages` retourne la chaîne post-compaction

getSessionMessages({ sessionStore }) retourne la chaîne de messages liée que l'agent verrait à la reprise. Après la compaction automatique, les tours antérieurs sont remplacés par un résumé, donc une session dont le magasin contient 503 entrées brutes peut retourner 18 messages de getSessionMessages. Pour l'historique brut complet, y compris les tours pré-compaction et les entrées de métadonnées, appelez store.load(key) directement.

`forkSession` n'est pas une copie byte

forkSession({ sessionStore }) lit les entrées source, réécrit chaque champ sessionId et remapte les UUID de message, puis ajoute les entrées transformées sous une nouvelle clé. Une copie au niveau de l'adaptateur ou un raccourci CopyObject produirait une transcription qui référence toujours l'ancien ID de session, donc le SDK n'en utilise pas.

Transcriptions de sous-agents

Les transcriptions de sous-agents sont mises en miroir sous subpath: "subagents/agent-<id>". listSubagents({ sessionStore }) nécessite que l'adaptateur implémente listSubkeys ; getSubagentMessages({ sessionStore }) l'utilise quand disponible mais revient au subpath direct quand il n'est pas défini. La reprise appelle également listSubkeys pour restaurer les fichiers de sous-agents ; sans cela, seule la transcription principale est matérialisée.

Rétention

Le SDK ne supprime jamais de votre magasin de son propre chef. La rétention est la responsabilité de l'adaptateur : implémentez des TTL, des politiques de cycle de vie S3 ou un nettoyage programmé selon vos exigences de conformité. Les transcriptions locales sous CLAUDE_CONFIG_DIR sont balayées indépendamment par le paramètre cleanupPeriodDays.

Supporté sur

Les fonctions SDK suivantes acceptent une option sessionStore et opèrent par rapport au magasin au lieu du système de fichiers local quand elle est fournie :