Fix multi-environment process tool cleanup

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
starr-openai
2026-05-01 04:34:03 +00:00
co-authored by Codex
parent 54ff703447
commit 2e98a764ec
8 changed files with 40 additions and 21 deletions
@@ -2024,11 +2024,11 @@ async fn turn_start_model_surface_gates_multi_environment_process_tools() -> Res
assert!(body_contains(multi_request, "<environments>"));
assert!(body_contains(
multi_request,
r#"<environment id=\"local\" primary=\"true\">"#
r#"<environment id=\"local\" default=\"true\">"#
));
assert!(body_contains(
multi_request,
r#"<environment id=\"remote\" primary=\"false\">"#
r#"<environment id=\"remote\" default=\"false\">"#
));
assert!(body_contains(multi_request, "environment_id"));
@@ -21,7 +21,7 @@ pub(crate) struct EnvironmentContext {
pub(crate) struct EnvironmentContextEnvironment {
pub(crate) id: String,
pub(crate) cwd: PathBuf,
pub(crate) primary: bool,
pub(crate) default: bool,
}
impl EnvironmentContextEnvironment {
@@ -34,7 +34,7 @@ impl EnvironmentContextEnvironment {
.map(|(index, environment)| Self {
id: environment.environment_id.clone(),
cwd: environment.cwd.to_path_buf(),
primary: index == 0,
default: index == 0,
})
.collect()
}
@@ -48,7 +48,7 @@ impl EnvironmentContextEnvironment {
.map(|(index, environment)| Self {
id: environment.environment_id.clone(),
cwd: environment.cwd.to_path_buf(),
primary: index == 0,
default: index == 0,
})
.collect()
}
@@ -146,10 +146,17 @@ impl EnvironmentContext {
}
pub(crate) fn from_turn_context(turn_context: &TurnContext, shell: &Shell) -> Self {
let environments =
EnvironmentContextEnvironment::from_turn_environments(&turn_context.environments);
let environments = if environments.len() > 1 {
environments
} else {
Vec::new()
};
Self::new(
Some(turn_context.cwd.to_path_buf()),
shell.name().to_string(),
EnvironmentContextEnvironment::from_turn_environments(&turn_context.environments),
environments,
turn_context.current_date.clone(),
turn_context.timezone.clone(),
Self::network_from_turn_context(turn_context),
@@ -239,8 +246,8 @@ impl ContextualUserFragment for EnvironmentContext {
lines.push(" <environments>".to_string());
for environment in &self.environments {
lines.push(format!(
" <environment id=\"{}\" primary=\"{}\">",
environment.id, environment.primary
" <environment id=\"{}\" default=\"{}\">",
environment.id, environment.default
));
lines.push(format!(
" <cwd>{}</cwd>",
@@ -210,22 +210,22 @@ fn serialize_environment_context_with_multiple_selected_environments() {
EnvironmentContextEnvironment {
id: "local".to_string(),
cwd: test_path_buf("/primary"),
primary: true,
default: true,
},
EnvironmentContextEnvironment {
id: "remote".to_string(),
cwd: test_path_buf("/remote/repo"),
primary: false,
default: false,
},
];
let expected = format!(
r#"<environment_context>
<environments>
<environment id="local" primary="true">
<environment id="local" default="true">
<cwd>{}</cwd>
</environment>
<environment id="remote" primary="false">
<environment id="remote" default="false">
<cwd>{}</cwd>
</environment>
</environments>
@@ -174,4 +174,15 @@ mod tests {
"local"
);
}
#[tokio::test]
async fn resolved_environment_selections_use_fallback_without_selections() {
let cwd = AbsolutePathBuf::current_dir().expect("cwd");
let manager = EnvironmentManager::default_for_tests();
let resolved =
resolve_environment_selections(&manager, &[]).expect("empty selections are valid");
assert_eq!(resolved.primary_cwd_or_fallback(&cwd), cwd);
}
}
@@ -105,10 +105,6 @@ impl TurnContext {
self.permission_profile.network_sandbox_policy()
}
pub(crate) fn primary_environment(&self) -> Option<&TurnEnvironment> {
self.environments.first()
}
pub(crate) fn sandbox_policy(&self) -> SandboxPolicy {
let file_system_sandbox_policy = self.file_system_sandbox_policy();
let network_sandbox_policy = self.network_sandbox_policy();
+3 -4
View File
@@ -109,11 +109,10 @@ pub(crate) fn resolve_process_tool_environment(
) -> Result<Option<ProcessToolEnvironment>, FunctionCallError> {
if environment_id.is_none() && !turn.has_multiple_selected_environments() {
return Ok(turn
.environment
.as_ref()
.primary_environment()
.map(|environment| ProcessToolEnvironment {
environment: Arc::clone(environment),
cwd: turn.cwd.clone(),
environment: Arc::clone(&environment.environment),
cwd: environment.cwd.clone(),
}));
}
@@ -176,7 +176,12 @@ async fn failed_initial_end_for_unstored_process_uses_fallback_output() {
yield_time_ms: 1000,
max_output_tokens: None,
workdir: None,
environment: turn.environment.as_ref().expect("turn environment").clone(),
environment: Arc::clone(
&turn
.primary_environment()
.expect("turn environment")
.environment,
),
network: None,
tty: true,
sandbox_permissions: crate::sandboxing::SandboxPermissions::UseDefault,
+1
View File
@@ -44,6 +44,7 @@ use codex_protocol::protocol::McpToolCallBeginEvent;
use codex_protocol::protocol::Op;
use codex_protocol::user_input::UserInput;
use codex_utils_cargo_bin::cargo_bin;
use core_test_support::PathBufExt;
use core_test_support::assert_regex_match;
use core_test_support::remote_env_env_var;
use core_test_support::responses;