Use selected turn environments for runtime context (#20281)

## Summary
- make selected turn environments the source of truth for session
runtime cwd and MCP runtime environment selection
- keep local/no-selection fallback behavior intact
- add coverage for duplicate selected environments, cwd resolution, and
MCP runtime environment selection

## Validation
- git diff --check
- rustfmt was run on touched Rust files during the implementation
workflow

CI should provide the full Bazel/test signal.

---------

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
starr-openai
2026-05-01 11:00:14 -07:00
committed by GitHub
co-authored by Codex
parent e4d6675632
commit be71b6fcd1
18 changed files with 456 additions and 242 deletions
@@ -225,6 +225,7 @@ use codex_app_server_protocol::ThreadUnsubscribeParams;
use codex_app_server_protocol::ThreadUnsubscribeResponse;
use codex_app_server_protocol::ThreadUnsubscribeStatus;
use codex_app_server_protocol::Turn;
use codex_app_server_protocol::TurnEnvironmentParams;
use codex_app_server_protocol::TurnError;
use codex_app_server_protocol::TurnInterruptParams;
use codex_app_server_protocol::TurnInterruptResponse;
@@ -2527,28 +2528,13 @@ impl CodexMessageProcessor {
.await;
return;
}
let environments = environments.map(|environments| {
environments
.into_iter()
.map(|environment| TurnEnvironmentSelection {
environment_id: environment.environment_id,
cwd: environment.cwd,
})
.collect::<Vec<_>>()
});
if let Some(environments) = environments.as_ref()
&& let Err(err) = self
.thread_manager
.validate_environment_selections(environments)
{
self.outgoing
.send_error(
request_id,
invalid_request(environment_selection_error_message(err)),
)
.await;
return;
}
let environment_selections = match self.parse_environment_selections(environments) {
Ok(environment_selections) => environment_selections,
Err(error) => {
self.outgoing.send_error(request_id, error).await;
return;
}
};
let mut typesafe_overrides = self.build_thread_config_overrides(
model,
model_provider,
@@ -2587,7 +2573,7 @@ impl CodexMessageProcessor {
typesafe_overrides,
dynamic_tools,
session_start_source,
environments,
environment_selections,
persist_extended_history,
service_name,
experimental_raw_events,
@@ -3012,6 +2998,27 @@ impl CodexMessageProcessor {
overrides
}
fn parse_environment_selections(
&self,
environments: Option<Vec<TurnEnvironmentParams>>,
) -> Result<Option<Vec<TurnEnvironmentSelection>>, JSONRPCErrorError> {
let environment_selections = environments.map(|environments| {
environments
.into_iter()
.map(|environment| TurnEnvironmentSelection {
environment_id: environment.environment_id,
cwd: environment.cwd,
})
.collect::<Vec<_>>()
});
if let Some(environment_selections) = environment_selections.as_ref() {
self.thread_manager
.validate_environment_selections(environment_selections)
.map_err(|err| invalid_request(environment_selection_error_message(err)))?;
}
Ok(environment_selections)
}
async fn thread_archive(&self, request_id: ConnectionRequestId, params: ThreadArchiveParams) {
let _thread_list_state_permit = match self.acquire_thread_list_state_permit().await {
Ok(permit) => permit,
@@ -6686,21 +6693,7 @@ impl CodexMessageProcessor {
let collaboration_mode = params
.collaboration_mode
.map(|mode| self.normalize_turn_start_collaboration_mode(mode));
let environments: Option<Vec<TurnEnvironmentSelection>> =
params.environments.map(|environments| {
environments
.into_iter()
.map(|environment| TurnEnvironmentSelection {
environment_id: environment.environment_id,
cwd: environment.cwd,
})
.collect()
});
if let Some(environments) = environments.as_ref() {
self.thread_manager
.validate_environment_selections(environments)
.map_err(|err| invalid_request(environment_selection_error_message(err)))?;
}
let environment_selections = self.parse_environment_selections(params.environments)?;
// Map v2 input items to core input items.
let mapped_items: Vec<CoreInputItem> = params
@@ -6809,7 +6802,7 @@ impl CodexMessageProcessor {
let turn_op = if has_any_overrides {
Op::UserInputWithTurnContext {
items: mapped_items,
environments,
environments: environment_selections,
final_output_json_schema: params.output_schema,
responsesapi_client_metadata: params.responsesapi_client_metadata,
cwd,
@@ -6829,7 +6822,7 @@ impl CodexMessageProcessor {
} else {
Op::UserInput {
items: mapped_items,
environments,
environments: environment_selections,
final_output_json_schema: params.output_schema,
responsesapi_client_metadata: params.responsesapi_client_metadata,
}