Skip to content

Commit be053ff

Browse files
committed
Add OpenAISession
1 parent c919f6e commit be053ff

File tree

8 files changed

+476
-277
lines changed

8 files changed

+476
-277
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
"""
2+
Example demonstrating session memory functionality.
3+
4+
This example shows how to use session memory to maintain conversation history
5+
across multiple agent runs without manually handling .to_input_list().
6+
"""
7+
8+
import asyncio
9+
10+
from agents import Agent, OpenAISession, Runner
11+
12+
13+
async def main():
14+
# Create an agent
15+
agent = Agent(
16+
name="Assistant",
17+
instructions="Reply very concisely.",
18+
)
19+
20+
# Create a session instance that will persist across runs
21+
session = OpenAISession()
22+
23+
print("=== Session Example ===")
24+
print("The agent will remember previous messages automatically.\n")
25+
26+
# First turn
27+
print("First turn:")
28+
print("User: What city is the Golden Gate Bridge in?")
29+
result = await Runner.run(
30+
agent,
31+
"What city is the Golden Gate Bridge in?",
32+
session=session,
33+
)
34+
print(f"Assistant: {result.final_output}")
35+
print()
36+
37+
# Second turn - the agent will remember the previous conversation
38+
print("Second turn:")
39+
print("User: What state is it in?")
40+
result = await Runner.run(agent, "What state is it in?", session=session)
41+
print(f"Assistant: {result.final_output}")
42+
print()
43+
44+
# Third turn - continuing the conversation
45+
print("Third turn:")
46+
print("User: What's the population of that state?")
47+
result = await Runner.run(
48+
agent,
49+
"What's the population of that state?",
50+
session=session,
51+
)
52+
print(f"Assistant: {result.final_output}")
53+
print()
54+
55+
print("=== Conversation Complete ===")
56+
print("Notice how the agent remembered the context from previous turns!")
57+
print("Sessions automatically handles conversation history.")
58+
59+
# Demonstrate the limit parameter - get only the latest 2 items
60+
print("\n=== Latest Items Demo ===")
61+
latest_items = await session.get_items(limit=2)
62+
# print(latest_items)
63+
print("Latest 2 items:")
64+
for i, msg in enumerate(latest_items, 1):
65+
role = msg.get("role", "unknown")
66+
content = msg.get("content", "")
67+
print(f" {i}. {role}: {content}")
68+
69+
print(f"\nFetched {len(latest_items)} out of total conversation history.")
70+
71+
# Get all items to show the difference
72+
all_items = await session.get_items()
73+
# print(all_items)
74+
print(f"Total items in session: {len(all_items)}")
75+
76+
77+
if __name__ == "__main__":
78+
asyncio.run(main())

examples/basic/sqlalchemy_session_example.py renamed to examples/memory/sqlalchemy_session_example.py

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,28 +20,56 @@ async def main():
2020
create_tables=True,
2121
)
2222

23-
print("=== SQLAlchemySession Example ===")
23+
print("=== Session Example ===")
2424
print("The agent will remember previous messages automatically.\n")
2525

2626
# First turn
27+
print("First turn:")
2728
print("User: What city is the Golden Gate Bridge in?")
2829
result = await Runner.run(
2930
agent,
3031
"What city is the Golden Gate Bridge in?",
3132
session=session,
3233
)
33-
print(f"Assistant: {result.final_output}\n")
34+
print(f"Assistant: {result.final_output}")
35+
print()
3436

3537
# Second turn - the agent will remember the previous conversation
38+
print("Second turn:")
3639
print("User: What state is it in?")
40+
result = await Runner.run(agent, "What state is it in?", session=session)
41+
print(f"Assistant: {result.final_output}")
42+
print()
43+
44+
# Third turn - continuing the conversation
45+
print("Third turn:")
46+
print("User: What's the population of that state?")
3747
result = await Runner.run(
3848
agent,
39-
"What state is it in?",
49+
"What's the population of that state?",
4050
session=session,
4151
)
42-
print(f"Assistant: {result.final_output}\n")
52+
print(f"Assistant: {result.final_output}")
53+
print()
4354

