Sessions
The Agents SDK provides built-in session memory to automatically maintain conversation history across multiple agent runs, eliminating the need to manually handle .to_input_list()
between turns.
Sessions stores conversation history for a specific session, allowing agents to maintain context without requiring explicit manual memory management. This is particularly useful for building chat applications or multi-turn conversations where you want the agent to remember previous interactions.
Quick start
from agents import Agent, Runner, SQLiteSession
# Create agent
agent = Agent(
name="Assistant",
instructions="Reply very concisely.",
)
# Create a session instance with a session ID
session = SQLiteSession("conversation_123")
# First turn
result = await Runner.run(
agent,
"What city is the Golden Gate Bridge in?",
session=session
)
print(result.final_output) # "San Francisco"
# Second turn - agent automatically remembers previous context
result = await Runner.run(
agent,
"What state is it in?",
session=session
)
print(result.final_output) # "California"
# Also works with synchronous runner
result = Runner.run_sync(
agent,
"What's the population?",
session=session
)
print(result.final_output) # "Approximately 39 million"
How it works
When session memory is enabled:
- Before each run: The runner automatically retrieves the conversation history for the session and prepends it to the input items.
- After each run: All new items generated during the run (user input, assistant responses, tool calls, etc.) are automatically stored in the session.
- Context preservation: Each subsequent run with the same session includes the full conversation history, allowing the agent to maintain context.
This eliminates the need to manually call .to_input_list()
and manage conversation state between runs.
Memory operations
Basic operations
Sessions supports several operations for managing conversation history:
from agents import SQLiteSession
session = SQLiteSession("user_123", "conversations.db")
# Get all items in a session
items = await session.get_items()
# Add new items to a session
new_items = [
{"role": "user", "content": "Hello"},
{"role": "assistant", "content": "Hi there!"}
]
await session.add_items(new_items)
# Remove and return the most recent item
last_item = await session.pop_item()
print(last_item) # {"role": "assistant", "content": "Hi there!"}
# Clear all items from a session
await session.clear_session()
Using pop_item for corrections
The pop_item
method is particularly useful when you want to undo or modify the last item in a conversation:
from agents import Agent, Runner, SQLiteSession
agent = Agent(name="Assistant")
session = SQLiteSession("correction_example")
# Initial conversation
result = await Runner.run(
agent,
"What's 2 + 2?",
session=session
)
print(f"Agent: {result.final_output}")
# User wants to correct their question
assistant_item = await session.pop_item() # Remove agent's response
user_item = await session.pop_item() # Remove user's question
# Ask a corrected question
result = await Runner.run(
agent,
"What's 2 + 3?",
session=session
)
print(f"Agent: {result.final_output}")
Memory options
No memory (default)
OpenAI Conversations API memory
Use the OpenAI Conversations API to persist conversation state without managing your own database. This is helpful when you already rely on OpenAI-hosted infrastructure for storing conversation history.
from agents import OpenAIConversationsSession
session = OpenAIConversationsSession()
# Optionally resume a previous conversation by passing a conversation ID
# session = OpenAIConversationsSession(conversation_id="conv_123")
result = await Runner.run(
agent,
"Hello",
session=session,
)
SQLite memory
from agents import SQLiteSession
# In-memory database (lost when process ends)
session = SQLiteSession("user_123")
# Persistent file-based database
session = SQLiteSession("user_123", "conversations.db")
# Use the session
result = await Runner.run(
agent,
"Hello",
session=session
)
Multiple sessions
from agents import Agent, Runner, SQLiteSession
agent = Agent(name="Assistant")
# Different sessions maintain separate conversation histories
session_1 = SQLiteSession("user_123", "conversations.db")
session_2 = SQLiteSession("user_456", "conversations.db")
result1 = await Runner.run(
agent,
"Hello",
session=session_1
)
result2 = await Runner.run(
agent,
"Hello",
session=session_2
)
SQLAlchemy-powered sessions
For more advanced use cases, you can use a SQLAlchemy-powered session backend. This allows you to use any database supported by SQLAlchemy (PostgreSQL, MySQL, SQLite, etc.) for session storage.
Example 1: Using from_url
with in-memory SQLite
This is the simplest way to get started, ideal for development and testing.
import asyncio
from agents import Agent, Runner
from agents.extensions.memory.sqlalchemy_session import SQLAlchemySession
async def main():
agent = Agent("Assistant")
session = SQLAlchemySession.from_url(
"user-123",
url="sqlite+aiosqlite:///:memory:",
create_tables=True, # Auto-create tables for the demo
)
result = await Runner.run(agent, "Hello", session=session)
if __name__ == "__main__":
asyncio.run(main())
Example 2: Using an existing SQLAlchemy engine
In a production application, you likely already have a SQLAlchemy AsyncEngine
instance. You can pass it directly to the session.
import asyncio
from agents import Agent, Runner
from agents.extensions.memory.sqlalchemy_session import SQLAlchemySession
from sqlalchemy.ext.asyncio import create_async_engine
async def main():
# In your application, you would use your existing engine
engine = create_async_engine("sqlite+aiosqlite:///conversations.db")
agent = Agent("Assistant")
session = SQLAlchemySession(
"user-456",
engine=engine,
create_tables=True, # Auto-create tables for the demo
)
result = await Runner.run(agent, "Hello", session=session)
print(result.final_output)
await engine.dispose()
if __name__ == "__main__":
asyncio.run(main())
Custom memory implementations
You can implement your own session memory by creating a class that follows the Session
protocol:
from agents.memory.session import SessionABC
from agents.items import TResponseInputItem
from typing import List
class MyCustomSession(SessionABC):
"""Custom session implementation following the Session protocol."""
def __init__(self, session_id: str):
self.session_id = session_id
# Your initialization here
async def get_items(self, limit: int | None = None) -> List[TResponseInputItem]:
"""Retrieve conversation history for this session."""
# Your implementation here
pass
async def add_items(self, items: List[TResponseInputItem]) -> None:
"""Store new items for this session."""
# Your implementation here
pass
async def pop_item(self) -> TResponseInputItem | None:
"""Remove and return the most recent item from this session."""
# Your implementation here
pass
async def clear_session(self) -> None:
"""Clear all items for this session."""
# Your implementation here
pass
# Use your custom session
agent = Agent(name="Assistant")
result = await Runner.run(
agent,
"Hello",
session=MyCustomSession("my_session")
)
Session management
Session ID naming
Use meaningful session IDs that help you organize conversations:
- User-based:
"user_12345"
- Thread-based:
"thread_abc123"
- Context-based:
"support_ticket_456"
Memory persistence
- Use in-memory SQLite (
SQLiteSession("session_id")
) for temporary conversations - Use file-based SQLite (
SQLiteSession("session_id", "path/to/db.sqlite")
) for persistent conversations - Use SQLAlchemy-powered sessions (
SQLAlchemySession("session_id", engine=engine, create_tables=True)
) for production systems with existing databases supported by SQLAlchemy - Use OpenAI-hosted storage (
OpenAIConversationsSession()
) when you prefer to store history in the OpenAI Conversations API - Consider implementing custom session backends for other production systems (Redis, Django, etc.) for more advanced use cases
Session management
# Clear a session when conversation should start fresh
await session.clear_session()
# Different agents can share the same session
support_agent = Agent(name="Support")
billing_agent = Agent(name="Billing")
session = SQLiteSession("user_123")
# Both agents will see the same conversation history
result1 = await Runner.run(
support_agent,
"Help me with my account",
session=session
)
result2 = await Runner.run(
billing_agent,
"What are my charges?",
session=session
)
Complete example
Here's a complete example showing session memory in action:
import asyncio
from agents import Agent, Runner, SQLiteSession
async def main():
# Create an agent
agent = Agent(
name="Assistant",
instructions="Reply very concisely.",
)
# Create a session instance that will persist across runs
session = SQLiteSession("conversation_123", "conversation_history.db")
print("=== Sessions Example ===")
print("The agent will remember previous messages automatically.\n")
# First turn
print("First turn:")
print("User: What city is the Golden Gate Bridge in?")
result = await Runner.run(
agent,
"What city is the Golden Gate Bridge in?",
session=session
)
print(f"Assistant: {result.final_output}")
print()
# Second turn - the agent will remember the previous conversation
print("Second turn:")
print("User: What state is it in?")
result = await Runner.run(
agent,
"What state is it in?",
session=session
)
print(f"Assistant: {result.final_output}")
print()
# Third turn - continuing the conversation
print("Third turn:")
print("User: What's the population of that state?")
result = await Runner.run(
agent,
"What's the population of that state?",
session=session
)
print(f"Assistant: {result.final_output}")
print()
print("=== Conversation Complete ===")
print("Notice how the agent remembered the context from previous turns!")
print("Sessions automatically handles conversation history.")
if __name__ == "__main__":
asyncio.run(main())
API Reference
For detailed API documentation, see:
Session
- Protocol interfaceSQLiteSession
- SQLite implementationOpenAIConversationsSession
- OpenAI Conversations API implementationSQLAlchemySession
- SQLAlchemy-powered implementation