Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/agents/realtime/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down
35 changes: 28 additions & 7 deletions tests/realtime/test_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -565,17 +565,38 @@ async def test_item_deleted_event_removes_item(self, mock_model, mock_agent):
assert len(history_event.history) == 1

@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"""
async def test_transcript_delta_updates_history_and_emits_history_updated(
self, mock_model, mock_agent
):
"""Test that transcript delta events update history and emit history_updated."""
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)

assert session._event_queue.qsize() == 2

raw_event = await session._event_queue.get()
assert isinstance(raw_event, RealtimeRawModelEvent)
assert raw_event.data == transcript_event

history_event = await session._event_queue.get()
assert isinstance(history_event, RealtimeHistoryUpdated)
assert history_event.history == session._history
assert len(history_event.history) == 1

updated_item = cast(AssistantMessageItem, history_event.history[0])
assert updated_item.item_id == "item_1"
assert isinstance(updated_item.content[0], AssistantAudio)
assert updated_item.content[0].transcript == "hello"

@pytest.mark.asyncio
async def test_ignored_events_only_generate_raw_events(self, mock_model, mock_agent):
"""Test that connection_status and other events only generate raw events."""
session = RealtimeSession(mock_model, mock_agent, None)

# Test connection status (should be ignored)
connection_event = RealtimeModelConnectionStatusEvent(status="connected")
await session.on_event(connection_event)
Expand All @@ -584,10 +605,10 @@ 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)

Expand Down