Skip to main content
The ClaudeAgentStorage integration persists messages from the Claude Agent SDK to Acontext automatically. It stores only UserMessage and AssistantMessage in Anthropic format — SystemMessage, ResultMessage, and StreamEvent are used only for session-id resolution.

Quick Start

1

Install dependencies

pip install claude-agent-sdk acontext python-dotenv
2

Configure environment

ANTHROPIC_API_KEY=your_anthropic_key_here
ACONTEXT_API_KEY=sk-ac-your-api-key
3

Run agent with Acontext

import asyncio
from acontext import AcontextAsyncClient, ClaudeAgentStorage
from claude_agent_sdk import ClaudeAgentOptions, ClaudeSDKClient

async def main():
    acontext_client = AcontextAsyncClient(api_key="sk-ac-your-api-key")
    storage = ClaudeAgentStorage(client=acontext_client)

    options = ClaudeAgentOptions(
        extra_args={"replay-user-messages": None},  # include UserMessage in stream
    )
    async with ClaudeSDKClient(options=options) as claude_client:
        await claude_client.query("What is the capital of France?")
        async for message in claude_client.receive_response():
            await storage.save_message(message)

asyncio.run(main())
The replay-user-messages flag ensures UserMessage is included in the receive_response() stream so that both sides of the conversation are stored. Without it, only AssistantMessage appears in the stream and user messages won’t be persisted.

Session Handling

Auto-discovered session id

By default, ClaudeAgentStorage discovers the session id from the Claude Agent SDK. When the Claude session id is a valid UUID, Acontext reuses it as the Acontext session id (via use_uuid). This means the Acontext session and the Claude session share the same id, making it easy to correlate them across systems. If the Claude stream provides a non-UUID session id, it is ignored and Acontext generates its own session id instead.
storage = ClaudeAgentStorage(client=acontext_client)

# session_id is None until the init message arrives
async for message in claude_client.receive_response():
    await storage.save_message(message)

# After init: storage.session_id matches the Claude session id
print(storage.session_id)

Explicit Acontext session

To correlate the Claude run with a specific Acontext session:
session = await acontext_client.sessions.create()
storage = ClaudeAgentStorage(client=acontext_client, session_id=session.id)

async for message in claude_client.receive_response():
    await storage.save_message(message)

Options

Include thinking blocks

By default, ThinkingBlock content is omitted from stored messages. To include it as native thinking blocks:
storage = ClaudeAgentStorage(
    client=acontext_client,
    include_thinking=True,
)
Thinking blocks are stored as Anthropic thinking content blocks with their signature preserved. When retrieved in Anthropic or Gemini format, they round-trip as native thinking blocks. When retrieved in OpenAI format, thinking content is automatically downgraded to plain text. The stored message meta will contain "has_thinking": True for observability.

Custom error handling

By default, API errors during storage are logged and swallowed so your message loop is never interrupted. To customize:
storage = ClaudeAgentStorage(
    client=acontext_client,
    on_error=lambda exc, msg: print(f"Storage failed: {exc}"),
)

User identifier

Pass a user string to associate the Acontext session with a specific user. This value is forwarded to sessions.create() when the session is first created:
storage = ClaudeAgentStorage(
    client=acontext_client,
    user="alice@example.com",
)

What gets stored

Message typeStored?Notes
UserMessageYesrole: "user". String content wrapped as text block. ToolUseBlock skipped (invalid in user role).
AssistantMessageYesrole: "assistant". model stored in message meta. ToolResultBlock skipped (invalid in assistant role). If error field is set, its value is included in meta.error for observability.
SystemMessageNoUsed only for session-id resolution (subtype == "init" in Python, session_id field in TypeScript).
ResultMessageNoFallback session-id source.
StreamEventNoFallback session-id source.

Next Steps