This pull request adds a new script for docs, which generates missing
`ref/**/*.md` files. The script can be executed when you run `make
build-docs` command. The script does not do:
- overwrite the existing ones
- create files for _XXX.py and `__init__.py`
Note that the title part is generated like `tool_context` to `Tool
Context`. `openai_provider` will be `Openai Provider`, so some of them
needs a little manual work to adjust.
The direct need is to add `tool_context.md` for
https://github.com/openai/openai-agents-python/pull/1043 but it should
be useful for future maintenance.
This pull request adds a new GitHub Actions job to automate the
translation of document pages.
- Before this job can run, **OPENAI_API_KEY must be added to the project
secrets.**
- It typically takes 8–10 minutes using the o3 model, so the job is
configured to run only when there are changes under docs/ or in
mkdocs.yml.
- The job commits and pushes the translated changes, but it does not
deploy the documents to GitHub Pages. If we think it’s better to deploy
the latest changes automatically as well, I’m happy to update the
workflow. (Personally, I don’t think it’s necessary, since the changes
will be deployed with the next deployment job execution)
# 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>
This pull request introduces the following changes:
1. **Exclude translated pages from search**: I explored ways to make the
search plugin work with the i18n plugin, but it would require extensive
custom JavaScript hacks. So for now, I’m holding off on this work.
2. **Switch from GPT-4.1 to o3 for even better translation quality**:
While 4.1 performs well, o3 shows even greater quality for this task,
and there’s no reason to avoid using it.
This pull request enhances the document translation workflow by
switching to the new GPT-4.1 model. The generator script’s prompt now
includes a “workflow” section that guides the model to iterate
self-reviews on its outputs to autonomously achieve the highest quality.
This addition has noticeably improved the naturalness and consistency of
the wording in the translated outputs.
Detected typos using typos-cli (https://crates.io/crates/typos-cli). It
detected "occured" in a string constant "handoff_occured" too, but I
didn't change the part this time because it could be a minor breaking
change.
Full outputs:
```
% typos .
error: `Supresses` should be `Suppresses`
--> ./src/agents/function_schema.py:134:7
|
134 | # Supresses warnings about missing annotations for params
| ^^^^^^^^^
|
error: `typ` should be `typo`, `type`
--> ./src/agents/strict_schema.py:51:5
|
51 | typ = json_schema.get("type")
| ^^^
|
error: `typ` should be `typo`, `type`
--> ./src/agents/strict_schema.py:52:8
|
52 | if typ == "object" and "additionalProperties" not in json_schema:
| ^^^
|
error: `typ` should be `typo`, `type`
--> ./src/agents/strict_schema.py:55:9
|
55 | typ == "object"
| ^^^
|
error: `occured` should be `occurred`
--> ./src/agents/stream_events.py:34:18
|
34 | "handoff_occured",
| ^^^^^^^
|
error: `occured` should be `occurred`
--> ./src/agents/_run_impl.py:723:69
|
723 | event = RunItemStreamEvent(item=item, name="handoff_occured")
| ^^^^^^^
|
error: `desitnation` should be `destination`
--> ./src/agents/tracing/span_data.py:171:25
|
171 | Includes source and desitnation agents.
| ^^^^^^^^^^^
|
error: `exmaples` should be `examples`
--> ./docs/scripts/translate_docs.py:71:145
|
71 | "* The term 'examples' must be code examples when the page mentions the code examples in the repo, it can be translated as either 'code exmaples' or 'sample code'.",
| ^^^^^^^^
|
error: `structed` should be `structured`
--> ./tests/test_agent_hooks.py:227:16
|
227 | async def test_structed_output_non_streamed_agent_hooks():
| ^^^^^^^^
|
error: `structed` should be `structured`
--> ./tests/test_agent_hooks.py:298:16
|
298 | async def test_structed_output_streamed_agent_hooks():
| ^^^^^^^^
|
```