Skip to content

Conversation

knowsuchagency
Copy link
Contributor

@knowsuchagency knowsuchagency commented May 24, 2025

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

# 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:

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

# 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

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

# 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

# In-memory database (lost when process ends)
session = SQLiteSession("user_123")

# Persistent file-based database
session = SQLiteSession("user_123", "conversations.db")

Session Management Operations

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

# 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.

## Summary
- Introduced `SessionMemory` and `SQLiteSessionMemory` classes for automatic conversation history management.
- Updated `Agent` class to support session memory configuration.
- Enhanced `Runner` class to handle input preparation and result saving with session memory.
- Added example demonstrating session memory usage.
- Implemented tests for session memory functionality.

## Testing
- `make format`
- `make lint`
- `make mypy`
- `make tests`
- Added a check to raise a ValueError if `session_id` is not provided when session memory is enabled.
- Updated the `SessionMemory` class to use a Protocol instead of an abstract base class, simplifying the implementation.
- Modified tests to ensure an exception is raised when attempting to run with memory enabled but no session_id is provided.
- Introduced a section on creating custom memory implementations following the `SessionMemory` protocol.
- Added code examples demonstrating how to implement and use a custom memory class.
- Highlighted the requirement for `session_id` when session memory is enabled, with examples illustrating correct usage.
- Updated the Runner class to ensure that when memory=True, a single instance of SQLiteSessionMemory is created and reused across runs.
- Added a test to verify that the same memory instance is returned for multiple calls when memory is enabled.
- Ensured the agent stores the memory instance for consistency.
- Updated README and example scripts to utilize `SQLiteSessionMemory` explicitly instead of using a boolean flag for memory.
- Modified `RunConfig` to accept a memory instance directly, enhancing clarity and flexibility in session management.
- Adjusted tests to reflect the new memory handling approach, ensuring consistent behavior across different configurations.
- Updated `mkdocs.yml` to include `session_memory.md` in the documentation.
- Enhanced `index.md` to highlight the new **Session Memory** feature for automatic conversation history management.
- Modified `running_agents.md` to include details about the `memory` and `session_id` parameters in `RunConfig`.
- Added comprehensive documentation for session memory functionality in the new `session_memory.md` file, including usage examples and best practices.
- Included `memory.md` in the documentation by updating `mkdocs.yml`.
- Corrected links in `session_memory.md` to point to the appropriate memory classes.
- Created a new `memory.md` file detailing the `SessionMemory` and `SQLiteSessionMemory` classes.
…essions and messages

- Updated the constructor to accept `sessions_table` and `messages_table` parameters, allowing users to specify custom table names.
- Modified SQL queries to utilize the provided table names, ensuring flexibility in database schema.
- Adjusted index creation and deletion queries to reflect the new table name parameters.
@knowsuchagency knowsuchagency marked this pull request as draft May 24, 2025 06:35
- Implemented the `pop_message` method to remove and return the most recent message from a session.
- Updated the `SessionMemory` protocol to include the new method signature.
- Enhanced documentation in `session_memory.md` with examples demonstrating the usage of `pop_message`.
- Added tests to verify the functionality of `pop_message`, including edge cases for empty sessions and multiple sessions.
- Converted synchronous database operations in `get_messages`, `add_messages`, `pop_message`, and `clear_session` methods to asynchronous using `asyncio.to_thread`.
- Improved performance and responsiveness of the session memory handling by allowing non-blocking database interactions.
- Implemented a check in the Runner class to raise a ValueError if a session_id is provided without enabling memory in the RunConfig.
- Updated tests to verify that the appropriate exception is raised when session_id is used without memory.
- Updated README, session_memory.md, and example scripts to remove the use of RunConfig for session memory configuration, directly passing memory and session_id parameters to the Runner.run method.
- Enhanced clarity in documentation regarding the requirement of session_id when memory is enabled.
- Adjusted tests to reflect the new approach, ensuring consistent behavior across different configurations.
- Introduced a new method `_init_db_for_connection` to handle database schema initialization for a specific connection.
- Updated the `_init_db` method to call the new method, improving clarity and separation of concerns.
- Added a comment to indicate the initialization of the database schema for the connection.
- Deleted the `_init_db` method as database schema initialization is now handled in `_init_db_for_connection`.
- This change simplifies the class structure and improves clarity in the database connection management.
- Introduced a shared connection for in-memory databases to avoid thread isolation, improving concurrency.
- Implemented a locking mechanism for database operations to ensure thread safety, regardless of the database type.
- Updated the `_get_connection`, `_add_messages_sync`, `_pop_message_sync`, and `_clear_session_sync` methods to utilize the new locking and connection management logic.
- Added logic to initialize the database schema for file databases during connection setup.
- Ensured that the schema is only initialized once, improving efficiency and clarity in connection management.
- Enhanced the error handling mechanism in the Runner class to ensure that exceptions during setup result in a completion sentinel being placed in the event queue.
- Streamlined the input preparation process by consolidating the logic for handling session memory and updating the streamed result.
- Improved clarity and maintainability of the code by restructuring the try-except blocks and ensuring proper resource management for spans and traces.
- Removed unused imports and streamlined the import statements for clarity and maintainability.
- This change enhances the readability of the test file by focusing on the necessary components.
@knowsuchagency knowsuchagency marked this pull request as ready for review May 24, 2025 21:37
…clarity

