codex: address PR review feedback (#17178)

- preserve provider-pinned realtime models on v2 starts
- add regression coverage for provider model query params

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Ahmed Ibrahim
2026-04-08 20:22:30 -07:00
co-authored by Codex
parent 40c63351ae
commit 3185ee47fb
2 changed files with 93 additions and 1 deletions
+6 -1
View File
@@ -555,6 +555,7 @@ pub(crate) async fn build_realtime_session_config(
voice: Option<RealtimeVoice>,
) -> CodexResult<RealtimeSessionConfig> {
let config = sess.get_config().await;
let provider = sess.provider().await;
let prompt = prepare_realtime_backend_prompt(
prompt,
config.experimental_realtime_ws_backend_prompt.clone(),
@@ -573,8 +574,12 @@ pub(crate) async fn build_realtime_session_config(
(false, true) => prompt,
(false, false) => format!("{prompt}\n\n{startup_context}"),
};
let provider_pins_model = provider
.query_params
.as_ref()
.is_some_and(|query_params| query_params.contains_key("model"));
let model = config.experimental_realtime_ws_model.clone().or_else(|| {
(config.realtime.version == RealtimeWsVersion::V2)
(config.realtime.version == RealtimeWsVersion::V2 && !provider_pins_model)
.then(|| DEFAULT_REALTIME_MODEL.to_string())
});
let event_parser = match config.realtime.version {
@@ -40,6 +40,7 @@ use core_test_support::wait_for_event_match;
use pretty_assertions::assert_eq;
use serde_json::Value;
use serde_json::json;
use std::collections::HashMap;
use std::fs;
use std::process::Command;
use std::sync::Arc;
@@ -530,6 +531,92 @@ async fn conversation_start_v1_without_model_override_preserves_provider_default
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn conversation_start_v2_with_provider_model_preserves_provider_default() -> Result<()> {
skip_if_no_network!(Ok(()));
let api_server = start_mock_server().await;
let realtime_server = start_websocket_server(vec![
vec![],
vec![vec![json!({
"type": "session.updated",
"session": { "id": "sess_v2_provider", "instructions": "backend prompt" }
})]],
])
.await;
let realtime_ws_base_url = realtime_server.uri().to_string();
let mut builder = test_codex().with_config(move |config| {
config.experimental_realtime_ws_backend_prompt = Some("backend prompt".to_string());
config.experimental_realtime_ws_base_url = Some(realtime_ws_base_url);
config.model_provider.supports_websockets = true;
config.model_provider.query_params = Some(HashMap::from([(
"model".to_string(),
"provider-realtime-model".to_string(),
)]));
});
let test = builder.build(&api_server).await?;
assert!(
realtime_server
.wait_for_handshakes(/*expected*/ 1, Duration::from_secs(2))
.await
);
test.codex
.submit(Op::RealtimeConversationStart(ConversationStartParams {
prompt: "backend prompt".to_string(),
session_id: None,
transport: None,
}))
.await?;
let started = wait_for_event_match(&test.codex, |msg| match msg {
EventMsg::RealtimeConversationStarted(started) => Some(Ok(started.clone())),
EventMsg::Error(err) => Some(Err(err.clone())),
_ => None,
})
.await
.unwrap_or_else(|err: ErrorEvent| panic!("conversation start failed: {err:?}"));
assert_eq!(started.version, RealtimeConversationVersion::V2);
let session_updated = wait_for_event_match(&test.codex, |msg| match msg {
EventMsg::RealtimeConversationRealtime(RealtimeConversationRealtimeEvent {
payload: RealtimeEvent::SessionUpdated { session_id, .. },
}) => Some(session_id.clone()),
_ => None,
})
.await;
assert_eq!(session_updated, "sess_v2_provider");
let connections = realtime_server.connections();
assert_eq!(connections.len(), 2);
assert_eq!(
realtime_server.handshakes()[1].uri(),
"/v1/realtime?model=provider-realtime-model"
);
let expected_session_update = json!({
"type": "session.update",
"session": session_update_session_json(RealtimeSessionConfig {
instructions: "backend prompt".to_string(),
model: None,
session_id: started.session_id.clone(),
event_parser: RealtimeEventParser::RealtimeV2,
session_mode: RealtimeSessionMode::Conversational,
})?
});
assert_eq!(connections[1][0].body_json(), expected_session_update);
test.codex.submit(Op::RealtimeConversationClose).await?;
let _closed = wait_for_event_match(&test.codex, |msg| match msg {
EventMsg::RealtimeConversationClosed(closed) => Some(closed.clone()),
_ => None,
})
.await;
realtime_server.shutdown().await;
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn conversation_webrtc_start_posts_generated_session() -> Result<()> {
skip_if_no_network!(Ok(()));