From ca3f6a5c83bf185944b6c589d08151c6d501d8c4 Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Mon, 8 Sep 2025 17:55:06 +0900 Subject: [PATCH 1/2] Preserve realtime session voice settings --- src/agents/realtime/session.py | 26 ++++++++++++++++++--- tests/realtime/test_session.py | 41 ++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/agents/realtime/session.py b/src/agents/realtime/session.py index c309a2655..41eb7761d 100644 --- a/src/agents/realtime/session.py +++ b/src/agents/realtime/session.py @@ -95,6 +95,24 @@ def __init__( self._history: list[RealtimeItem] = [] self._model_config = model_config or {} self._run_config = run_config or {} + initial_model_settings = ( + cast( + RealtimeSessionModelSettings | None, + self._model_config.get("initial_model_settings"), + ) + or {} + ) + run_config_settings = ( + cast( + RealtimeSessionModelSettings | None, + self._run_config.get("model_settings"), + ) + or {} + ) + self._base_model_settings: RealtimeSessionModelSettings = { + **run_config_settings, + **initial_model_settings, + } self._event_queue: asyncio.Queue[RealtimeSessionEvent] = asyncio.Queue() self._closed = False self._stored_exception: Exception | None = None @@ -619,9 +637,11 @@ async def _get_updated_model_settings_from_agent( starting_settings: RealtimeSessionModelSettings | None, agent: RealtimeAgent, ) -> RealtimeSessionModelSettings: - # Start with run config model settings as base - run_config_settings = self._run_config.get("model_settings", {}) - updated_settings: RealtimeSessionModelSettings = run_config_settings.copy() + # Start with the merged base settings from run and model configuration. + updated_settings = cast( + RealtimeSessionModelSettings, + self._base_model_settings.copy(), + ) # Apply starting settings (from model config) next if starting_settings: updated_settings.update(starting_settings) diff --git a/tests/realtime/test_session.py b/tests/realtime/test_session.py index cd562c522..66db03ef1 100644 --- a/tests/realtime/test_session.py +++ b/tests/realtime/test_session.py @@ -1606,6 +1606,47 @@ async def mock_get_handoffs(cls, agent, context_wrapper): assert model_settings["tool_choice"] == "required" assert model_settings["output_audio_format"] == "g711_ulaw" + @pytest.mark.asyncio + async def test_model_settings_preserve_initial_settings_on_updates(self): + """Initial model settings should persist when we recompute settings for updates.""" + + agent = RealtimeAgent(name="test_agent", instructions="test") + agent.handoffs = [] + agent.get_system_prompt = AsyncMock(return_value="test_prompt") # type: ignore + agent.get_all_tools = AsyncMock(return_value=[]) # type: ignore + + mock_model = Mock(spec=RealtimeModel) + + initial_settings: RealtimeSessionModelSettings = { + "voice": "initial_voice", + "output_audio_format": "pcm16", + } + + session = RealtimeSession( + model=mock_model, + agent=agent, + context=None, + model_config={"initial_model_settings": initial_settings}, + run_config={}, + ) + + async def mock_get_handoffs(cls, agent, context_wrapper): + return [] + + with pytest.MonkeyPatch().context() as m: + m.setattr( + "agents.realtime.session.RealtimeSession._get_handoffs", + mock_get_handoffs, + ) + + model_settings = await session._get_updated_model_settings_from_agent( + starting_settings=None, + agent=agent, + ) + + assert model_settings["voice"] == "initial_voice" + assert model_settings["output_audio_format"] == "pcm16" + class TestUpdateAgentFunctionality: """Tests for update agent functionality in RealtimeSession""" From dfb709abdd9c56ddf811e00ef8aa0ce03e23bf91 Mon Sep 17 00:00:00 2001 From: Kazuhiro Sera Date: Mon, 8 Sep 2025 18:01:09 +0900 Subject: [PATCH 2/2] fix --- src/agents/realtime/session.py | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/src/agents/realtime/session.py b/src/agents/realtime/session.py index 41eb7761d..e5a4571cc 100644 --- a/src/agents/realtime/session.py +++ b/src/agents/realtime/session.py @@ -95,23 +95,11 @@ def __init__( self._history: list[RealtimeItem] = [] self._model_config = model_config or {} self._run_config = run_config or {} - initial_model_settings = ( - cast( - RealtimeSessionModelSettings | None, - self._model_config.get("initial_model_settings"), - ) - or {} - ) - run_config_settings = ( - cast( - RealtimeSessionModelSettings | None, - self._run_config.get("model_settings"), - ) - or {} - ) + initial_model_settings = self._model_config.get("initial_model_settings") + run_config_settings = self._run_config.get("model_settings") self._base_model_settings: RealtimeSessionModelSettings = { - **run_config_settings, - **initial_model_settings, + **(run_config_settings or {}), + **(initial_model_settings or {}), } self._event_queue: asyncio.Queue[RealtimeSessionEvent] = asyncio.Queue() self._closed = False @@ -638,10 +626,7 @@ async def _get_updated_model_settings_from_agent( agent: RealtimeAgent, ) -> RealtimeSessionModelSettings: # Start with the merged base settings from run and model configuration. - updated_settings = cast( - RealtimeSessionModelSettings, - self._base_model_settings.copy(), - ) + updated_settings = self._base_model_settings.copy() # Apply starting settings (from model config) next if starting_settings: updated_settings.update(starting_settings)