Stateful agents maintain conversational history and state across interactions using sessions. The ACP SDK leverages this concept by maintaining a descriptor for each session and storing its contents at resource servers. This allows agents to access the complete history of interactions within a session, provided that the same session is used consistently across runs.

ACP Client Sessions

The ACP SDK provides a convenient way to maintain session through the session() context manager. When using a session, the SDK automatically handles session ID management, ensuring that all runs within the session share the same ID. This makes it easy to build stateful conversations where agents can reference previous interactions:
session.py
async with Client(base_url="http://localhost:8000") as client, client.session() as session:
    # First interaction
    run = await session.run_sync(agent="echo", input=[Message(parts=[MessagePart(content="Hello, my name is Joseph!")])])
    # Second interaction in same session
    run = await session.run_sync(agent="echo", input=[Message(parts=[MessagePart(content="What is my name?")])])

ACP Server sessions

When building ACP agent, the context argument contains a session instance containing session’s ID, history and latest state from all the previous runs in the same session.
stateful_agent.py
@server.agent()
async def stateful_agent(input: list[Message], context: Context) -> AsyncGenerator[RunYield, RunYieldResume]:
    history = [message async for message in context.session.load_history()]
    large_state = await context.session.load_state()
    # run agent
    #   mutate part of the state
    #   yield messages ...
    context.session.state = await context.session.store_state(large_state)
    # history is updated automatically by the SDK based on yields