Skip to content

Commit 96140c5

Browse files
committed
Realtime: make sure we use the initial model settings
1 parent af83fd0 commit 96140c5

File tree

4 files changed

+304
-128
lines changed

4 files changed

+304
-128
lines changed

README.md

Lines changed: 113 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -17,125 +17,19 @@ The OpenAI Agents SDK is a lightweight yet powerful framework for building multi
1717

1818
Explore the [examples](examples) directory to see the SDK in action, and read our [documentation](https://openai.github.io/openai-agents-python/) for more details.
1919

20-
## Sessions
21-
22-
The Agents SDK provides built-in session memory to automatically maintain conversation history across multiple agent runs, eliminating the need to manually handle `.to_input_list()` between turns.
23-
24-
### Quick start
25-
26-
```python
27-
from agents import Agent, Runner, SQLiteSession
28-
29-
# Create agent
30-
agent = Agent(
31-
name="Assistant",
32-
instructions="Reply very concisely.",
33-
)
34-
35-
# Create a session instance
36-
session = SQLiteSession("conversation_123")
37-
38-
# First turn
39-
result = await Runner.run(
40-
agent,
41-
"What city is the Golden Gate Bridge in?",
42-
session=session
43-
)
44-
print(result.final_output) # "San Francisco"
45-
46-
# Second turn - agent automatically remembers previous context
47-
result = await Runner.run(
48-
agent,
49-
"What state is it in?",
50-
session=session
51-
)
52-
print(result.final_output) # "California"
53-
54-
# Also works with synchronous runner
55-
result = Runner.run_sync(
56-
agent,
57-
"What's the population?",
58-
session=session
59-
)
60-
print(result.final_output) # "Approximately 39 million"
61-
```
62-
63-
### Session options
64-
65-
- **No memory** (default): No session memory when session parameter is omitted
66-
- **`session: Session = DatabaseSession(...)`**: Use a Session instance to manage conversation history
67-
68-
```python
69-
from agents import Agent, Runner, SQLiteSession
70-
71-
# Custom SQLite database file
72-
session = SQLiteSession("user_123", "conversations.db")
73-
agent = Agent(name="Assistant")
74-
75-
# Different session IDs maintain separate conversation histories
76-
result1 = await Runner.run(
77-
agent,
78-
"Hello",
79-
session=session
80-
)
81-
result2 = await Runner.run(
82-
agent,
83-
"Hello",
84-
session=SQLiteSession("user_456", "conversations.db")
85-
)
86-
```
87-
88-
### Custom session implementations
89-
90-
You can implement your own session memory by creating a class that follows the `Session` protocol:
91-
92-
```python
93-
from agents.memory import Session
94-
from typing import List
95-
96-
class MyCustomSession:
97-
"""Custom session implementation following the Session protocol."""
98-
99-
def __init__(self, session_id: str):
100-
self.session_id = session_id
101-
# Your initialization here
102-
103-
async def get_items(self, limit: int | None = None) -> List[dict]:
104-
# Retrieve conversation history for the session
105-
pass
106-
107-
async def add_items(self, items: List[dict]) -> None:
108-
# Store new items for the session
109-
pass
110-
111-
async def pop_item(self) -> dict | None:
112-
# Remove and return the most recent item from the session
113-
pass
114-
115-
async def clear_session(self) -> None:
116-
# Clear all items for the session
117-
pass
118-
119-
# Use your custom session
120-
agent = Agent(name="Assistant")
121-
result = await Runner.run(
122-
agent,
123-
"Hello",
124-
session=MyCustomSession("my_session")
125-
)
126-
```
127-
12820
## Get started
12921

13022
1. Set up your Python environment
13123

132-
- Option A: Using venv (traditional method)
24+
- Option A: Using venv (traditional method)
25+
13326
```bash
13427
python -m venv env
13528
source env/bin/activate # On Windows: env\Scripts\activate
13629
```
13730

138-
- Option B: Using uv (recommended)
31+
- Option B: Using uv (recommended)
32+
13933
```bash
14034
uv venv
14135
source .venv/bin/activate # On Windows: .venv\Scripts\activate
@@ -263,6 +157,114 @@ The Agents SDK is designed to be highly flexible, allowing you to model a wide r
263157

264158
The Agents SDK automatically traces your agent runs, making it easy to track and debug the behavior of your agents. Tracing is extensible by design, supporting custom spans and a wide variety of external destinations, including [Logfire](https://logfire.pydantic.dev/docs/integrations/llms/openai/#openai-agents), [AgentOps](https://docs.agentops.ai/v1/integrations/agentssdk), [Braintrust](https://braintrust.dev/docs/guides/traces/integrations#openai-agents-sdk), [Scorecard](https://docs.scorecard.io/docs/documentation/features/tracing#openai-agents-sdk-integration), and [Keywords AI](https://docs.keywordsai.co/integration/development-frameworks/openai-agent). For more details about how to customize or disable tracing, see [Tracing](http://openai.github.io/openai-agents-python/tracing), which also includes a larger list of [external tracing processors](http://openai.github.io/openai-agents-python/tracing/#external-tracing-processors-list).
265159

160+
## Sessions
161+
162+
The Agents SDK provides built-in session memory to automatically maintain conversation history across multiple agent runs, eliminating the need to manually handle `.to_input_list()` between turns.
163+
164+
### Quick start
165+
166+
```python
167+
from agents import Agent, Runner, SQLiteSession
168+
169+
# Create agent
170+
agent = Agent(
171+
name="Assistant",
172+
instructions="Reply very concisely.",
173+
)
174+
175+
# Create a session instance
176+
session = SQLiteSession("conversation_123")
177+
178+
# First turn
179+
result = await Runner.run(
180+
agent,
181+
"What city is the Golden Gate Bridge in?",
182+
session=session
183+
)
184+
print(result.final_output) # "San Francisco"
185+
186+
# Second turn - agent automatically remembers previous context
187+
result = await Runner.run(
188+
agent,
189+
"What state is it in?",
190+
session=session
191+
)
192+
print(result.final_output) # "California"
193+
194+
# Also works with synchronous runner
195+
result = Runner.run_sync(
196+
agent,
197+
"What's the population?",
198+
session=session
199+
)
200+
print(result.final_output) # "Approximately 39 million"
201+
```
202+
203+
### Session options
204+
205+
- **No memory** (default): No session memory when session parameter is omitted
206+
- **`session: Session = DatabaseSession(...)`**: Use a Session instance to manage conversation history
207+
208+
```python
209+
from agents import Agent, Runner, SQLiteSession
210+
211+
# Custom SQLite database file
212+
session = SQLiteSession("user_123", "conversations.db")
213+
agent = Agent(name="Assistant")
214+
215+
# Different session IDs maintain separate conversation histories
216+
result1 = await Runner.run(
217+
agent,
218+
"Hello",
219+
session=session
220+
)
221+
result2 = await Runner.run(
222+
agent,
223+
"Hello",
224+
session=SQLiteSession("user_456", "conversations.db")
225+
)
226+
```
227+
228+
### Custom session implementations
229+
230+
You can implement your own session memory by creating a class that follows the `Session` protocol:
231+
232+
```python
233+
from agents.memory import Session
234+
from typing import List
235+
236+
class MyCustomSession:
237+
"""Custom session implementation following the Session protocol."""
238+
239+
def __init__(self, session_id: str):
240+
self.session_id = session_id
241+
# Your initialization here
242+
243+
async def get_items(self, limit: int | None = None) -> List[dict]:
244+
# Retrieve conversation history for the session
245+
pass
246+
247+
async def add_items(self, items: List[dict]) -> None:
248+
# Store new items for the session
249+
pass
250+
251+
async def pop_item(self) -> dict | None:
252+
# Remove and return the most recent item from the session
253+
pass
254+
255+
async def clear_session(self) -> None:
256+
# Clear all items for the session
257+
pass
258+
259+
# Use your custom session
260+
agent = Agent(name="Assistant")
261+
result = await Runner.run(
262+
agent,
263+
"Hello",
264+
session=MyCustomSession("my_session")
265+
)
266+
```
267+
266268
## Development (only needed if you need to edit the SDK/examples)
267269

268270
0. Ensure you have [`uv`](https://docs.astral.sh/uv/) installed.
@@ -284,6 +286,7 @@ make check # run tests linter and typechecker
284286
```
285287

286288
Or to run them individually:
289+
287290
```
288291
make tests # run tests
289292
make mypy # run typechecker

src/agents/realtime/session.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ async def __aenter__(self) -> RealtimeSession:
121121

122122
model_config = self._model_config.copy()
123123
model_config["initial_model_settings"] = await self._get_updated_model_settings_from_agent(
124-
self._current_agent
124+
starting_settings=self._model_config.get("initial_model_settings", None),
125+
agent=self._current_agent,
125126
)
126127

127128
# Connect to the model
@@ -330,7 +331,8 @@ async def _handle_tool_call(self, event: RealtimeModelToolCallEvent) -> None:
330331

331332
# Get updated model settings from new agent
332333
updated_settings = await self._get_updated_model_settings_from_agent(
333-
self._current_agent
334+
starting_settings=None,
335+
agent=self._current_agent,
334336
)
335337

336338
# Send handoff event
@@ -509,9 +511,16 @@ async def _cleanup(self) -> None:
509511

510512
async def _get_updated_model_settings_from_agent(
511513
self,
514+
starting_settings: RealtimeSessionModelSettings | None,
512515
agent: RealtimeAgent,
513516
) -> RealtimeSessionModelSettings:
514-
updated_settings: RealtimeSessionModelSettings = {}
517+
# Start with run config model settings as base
518+
run_config_settings = self._run_config.get("model_settings", {})
519+
updated_settings: RealtimeSessionModelSettings = run_config_settings.copy()
520+
# Apply starting settings (from model config) next
521+
if starting_settings:
522+
updated_settings.update(starting_settings)
523+
515524
instructions, tools, handoffs = await asyncio.gather(
516525
agent.get_system_prompt(self._context_wrapper),
517526
agent.get_all_tools(self._context_wrapper),
@@ -521,10 +530,6 @@ async def _get_updated_model_settings_from_agent(
521530
updated_settings["tools"] = tools or []
522531
updated_settings["handoffs"] = handoffs or []
523532

524-
# Override with initial settings
525-
initial_settings = self._model_config.get("initial_model_settings", {})
526-
updated_settings.update(initial_settings)
527-
528533
disable_tracing = self._run_config.get("tracing_disabled", False)
529534
if disable_tracing:
530535
updated_settings["tracing"] = None

0 commit comments

Comments
 (0)