Commit 6b94ad0
Add Sessions for Automatic Conversation History Management (#752)
# Overview
Resolves #745
This PR introduces **Sessions**, a new core feature that automatically
maintains conversation history across multiple agent runs, eliminating
the need to manually handle `.to_input_list()` between turns.
## Key Features
### 🧠 Automatic Memory Management
- **Zero-effort conversation continuity**: Agents automatically remember
previous context without manual state management
- **Session-based organization**: Each conversation is isolated by
unique session IDs
- **Seamless integration**: Works with existing `Runner.run()`,
`Runner.run_sync()`, and `Runner.run_streamed()` methods
### 🔌 Extensible Session Protocol
- **Library-agnostic design**: Clean protocol interface allows any
storage backend
- **Drop-in implementations**: Easy integration with Redis, PostgreSQL,
MongoDB, or any custom storage
- **Production-ready interface**: Async-first design with proper error
handling and type safety
- **Vendor flexibility**: Library authors can provide their own Session
implementations
### 💾 Built-in SQLite Implementation
- **In-memory SQLite**: Perfect for temporary conversations during
development
- **Persistent SQLite**: File-based storage for conversations that
survive application restarts
- **Thread-safe operations**: Production-ready with connection pooling
and proper concurrency handling
### 🔧 Simple API
```python
# Before: Manual conversation management
result1 = await Runner.run(agent, "What's the weather?")
new_input = result1.to_input_list() + [{"role": "user", "content": "How about tomorrow?"}]
result2 = await Runner.run(agent, new_input)
# After: Automatic with Sessions
session = SQLiteSession("user_123")
result1 = await Runner.run(agent, "What's the weather?", session=session)
result2 = await Runner.run(agent, "How about tomorrow?", session=session) # Remembers context automatically
```
## What's Included
### Core Session Protocol
- **`Session` Protocol**: Clean, async interface that any storage
backend can implement
- **Type-safe design**: Full type hints and runtime validation
- **Standard operations**: `get_items()`, `add_items()`, `pop_item()`,
`clear_session()`
- **Extensibility-first**: Designed for third-party implementations
### Reference Implementation
- **`SQLiteSession` Class**: Production-ready SQLite implementation
- **Automatic schema management**: Creates tables and indexes
automatically
- **Connection pooling**: Thread-safe operations with proper resource
management
- **Flexible storage**: In-memory or persistent file-based databases
### Runner Integration
- **New `session` parameter**: Drop-in addition to existing `Runner`
methods
- **Backward compatibility**: Zero breaking changes to existing code
- **Automatic history management**: Prepends conversation history before
each run
## Session Protocol for Library Authors
The Session protocol provides a clean interface for implementing custom
storage backends:
```python
from agents.memory import Session
from typing import List
class MyCustomSession:
"""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[dict]:
"""Retrieve conversation history for this session."""
# Your implementation here
pass
async def add_items(self, items: List[dict]) -> None:
"""Store new items for this session."""
# Your implementation here
pass
async def pop_item(self) -> dict | 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
# Works seamlessly with any custom implementation
result = await Runner.run(agent, "Hello", session=MyCustomSession("session_123"))
```
### Example Third-Party Implementations
```python
# Redis-based session (hypothetical library implementation)
from redis_sessions import RedisSession
session = RedisSession("user_123", redis_url="redis://localhost:6379")
# PostgreSQL-based session (hypothetical library implementation)
from postgres_sessions import PostgreSQLSession
session = PostgreSQLSession("user_123", connection_string="postgresql://...")
# Cloud-based session (hypothetical library implementation)
from cloud_sessions import CloudSession
session = CloudSession("user_123", api_key="...", region="us-east-1")
# All work identically with the Runner
result = await Runner.run(agent, "Hello", session=session)
```
## Benefits
### For Application Developers
- **Reduces boilerplate**: No more manual `.to_input_list()` management
- **Prevents memory leaks**: Automatic cleanup and organized storage
- **Easier debugging**: Clear conversation history tracking
- **Flexible storage**: Choose the right backend for your needs
### For Library Authors
- **Clean integration**: Simple protocol to implement for any storage
backend
- **Type safety**: Full type hints and runtime validation
- **Async-first**: Modern async/await design throughout
- **Documentation**: Comprehensive examples and API reference
### For Applications
- **Better user experience**: Seamless conversation continuity
- **Scalable architecture**: Support for multiple concurrent
conversations
- **Flexible deployment**: In-memory for development, production storage
for scale
- **Multi-agent support**: Same conversation history can be shared
across different agents
## Usage Examples
### Basic Usage with SQLiteSession
```python
from agents import Agent, Runner, SQLiteSession
agent = Agent(name="Assistant", instructions="Reply concisely.")
session = SQLiteSession("conversation_123")
# Conversation flows naturally
await Runner.run(agent, "Hi, I'm planning a trip to Japan", session=session)
await Runner.run(agent, "What's the best time to visit?", session=session)
await Runner.run(agent, "How about cherry blossom season?", session=session)
```
### Multiple Sessions with Isolation
```python
# Different users get separate conversation histories
session_alice = SQLiteSession("user_alice")
session_bob = SQLiteSession("user_bob")
# Completely isolated conversations
await Runner.run(agent, "I like pizza", session=session_alice)
await Runner.run(agent, "I like sushi", session=session_bob)
```
### Persistent vs In-Memory Storage
```python
# In-memory database (lost when process ends)
session = SQLiteSession("user_123")
# Persistent file-based database
session = SQLiteSession("user_123", "conversations.db")
```
### Session Management Operations
```python
session = SQLiteSession("user_123")
# 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 (useful for corrections)
last_item = await session.pop_item()
# Clear all items from a session
await session.clear_session()
```
### Message Correction Pattern
```python
# User wants to correct their last question
user_message = await session.pop_item() # Remove user's question
assistant_message = await session.pop_item() # Remove agent's response
# Ask a corrected question
result = await Runner.run(
agent,
"What's 2 + 3?", # Corrected question
session=session
)
```
## Technical Details
### Session Protocol Design
- **Async-first**: All operations are async for non-blocking I/O
- **Type-safe**: Full type hints with runtime validation
- **Error handling**: Graceful degradation and detailed error messages
- **Resource management**: Proper cleanup and connection handling
### SQLiteSession Implementation
- **Thread-safe operations** with connection pooling
- **Automatic schema management** with proper indexing
- **JSON serialization** for message storage
- **Memory-efficient** conversation retrieval and storage
- **Cross-platform compatibility**
## Breaking Changes
None. This is a purely additive feature that doesn't affect existing
functionality.
## Documentation
- Updated core concepts in `docs/index.md` to highlight Sessions as a
key primitive
- New comprehensive guide at `docs/sessions.md` with protocol
implementation examples
- Enhanced `docs/running_agents.md` with automatic vs manual
conversation management
- Full API reference integration via `docs/ref/memory.md`
- Implementation guide for library authors
Sessions represent a significant architectural improvement for building
conversational AI applications with the Agents SDK. The extensible
Session protocol enables the ecosystem to provide specialized storage
backends while maintaining a consistent, simple API for application
developers.
---------
Co-authored-by: Rohan Mehta <rm@openai.com>1 parent db85a6d commit 6b94ad0
File tree
21 files changed
+1462
-33
lines changed- docs
- ref
- scripts
- examples
- basic
- reasoning_content
- src/agents
- memory
- tests
- mcp
- model_settings
21 files changed
+1462
-33
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
| 15 | + | |
| 16 | + | |
16 | 17 | | |
17 | 18 | | |
18 | 19 | | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
19 | 128 | | |
20 | 129 | | |
21 | 130 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
21 | 22 | | |
22 | 23 | | |
23 | 24 | | |
| 25 | + | |
24 | 26 | | |
25 | 27 | | |
26 | 28 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
68 | | - | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
69 | 71 | | |
70 | 72 | | |
71 | 73 | | |
| |||
84 | 86 | | |
85 | 87 | | |
86 | 88 | | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
87 | 122 | | |
88 | 123 | | |
89 | 124 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
266 | 266 | | |
267 | 267 | | |
268 | 268 | | |
269 | | - | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
270 | 272 | | |
271 | 273 | | |
272 | 274 | | |
| |||
0 commit comments