From 0efd33f7f4291d6a056dc39a9654ce04ebe0400c Mon Sep 17 00:00:00 2001 From: pakrym-oai Date: Wed, 4 Feb 2026 08:38:06 -0800 Subject: [PATCH] Update tests to stop using sse_completed fixture (#10638) Summary: - replace the `sse_completed` fixture and related JSON template with direct `responses::ev_completed` payload builders - cascade the new SSE helpers through all affected core tests for consistency and clarity - remove legacy fixtures that were no longer needed once the helpers are in place Testing: - Not run (not requested) --- codex-rs/core/tests/common/lib.rs | 35 ----- .../tests/fixtures/completed_template.json | 16 --- codex-rs/core/tests/suite/client.rs | 124 ++++++++++++++---- .../tests/suite/collaboration_instructions.rs | 100 +++++++++++--- codex-rs/core/tests/suite/fork_thread.rs | 10 +- .../core/tests/suite/hierarchical_agents.rs | 20 ++- codex-rs/core/tests/suite/model_tools.rs | 10 +- .../core/tests/suite/permissions_messages.rs | 82 +++++++++--- codex-rs/core/tests/suite/personality.rs | 48 +++++-- codex-rs/core/tests/suite/prompt_caching.rs | 99 +++++++++++--- codex-rs/core/tests/suite/sqlite_state.rs | 10 +- .../suite/stream_error_allows_next_turn.rs | 16 ++- .../core/tests/suite/stream_no_completed.rs | 16 ++- codex-rs/core/tests/suite/web_search.rs | 36 +++-- 14 files changed, 428 insertions(+), 194 deletions(-) delete mode 100644 codex-rs/core/tests/fixtures/completed_template.json diff --git a/codex-rs/core/tests/common/lib.rs b/codex-rs/core/tests/common/lib.rs index 5df2a74ed..3feadb072 100644 --- a/codex-rs/core/tests/common/lib.rs +++ b/codex-rs/core/tests/common/lib.rs @@ -1,7 +1,6 @@ #![expect(clippy::expect_used)] use codex_utils_cargo_bin::CargoBinError; -use codex_utils_cargo_bin::find_resource; use tempfile::TempDir; use codex_core::CodexThread; @@ -147,40 +146,6 @@ pub fn load_sse_fixture_with_id_from_str(raw: &str, id: &str) -> String { .collect() } -/// Same as [`load_sse_fixture`], but replaces the placeholder `__ID__` in the -/// fixture template with the supplied identifier before parsing. This lets a -/// single JSON template be reused by multiple tests that each need a unique -/// `response_id`. -pub fn load_sse_fixture_with_id(path: impl AsRef, id: &str) -> String { - let p = path.as_ref(); - let full_path = match find_resource!(p) { - Ok(p) => p, - Err(err) => panic!( - "failed to find fixture template at {:?}: {err}", - path.as_ref() - ), - }; - - let raw = std::fs::read_to_string(full_path).expect("read fixture template"); - let replaced = raw.replace("__ID__", id); - let events: Vec = - serde_json::from_str(&replaced).expect("parse JSON fixture"); - events - .into_iter() - .map(|e| { - let kind = e - .get("type") - .and_then(|v| v.as_str()) - .expect("fixture event missing type"); - if e.as_object().map(|o| o.len() == 1).unwrap_or(false) { - format!("event: {kind}\n\n") - } else { - format!("event: {kind}\ndata: {e}\n\n") - } - }) - .collect() -} - pub async fn wait_for_event(codex: &CodexThread, predicate: F) -> codex_core::protocol::EventMsg where F: FnMut(&codex_core::protocol::EventMsg) -> bool, diff --git a/codex-rs/core/tests/fixtures/completed_template.json b/codex-rs/core/tests/fixtures/completed_template.json deleted file mode 100644 index 1774dc5e8..000000000 --- a/codex-rs/core/tests/fixtures/completed_template.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "type": "response.completed", - "response": { - "id": "__ID__", - "usage": { - "input_tokens": 0, - "input_tokens_details": null, - "output_tokens": 0, - "output_tokens_details": null, - "total_tokens": 0 - }, - "output": [] - } - } -] diff --git a/codex-rs/core/tests/suite/client.rs b/codex-rs/core/tests/suite/client.rs index bd50708a2..62135127f 100644 --- a/codex-rs/core/tests/suite/client.rs +++ b/codex-rs/core/tests/suite/client.rs @@ -36,8 +36,9 @@ use codex_protocol::models::WebSearchAction; use codex_protocol::openai_models::ReasoningEffort; use codex_protocol::user_input::UserInput; use core_test_support::load_default_config_for_test; -use core_test_support::load_sse_fixture_with_id; +use core_test_support::responses::ev_completed; use core_test_support::responses::ev_completed_with_tokens; +use core_test_support::responses::ev_response_created; use core_test_support::responses::mount_sse_once; use core_test_support::responses::mount_sse_once_match; use core_test_support::responses::mount_sse_sequence; @@ -64,11 +65,6 @@ use wiremock::matchers::method; use wiremock::matchers::path; use wiremock::matchers::query_param; -/// Build minimal SSE stream with completed marker using the JSON fixture. -fn sse_completed(id: &str) -> String { - load_sse_fixture_with_id("../fixtures/completed_template.json", id) -} - #[expect(clippy::unwrap_used)] fn assert_message_role(request_body: &serde_json::Value, role: &str) { assert_eq!(request_body["role"].as_str().unwrap(), role); @@ -259,7 +255,11 @@ async fn resume_includes_initial_messages_and_sends_prior_items() { // Mock server that will receive the resumed request let server = MockServer::start().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; // Configure Codex to resume from our file let codex_home = Arc::new(TempDir::new().unwrap()); @@ -377,7 +377,11 @@ async fn includes_conversation_id_and_model_headers_in_request() { // Mock server let server = MockServer::start().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let mut builder = test_codex().with_auth(CodexAuth::from_api_key("Test API Key")); let test = builder @@ -418,7 +422,11 @@ async fn includes_base_instructions_override_in_request() { skip_if_no_network!(); // Mock server let server = MockServer::start().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let mut builder = test_codex() .with_auth(CodexAuth::from_api_key("Test API Key")) @@ -462,7 +470,11 @@ async fn chatgpt_auth_sends_correct_request() { // Mock server let server = MockServer::start().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let mut model_provider = built_in_model_providers()["openai"].clone(); model_provider.base_url = Some(format!("{}/api/codex", server.uri())); @@ -524,7 +536,10 @@ async fn prefers_apikey_when_config_prefers_apikey_even_with_chatgpt_tokens() { let first = ResponseTemplate::new(200) .insert_header("content-type", "text/event-stream") - .set_body_raw(sse_completed("resp1"), "text/event-stream"); + .set_body_raw( + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + "text/event-stream", + ); // Expect API key header, no ChatGPT account header required. Mock::given(method("POST")) @@ -590,7 +605,11 @@ async fn includes_user_instructions_message_in_request() { skip_if_no_network!(); let server = MockServer::start().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let mut builder = test_codex() .with_auth(CodexAuth::from_api_key("Test API Key")) @@ -652,7 +671,11 @@ async fn skills_append_to_instructions() { skip_if_no_network!(); let server = MockServer::start().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let codex_home = Arc::new(TempDir::new().unwrap()); let skill_dir = codex_home.path().join("skills/demo"); @@ -720,7 +743,11 @@ async fn includes_configured_effort_in_request() -> anyhow::Result<()> { skip_if_no_network!(Ok(())); let server = MockServer::start().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let TestCodex { codex, .. } = test_codex() .with_model("gpt-5.1-codex") .with_config(|config| { @@ -761,7 +788,11 @@ async fn includes_no_effort_in_request() -> anyhow::Result<()> { skip_if_no_network!(Ok(())); let server = MockServer::start().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let TestCodex { codex, .. } = test_codex() .with_model("gpt-5.1-codex") .build(&server) @@ -800,7 +831,11 @@ async fn includes_default_reasoning_effort_in_request_when_defined_by_model_info skip_if_no_network!(Ok(())); let server = MockServer::start().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let TestCodex { codex, .. } = test_codex().with_model("gpt-5.1").build(&server).await?; codex @@ -835,7 +870,11 @@ async fn user_turn_collaboration_mode_overrides_model_and_effort() -> anyhow::Re skip_if_no_network!(Ok(())); let server = MockServer::start().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let TestCodex { codex, config, @@ -893,7 +932,11 @@ async fn configured_reasoning_summary_is_sent() -> anyhow::Result<()> { skip_if_no_network!(Ok(())); let server = MockServer::start().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let TestCodex { codex, .. } = test_codex() .with_config(|config| { config.model_reasoning_summary = ReasoningSummary::Concise; @@ -933,7 +976,11 @@ async fn reasoning_summary_is_omitted_when_disabled() -> anyhow::Result<()> { skip_if_no_network!(Ok(())); let server = MockServer::start().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let TestCodex { codex, .. } = test_codex() .with_config(|config| { config.model_reasoning_summary = ReasoningSummary::None; @@ -972,7 +1019,11 @@ async fn includes_default_verbosity_in_request() -> anyhow::Result<()> { skip_if_no_network!(Ok(())); let server = MockServer::start().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let TestCodex { codex, .. } = test_codex().with_model("gpt-5.1").build(&server).await?; codex @@ -1007,7 +1058,11 @@ async fn configured_verbosity_not_sent_for_models_without_support() -> anyhow::R skip_if_no_network!(Ok(())); let server = MockServer::start().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let TestCodex { codex, .. } = test_codex() .with_model("gpt-5.1-codex") .with_config(|config| { @@ -1047,7 +1102,11 @@ async fn configured_verbosity_is_sent() -> anyhow::Result<()> { skip_if_no_network!(Ok(())); let server = MockServer::start().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let TestCodex { codex, .. } = test_codex() .with_model("gpt-5.1") .with_config(|config| { @@ -1088,7 +1147,11 @@ async fn includes_developer_instructions_message_in_request() { skip_if_no_network!(); let server = MockServer::start().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let mut builder = test_codex() .with_auth(CodexAuth::from_api_key("Test API Key")) .with_config(|config| { @@ -1570,7 +1633,10 @@ async fn context_window_error_sets_total_tokens_to_model_window() -> anyhow::Res mount_sse_once_match( &server, body_string_contains("seed turn"), - sse_completed("resp_seed"), + sse(vec![ + ev_response_created("resp_seed"), + ev_completed("resp_seed"), + ]), ) .await; @@ -1656,7 +1722,10 @@ async fn azure_overrides_assign_properties_used_for_responses_url() { // First request – must NOT include `previous_response_id`. let first = ResponseTemplate::new(200) .insert_header("content-type", "text/event-stream") - .set_body_raw(sse_completed("resp1"), "text/event-stream"); + .set_body_raw( + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + "text/event-stream", + ); // Expect POST to /openai/responses with api-version query param Mock::given(method("POST")) @@ -1737,7 +1806,10 @@ async fn env_var_overrides_loaded_auth() { // First request – must NOT include `previous_response_id`. let first = ResponseTemplate::new(200) .insert_header("content-type", "text/event-stream") - .set_body_raw(sse_completed("resp1"), "text/event-stream"); + .set_body_raw( + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + "text/event-stream", + ); // Expect POST to /openai/responses with api-version query param Mock::given(method("POST")) diff --git a/codex-rs/core/tests/suite/collaboration_instructions.rs b/codex-rs/core/tests/suite/collaboration_instructions.rs index 21a0b2761..dc9905379 100644 --- a/codex-rs/core/tests/suite/collaboration_instructions.rs +++ b/codex-rs/core/tests/suite/collaboration_instructions.rs @@ -18,10 +18,6 @@ use core_test_support::wait_for_event; use pretty_assertions::assert_eq; use serde_json::Value; -fn sse_completed(id: &str) -> String { - sse(vec![ev_response_created(id), ev_completed(id)]) -} - fn collab_mode_with_mode_and_instructions( mode: ModeKind, instructions: Option<&str>, @@ -72,7 +68,11 @@ async fn no_collaboration_instructions_by_default() -> Result<()> { skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let req = mount_sse_once(&server, sse_completed("resp-1")).await; + let req = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; let test = test_codex().build(&server).await?; @@ -100,7 +100,11 @@ async fn user_input_includes_collaboration_instructions_after_override() -> Resu skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let req = mount_sse_once(&server, sse_completed("resp-1")).await; + let req = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; let test = test_codex().build(&server).await?; @@ -144,7 +148,11 @@ async fn collaboration_instructions_added_on_user_turn() -> Result<()> { skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let req = mount_sse_once(&server, sse_completed("resp-1")).await; + let req = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; let test = test_codex().build(&server).await?; let collab_text = "turn instructions"; @@ -182,7 +190,11 @@ async fn override_then_next_turn_uses_updated_collaboration_instructions() -> Re skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let req = mount_sse_once(&server, sse_completed("resp-1")).await; + let req = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; let test = test_codex().build(&server).await?; let collab_text = "override instructions"; @@ -226,7 +238,11 @@ async fn user_turn_overrides_collaboration_instructions_after_override() -> Resu skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let req = mount_sse_once(&server, sse_completed("resp-1")).await; + let req = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; let test = test_codex().build(&server).await?; let base_text = "base instructions"; @@ -282,8 +298,16 @@ async fn collaboration_mode_update_emits_new_instruction_message() -> Result<()> skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let _req1 = mount_sse_once(&server, sse_completed("resp-1")).await; - let req2 = mount_sse_once(&server, sse_completed("resp-2")).await; + let _req1 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; + let req2 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ) + .await; let test = test_codex().build(&server).await?; let first_text = "first instructions"; @@ -354,8 +378,16 @@ async fn collaboration_mode_update_noop_does_not_append() -> Result<()> { skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let _req1 = mount_sse_once(&server, sse_completed("resp-1")).await; - let req2 = mount_sse_once(&server, sse_completed("resp-2")).await; + let _req1 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; + let req2 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ) + .await; let test = test_codex().build(&server).await?; let collab_text = "same instructions"; @@ -423,8 +455,16 @@ async fn collaboration_mode_update_emits_new_instruction_message_when_mode_chang skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let _req1 = mount_sse_once(&server, sse_completed("resp-1")).await; - let req2 = mount_sse_once(&server, sse_completed("resp-2")).await; + let _req1 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; + let req2 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ) + .await; let test = test_codex().build(&server).await?; let default_text = "default mode instructions"; @@ -501,8 +541,16 @@ async fn collaboration_mode_update_noop_does_not_append_when_mode_is_unchanged() skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let _req1 = mount_sse_once(&server, sse_completed("resp-1")).await; - let req2 = mount_sse_once(&server, sse_completed("resp-2")).await; + let _req1 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; + let req2 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ) + .await; let test = test_codex().build(&server).await?; let collab_text = "mode-stable instructions"; @@ -576,8 +624,16 @@ async fn resume_replays_collaboration_instructions() -> Result<()> { skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let _req1 = mount_sse_once(&server, sse_completed("resp-1")).await; - let req2 = mount_sse_once(&server, sse_completed("resp-2")).await; + let _req1 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; + let req2 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ) + .await; let mut builder = test_codex(); let initial = builder.build(&server).await?; @@ -642,7 +698,11 @@ async fn empty_collaboration_instructions_are_ignored() -> Result<()> { skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let req = mount_sse_once(&server, sse_completed("resp-1")).await; + let req = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; let test = test_codex().build(&server).await?; diff --git a/codex-rs/core/tests/suite/fork_thread.rs b/codex-rs/core/tests/suite/fork_thread.rs index 55474a68a..d5363cc0a 100644 --- a/codex-rs/core/tests/suite/fork_thread.rs +++ b/codex-rs/core/tests/suite/fork_thread.rs @@ -6,6 +6,9 @@ use codex_core::protocol::RolloutItem; use codex_core::protocol::RolloutLine; use codex_protocol::items::TurnItem; use codex_protocol::user_input::UserInput; +use core_test_support::responses::ev_completed; +use core_test_support::responses::ev_response_created; +use core_test_support::responses::sse; use core_test_support::skip_if_no_network; use core_test_support::test_codex::test_codex; use core_test_support::wait_for_event; @@ -15,18 +18,13 @@ use wiremock::ResponseTemplate; use wiremock::matchers::method; use wiremock::matchers::path; -/// Build minimal SSE stream with completed marker using the JSON fixture. -fn sse_completed(id: &str) -> String { - core_test_support::load_sse_fixture_with_id("../fixtures/completed_template.json", id) -} - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn fork_thread_twice_drops_to_first_message() { skip_if_no_network!(); // Start a mock server that completes three turns. let server = MockServer::start().await; - let sse = sse_completed("resp"); + let sse = sse(vec![ev_response_created("resp"), ev_completed("resp")]); let first = ResponseTemplate::new(200) .insert_header("content-type", "text/event-stream") .set_body_raw(sse.clone(), "text/event-stream"); diff --git a/codex-rs/core/tests/suite/hierarchical_agents.rs b/codex-rs/core/tests/suite/hierarchical_agents.rs index 5dfa63648..5f1f84340 100644 --- a/codex-rs/core/tests/suite/hierarchical_agents.rs +++ b/codex-rs/core/tests/suite/hierarchical_agents.rs @@ -1,20 +1,22 @@ use codex_core::features::Feature; -use core_test_support::load_sse_fixture_with_id; +use core_test_support::responses::ev_completed; +use core_test_support::responses::ev_response_created; use core_test_support::responses::mount_sse_once; +use core_test_support::responses::sse; use core_test_support::responses::start_mock_server; use core_test_support::test_codex::test_codex; const HIERARCHICAL_AGENTS_SNIPPET: &str = "Files called AGENTS.md commonly appear in many places inside a container"; -fn sse_completed(id: &str) -> String { - load_sse_fixture_with_id("../fixtures/completed_template.json", id) -} - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn hierarchical_agents_appends_to_project_doc_in_user_instructions() { let server = start_mock_server().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let mut builder = test_codex().with_config(|config| { config.features.enable(Feature::ChildAgentsMd); @@ -49,7 +51,11 @@ async fn hierarchical_agents_appends_to_project_doc_in_user_instructions() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn hierarchical_agents_emits_when_no_project_doc() { let server = start_mock_server().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp1"), ev_completed("resp1")]), + ) + .await; let mut builder = test_codex().with_config(|config| { config.features.enable(Feature::ChildAgentsMd); diff --git a/codex-rs/core/tests/suite/model_tools.rs b/codex-rs/core/tests/suite/model_tools.rs index b08b5281c..c687545f2 100644 --- a/codex-rs/core/tests/suite/model_tools.rs +++ b/codex-rs/core/tests/suite/model_tools.rs @@ -2,16 +2,11 @@ use codex_core::features::Feature; use codex_protocol::config_types::WebSearchMode; -use core_test_support::load_sse_fixture_with_id; use core_test_support::responses; use core_test_support::responses::start_mock_server; use core_test_support::skip_if_no_network; use core_test_support::test_codex::test_codex; -fn sse_completed(id: &str) -> String { - load_sse_fixture_with_id("../fixtures/completed_template.json", id) -} - #[allow(clippy::expect_used)] fn tool_identifiers(body: &serde_json::Value) -> Vec { body["tools"] @@ -31,7 +26,10 @@ fn tool_identifiers(body: &serde_json::Value) -> Vec { #[allow(clippy::expect_used)] async fn collect_tool_identifiers_for_model(model: &str) -> Vec { let server = start_mock_server().await; - let sse = sse_completed(model); + let sse = responses::sse(vec![ + responses::ev_response_created(model), + responses::ev_completed(model), + ]); let resp_mock = responses::mount_sse_once(&server, sse).await; let mut builder = test_codex() diff --git a/codex-rs/core/tests/suite/permissions_messages.rs b/codex-rs/core/tests/suite/permissions_messages.rs index c54203b4f..fc1f0fa0b 100644 --- a/codex-rs/core/tests/suite/permissions_messages.rs +++ b/codex-rs/core/tests/suite/permissions_messages.rs @@ -43,16 +43,16 @@ fn permissions_texts(input: &[serde_json::Value]) -> Vec { .collect() } -fn sse_completed(id: &str) -> String { - sse(vec![ev_response_created(id), ev_completed(id)]) -} - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn permissions_message_sent_once_on_start() -> Result<()> { skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let req = mount_sse_once(&server, sse_completed("resp-1")).await; + let req = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; let mut builder = test_codex().with_config(move |config| { config.approval_policy = Constrained::allow_any(AskForApproval::OnRequest); @@ -84,8 +84,16 @@ async fn permissions_message_added_on_override_change() -> Result<()> { skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let req1 = mount_sse_once(&server, sse_completed("resp-1")).await; - let req2 = mount_sse_once(&server, sse_completed("resp-2")).await; + let req1 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; + let req2 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ) + .await; let mut builder = test_codex().with_config(move |config| { config.approval_policy = Constrained::allow_any(AskForApproval::OnRequest); @@ -148,8 +156,16 @@ async fn permissions_message_not_added_when_no_change() -> Result<()> { skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let req1 = mount_sse_once(&server, sse_completed("resp-1")).await; - let req2 = mount_sse_once(&server, sse_completed("resp-2")).await; + let req1 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; + let req2 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ) + .await; let mut builder = test_codex().with_config(move |config| { config.approval_policy = Constrained::allow_any(AskForApproval::OnRequest); @@ -197,9 +213,21 @@ async fn resume_replays_permissions_messages() -> Result<()> { skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let _req1 = mount_sse_once(&server, sse_completed("resp-1")).await; - let _req2 = mount_sse_once(&server, sse_completed("resp-2")).await; - let req3 = mount_sse_once(&server, sse_completed("resp-3")).await; + let _req1 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; + let _req2 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ) + .await; + let req3 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-3"), ev_completed("resp-3")]), + ) + .await; let mut builder = test_codex().with_config(|config| { config.approval_policy = Constrained::allow_any(AskForApproval::OnRequest); @@ -279,10 +307,26 @@ async fn resume_and_fork_append_permissions_messages() -> Result<()> { skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let _req1 = mount_sse_once(&server, sse_completed("resp-1")).await; - let req2 = mount_sse_once(&server, sse_completed("resp-2")).await; - let req3 = mount_sse_once(&server, sse_completed("resp-3")).await; - let req4 = mount_sse_once(&server, sse_completed("resp-4")).await; + let _req1 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; + let req2 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ) + .await; + let req3 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-3"), ev_completed("resp-3")]), + ) + .await; + let req4 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-4"), ev_completed("resp-4")]), + ) + .await; let mut builder = test_codex().with_config(|config| { config.approval_policy = Constrained::allow_any(AskForApproval::OnRequest); @@ -404,7 +448,11 @@ async fn permissions_message_includes_writable_roots() -> Result<()> { skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let req = mount_sse_once(&server, sse_completed("resp-1")).await; + let req = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; let writable = TempDir::new()?; let writable_root = AbsolutePathBuf::try_from(writable.path())?; let sandbox_policy = SandboxPolicy::WorkspaceWrite { diff --git a/codex-rs/core/tests/suite/personality.rs b/codex-rs/core/tests/suite/personality.rs index 87978ceb5..919ce852e 100644 --- a/codex-rs/core/tests/suite/personality.rs +++ b/codex-rs/core/tests/suite/personality.rs @@ -42,10 +42,6 @@ const LOCAL_FRIENDLY_TEMPLATE: &str = "You optimize for team morale and being a supportive teammate as much as code quality."; const LOCAL_PRAGMATIC_TEMPLATE: &str = "You are a deeply pragmatic, effective software engineer."; -fn sse_completed(id: &str) -> String { - sse(vec![ev_response_created(id), ev_completed(id)]) -} - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn personality_does_not_mutate_base_instructions_without_template() { let codex_home = TempDir::new().expect("create temp dir"); @@ -82,7 +78,11 @@ async fn user_turn_personality_none_does_not_add_update_message() -> anyhow::Res skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; let mut builder = test_codex() .with_model("gpt-5.2-codex") .with_config(|config| { @@ -128,7 +128,11 @@ async fn config_personality_some_sets_instructions_template() -> anyhow::Result< skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; let mut builder = test_codex() .with_model("gpt-5.2-codex") .with_config(|config| { @@ -184,7 +188,10 @@ async fn user_turn_personality_some_adds_update_message() -> anyhow::Result<()> let server = start_mock_server().await; let resp_mock = mount_sse_sequence( &server, - vec![sse_completed("resp-1"), sse_completed("resp-2")], + vec![ + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ], ) .await; let mut builder = test_codex() @@ -280,7 +287,10 @@ async fn user_turn_personality_same_value_does_not_add_update_message() -> anyho let server = start_mock_server().await; let resp_mock = mount_sse_sequence( &server, - vec![sse_completed("resp-1"), sse_completed("resp-2")], + vec![ + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ], ) .await; let mut builder = test_codex() @@ -387,7 +397,10 @@ async fn user_turn_personality_skips_if_feature_disabled() -> anyhow::Result<()> let server = start_mock_server().await; let resp_mock = mount_sse_sequence( &server, - vec![sse_completed("resp-1"), sse_completed("resp-2")], + vec![ + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ], ) .await; let mut builder = test_codex() @@ -524,7 +537,11 @@ async fn ignores_remote_personality_if_remote_models_disabled() -> anyhow::Resul ) .await; - let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; let mut builder = test_codex() .with_auth(codex_core::CodexAuth::create_dummy_chatgpt_auth_for_testing()) @@ -640,7 +657,11 @@ async fn remote_model_friendly_personality_instructions_with_feature() -> anyhow ) .await; - let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await; + let resp_mock = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; let mut builder = test_codex() .with_auth(codex_core::CodexAuth::create_dummy_chatgpt_auth_for_testing()) @@ -753,7 +774,10 @@ async fn user_turn_personality_remote_model_template_includes_update_message() - let resp_mock = mount_sse_sequence( &server, - vec![sse_completed("resp-1"), sse_completed("resp-2")], + vec![ + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ], ) .await; diff --git a/codex-rs/core/tests/suite/prompt_caching.rs b/codex-rs/core/tests/suite/prompt_caching.rs index bf1819cbf..810cd5249 100644 --- a/codex-rs/core/tests/suite/prompt_caching.rs +++ b/codex-rs/core/tests/suite/prompt_caching.rs @@ -18,8 +18,10 @@ use codex_protocol::config_types::WebSearchMode; use codex_protocol::openai_models::ReasoningEffort; use codex_protocol::user_input::UserInput; use codex_utils_absolute_path::AbsolutePathBuf; -use core_test_support::load_sse_fixture_with_id; +use core_test_support::responses::ev_completed; +use core_test_support::responses::ev_response_created; use core_test_support::responses::mount_sse_once; +use core_test_support::responses::sse; use core_test_support::responses::start_mock_server; use core_test_support::skip_if_no_network; use core_test_support::test_codex::TestCodex; @@ -46,11 +48,6 @@ fn default_env_context_str(cwd: &str, shell: &Shell) -> String { ) } -/// Build minimal SSE stream with completed marker using the JSON fixture. -fn sse_completed(id: &str) -> String { - load_sse_fixture_with_id("../fixtures/completed_template.json", id) -} - fn assert_tool_names(body: &serde_json::Value, expected_names: &[&str]) { assert_eq!( body["tools"] @@ -79,8 +76,16 @@ async fn prompt_tools_are_consistent_across_requests() -> anyhow::Result<()> { use pretty_assertions::assert_eq; let server = start_mock_server().await; - let req1 = mount_sse_once(&server, sse_completed("resp-1")).await; - let req2 = mount_sse_once(&server, sse_completed("resp-2")).await; + let req1 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; + let req2 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ) + .await; let TestCodex { codex, @@ -172,8 +177,16 @@ async fn codex_mini_latest_tools() -> anyhow::Result<()> { use pretty_assertions::assert_eq; let server = start_mock_server().await; - let req1 = mount_sse_once(&server, sse_completed("resp-1")).await; - let req2 = mount_sse_once(&server, sse_completed("resp-2")).await; + let req1 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; + let req2 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ) + .await; let TestCodex { codex, .. } = test_codex() .with_config(|config| { @@ -238,8 +251,16 @@ async fn prefixes_context_and_instructions_once_and_consistently_across_requests use pretty_assertions::assert_eq; let server = start_mock_server().await; - let req1 = mount_sse_once(&server, sse_completed("resp-1")).await; - let req2 = mount_sse_once(&server, sse_completed("resp-2")).await; + let req1 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; + let req2 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ) + .await; let TestCodex { codex, config, .. } = test_codex() .with_config(|config| { @@ -315,8 +336,16 @@ async fn overrides_turn_context_but_keeps_cached_prefix_and_key_constant() -> an use pretty_assertions::assert_eq; let server = start_mock_server().await; - let req1 = mount_sse_once(&server, sse_completed("resp-1")).await; - let req2 = mount_sse_once(&server, sse_completed("resp-2")).await; + let req1 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; + let req2 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ) + .await; let TestCodex { codex, .. } = test_codex() .with_config(|config| { @@ -407,7 +436,11 @@ async fn override_before_first_turn_emits_environment_context() -> anyhow::Resul skip_if_no_network!(Ok(())); let server = start_mock_server().await; - let req = mount_sse_once(&server, sse_completed("resp-1")).await; + let req = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; let TestCodex { codex, .. } = test_codex().build(&server).await?; @@ -542,8 +575,16 @@ async fn per_turn_overrides_keep_cached_prefix_and_key_constant() -> anyhow::Res use pretty_assertions::assert_eq; let server = start_mock_server().await; - let req1 = mount_sse_once(&server, sse_completed("resp-1")).await; - let req2 = mount_sse_once(&server, sse_completed("resp-2")).await; + let req1 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; + let req2 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ) + .await; let TestCodex { codex, .. } = test_codex() .with_config(|config| { @@ -646,8 +687,16 @@ async fn send_user_turn_with_no_changes_does_not_send_environment_context() -> a use pretty_assertions::assert_eq; let server = start_mock_server().await; - let req1 = mount_sse_once(&server, sse_completed("resp-1")).await; - let req2 = mount_sse_once(&server, sse_completed("resp-2")).await; + let req1 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; + let req2 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ) + .await; let TestCodex { codex, @@ -747,8 +796,16 @@ async fn send_user_turn_with_changes_sends_environment_context() -> anyhow::Resu let server = start_mock_server().await; - let req1 = mount_sse_once(&server, sse_completed("resp-1")).await; - let req2 = mount_sse_once(&server, sse_completed("resp-2")).await; + let req1 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + ) + .await; + let req2 = mount_sse_once( + &server, + sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ) + .await; let TestCodex { codex, config, diff --git a/codex-rs/core/tests/suite/sqlite_state.rs b/codex-rs/core/tests/suite/sqlite_state.rs index ac71c14d3..07268f4fd 100644 --- a/codex-rs/core/tests/suite/sqlite_state.rs +++ b/codex-rs/core/tests/suite/sqlite_state.rs @@ -9,7 +9,6 @@ use codex_protocol::protocol::SessionMeta; use codex_protocol::protocol::SessionMetaLine; use codex_protocol::protocol::SessionSource; use codex_protocol::protocol::UserMessageEvent; -use core_test_support::load_sse_fixture_with_id; use core_test_support::responses; use core_test_support::responses::ev_completed; use core_test_support::responses::ev_function_call; @@ -24,10 +23,6 @@ use tokio::time::Duration; use tracing_subscriber::prelude::*; use uuid::Uuid; -fn sse_completed(id: &str) -> String { - load_sse_fixture_with_id("../fixtures/completed_template.json", id) -} - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn new_thread_is_recorded_in_state_db() -> Result<()> { let server = start_mock_server().await; @@ -195,7 +190,10 @@ async fn user_messages_persist_in_state_db() -> Result<()> { let server = start_mock_server().await; mount_sse_sequence( &server, - vec![sse_completed("resp-1"), sse_completed("resp-2")], + vec![ + responses::sse(vec![ev_response_created("resp-1"), ev_completed("resp-1")]), + responses::sse(vec![ev_response_created("resp-2"), ev_completed("resp-2")]), + ], ) .await; diff --git a/codex-rs/core/tests/suite/stream_error_allows_next_turn.rs b/codex-rs/core/tests/suite/stream_error_allows_next_turn.rs index ec1881623..3562ec250 100644 --- a/codex-rs/core/tests/suite/stream_error_allows_next_turn.rs +++ b/codex-rs/core/tests/suite/stream_error_allows_next_turn.rs @@ -3,7 +3,9 @@ use codex_core::WireApi; use codex_core::protocol::EventMsg; use codex_core::protocol::Op; use codex_protocol::user_input::UserInput; -use core_test_support::load_sse_fixture_with_id; +use core_test_support::responses::ev_completed; +use core_test_support::responses::ev_response_created; +use core_test_support::responses::sse; use core_test_support::skip_if_no_network; use core_test_support::test_codex::TestCodex; use core_test_support::test_codex::test_codex; @@ -15,10 +17,6 @@ use wiremock::matchers::body_string_contains; use wiremock::matchers::method; use wiremock::matchers::path; -fn sse_completed(id: &str) -> String { - load_sse_fixture_with_id("../fixtures/completed_template.json", id) -} - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn continue_after_stream_error() { skip_if_no_network!(); @@ -46,7 +44,13 @@ async fn continue_after_stream_error() { let ok = ResponseTemplate::new(200) .insert_header("content-type", "text/event-stream") - .set_body_raw(sse_completed("resp_ok2"), "text/event-stream"); + .set_body_raw( + sse(vec![ + ev_response_created("resp_ok2"), + ev_completed("resp_ok2"), + ]), + "text/event-stream", + ); Mock::given(method("POST")) .and(path("/v1/responses")) diff --git a/codex-rs/core/tests/suite/stream_no_completed.rs b/codex-rs/core/tests/suite/stream_no_completed.rs index 68b7763ec..e8b130970 100644 --- a/codex-rs/core/tests/suite/stream_no_completed.rs +++ b/codex-rs/core/tests/suite/stream_no_completed.rs @@ -7,7 +7,9 @@ use codex_core::protocol::EventMsg; use codex_core::protocol::Op; use codex_protocol::user_input::UserInput; use core_test_support::load_sse_fixture; -use core_test_support::load_sse_fixture_with_id; +use core_test_support::responses::ev_completed; +use core_test_support::responses::ev_response_created; +use core_test_support::responses::sse; use core_test_support::skip_if_no_network; use core_test_support::test_codex::TestCodex; use core_test_support::test_codex::test_codex; @@ -24,10 +26,6 @@ fn sse_incomplete() -> String { load_sse_fixture("tests/fixtures/incomplete_sse.json") } -fn sse_completed(id: &str) -> String { - load_sse_fixture_with_id("../fixtures/completed_template.json", id) -} - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn retries_on_early_close() { skip_if_no_network!(); @@ -48,7 +46,13 @@ async fn retries_on_early_close() { } else { ResponseTemplate::new(200) .insert_header("content-type", "text/event-stream") - .set_body_raw(sse_completed("resp_ok"), "text/event-stream") + .set_body_raw( + sse(vec![ + ev_response_created("resp_ok"), + ev_completed("resp_ok"), + ]), + "text/event-stream", + ) } } } diff --git a/codex-rs/core/tests/suite/web_search.rs b/codex-rs/core/tests/suite/web_search.rs index 9397e88ed..8b1cc2a4e 100644 --- a/codex-rs/core/tests/suite/web_search.rs +++ b/codex-rs/core/tests/suite/web_search.rs @@ -5,7 +5,6 @@ use codex_core::built_in_model_providers; use codex_core::features::Feature; use codex_core::protocol::SandboxPolicy; use codex_protocol::config_types::WebSearchMode; -use core_test_support::load_sse_fixture_with_id; use core_test_support::responses; use core_test_support::responses::start_mock_server; use core_test_support::skip_if_no_network; @@ -13,10 +12,6 @@ use core_test_support::test_codex::test_codex; use pretty_assertions::assert_eq; use serde_json::Value; -fn sse_completed(id: &str) -> String { - load_sse_fixture_with_id("../fixtures/completed_template.json", id) -} - #[allow(clippy::expect_used)] fn find_web_search_tool(body: &Value) -> &Value { body["tools"] @@ -41,7 +36,10 @@ async fn web_search_mode_cached_sets_external_web_access_false() { skip_if_no_network!(); let server = start_mock_server().await; - let sse = sse_completed("resp-1"); + let sse = responses::sse(vec![ + responses::ev_response_created("resp-1"), + responses::ev_completed("resp-1"), + ]); let resp_mock = responses::mount_sse_once(&server, sse).await; let mut builder = test_codex() @@ -72,7 +70,10 @@ async fn web_search_mode_takes_precedence_over_legacy_flags() { skip_if_no_network!(); let server = start_mock_server().await; - let sse = sse_completed("resp-1"); + let sse = responses::sse(vec![ + responses::ev_response_created("resp-1"), + responses::ev_completed("resp-1"), + ]); let resp_mock = responses::mount_sse_once(&server, sse).await; let mut builder = test_codex() @@ -104,7 +105,10 @@ async fn web_search_mode_defaults_to_cached_when_unset() { skip_if_no_network!(); let server = start_mock_server().await; - let sse = sse_completed("resp-1"); + let sse = responses::sse(vec![ + responses::ev_response_created("resp-1"), + responses::ev_completed("resp-1"), + ]); let resp_mock = responses::mount_sse_once(&server, sse).await; let mut builder = test_codex() @@ -139,7 +143,16 @@ async fn web_search_mode_updates_between_turns_with_sandbox_policy() { let server = start_mock_server().await; let resp_mock = responses::mount_sse_sequence( &server, - vec![sse_completed("resp-1"), sse_completed("resp-2")], + vec![ + responses::sse(vec![ + responses::ev_response_created("resp-1"), + responses::ev_completed("resp-1"), + ]), + responses::sse(vec![ + responses::ev_response_created("resp-2"), + responses::ev_completed("resp-2"), + ]), + ], ) .await; @@ -191,7 +204,10 @@ async fn web_search_mode_defaults_to_disabled_for_azure_responses() { skip_if_no_network!(); let server = start_mock_server().await; - let sse = sse_completed("resp-1"); + let sse = responses::sse(vec![ + responses::ev_response_created("resp-1"), + responses::ev_completed("resp-1"), + ]); let resp_mock = responses::mount_sse_once(&server, sse).await; let mut builder = test_codex()