- Replaced `SQLiteSessionMemory` with `SQLiteSession` in the codebase, streamlining session management.
- Updated documentation and examples to reflect the new session handling approach, removing the need for `session_id` when using sessions.
- Enhanced the `Session` protocol to better define session behavior and improve consistency across implementations.
- Adjusted tests to ensure compatibility with the new session structure, maintaining functionality across various scenarios.
- Renamed `session_memory.md` to `session.md` for clarity and consistency.
- Updated links in `running_agents.md` to reflect the new documentation filename.
- Added comprehensive documentation for session memory functionality, including usage examples and API reference.
- Removed references to `SessionMemory` and `SQLiteSessionMemory` from the codebase to streamline session management.
- Changed all references from "Session Memory" to "Sessions" in README, documentation, and example files for consistency.
- Updated descriptions to clarify the functionality of Sessions in managing conversation history across agent runs.
- Renamed instances of "session.md" to "sessions.md" in mkdocs.yml and running_agents.md for consistency.
- Added new sessions.md file detailing the functionality and usage of session memory in the Agents SDK, including examples and API reference.
- Updated the `get_messages` method in the `Session` and `SQLiteSession` classes to accept an optional `amount` parameter, allowing retrieval of the latest N messages or all messages if not specified.
- Added a demonstration in `session_example.py` to showcase the new functionality for fetching the latest messages.
- Implemented tests in `test_session.py` to verify the behavior of the `get_messages` method with various amounts, ensuring correct message retrieval.
…tions" and clarify session implementation details. Adjusted section headers and descriptions for consistency with recent documentation updates.
@knowsuchagency knowsuchagency changed the title Add Session Memory for Automatic Conversation History Management Add Sessions for Automatic Conversation History Management May 25, 2025
### Changes
- Simplified method calls in `AgentRunner` by using class methods directly.
- Consolidated input preparation and event queue updates for clarity.
- Improved formatting and reduced line breaks for better readability.

This refactor enhances the maintainability of the code by standardizing method usage and improving overall structure.
…stency

### Changes
- Removed the `session` field from `RunOptions` and its related comments to simplify the interface.
- Improved method calls by using class methods directly for better maintainability.

This refactor streamlines the code structure and improves the overall clarity of the `run.py` file.
…eparation in `AgentRunner`

### Changes
- Consolidated error handling to ensure `streamed_result.is_complete` is set even if an exception occurs.
- Improved the structure of input preparation and event queue updates for better readability and maintainability.

This refactor enhances the robustness of the `AgentRunner` class by ensuring proper completion signaling and clearer code flow.
### Changes
- Added `session` field to `RunOptions` for session management.
- Refactored `AgentRunner` methods to accept parameters via `kwargs`, improving flexibility and maintainability.

This update streamlines parameter handling and enhances the functionality of the `AgentRunner` class.
…rove clarity and maintainability

### Changes
- Moved the initialization of variables closer to their usage for better readability.
- Removed redundant exception handling to streamline the flow of the method.
- Ensured that the completion signaling for `streamed_result` is handled more clearly.

This update enhances the robustness and clarity of the `AgentRunner` class.
@knowsuchagency knowsuchagency requested a review from rm-openai June 28, 2025 00:27
@knowsuchagency
Copy link
Contributor Author

The changes in run.py should be a lot more straightforward now @rm-openai. The business logic is largely the same with minor edits to accommodate the new Session interface. LMK if you notice any other necessary edits, thanks!

…bility

### Changes
- Adjusted formatting of docstrings and SQL queries for better clarity.
- Simplified SQL query structure by removing unnecessary line breaks.
- Enhanced the logic for fetching messages to ensure chronological order when using descending order.

This update improves the overall structure and readability of the `SQLiteSession` class.
Replace separate SELECT and DELETE queries with a single atomic DELETE...RETURNING
operation as suggested by slyapustin. This improves performance and eliminates
potential race conditions while simplifying the error handling logic.
@rm-openai
Copy link
Collaborator

@knowsuchagency this is good to merge, just need to fix the lint/types. You can just copy the last 2 commits from this: #1040

(I can't add to this PR unfortunately)

@sebastian-montero
Copy link

Thank you for this @knowsuchagency !! Looking forward to seeing it merged.

@knowsuchagency
Copy link
Contributor Author

Done thanks @rm-openai !

@rm-openai rm-openai merged commit 6b94ad0 into openai:main Jul 10, 2025
5 checks passed
@rm-openai
Copy link
Collaborator

Awesome work @knowsuchagency, thanks for bearing with the long review process and getting this in! Excited for people to use it.

@knowsuchagency
Copy link
Contributor Author

Thanks for all the excellent feedback and patience as well @rm-openai !! I agree it will be a great feature for users 😃

@knowsuchagency knowsuchagency deleted the feature/session-memory branch July 10, 2025 23:10
@knowsuchagency
Copy link
Contributor Author

Thanks for your review also @slyapustin !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request feature:core
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Session Memory
10 participants