From d77d23da2ef93949fa34dfa59561577ad8f48c00 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Tue, 28 Apr 2026 17:09:12 -0700 Subject: [PATCH] core tests: migrate model/personality turns to profiles (#20018) ## Summary - Migrates `model_switching.rs` and `personality.rs` direct `Op::UserTurn` construction from legacy `SandboxPolicy` literals to `PermissionProfile`-backed turn fields. - Adds small local helpers in each file so tests keep asserting model/personality behavior without repeating permission plumbing. - Reduces `rg -l '\bSandboxPolicy\b' codex-rs/core/tests` from 20 files to 18; `codex-rs/tui` remains at zero `SandboxPolicy` references. ## Testing - `cargo check -p codex-core --tests` - `just fmt` --- codex-rs/core/tests/suite/model_switching.rs | 319 +++++----------- codex-rs/core/tests/suite/personality.rs | 370 ++++++------------- 2 files changed, 216 insertions(+), 473 deletions(-) diff --git a/codex-rs/core/tests/suite/model_switching.rs b/codex-rs/core/tests/suite/model_switching.rs index b3e921563..43ec50746 100644 --- a/codex-rs/core/tests/suite/model_switching.rs +++ b/codex-rs/core/tests/suite/model_switching.rs @@ -5,6 +5,7 @@ use codex_login::CodexAuth; use codex_models_manager::manager::RefreshStrategy; use codex_protocol::config_types::ReasoningSummary; use codex_protocol::config_types::ServiceTier; +use codex_protocol::models::PermissionProfile; use codex_protocol::openai_models::ConfigShellToolType; use codex_protocol::openai_models::InputModality; use codex_protocol::openai_models::ModelInfo; @@ -17,7 +18,6 @@ use codex_protocol::openai_models::default_input_modalities; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::Op; -use codex_protocol::protocol::SandboxPolicy; use codex_protocol::user_input::UserInput; use core_test_support::responses::ev_completed_with_tokens; use core_test_support::responses::ev_image_generation_call; @@ -29,13 +29,36 @@ use core_test_support::responses::sse; use core_test_support::responses::sse_completed; use core_test_support::responses::start_mock_server; use core_test_support::skip_if_no_network; +use core_test_support::test_codex::TestCodex; use core_test_support::test_codex::test_codex; +use core_test_support::test_codex::turn_permission_fields; use core_test_support::wait_for_event; use pretty_assertions::assert_eq; use std::path::Path; use std::path::PathBuf; use wiremock::MockServer; +fn read_only_user_turn(test: &TestCodex, items: Vec, model: String) -> Op { + let (sandbox_policy, permission_profile) = + turn_permission_fields(PermissionProfile::read_only(), test.cwd_path()); + Op::UserTurn { + environments: None, + items, + final_output_json_schema: None, + cwd: test.cwd_path().to_path_buf(), + approval_policy: AskForApproval::Never, + approvals_reviewer: None, + sandbox_policy, + permission_profile, + model, + effort: test.config.model_reasoning_effort, + summary: None, + service_tier: None, + collaboration_mode: None, + personality: None, + } +} + fn image_generation_artifact_path(codex_home: &Path, session_id: &str, call_id: &str) -> PathBuf { fn sanitize(value: &str) -> String { let mut sanitized: String = value @@ -120,25 +143,14 @@ async fn model_change_appends_model_instructions_developer_message() -> Result<( let next_model = "gpt-5.4"; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { + .submit(read_only_user_turn( + &test, + vec![UserInput::Text { text: "hello".into(), text_elements: Vec::new(), }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: test.session_configured.model.clone(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + test.session_configured.model.clone(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -160,25 +172,14 @@ async fn model_change_appends_model_instructions_developer_message() -> Result<( .await?; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { + .submit(read_only_user_turn( + &test, + vec![UserInput::Text { text: "switch models".into(), text_elements: Vec::new(), }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: next_model.to_string(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + next_model.to_string(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -222,25 +223,14 @@ async fn model_and_personality_change_only_appends_model_instructions() -> Resul let next_model = "exp-codex-personality"; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { + .submit(read_only_user_turn( + &test, + vec![UserInput::Text { text: "hello".into(), text_elements: Vec::new(), }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: test.session_configured.model.clone(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + test.session_configured.model.clone(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -262,25 +252,14 @@ async fn model_and_personality_change_only_appends_model_instructions() -> Resul .await?; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { + .submit(read_only_user_turn( + &test, + vec![UserInput::Text { text: "switch model and personality".into(), text_elements: Vec::new(), }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: next_model.to_string(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + next_model.to_string(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -401,9 +380,9 @@ async fn model_change_from_image_to_text_strips_prior_image_content() -> Result< .to_string(); test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![ + .submit(read_only_user_turn( + &test, + vec![ UserInput::Image { image_url: image_url.clone(), }, @@ -412,42 +391,20 @@ async fn model_change_from_image_to_text_strips_prior_image_content() -> Result< text_elements: Vec::new(), }, ], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: image_model_slug.to_string(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + image_model_slug.to_string(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { + .submit(read_only_user_turn( + &test, + vec![UserInput::Text { text: "second turn".to_string(), text_elements: Vec::new(), }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: text_model_slug.to_string(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + text_model_slug.to_string(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -539,48 +496,26 @@ async fn generated_image_is_replayed_for_image_capable_models() -> Result<()> { .await; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { + .submit(read_only_user_turn( + &test, + vec![UserInput::Text { text: "generate a lobster".to_string(), text_elements: Vec::new(), }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: image_model_slug.to_string(), - effort: test.config.model_reasoning_effort, - service_tier: None, - summary: None, - collaboration_mode: None, - personality: None, - }) + image_model_slug.to_string(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { + .submit(read_only_user_turn( + &test, + vec![UserInput::Text { text: "describe the generated image".to_string(), text_elements: Vec::new(), }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: image_model_slug.to_string(), - effort: test.config.model_reasoning_effort, - service_tier: None, - summary: None, - collaboration_mode: None, - personality: None, - }) + image_model_slug.to_string(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -675,48 +610,26 @@ async fn model_change_from_generated_image_to_text_preserves_prior_generated_ima .await; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { + .submit(read_only_user_turn( + &test, + vec![UserInput::Text { text: "generate a lobster".to_string(), text_elements: Vec::new(), }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: image_model_slug.to_string(), - effort: test.config.model_reasoning_effort, - service_tier: None, - summary: None, - collaboration_mode: None, - personality: None, - }) + image_model_slug.to_string(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { + .submit(read_only_user_turn( + &test, + vec![UserInput::Text { text: "describe the generated image".to_string(), text_elements: Vec::new(), }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: text_model_slug.to_string(), - effort: test.config.model_reasoning_effort, - service_tier: None, - summary: None, - collaboration_mode: None, - personality: None, - }) + text_model_slug.to_string(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -813,25 +726,14 @@ async fn thread_rollback_after_generated_image_drops_entire_image_turn_history() .await; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { + .submit(read_only_user_turn( + &test, + vec![UserInput::Text { text: "generate a lobster".to_string(), text_elements: Vec::new(), }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: image_model_slug.to_string(), - effort: test.config.model_reasoning_effort, - service_tier: None, - summary: None, - collaboration_mode: None, - personality: None, - }) + image_model_slug.to_string(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -844,25 +746,14 @@ async fn thread_rollback_after_generated_image_drops_entire_image_turn_history() .await; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { + .submit(read_only_user_turn( + &test, + vec![UserInput::Text { text: "after rollback".to_string(), text_elements: Vec::new(), }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: image_model_slug.to_string(), - effort: test.config.model_reasoning_effort, - service_tier: None, - summary: None, - collaboration_mode: None, - personality: None, - }) + image_model_slug.to_string(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -1003,25 +894,14 @@ async fn model_switch_to_smaller_model_updates_token_context_window() -> Result< ); test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { + .submit(read_only_user_turn( + &test, + vec![UserInput::Text { text: "use larger model".into(), text_elements: Vec::new(), }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: large_model_slug.to_string(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + large_model_slug.to_string(), + )) .await?; let large_window_event = wait_for_event(&test.codex, |event| { @@ -1065,25 +945,14 @@ async fn model_switch_to_smaller_model_updates_token_context_window() -> Result< .await?; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { + .submit(read_only_user_turn( + &test, + vec![UserInput::Text { text: "switch to smaller model".into(), text_elements: Vec::new(), }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: smaller_model_slug.to_string(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + smaller_model_slug.to_string(), + )) .await?; let smaller_turn_started_event = wait_for_event(&test.codex, |event| { diff --git a/codex-rs/core/tests/suite/personality.rs b/codex-rs/core/tests/suite/personality.rs index a53242c0d..dde6d2ca5 100644 --- a/codex-rs/core/tests/suite/personality.rs +++ b/codex-rs/core/tests/suite/personality.rs @@ -3,6 +3,7 @@ use codex_features::Feature; use codex_models_manager::manager::RefreshStrategy; use codex_models_manager::manager::SharedModelsManager; use codex_protocol::config_types::ReasoningSummary; +use codex_protocol::models::PermissionProfile; use codex_protocol::openai_models::ConfigShellToolType; use codex_protocol::openai_models::ModelInfo; use codex_protocol::openai_models::ModelInstructionsVariables; @@ -16,7 +17,6 @@ use codex_protocol::openai_models::default_input_modalities; use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::Op; -use codex_protocol::protocol::SandboxPolicy; use codex_protocol::user_input::UserInput; use core_test_support::load_default_config_for_test; use core_test_support::responses::mount_models_once; @@ -25,7 +25,9 @@ use core_test_support::responses::mount_sse_sequence; use core_test_support::responses::sse_completed; use core_test_support::responses::start_mock_server; use core_test_support::skip_if_no_network; +use core_test_support::test_codex::TestCodex; use core_test_support::test_codex::test_codex; +use core_test_support::test_codex::turn_permission_fields; use core_test_support::wait_for_event; use pretty_assertions::assert_eq; use tempfile::TempDir; @@ -39,6 +41,46 @@ 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 read_only_text_turn( + test: &TestCodex, + text: &str, + model: String, + approval_policy: AskForApproval, +) -> Op { + let personality = None; + read_only_text_turn_with_personality(test, text, model, approval_policy, personality) +} + +fn read_only_text_turn_with_personality( + test: &TestCodex, + text: &str, + model: String, + approval_policy: AskForApproval, + personality: Option, +) -> Op { + let (sandbox_policy, permission_profile) = + turn_permission_fields(PermissionProfile::read_only(), test.cwd_path()); + Op::UserTurn { + environments: None, + items: vec![UserInput::Text { + text: text.into(), + text_elements: Vec::new(), + }], + final_output_json_schema: None, + cwd: test.cwd_path().to_path_buf(), + approval_policy, + approvals_reviewer: None, + sandbox_policy, + permission_profile, + model, + effort: test.config.model_reasoning_effort, + summary: None, + service_tier: None, + collaboration_mode: None, + personality, + } +} + #[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"); @@ -94,25 +136,12 @@ async fn user_turn_personality_none_does_not_add_update_message() -> anyhow::Res let test = builder.build(&server).await?; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { - text: "hello".into(), - text_elements: Vec::new(), - }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: test.config.permissions.approval_policy.value(), - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: test.session_configured.model.clone(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + .submit(read_only_text_turn( + &test, + "hello", + test.session_configured.model.clone(), + test.config.permissions.approval_policy.value(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -147,25 +176,12 @@ async fn config_personality_some_sets_instructions_template() -> anyhow::Result< let test = builder.build(&server).await?; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { - text: "hello".into(), - text_elements: Vec::new(), - }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: test.config.permissions.approval_policy.value(), - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: test.session_configured.model.clone(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + .submit(read_only_text_turn( + &test, + "hello", + test.session_configured.model.clone(), + test.config.permissions.approval_policy.value(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -207,25 +223,12 @@ async fn config_personality_none_sends_no_personality() -> anyhow::Result<()> { let test = builder.build(&server).await?; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { - text: "hello".into(), - text_elements: Vec::new(), - }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: test.config.permissions.approval_policy.value(), - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: test.session_configured.model.clone(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + .submit(read_only_text_turn( + &test, + "hello", + test.session_configured.model.clone(), + test.config.permissions.approval_policy.value(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -273,25 +276,12 @@ async fn default_personality_is_pragmatic_without_config_toml() -> anyhow::Resul let test = builder.build(&server).await?; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { - text: "hello".into(), - text_elements: Vec::new(), - }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: test.config.permissions.approval_policy.value(), - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: test.session_configured.model.clone(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + .submit(read_only_text_turn( + &test, + "hello", + test.session_configured.model.clone(), + test.config.permissions.approval_policy.value(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -327,25 +317,12 @@ async fn user_turn_personality_some_adds_update_message() -> anyhow::Result<()> let test = builder.build(&server).await?; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { - text: "hello".into(), - text_elements: Vec::new(), - }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: test.config.permissions.approval_policy.value(), - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: test.session_configured.model.clone(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + .submit(read_only_text_turn( + &test, + "hello", + test.session_configured.model.clone(), + test.config.permissions.approval_policy.value(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -368,25 +345,12 @@ async fn user_turn_personality_some_adds_update_message() -> anyhow::Result<()> .await?; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { - text: "hello".into(), - text_elements: Vec::new(), - }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: test.config.permissions.approval_policy.value(), - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: test.session_configured.model.clone(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + .submit(read_only_text_turn( + &test, + "hello", + test.session_configured.model.clone(), + test.config.permissions.approval_policy.value(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -437,25 +401,12 @@ async fn user_turn_personality_same_value_does_not_add_update_message() -> anyho let test = builder.build(&server).await?; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { - text: "hello".into(), - text_elements: Vec::new(), - }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: test.config.permissions.approval_policy.value(), - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: test.session_configured.model.clone(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + .submit(read_only_text_turn( + &test, + "hello", + test.session_configured.model.clone(), + test.config.permissions.approval_policy.value(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -478,25 +429,12 @@ async fn user_turn_personality_same_value_does_not_add_update_message() -> anyho .await?; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { - text: "hello".into(), - text_elements: Vec::new(), - }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: test.config.permissions.approval_policy.value(), - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: test.session_configured.model.clone(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + .submit(read_only_text_turn( + &test, + "hello", + test.session_configured.model.clone(), + test.config.permissions.approval_policy.value(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -560,25 +498,12 @@ async fn user_turn_personality_skips_if_feature_disabled() -> anyhow::Result<()> let test = builder.build(&server).await?; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { - text: "hello".into(), - text_elements: Vec::new(), - }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: test.config.permissions.approval_policy.value(), - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: test.session_configured.model.clone(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + .submit(read_only_text_turn( + &test, + "hello", + test.session_configured.model.clone(), + test.config.permissions.approval_policy.value(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -601,25 +526,12 @@ async fn user_turn_personality_skips_if_feature_disabled() -> anyhow::Result<()> .await?; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { - text: "hello".into(), - text_elements: Vec::new(), - }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: test.config.permissions.approval_policy.value(), - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: test.session_configured.model.clone(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + .submit(read_only_text_turn( + &test, + "hello", + test.session_configured.model.clone(), + test.config.permissions.approval_policy.value(), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -722,25 +634,13 @@ async fn remote_model_friendly_personality_instructions_with_feature() -> anyhow wait_for_model_available(&test.thread_manager.get_models_manager(), remote_slug).await; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { - text: "hello".into(), - text_elements: Vec::new(), - }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: remote_slug.to_string(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: Some(Personality::Friendly), - }) + .submit(read_only_text_turn_with_personality( + &test, + "hello", + remote_slug.to_string(), + AskForApproval::Never, + Some(Personality::Friendly), + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -845,25 +745,12 @@ async fn user_turn_personality_remote_model_template_includes_update_message() - wait_for_model_available(&test.thread_manager.get_models_manager(), remote_slug).await; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { - text: "hello".into(), - text_elements: Vec::new(), - }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: remote_slug.to_string(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + .submit(read_only_text_turn( + &test, + "hello", + remote_slug.to_string(), + AskForApproval::Never, + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await; @@ -886,25 +773,12 @@ async fn user_turn_personality_remote_model_template_includes_update_message() - .await?; test.codex - .submit(Op::UserTurn { - environments: None, - items: vec![UserInput::Text { - text: "hello".into(), - text_elements: Vec::new(), - }], - final_output_json_schema: None, - cwd: test.cwd_path().to_path_buf(), - approval_policy: AskForApproval::Never, - approvals_reviewer: None, - sandbox_policy: SandboxPolicy::new_read_only_policy(), - permission_profile: None, - model: remote_slug.to_string(), - effort: test.config.model_reasoning_effort, - summary: None, - service_tier: None, - collaboration_mode: None, - personality: None, - }) + .submit(read_only_text_turn( + &test, + "hello", + remote_slug.to_string(), + AskForApproval::Never, + )) .await?; wait_for_event(&test.codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;