From b5ce75a87077f7ded3e17f01ddcd7fcce79cca26 Mon Sep 17 00:00:00 2001 From: Quratulain-bilal Date: Sat, 2 May 2026 14:01:14 +0500 Subject: [PATCH 1/2] fix: #2940 emit RealtimeHistoryUpdated on transcript_delta When RealtimeSession received a RealtimeModelTranscriptDeltaEvent, it accumulated transcript text into self._history but only forwarded the raw model event. Subscribers that follow the documented history_added / history_updated pattern never observed the live transcript update. Emit RealtimeHistoryUpdated after the history mutation, matching the input_audio_transcription_completed branch, and update the session test that asserted transcript_delta was an ignored event. --- src/agents/realtime/session.py | 3 +++ tests/realtime/test_session.py | 37 ++++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/agents/realtime/session.py b/src/agents/realtime/session.py index 89f63b02fa..7ddf19813c 100644 --- a/src/agents/realtime/session.py +++ b/src/agents/realtime/session.py @@ -313,6 +313,9 @@ async def on_event(self, event: RealtimeModelEvent) -> None: content=[AssistantAudio(transcript=self._item_transcripts[item_id])], ), ) + await self._put_event( + RealtimeHistoryUpdated(info=self._event_info, history=self._history) + ) # Check if we should run guardrails based on debounce threshold current_length = len(self._item_transcripts[item_id]) diff --git a/tests/realtime/test_session.py b/tests/realtime/test_session.py index c1c919a866..9d361c825e 100644 --- a/tests/realtime/test_session.py +++ b/tests/realtime/test_session.py @@ -565,16 +565,9 @@ async def test_item_deleted_event_removes_item(self, mock_model, mock_agent): @pytest.mark.asyncio async def test_ignored_events_only_generate_raw_events(self, mock_model, mock_agent): - """Test that ignored events (transcript_delta, connection_status, other) only generate raw - events""" + """Test that ignored events (connection_status, other) only generate raw events.""" session = RealtimeSession(mock_model, mock_agent, None) - # Test transcript delta (should be ignored per TODO comment) - transcript_event = RealtimeModelTranscriptDeltaEvent( - item_id="item_1", delta="hello", response_id="resp_1" - ) - await session.on_event(transcript_event) - # Test connection status (should be ignored) connection_event = RealtimeModelConnectionStatusEvent(status="connected") await session.on_event(connection_event) @@ -583,13 +576,35 @@ async def test_ignored_events_only_generate_raw_events(self, mock_model, mock_ag other_event = RealtimeModelOtherEvent(data={"custom": "data"}) await session.on_event(other_event) - # Should only have 3 raw events (no transformed events) - assert session._event_queue.qsize() == 3 + # Should only have 2 raw events (no transformed events) + assert session._event_queue.qsize() == 2 - for _ in range(3): + for _ in range(2): event = await session._event_queue.get() assert isinstance(event, RealtimeRawModelEvent) + @pytest.mark.asyncio + async def test_transcript_delta_emits_history_updated(self, mock_model, mock_agent): + """transcript_delta updates the live history and must emit RealtimeHistoryUpdated + so subscribers following history_added/history_updated stay in sync (issue #2940).""" + session = RealtimeSession(mock_model, mock_agent, None) + + transcript_event = RealtimeModelTranscriptDeltaEvent( + item_id="item_1", delta="hello", response_id="resp_1" + ) + await session.on_event(transcript_event) + + # Expect a raw event plus a history_updated event. + assert session._event_queue.qsize() == 2 + + events = [await session._event_queue.get() for _ in range(2)] + assert any(isinstance(e, RealtimeRawModelEvent) for e in events) + history_updated = next( + (e for e in events if isinstance(e, RealtimeHistoryUpdated)), None + ) + assert history_updated is not None + assert history_updated.history == session._history + @pytest.mark.asyncio async def test_function_call_event_triggers_tool_handling(self, mock_model, mock_agent): """Test that function_call events trigger tool call handling synchronously when disabled""" From e9c20432e962d18553e55b338ced1763dcbbfb9a Mon Sep 17 00:00:00 2001 From: Quratulain-bilal Date: Sat, 2 May 2026 19:40:26 +0500 Subject: [PATCH 2/2] style: ruff format test_session.py --- tests/realtime/test_session.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/realtime/test_session.py b/tests/realtime/test_session.py index 9d361c825e..bdbac69657 100644 --- a/tests/realtime/test_session.py +++ b/tests/realtime/test_session.py @@ -599,9 +599,7 @@ async def test_transcript_delta_emits_history_updated(self, mock_model, mock_age events = [await session._event_queue.get() for _ in range(2)] assert any(isinstance(e, RealtimeRawModelEvent) for e in events) - history_updated = next( - (e for e in events if isinstance(e, RealtimeHistoryUpdated)), None - ) + history_updated = next((e for e in events if isinstance(e, RealtimeHistoryUpdated)), None) assert history_updated is not None assert history_updated.history == session._history