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
4 changes: 3 additions & 1 deletion src/agents/realtime/openai_realtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -2011,7 +2011,9 @@ def conversation_item_to_realtime_message_item(
"type": item.type,
"role": item.role,
"content": content,
"status": "in_progress",
# Keep the server's status: hardcoding "in_progress" regressed
# completed items every time one was retrieved (#4597).
"status": item.status or "in_progress",
},
)

Expand Down
30 changes: 30 additions & 0 deletions tests/realtime/test_item_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,33 @@ def test_system_message_conversion() -> None:
)

assert isinstance(converted, SystemMessageItem)


def test_status_is_taken_from_the_server_item() -> None:
"""A retrieved item reports its real status; overriding it regressed history (#4597)."""
item = RealtimeConversationItemAssistantMessage(
id="123",
type="message",
role="assistant",
status="completed",
content=[AssistantMessageContent(type="output_text", text="hi")],
)

converted = _ConversionHelper.conversation_item_to_realtime_message_item(item, None)

assert isinstance(converted, AssistantMessageItem)
assert converted.status == "completed"


def test_status_defaults_to_in_progress_when_the_server_omits_it() -> None:
item = RealtimeConversationItemAssistantMessage(
id="123",
type="message",
role="assistant",
content=[AssistantMessageContent(type="output_text", text="hi")],
)

converted = _ConversionHelper.conversation_item_to_realtime_message_item(item, None)

assert isinstance(converted, AssistantMessageItem)
assert converted.status == "in_progress"
23 changes: 23 additions & 0 deletions tests/realtime/test_openai_realtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,29 @@ async def test_raw_event_preserves_null_previous_item_id(self, model):
item_updated_event = mock_listener.on_event.call_args_list[1][0][0]
assert item_updated_event.item.previous_item_id == ""

@pytest.mark.asyncio
async def test_retrieved_item_keeps_the_status_the_server_reported(self, model):
"""A retrieve of a finished item must not regress it to in_progress (#4597)."""
mock_listener = AsyncMock()
model.add_listener(mock_listener)
server_event = {
"type": "conversation.item.retrieved",
"event_id": "event_1",
"item": {
"id": "item_1",
"type": "message",
"role": "assistant",
"status": "completed",
"content": [{"type": "output_audio", "transcript": "hello there"}],
},
}

await model._handle_ws_event(server_event)

assert mock_listener.on_event.call_count == 2
item_updated_event = mock_listener.on_event.call_args_list[1][0][0]
assert item_updated_event.item.status == "completed"

@pytest.mark.asyncio
async def test_handle_malformed_json_logs_error_continues(self, model):
"""Test that malformed JSON emits error event but doesn't crash."""
Expand Down