4455
print("=== Conversation Complete ===")
56+
print("Notice how the agent remembered the context from previous turns!")
57+
print("Sessions automatically handles conversation history.")
58+
59+
# Demonstrate the limit parameter - get only the latest 2 items
60+
print("\n=== Latest Items Demo ===")
61+
latest_items = await session.get_items(limit=2)
62+
print("Latest 2 items:")
63+
for i, msg in enumerate(latest_items, 1):
64+
role = msg.get("role", "unknown")
65+
content = msg.get("content", "")
66+
print(f" {i}. {role}: {content}")
67+
68+
print(f"\nFetched {len(latest_items)} out of total conversation history.")
69+
70+
# Get all items to show the difference
71+
all_items = await session.get_items()
72+
print(f"Total items in session: {len(all_items)}")
4573

4674

4775
if __name__ == "__main__":

src/agents/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
TResponseInputItem,
4747
)
4848
from .lifecycle import AgentHooks, RunHooks
49-
from .memory import Session, SQLiteSession
49+
from .memory import OpenAISession, Session, SessionABC, SQLiteSession
5050
from .model_settings import ModelSettings
5151
from .models.interface import Model, ModelProvider, ModelTracing
5252
from .models.multi_provider import MultiProvider
@@ -221,7 +221,9 @@ def enable_verbose_stdout_logging():
221221
"RunHooks",
222222
"AgentHooks",
223223
"Session",
224+
"SessionABC",
224225
"SQLiteSession",
226+
"OpenAISession",
225227
"RunContextWrapper",
226228
"TContext",
227229
"RunErrorDetails",

src/agents/memory/__init__.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1-
from .session import Session, SQLiteSession
1+
from .openai_session import OpenAISession
2+
from .session import Session, SessionABC
3+
from .sqlite_session import SQLiteSession
24

3-
__all__ = ["Session", "SQLiteSession"]
5+
__all__ = [
6+
"Session",
7+
"SessionABC",
8+
"SQLiteSession",
9+
"OpenAISession",
10+
]
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
from openai import AsyncOpenAI
2+
3+
from agents.models._openai_shared import get_default_openai_client
4+
5+
from ..items import TResponseInputItem
6+
from .session import SessionABC
7+
8+
9+
async def start_openai_session(openai_client: AsyncOpenAI | None = None) -> str:
10+
_openai_client = openai_client
11+
if openai_client is None:
12+
_openai_client = get_default_openai_client() or AsyncOpenAI()
13+
14+
response = await _openai_client.conversations.create(items=[])
15+
return response.id
16+
17+
18+
class OpenAISession(SessionABC):
19+
def __init__(
20+
self,
21+
session_id: str | None = None,
22+
openai_client: AsyncOpenAI | None = None,
23+
):
24+
self.session_id = session_id
25+
self.openai_client = openai_client
26+
if self.openai_client is None:
27+
self.openai_client = get_default_openai_client() or AsyncOpenAI()
28+
29+
async def _ensure_session_id(self) -> None:
30+
if self.session_id is None:
31+
self.session_id = await start_openai_session(self.openai_client)
32+
33+
async def get_items(self, limit: int | None = None) -> list[TResponseInputItem]:
34+
await self._ensure_session_id()
35+
36+
all_items = []
37+
if limit is None:
38+
async for item in self.openai_client.conversations.items.list(
39+
conversation_id=self.session_id,
40+
order="asc",
41+
):
42+
all_items.append(item.model_dump())
43+
else:
44+
async for item in self.openai_client.conversations.items.list(
45+
conversation_id=self.session_id,
46+
limit=limit,
47+
order="desc",
48+
):
49+
all_items.append(item.model_dump())
50+
if limit is not None and len(all_items) >= limit:
51+
break
52+
all_items.reverse()
53+
54+
return all_items
55+
56+
async def add_items(self, items: list[TResponseInputItem]) -> None:
57+
await self._ensure_session_id()
58+
await self.openai_client.conversations.items.create(
59+
conversation_id=self.session_id,
60+
items=items,
61+
)
62+
63+
async def pop_item(self) -> TResponseInputItem | None:
64+
await self._ensure_session_id()
65+
items = await self.get_items(limit=1)
66+
if not items:
67+
return None
68+
await self.openai_client.conversations.items.delete(
69+
conversation_id=self.session_id,
70+
item_id=items[0].id,
71+
)
72+
return items[0]
73+
74+
async def clear_session(self) -> None:
75+
await self._ensure_session_id()
76+
await self.openai_client.conversations.delete(
77+
conversation_id=self.session_id,
78+
)
79+
self.session_id = None

0 commit comments

Comments
 (0)