diff --git a/codex-rs/core/tests/common/test_codex.rs b/codex-rs/core/tests/common/test_codex.rs index e7db3f404..fd53e828a 100644 --- a/codex-rs/core/tests/common/test_codex.rs +++ b/codex-rs/core/tests/common/test_codex.rs @@ -296,11 +296,14 @@ impl TestCodexBuilder { }; let base_url = format!("{}/v1", server.uri()); let test_env = TestEnv::local().await?; - Box::pin(self.build_with_home_and_base_url(base_url, home, /*resume_from*/ None, test_env)) - .await + Box::pin(self.build_with_home_and_base_url( + base_url, home, /*resume_from*/ None, test_env, + /*include_local_environment*/ false, + )) + .await } - pub async fn build_remote_aware( + pub async fn build_with_remote_env( &mut self, server: &wiremock::MockServer, ) -> anyhow::Result { @@ -310,8 +313,28 @@ impl TestCodexBuilder { }; let base_url = format!("{}/v1", server.uri()); let test_env = test_env().await?; - Box::pin(self.build_with_home_and_base_url(base_url, home, /*resume_from*/ None, test_env)) - .await + Box::pin(self.build_with_home_and_base_url( + base_url, home, /*resume_from*/ None, test_env, + /*include_local_environment*/ false, + )) + .await + } + + pub async fn build_with_remote_and_local_env( + &mut self, + server: &wiremock::MockServer, + ) -> anyhow::Result { + let home = match self.home.clone() { + Some(home) => home, + None => Arc::new(TempDir::new()?), + }; + let base_url = format!("{}/v1", server.uri()); + let test_env = test_env().await?; + Box::pin(self.build_with_home_and_base_url( + base_url, home, /*resume_from*/ None, test_env, + /*include_local_environment*/ true, + )) + .await } pub async fn build_with_streaming_server( @@ -329,6 +352,7 @@ impl TestCodexBuilder { home, /*resume_from*/ None, test_env, + /*include_local_environment*/ false, )) .await } @@ -350,8 +374,11 @@ impl TestCodexBuilder { config.realtime.version = RealtimeWsVersion::V1; })); let test_env = TestEnv::local().await?; - Box::pin(self.build_with_home_and_base_url(base_url, home, /*resume_from*/ None, test_env)) - .await + Box::pin(self.build_with_home_and_base_url( + base_url, home, /*resume_from*/ None, test_env, + /*include_local_environment*/ false, + )) + .await } pub async fn resume( @@ -362,8 +389,14 @@ impl TestCodexBuilder { ) -> anyhow::Result { let base_url = format!("{}/v1", server.uri()); let test_env = TestEnv::local().await?; - Box::pin(self.build_with_home_and_base_url(base_url, home, Some(rollout_path), test_env)) - .await + Box::pin(self.build_with_home_and_base_url( + base_url, + home, + Some(rollout_path), + test_env, + /*include_local_environment*/ false, + )) + .await } async fn build_with_home_and_base_url( @@ -372,6 +405,7 @@ impl TestCodexBuilder { home: Arc, resume_from: Option, test_env: TestEnv, + include_local_environment: bool, ) -> anyhow::Result { let (config, fallback_cwd) = self .prepare_config(base_url, &home, test_env.cwd().clone()) @@ -391,13 +425,19 @@ impl TestCodexBuilder { std::env::current_exe()?, codex_linux_sandbox_exe, )?; - let environment_manager = Arc::new( + let environment_manager = Arc::new(if include_local_environment { + codex_exec_server::EnvironmentManager::create_for_tests_with_local( + exec_server_url, + local_runtime_paths, + ) + .await + } else { codex_exec_server::EnvironmentManager::create_for_tests( exec_server_url, local_runtime_paths, ) - .await, - ); + .await + }); let file_system = test_env.environment().get_filesystem(); let mut workspace_setups = vec![]; swap(&mut self.workspace_setups, &mut workspace_setups); @@ -788,9 +828,9 @@ impl TestCodexHarness { Ok(Self { server, test }) } - pub async fn with_remote_aware_builder(mut builder: TestCodexBuilder) -> Result { + pub async fn with_remote_env_builder(mut builder: TestCodexBuilder) -> Result { let server = start_mock_server().await; - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; Ok(Self { server, test }) } diff --git a/codex-rs/core/tests/suite/agents_md.rs b/codex-rs/core/tests/suite/agents_md.rs index 724b85239..276fa4bb5 100644 --- a/codex-rs/core/tests/suite/agents_md.rs +++ b/codex-rs/core/tests/suite/agents_md.rs @@ -16,7 +16,7 @@ async fn agents_instructions(mut builder: TestCodexBuilder) -> Result { ) .await; - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; test.submit_turn("hello").await?; let request = resp_mock.single_request(); diff --git a/codex-rs/core/tests/suite/apply_patch_cli.rs b/codex-rs/core/tests/suite/apply_patch_cli.rs index e42057215..b692d3256 100644 --- a/codex-rs/core/tests/suite/apply_patch_cli.rs +++ b/codex-rs/core/tests/suite/apply_patch_cli.rs @@ -64,7 +64,7 @@ async fn apply_patch_harness_with( }); // Box harness construction so apply_patch_cli tests do not inline the // full test-thread startup path into each test future. - Box::pin(TestCodexHarness::with_remote_aware_builder(builder)).await + Box::pin(TestCodexHarness::with_remote_env_builder(builder)).await } async fn submit_without_wait(harness: &TestCodexHarness, prompt: &str) -> Result<()> { diff --git a/codex-rs/core/tests/suite/hierarchical_agents.rs b/codex-rs/core/tests/suite/hierarchical_agents.rs index 212303ed0..751807623 100644 --- a/codex-rs/core/tests/suite/hierarchical_agents.rs +++ b/codex-rs/core/tests/suite/hierarchical_agents.rs @@ -32,7 +32,7 @@ async fn hierarchical_agents_appends_to_project_doc_in_user_instructions() { Ok::<(), anyhow::Error>(()) }); let test = builder - .build_remote_aware(&server) + .build_with_remote_env(&server) .await .expect("build test codex"); @@ -76,7 +76,7 @@ async fn hierarchical_agents_emits_when_no_project_doc() { .expect("test config should allow feature update"); }); let test = builder - .build_remote_aware(&server) + .build_with_remote_env(&server) .await .expect("build test codex"); diff --git a/codex-rs/core/tests/suite/remote_env.rs b/codex-rs/core/tests/suite/remote_env.rs index dc6d5cefc..9c3414bae 100644 --- a/codex-rs/core/tests/suite/remote_env.rs +++ b/codex-rs/core/tests/suite/remote_env.rs @@ -58,7 +58,7 @@ async fn unified_exec_test(server: &wiremock::MockServer) -> Result { "unified exec should enable for test: {result:?}", ); }); - builder.build_remote_aware(server).await + builder.build_with_remote_and_local_env(server).await } async fn submit_turn_with_approval_and_environments( @@ -77,7 +77,7 @@ async fn submit_turn_with_approval_and_environments( cwd: test.cwd.path().to_path_buf(), approval_policy: AskForApproval::OnRequest, approvals_reviewer: Some(ApprovalsReviewer::User), - sandbox_policy: SandboxPolicy::new_workspace_write_policy(), + sandbox_policy: SandboxPolicy::new_read_only_policy(), permission_profile: None, model: test.session_configured.model.clone(), effort: None, @@ -350,7 +350,7 @@ async fn apply_patch_freeform_routes_to_selected_remote_environment() -> Result< let mut builder = test_codex().with_config(|config| { config.include_apply_patch_tool = true; }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_and_local_env(&server).await?; let local_cwd = TempDir::new()?; let file_name = "apply_patch_remote_freeform.txt"; let remote_cwd = PathBuf::from(format!( @@ -439,7 +439,7 @@ async fn apply_patch_approvals_are_remembered_per_environment() -> Result<()> { config.permissions.approval_policy = Constrained::allow_any(AskForApproval::OnRequest); config.approvals_reviewer = ApprovalsReviewer::User; }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_and_local_env(&server).await?; let local_cwd = TempDir::new()?; let remote_cwd = PathBuf::from(format!( "/tmp/codex-remote-apply-patch-approval-cwd-{}", diff --git a/codex-rs/core/tests/suite/rmcp_client.rs b/codex-rs/core/tests/suite/rmcp_client.rs index d1973d97a..7ead0364d 100644 --- a/codex-rs/core/tests/suite/rmcp_client.rs +++ b/codex-rs/core/tests/suite/rmcp_client.rs @@ -480,7 +480,7 @@ async fn stdio_server_round_trip() -> anyhow::Result<()> { }, ); }) - .build_remote_aware(&server) + .build_with_remote_env(&server) .await?; fixture .codex @@ -603,7 +603,7 @@ async fn stdio_server_uses_configured_cwd_before_runtime_fallback() -> anyhow::R }, ); }) - .build_remote_aware(&server) + .build_with_remote_env(&server) .await?; let expected_cwd = expected_cwd @@ -656,7 +656,7 @@ async fn remote_stdio_server_uses_runtime_fallback_cwd_when_config_omits_cwd() - }, ); }) - .build_remote_aware(&server) + .build_with_remote_env(&server) .await?; let expected_cwd = expected_cwd @@ -775,7 +775,7 @@ async fn stdio_mcp_tool_call_includes_sandbox_state_meta() -> anyhow::Result<()> }, ); }) - .build_remote_aware(&server) + .build_with_remote_env(&server) .await?; wait_for_mcp_server(&fixture, server_name).await?; @@ -873,7 +873,7 @@ async fn stdio_mcp_parallel_tool_calls_default_false_runs_serially() -> anyhow:: }, ); }) - .build_remote_aware(&server) + .build_with_remote_env(&server) .await?; fixture .codex @@ -990,7 +990,7 @@ async fn stdio_mcp_parallel_tool_calls_opt_in_runs_concurrently() -> anyhow::Res }, ); }) - .build_remote_aware(&server) + .build_with_remote_env(&server) .await?; fixture .codex @@ -1071,7 +1071,7 @@ async fn stdio_image_responses_round_trip() -> anyhow::Result<()> { }, ); }) - .build_remote_aware(&server) + .build_with_remote_env(&server) .await?; wait_for_mcp_server(&fixture, server_name).await?; @@ -1203,7 +1203,7 @@ async fn stdio_image_responses_preserve_original_detail_metadata() -> anyhow::Re }, ); }) - .build_remote_aware(&server) + .build_with_remote_env(&server) .await?; wait_for_mcp_server(&fixture, server_name).await?; @@ -1338,7 +1338,7 @@ async fn stdio_image_responses_are_sanitized_for_text_only_model() -> anyhow::Re }, ); }) - .build_remote_aware(&server) + .build_with_remote_env(&server) .await?; fixture @@ -1440,7 +1440,7 @@ async fn stdio_server_propagates_whitelisted_env_vars() -> anyhow::Result<()> { }, ); }) - .build_remote_aware(&server) + .build_with_remote_env(&server) .await?; fixture .codex @@ -1558,7 +1558,7 @@ async fn stdio_server_propagates_explicit_local_env_var_source() -> anyhow::Resu }, ); }) - .build_remote_aware(&server) + .build_with_remote_env(&server) .await?; fixture @@ -1650,7 +1650,7 @@ async fn remote_stdio_env_var_source_does_not_copy_local_env() -> anyhow::Result }, ); }) - .build_remote_aware(&server) + .build_with_remote_env(&server) .await?; fixture @@ -1833,7 +1833,7 @@ async fn streamable_http_tool_call_round_trip() -> anyhow::Result<()> { }, ); }) - .build_remote_aware(&server) + .build_with_remote_env(&server) .await?; // Phase 4: submit the user turn that should trigger the MCP tool call. fixture @@ -2019,7 +2019,7 @@ async fn streamable_http_with_oauth_round_trip_impl() -> anyhow::Result<()> { }, ); }) - .build_remote_aware(&server) + .build_with_remote_env(&server) .await?; // Phase 5: wait for MCP startup before the turn is submitted, which keeps // failures tied to server startup/discovery. diff --git a/codex-rs/core/tests/suite/skills.rs b/codex-rs/core/tests/suite/skills.rs index 894110a6f..6434f9c53 100644 --- a/codex-rs/core/tests/suite/skills.rs +++ b/codex-rs/core/tests/suite/skills.rs @@ -50,7 +50,7 @@ async fn user_turn_includes_skill_instructions() -> Result<()> { let mut builder = test_codex().with_workspace_setup(move |cwd, fs| async move { write_repo_skill(cwd, fs, "demo", "demo skill", skill_body).await }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let skill_path = test .config diff --git a/codex-rs/core/tests/suite/unified_exec.rs b/codex-rs/core/tests/suite/unified_exec.rs index 76ed9cdcb..231d14f77 100644 --- a/codex-rs/core/tests/suite/unified_exec.rs +++ b/codex-rs/core/tests/suite/unified_exec.rs @@ -379,7 +379,7 @@ async fn unified_exec_emits_exec_command_begin_event() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let cwd = test.config.cwd.to_path_buf(); let call_id = "uexec-begin-event"; @@ -438,7 +438,7 @@ async fn unified_exec_resolves_relative_workdir() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let workdir_rel = std::path::PathBuf::from("uexec_relative_workdir"); let workdir = create_workspace_directory(&test, &workdir_rel).await?; @@ -507,7 +507,7 @@ async fn unified_exec_respects_workdir_override() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let workdir = create_workspace_directory(&test, "uexec_workdir_test").await?; @@ -572,7 +572,7 @@ async fn unified_exec_emits_exec_command_end_event() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let call_id = "uexec-end-event"; let args = json!({ @@ -645,7 +645,7 @@ async fn unified_exec_emits_output_delta_for_exec_command() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let call_id = "uexec-delta-1"; let args = json!({ @@ -703,7 +703,7 @@ async fn unified_exec_full_lifecycle_with_background_end_event() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let call_id = "uexec-full-lifecycle"; // This timing force the long-standing PTY @@ -910,7 +910,7 @@ allow_local_binding = true PermissionProfile::from_legacy_sandbox_policy(&sandbox_policy_for_config), ); }); - let test = builder.build_remote_aware(server).await?; + let test = builder.build_with_remote_env(server).await?; assert!( test.config.permissions.network.is_some(), "expected managed network proxy config to be present" @@ -991,7 +991,7 @@ async fn unified_exec_emits_terminal_interaction_for_write_stdin() -> Result<()> .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let open_call_id = "uexec-open"; let open_args = json!({ @@ -1074,7 +1074,7 @@ async fn unified_exec_terminal_interaction_captures_delayed_output() -> Result<( .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let open_call_id = "uexec-delayed-open"; let open_args = json!({ @@ -1253,7 +1253,7 @@ async fn unified_exec_emits_one_begin_and_one_end_event() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let open_call_id = "uexec-open-session"; let open_args = json!({ @@ -1367,7 +1367,7 @@ async fn exec_command_reports_chunk_and_exit_metadata() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let call_id = "uexec-metadata"; let args = serde_json::json!({ @@ -1462,7 +1462,7 @@ async fn exec_command_clamps_model_requested_max_output_tokens_to_policy() -> Re .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let call_id = "uexec-clamped-max-output"; let args = serde_json::json!({ @@ -1524,7 +1524,7 @@ async fn write_stdin_clamps_model_requested_max_output_tokens_to_policy() -> Res .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let start_call_id = "uexec-stdin-clamp-start"; let start_args = serde_json::json!({ @@ -1611,7 +1611,7 @@ async fn unified_exec_defaults_to_pipe() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let call_id = "uexec-default-pipe"; let args = serde_json::json!({ @@ -1680,7 +1680,7 @@ async fn unified_exec_can_enable_tty() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let call_id = "uexec-tty-enabled"; let args = serde_json::json!({ @@ -1746,7 +1746,7 @@ async fn unified_exec_respects_early_exit_notifications() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let call_id = "uexec-early-exit"; let args = serde_json::json!({ @@ -1829,7 +1829,7 @@ async fn write_stdin_returns_exit_metadata_and_clears_session() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let start_call_id = "uexec-cat-start"; let send_call_id = "uexec-cat-send"; @@ -1983,7 +1983,7 @@ async fn unified_exec_emits_end_event_when_session_dies_via_stdin() -> Result<() .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let start_call_id = "uexec-end-on-exit-start"; let start_args = serde_json::json!({ @@ -2266,7 +2266,7 @@ async fn unified_exec_reuses_session_via_stdin() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let first_call_id = "uexec-start"; let first_args = serde_json::json!({ @@ -2365,7 +2365,7 @@ async fn unified_exec_streams_after_lagged_output() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let script = r#"python3 - <<'PY' import sys @@ -2485,7 +2485,7 @@ async fn unified_exec_timeout_and_followup_poll() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let first_call_id = "uexec-timeout"; let first_args = serde_json::json!({ @@ -2574,7 +2574,7 @@ async fn unified_exec_formats_large_output_summary() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let script = r#"python3 - <<'PY' import sys @@ -3002,7 +3002,7 @@ async fn unified_exec_runs_on_all_platforms() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let call_id = "uexec"; let args = serde_json::json!({ @@ -3066,7 +3066,7 @@ async fn unified_exec_prunes_exited_sessions_first() -> Result<()> { .enable(Feature::UnifiedExec) .expect("test config should allow feature update"); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; const MAX_SESSIONS_FOR_TEST: i32 = 64; const FILLER_SESSIONS: i32 = MAX_SESSIONS_FOR_TEST - 1; diff --git a/codex-rs/core/tests/suite/view_image.rs b/codex-rs/core/tests/suite/view_image.rs index 4ff2062b4..5d5673b01 100644 --- a/codex-rs/core/tests/suite/view_image.rs +++ b/codex-rs/core/tests/suite/view_image.rs @@ -174,7 +174,7 @@ async fn assert_user_turn_local_image_resizes_to( let server = start_mock_server().await; let mut builder = test_codex(); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let TestCodex { codex, session_configured, @@ -266,7 +266,7 @@ async fn view_image_tool_attaches_local_image() -> anyhow::Result<()> { let server = start_mock_server().await; let mut builder = test_codex(); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let TestCodex { codex, session_configured, @@ -562,7 +562,7 @@ async fn view_image_routes_to_selected_remote_environment() -> anyhow::Result<() let server = start_mock_server().await; let mut builder = test_codex(); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_and_local_env(&server).await?; let local_cwd = TempDir::new()?; fs::write(local_cwd.path().join("remote.png"), b"not a remote image")?; let local_selection = TurnEnvironmentSelection { @@ -582,9 +582,7 @@ async fn view_image_routes_to_selected_remote_environment() -> anyhow::Result<() /*sandbox*/ None, ) .await?; - let png = BASE64_STANDARD.decode( - "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+/p9sAAAAASUVORK5CYII=", - )?; + let png = png_bytes(/*width*/ 1, /*height*/ 1, [0, 255, 0, 255])?; test.fs() .write_file(&image_path, png, /*sandbox*/ None) .await?; @@ -664,7 +662,7 @@ async fn view_image_tool_can_preserve_original_resolution_when_requested_on_gpt5 let server = start_mock_server().await; let mut builder = test_codex().with_model("gpt-5.3-codex"); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let TestCodex { codex, session_configured, @@ -755,7 +753,7 @@ async fn view_image_tool_errors_clearly_for_unsupported_detail_values() -> anyho let server = start_mock_server().await; let mut builder = test_codex().with_model("gpt-5.3-codex"); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let TestCodex { codex, session_configured, @@ -833,7 +831,7 @@ async fn view_image_tool_treats_null_detail_as_omitted() -> anyhow::Result<()> { let server = start_mock_server().await; let mut builder = test_codex().with_model("gpt-5.3-codex"); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let TestCodex { codex, session_configured, @@ -923,7 +921,7 @@ async fn view_image_tool_resizes_when_model_lacks_original_detail_support() -> a let server = start_mock_server().await; let mut builder = test_codex().with_model("gpt-5.2"); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let TestCodex { codex, session_configured, @@ -1017,7 +1015,7 @@ async fn view_image_tool_does_not_force_original_resolution_with_capability_only let server = start_mock_server().await; let mut builder = test_codex().with_model("gpt-5.3-codex"); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let TestCodex { codex, session_configured, @@ -1108,7 +1106,7 @@ async fn view_image_tool_errors_when_path_is_directory() -> anyhow::Result<()> { let server = start_mock_server().await; let mut builder = test_codex(); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let TestCodex { codex, session_configured, @@ -1178,7 +1176,7 @@ async fn view_image_tool_errors_for_non_image_files() -> anyhow::Result<()> { let server = start_mock_server().await; let mut builder = test_codex(); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let TestCodex { codex, session_configured, @@ -1255,7 +1253,7 @@ async fn view_image_tool_errors_when_file_missing() -> anyhow::Result<()> { let server = start_mock_server().await; let mut builder = test_codex(); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let TestCodex { codex, config, @@ -1385,7 +1383,7 @@ async fn view_image_tool_returns_unsupported_message_for_text_only_model() -> an .with_config(|config| { config.model = Some(model_slug.to_string()); }); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let TestCodex { codex, .. } = &test; let rel_path = "assets/example.png"; @@ -1472,7 +1470,7 @@ async fn replaces_invalid_local_image_after_bad_request() -> anyhow::Result<()> let completion_mock = responses::mount_sse_once(&server, success_response).await; let mut builder = test_codex(); - let test = builder.build_remote_aware(&server).await?; + let test = builder.build_with_remote_env(&server).await?; let TestCodex { codex, session_configured, diff --git a/codex-rs/exec-server/src/environment.rs b/codex-rs/exec-server/src/environment.rs index 7e4a3fb05..1d7d6e75f 100644 --- a/codex-rs/exec-server/src/environment.rs +++ b/codex-rs/exec-server/src/environment.rs @@ -135,6 +135,20 @@ impl EnvironmentManager { } } + /// Builds a test-only manager that keeps the provider default while also + /// allowing tests to select the local environment explicitly. + pub async fn create_for_tests_with_local( + exec_server_url: Option, + local_runtime_paths: ExecServerRuntimePaths, + ) -> Self { + let mut snapshot = DefaultEnvironmentProvider::new(exec_server_url).snapshot_inner(); + snapshot.include_local = true; + match Self::from_provider_snapshot(snapshot, local_runtime_paths) { + Ok(manager) => manager, + Err(err) => panic!("test provider with local should create valid environments: {err}"), + } + } + /// Builds a manager from a provider-supplied startup snapshot. pub async fn from_provider

( provider: &P,