diff --git a/examples/realtime/twilio_sip/server.py b/examples/realtime/twilio_sip/server.py index 6fd07ade26..9692dd8999 100644 --- a/examples/realtime/twilio_sip/server.py +++ b/examples/realtime/twilio_sip/server.py @@ -69,7 +69,7 @@ async def accept_call(call_id: str) -> None: f"/realtime/calls/{call_id}/accept", body={ "type": "realtime", - "model": "gpt-realtime", + "model": "gpt-realtime-1.5", "instructions": instructions_payload, }, cast_to=dict, diff --git a/src/agents/realtime/openai_realtime.py b/src/agents/realtime/openai_realtime.py index fdf6ac582c..6f7d5f08d5 100644 --- a/src/agents/realtime/openai_realtime.py +++ b/src/agents/realtime/openai_realtime.py @@ -158,6 +158,7 @@ _USER_AGENT = f"Agents/Python {__version__}" +DEFAULT_REALTIME_MODEL = "gpt-realtime-1.5" DEFAULT_MODEL_SETTINGS: RealtimeSessionModelSettings = { "voice": "ash", @@ -271,7 +272,7 @@ class OpenAIRealtimeWebSocketModel(RealtimeModel): """A model that uses OpenAI's WebSocket API.""" def __init__(self, *, transport_config: TransportConfig | None = None) -> None: - self.model = "gpt-realtime" # Default model + self.model = DEFAULT_REALTIME_MODEL self._websocket: ClientConnection | None = None self._websocket_task: asyncio.Task[None] | None = None self._listeners: list[RealtimeModelListener] = [] @@ -1105,7 +1106,7 @@ def _get_session_config( # Construct full session object. `type` will be excluded at serialization time for updates. session_create_request = OpenAISessionCreateRequest( type="realtime", - model=(model_settings.get("model_name") or self.model) or "gpt-realtime", + model=(model_settings.get("model_name") or self.model) or DEFAULT_REALTIME_MODEL, output_modalities=output_modalities, audio=OpenAIRealtimeAudioConfig( input=OpenAIRealtimeAudioInput(**audio_input_args), diff --git a/tests/realtime/test_conversion_helpers.py b/tests/realtime/test_conversion_helpers.py index 535621f135..9696b11e16 100644 --- a/tests/realtime/test_conversion_helpers.py +++ b/tests/realtime/test_conversion_helpers.py @@ -33,7 +33,7 @@ def test_try_convert_raw_message_valid_session_update(self): "type": "session.update", "other_data": { "session": { - "model": "gpt-realtime", + "model": "gpt-realtime-1.5", "type": "realtime", "modalities": ["text", "audio"], "voice": "ash", diff --git a/tests/realtime/test_openai_realtime.py b/tests/realtime/test_openai_realtime.py index 06dd210895..9f82093ac2 100644 --- a/tests/realtime/test_openai_realtime.py +++ b/tests/realtime/test_openai_realtime.py @@ -113,6 +113,36 @@ def mock_create_task_func(coro): assert model._websocket_task is not None assert model.model == "gpt-4o-realtime-preview" + @pytest.mark.asyncio + async def test_connect_defaults_to_gpt_realtime_1_5(self, model, mock_websocket): + """Test that connect() uses gpt-realtime-1.5 when no model is provided.""" + config = { + "api_key": "test-api-key-123", + "initial_model_settings": {}, + } + + async def async_websocket(*args, **kwargs): + return mock_websocket + + with patch("websockets.connect", side_effect=async_websocket) as mock_connect: + with patch("asyncio.create_task") as mock_create_task: + mock_task = AsyncMock() + + def mock_create_task_func(coro): + coro.close() + return mock_task + + mock_create_task.side_effect = mock_create_task_func + + await model.connect(config) + + mock_connect.assert_called_once() + call_args = mock_connect.call_args + assert call_args[0][0] == "wss://api.openai.com/v1/realtime?model=gpt-realtime-1.5" + assert model.model == "gpt-realtime-1.5" + + assert model._websocket_task is not None + @pytest.mark.asyncio async def test_session_update_includes_noise_reduction(self, model, mock_websocket): """Session.update should pass through input_audio_noise_reduction config.""" @@ -788,6 +818,7 @@ def test_get_and_update_session_config(self, model): def test_session_config_defaults_audio_formats_when_not_call(self, model): settings: dict[str, Any] = {} cfg = model._get_session_config(settings) + assert cfg.model == "gpt-realtime-1.5" assert cfg.audio is not None assert cfg.audio.input is not None assert cfg.audio.input.format is not None diff --git a/tests/realtime/test_realtime_model_settings.py b/tests/realtime/test_realtime_model_settings.py index f9da348605..6db201fb96 100644 --- a/tests/realtime/test_realtime_model_settings.py +++ b/tests/realtime/test_realtime_model_settings.py @@ -51,7 +51,7 @@ def helper() -> str: monkeypatch.setattr(agent, "get_all_tools", AsyncMock(return_value=[helper])) agent.handoffs = [RealtimeAgent(name="handoff-child")] - base_settings: RealtimeSessionModelSettings = {"model_name": "gpt-realtime"} + base_settings: RealtimeSessionModelSettings = {"model_name": "gpt-realtime-1.5"} starting_settings: RealtimeSessionModelSettings = {"voice": "verse"} run_config: RealtimeRunConfig = {"tracing_disabled": True} @@ -68,9 +68,9 @@ def helper() -> str: assert merged["tools"][0].name == helper.name assert merged["handoffs"][0].agent_name == "handoff-child" assert merged["voice"] == "verse" - assert merged["model_name"] == "gpt-realtime" + assert merged["model_name"] == "gpt-realtime-1.5" assert merged["tracing"] is None - assert base_settings == {"model_name": "gpt-realtime"} + assert base_settings == {"model_name": "gpt-realtime-1.5"} @pytest.mark.asyncio diff --git a/tests/realtime/test_session_payload_and_formats.py b/tests/realtime/test_session_payload_and_formats.py index f3e72ae13d..b60d8df861 100644 --- a/tests/realtime/test_session_payload_and_formats.py +++ b/tests/realtime/test_session_payload_and_formats.py @@ -26,10 +26,10 @@ class _DummyModel(pydantic.BaseModel): def _session_with_output(fmt: Any | None) -> RealtimeSessionCreateRequest: if fmt is None: - return RealtimeSessionCreateRequest(type="realtime", model="gpt-realtime") + return RealtimeSessionCreateRequest(type="realtime", model="gpt-realtime-1.5") return RealtimeSessionCreateRequest( type="realtime", - model="gpt-realtime", + model="gpt-realtime-1.5", # Use dict for output to avoid importing non-exported symbols in tests audio=RealtimeAudioConfig(output=cast(Any, {"format": fmt})), ) @@ -49,7 +49,7 @@ def test_normalize_session_payload_variants() -> None: assert Model._normalize_session_payload(transcription_mapping) is None # Valid realtime mapping should be converted to model - realtime_mapping: Mapping[str, object] = {"type": "realtime", "model": "gpt-realtime"} + realtime_mapping: Mapping[str, object] = {"type": "realtime", "model": "gpt-realtime-1.5"} as_model = Model._normalize_session_payload(realtime_mapping) assert isinstance(as_model, RealtimeSessionCreateRequest) assert as_model.type == "realtime" diff --git a/tests/realtime/test_tracing.py b/tests/realtime/test_tracing.py index 60004ab0b5..f01448e70b 100644 --- a/tests/realtime/test_tracing.py +++ b/tests/realtime/test_tracing.py @@ -100,7 +100,11 @@ async def async_websocket(*args, **kwargs): session_created_event = { "type": "session.created", "event_id": "event_123", - "session": {"id": "session_456", "type": "realtime", "model": "gpt-realtime"}, + "session": { + "id": "session_456", + "type": "realtime", + "model": "gpt-realtime-1.5", + }, } with patch.object(model, "_send_raw_message") as mock_send_raw_message: @@ -141,7 +145,11 @@ async def async_websocket(*args, **kwargs): session_created_event = { "type": "session.created", "event_id": "event_123", - "session": {"id": "session_456", "type": "realtime", "model": "gpt-realtime"}, + "session": { + "id": "session_456", + "type": "realtime", + "model": "gpt-realtime-1.5", + }, } with patch.object(model, "_send_raw_message") as mock_send_raw_message: @@ -166,7 +174,7 @@ async def test_tracing_config_none_skips_session_update(self, model, mock_websoc session_created_event = { "type": "session.created", "event_id": "event_123", - "session": {"id": "session_456", "type": "realtime", "model": "gpt-realtime"}, + "session": {"id": "session_456", "type": "realtime", "model": "gpt-realtime-1.5"}, } with patch.object(model, "send_event") as mock_send_event: @@ -205,7 +213,11 @@ async def async_websocket(*args, **kwargs): session_created_event = { "type": "session.created", "event_id": "event_123", - "session": {"id": "session_456", "type": "realtime", "model": "gpt-realtime"}, + "session": { + "id": "session_456", + "type": "realtime", + "model": "gpt-realtime-1.5", + }, } with patch.object(model, "_send_raw_message") as mock_send_raw_message: