From 8952a939f626bfac48727f7921e2fec6de9f9f90 Mon Sep 17 00:00:00 2001 From: Richard Luo Date: Wed, 1 Jul 2026 12:20:37 -0700 Subject: [PATCH 1/2] feat(realtime): expose current_agent and context_wrapper on RealtimeSession --- src/agents/realtime/session.py | 21 +++++++++++++++++++++ tests/realtime/test_session.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/src/agents/realtime/session.py b/src/agents/realtime/session.py index 3b186e5502..a4df023927 100644 --- a/src/agents/realtime/session.py +++ b/src/agents/realtime/session.py @@ -217,6 +217,27 @@ def model(self) -> RealtimeModel: """Access the underlying model for adding listeners or other direct interaction.""" return self._model + @property + def current_agent(self) -> RealtimeAgent: + """Return the agent that is currently active for this session. + + This reflects the initial agent and is updated whenever the active agent changes, + for example after a handoff or a call to `update_agent()`. Use it to read the active + agent from code that runs outside the session's event loop, such as telemetry, + routing, or background timers. + """ + return self._current_agent + + @property + def context_wrapper(self) -> RunContextWrapper[Any]: + """Return the run context wrapper backing this session. + + The returned wrapper is the same object the session was constructed with and exposes + the caller-provided context along with usage tracking. Use it to reach the run context + from code that runs outside the session's event loop. + """ + return self._context_wrapper + async def __aenter__(self) -> RealtimeSession: """Start the session by connecting to the model. After this, you will be able to stream events from the model and send messages and audio to the model. diff --git a/tests/realtime/test_session.py b/tests/realtime/test_session.py index 018f63b344..3dd1c587b6 100644 --- a/tests/realtime/test_session.py +++ b/tests/realtime/test_session.py @@ -3651,6 +3651,38 @@ async def test_update_agent_validation_failure_keeps_current_agent(self, mock_mo assert mock_model.sent_events == [] +class TestSessionAccessors: + """Tests for the public ``current_agent`` and ``context_wrapper`` accessors.""" + + @pytest.mark.asyncio + async def test_current_agent_reflects_initial_agent(self, mock_model): + agent = RealtimeAgent(name="initial", instructions="initial", tools=[], handoffs=[]) + session = RealtimeSession(mock_model, agent, None) + + assert session.current_agent is agent + + @pytest.mark.asyncio + async def test_current_agent_updates_after_update_agent(self, mock_model): + first_agent = RealtimeAgent(name="first", instructions="first", tools=[], handoffs=[]) + second_agent = RealtimeAgent(name="second", instructions="second", tools=[], handoffs=[]) + session = RealtimeSession(mock_model, first_agent, None) + + assert session.current_agent is first_agent + + await session.update_agent(second_agent) + + assert session.current_agent is second_agent + + @pytest.mark.asyncio + async def test_context_wrapper_returns_backing_wrapper(self, mock_model): + context = object() + agent = RealtimeAgent(name="agent", instructions="agent", tools=[], handoffs=[]) + session = RealtimeSession(mock_model, agent, context) + + assert session.context_wrapper is session._context_wrapper + assert session.context_wrapper.context is context + + class TestTranscriptPreservation: """Tests ensuring assistant transcripts are preserved across updates.""" From 1f54413bca698cbd83a1d9ceb0cc7ec253031123 Mon Sep 17 00:00:00 2001 From: Richard Luo Date: Wed, 1 Jul 2026 12:20:37 -0700 Subject: [PATCH 2/2] fix(realtime): address review for current_agent/context_wrapper accessors --- src/agents/realtime/session.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/agents/realtime/session.py b/src/agents/realtime/session.py index a4df023927..6e99efa73c 100644 --- a/src/agents/realtime/session.py +++ b/src/agents/realtime/session.py @@ -224,7 +224,9 @@ def current_agent(self) -> RealtimeAgent: This reflects the initial agent and is updated whenever the active agent changes, for example after a handoff or a call to `update_agent()`. Use it to read the active agent from code that runs outside the session's event loop, such as telemetry, - routing, or background timers. + routing, or background timers. This returns a live, unsynchronized snapshot, so a + background reader can observe the agent mid-handoff because it is reassigned in + `update_agent()` and after a handoff without any locking. """ return self._current_agent @@ -234,7 +236,9 @@ def context_wrapper(self) -> RunContextWrapper[Any]: The returned wrapper is the same object the session was constructed with and exposes the caller-provided context along with usage tracking. Use it to reach the run context - from code that runs outside the session's event loop. + from code that runs outside the session's event loop. This returns a live, + unsynchronized reference whose usage counters are mutated by the session's event loop, + so a background reader can observe values updated without any locking. """ return self._context_wrapper