From c5703a64552404d805bc969f831ff55458069bea Mon Sep 17 00:00:00 2001 From: pakrym-oai Date: Wed, 25 Feb 2026 15:59:36 -0800 Subject: [PATCH 1/2] Use websocket v2 for model-preferred websocket path --- codex-rs/core/src/client.rs | 6 ++-- .../core/tests/suite/client_websockets.rs | 32 +++++++++++++------ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/codex-rs/core/src/client.rs b/codex-rs/core/src/client.rs index 74a2f15c19b..7e9a55c9a1d 100644 --- a/codex-rs/core/src/client.rs +++ b/codex-rs/core/src/client.rs @@ -392,8 +392,8 @@ impl ModelClient { /// This combines provider capability and feature gating; both must be true for websocket paths /// to be eligible. /// - /// If websockets are only enabled via model preference (no explicit feature flag), default to - /// v1 behavior. + /// If websockets are only enabled via model preference (no explicit feature flag), prefer the + /// current v2 behavior. pub fn active_ws_version(&self, model_info: &ModelInfo) -> Option { if !self.state.provider.supports_websockets || self.state.disable_websockets.load(Ordering::Relaxed) @@ -403,7 +403,7 @@ impl ModelClient { match self.state.responses_websocket_version { Some(version) => Some(version), - None if model_info.prefer_websockets => Some(ResponsesWebsocketVersion::V1), + None if model_info.prefer_websockets => Some(ResponsesWebsocketVersion::V2), None => None, } } diff --git a/codex-rs/core/tests/suite/client_websockets.rs b/codex-rs/core/tests/suite/client_websockets.rs index 3dec0c44083..e7f3b6236e2 100755 --- a/codex-rs/core/tests/suite/client_websockets.rs +++ b/codex-rs/core/tests/suite/client_websockets.rs @@ -300,7 +300,7 @@ async fn responses_websocket_request_prewarm_is_reused_even_with_header_changes( } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn responses_websocket_prewarm_uses_model_preference_when_feature_disabled() { +async fn responses_websocket_prewarm_uses_v2_when_model_prefers_websockets_and_feature_disabled() { skip_if_no_network!(); let server = start_websocket_server(vec![vec![vec![ @@ -324,20 +324,34 @@ async fn responses_websocket_prewarm_uses_model_preference_when_feature_disabled .await .expect("websocket prewarm failed"); - // V1 prewarm only preconnects and should not issue a request. + // V2 prewarm issues a request on the websocket connection. assert_eq!(server.handshakes().len(), 1); - assert_eq!(server.single_connection().len(), 0); + assert_eq!(server.single_connection().len(), 1); + + let handshake = server.single_handshake(); + let openai_beta_header = handshake + .header(OPENAI_BETA_HEADER) + .expect("missing OpenAI-Beta header"); + assert!( + openai_beta_header + .split(',') + .map(str::trim) + .any(|value| value == WS_V2_BETA_HEADER_VALUE) + ); + assert!( + !openai_beta_header + .split(',') + .map(str::trim) + .any(|value| value == OPENAI_BETA_RESPONSES_WEBSOCKETS) + ); stream_until_complete(&mut client_session, &harness, &prompt).await; assert_eq!(server.handshakes().len(), 1); let connection = server.single_connection(); assert_eq!(connection.len(), 1); - let turn = connection - .first() - .expect("missing turn request") - .body_json(); - assert_eq!(turn["type"].as_str(), Some("response.create")); - assert_eq!(turn["input"], serde_json::to_value(&prompt.input).unwrap()); + let prewarm = connection.first().expect("missing prewarm request").body_json(); + assert_eq!(prewarm["type"].as_str(), Some("response.create")); + assert_eq!(prewarm["input"], serde_json::to_value(&prompt.input).unwrap()); server.shutdown().await; } From 077653cbd24c8bea22c39e05954e8c3774ffe0c3 Mon Sep 17 00:00:00 2001 From: pakrym-oai Date: Wed, 25 Feb 2026 16:05:22 -0800 Subject: [PATCH 2/2] Format websocket preference regression test --- codex-rs/core/tests/suite/client_websockets.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/codex-rs/core/tests/suite/client_websockets.rs b/codex-rs/core/tests/suite/client_websockets.rs index e7f3b6236e2..e7ed2ac12bd 100755 --- a/codex-rs/core/tests/suite/client_websockets.rs +++ b/codex-rs/core/tests/suite/client_websockets.rs @@ -349,9 +349,15 @@ async fn responses_websocket_prewarm_uses_v2_when_model_prefers_websockets_and_f assert_eq!(server.handshakes().len(), 1); let connection = server.single_connection(); assert_eq!(connection.len(), 1); - let prewarm = connection.first().expect("missing prewarm request").body_json(); + let prewarm = connection + .first() + .expect("missing prewarm request") + .body_json(); assert_eq!(prewarm["type"].as_str(), Some("response.create")); - assert_eq!(prewarm["input"], serde_json::to_value(&prompt.input).unwrap()); + assert_eq!( + prewarm["input"], + serde_json::to_value(&prompt.input).unwrap() + ); server.shutdown().await; }