Skip to content

Commit afc59f0

Browse files
committed
fix(realtime): emit history updates for transcript deltas
1 parent e80d2d2 commit afc59f0

File tree

2 files changed

+30
-7
lines changed

2 files changed

+30
-7
lines changed

src/agents/realtime/session.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,9 @@ async def on_event(self, event: RealtimeModelEvent) -> None:
313313
content=[AssistantAudio(transcript=self._item_transcripts[item_id])],
314314
),
315315
)
316+
await self._put_event(
317+
RealtimeHistoryUpdated(info=self._event_info, history=self._history)
318+
)
316319

317320
# Check if we should run guardrails based on debounce threshold
318321
current_length = len(self._item_transcripts[item_id])

tests/realtime/test_session.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -564,17 +564,37 @@ async def test_item_deleted_event_removes_item(self, mock_model, mock_agent):
564564
assert len(history_event.history) == 1
565565

566566
@pytest.mark.asyncio
567-
async def test_ignored_events_only_generate_raw_events(self, mock_model, mock_agent):
568-
"""Test that ignored events (transcript_delta, connection_status, other) only generate raw
569-
events"""
567+
async def test_transcript_delta_updates_history_and_emits_history_updated(
568+
self, mock_model, mock_agent
569+
):
570+
"""Test that transcript deltas keep high-level history subscribers in sync."""
570571
session = RealtimeSession(mock_model, mock_agent, None)
571572

572-
# Test transcript delta (should be ignored per TODO comment)
573573
transcript_event = RealtimeModelTranscriptDeltaEvent(
574574
item_id="item_1", delta="hello", response_id="resp_1"
575575
)
576576
await session.on_event(transcript_event)
577577

578+
assert len(session._history) == 1
579+
updated_item = cast(AssistantMessageItem, session._history[0])
580+
assert updated_item.item_id == "item_1"
581+
assert cast(AssistantAudio, updated_item.content[0]).transcript == "hello"
582+
583+
# Should have raw + high-level history_updated
584+
assert session._event_queue.qsize() == 2
585+
586+
raw_event = await session._event_queue.get()
587+
assert isinstance(raw_event, RealtimeRawModelEvent)
588+
history_event = await session._event_queue.get()
589+
assert isinstance(history_event, RealtimeHistoryUpdated)
590+
updated_history_item = cast(AssistantMessageItem, history_event.history[0])
591+
assert cast(AssistantAudio, updated_history_item.content[0]).transcript == "hello"
592+
593+
@pytest.mark.asyncio
594+
async def test_ignored_events_only_generate_raw_events(self, mock_model, mock_agent):
595+
"""Test that ignored events (connection_status, other) only generate raw events"""
596+
session = RealtimeSession(mock_model, mock_agent, None)
597+
578598
# Test connection status (should be ignored)
579599
connection_event = RealtimeModelConnectionStatusEvent(status="connected")
580600
await session.on_event(connection_event)
@@ -583,10 +603,10 @@ async def test_ignored_events_only_generate_raw_events(self, mock_model, mock_ag
583603
other_event = RealtimeModelOtherEvent(data={"custom": "data"})
584604
await session.on_event(other_event)
585605

586-
# Should only have 3 raw events (no transformed events)
587-
assert session._event_queue.qsize() == 3
606+
# Should only have 2 raw events (no transformed events)
607+
assert session._event_queue.qsize() == 2
588608

589-
for _ in range(3):
609+
for _ in range(2):
590610
event = await session._event_queue.get()
591611
assert isinstance(event, RealtimeRawModelEvent)
592612

0 commit comments

Comments
 (0)