Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,6 @@ cython_debug/
# PyPI configuration file
.pypirc
.aider*

# Redis database files
dump.rdb
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ pip install openai-agents

For voice support, install with the optional `voice` group: `pip install 'openai-agents[voice]'`.

For Redis session support, install with the optional `redis` group: `pip install 'openai-agents[redis]'`.

### uv

If you're familiar with [uv](https://docs.astral.sh/uv/), using the tool would be even similar:
Expand All @@ -42,6 +44,8 @@ uv add openai-agents

For voice support, install with the optional `voice` group: `uv add 'openai-agents[voice]'`.

For Redis session support, install with the optional `redis` group: `uv add 'openai-agents[redis]'`.

## Hello world example

```python
Expand Down Expand Up @@ -211,8 +215,13 @@ print(result.final_output) # "Approximately 39 million"
```python
from agents import Agent, Runner, SQLiteSession

# Custom SQLite database file
# SQLite - file-based or in-memory database
session = SQLiteSession("user_123", "conversations.db")

# Redis - for scalable, distributed deployments
# from agents.extensions.memory import RedisSession
# session = RedisSession.from_url("user_123", url="redis://localhost:6379/0")

agent = Agent(name="Assistant")

# Different session IDs maintain separate conversation histories
Expand Down
3 changes: 3 additions & 0 deletions docs/ref/extensions/memory/redis_session.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# `RedisSession`

::: agents.extensions.memory.redis_session.RedisSession
177 changes: 177 additions & 0 deletions examples/memory/redis_session_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
"""
Example demonstrating Redis session memory functionality.

This example shows how to use Redis-backed session memory to maintain conversation
history across multiple agent runs with persistence and scalability.

Note: This example clears the session at the start to ensure a clean demonstration.
In production, you may want to preserve existing conversation history.
"""

import asyncio

from agents import Agent, Runner
from agents.extensions.memory import RedisSession


async def main():
# Create an agent
agent = Agent(
name="Assistant",
instructions="Reply very concisely.",
)

print("=== Redis Session Example ===")
print("This example requires Redis to be running on localhost:6379")
print("Start Redis with: redis-server")
print()

# Create a Redis session instance
session_id = "redis_conversation_123"
try:
session = RedisSession.from_url(
session_id,
url="redis://localhost:6379/0", # Use database 0
)

# Test Redis connectivity
if not await session.ping():
print("Redis server is not available!")
print("Please start Redis server and try again.")
return

print("Connected to Redis successfully!")
print(f"Session ID: {session_id}")

# Clear any existing session data for a clean start
await session.clear_session()
print("Session cleared for clean demonstration.")
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("Redis session automatically handles conversation history with persistence.")

# Demonstrate session persistence
print("\n=== Session Persistence Demo ===")
all_items = await session.get_items()
print(f"Total messages stored in Redis: {len(all_items)}")

# Demonstrate the limit parameter
print("\n=== Latest Items Demo ===")
latest_items = await session.get_items(limit=2)
print("Latest 2 items:")
for i, msg in enumerate(latest_items, 1):
role = msg.get("role", "unknown")
content = msg.get("content", "")
print(f" {i}. {role}: {content}")

# Demonstrate session isolation with a new session
print("\n=== Session Isolation Demo ===")
new_session = RedisSession.from_url(
"different_conversation_456",
url="redis://localhost:6379/0",
)

print("Creating a new session with different ID...")
result = await Runner.run(
agent,
"Hello, this is a new conversation!",
session=new_session,
)
print(f"New session response: {result.final_output}")

# Show that sessions are isolated
original_items = await session.get_items()
new_items = await new_session.get_items()
print(f"Original session has {len(original_items)} items")
print(f"New session has {len(new_items)} items")
print("Sessions are completely isolated!")

# Clean up the new session
await new_session.clear_session()
await new_session.close()

# Optional: Demonstrate TTL (time-to-live) functionality
print("\n=== TTL Demo ===")
ttl_session = RedisSession.from_url(
"ttl_demo_session",
url="redis://localhost:6379/0",
ttl=3600, # 1 hour TTL
)

await Runner.run(
agent,
"This message will expire in 1 hour",
session=ttl_session,
)
print("Created session with 1-hour TTL - messages will auto-expire")

await ttl_session.close()

# Close the main session
await session.close()

except Exception as e:
print(f"Error: {e}")
print("Make sure Redis is running on localhost:6379")


async def demonstrate_advanced_features():
"""Demonstrate advanced Redis session features."""
print("\n=== Advanced Features Demo ===")

# Custom key prefix for multi-tenancy
tenant_session = RedisSession.from_url(
"user_123",
url="redis://localhost:6379/0",
key_prefix="tenant_abc:sessions", # Custom prefix for isolation
)

try:
if await tenant_session.ping():
print("Custom key prefix demo:")
await Runner.run(
Agent(name="Support", instructions="Be helpful"),
"Hello from tenant ABC",
session=tenant_session,
)
print("Session with custom key prefix created successfully")

await tenant_session.close()
except Exception as e:
print(f"Advanced features error: {e}")


if __name__ == "__main__":
asyncio.run(main())
asyncio.run(demonstrate_advanced_features())
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ litellm = ["litellm>=1.67.4.post1, <2"]
realtime = ["websockets>=15.0, <16"]
sqlalchemy = ["SQLAlchemy>=2.0", "asyncpg>=0.29.0"]
encrypt = ["cryptography>=45.0, <46"]
redis = ["redis>=6.4.0"]

[dependency-groups]
dev = [
Expand Down Expand Up @@ -67,6 +68,7 @@ dev = [
"fastapi >= 0.110.0, <1",
"aiosqlite>=0.21.0",
"cryptography>=45.0, <46",
"fakeredis>=2.31.3",
]

[tool.uv.workspace]
Expand Down
12 changes: 12 additions & 0 deletions src/agents/extensions/memory/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

__all__: list[str] = [
"EncryptedSession",
"RedisSession",
"SQLAlchemySession",
"AdvancedSQLiteSession",
]
Expand All @@ -29,6 +30,17 @@ def __getattr__(name: str) -> Any:
"Install it with: pip install openai-agents[encrypt]"
) from e

if name == "RedisSession":
try:
from .redis_session import RedisSession # noqa: F401

return RedisSession
except ModuleNotFoundError as e:
raise ImportError(
"RedisSession requires the 'redis' extra. "
"Install it with: pip install openai-agents[redis]"
) from e

if name == "SQLAlchemySession":
try:
from .sqlalchemy_session import SQLAlchemySession # noqa: F401
Expand Down
Loading