[codex] resolve environment shell metadata eagerly (#27709)

## Why

Turn construction passed resolved environments through several layers
while leaving the environment shell unresolved. As a result,
model-visible environment context could fall back to the session shell
instead of reporting the selected remote environment's shell.

Resolve environment metadata at the turn-context boundary so each turn
carries the shell that belongs to its selected environment. Keep request
validation in app-server, where invalid selections can be returned as
straightforward JSON-RPC errors without coupling core turn construction
to that policy.

## What changed

- resolve environment selections eagerly in
`new_turn_context_from_configuration`
- store the full resolved `Shell` on each `TurnEnvironment`
- simplify the now-redundant resolved-environment constructor plumbing
- keep duplicate and unknown-environment validation as a small
app-server preflight
- add a remote-environment integration test that runs a full
`test_codex` turn and verifies the model-visible environment message
reports `bash`

## Testing

- `cargo check -p codex-core --test all -p codex-app-server`
- `remote_test_env_exposes_bash_shell_to_model` on the Linux
remote-executor harness
This commit is contained in:
pakrym-oai authored and GitHub committed 2026-06-11 20:35:28 -07:00
1 parent e23d4df4ff
commit be338ee9a2
11 files changed
+162 -165

No files matched your search

@@ -1,8 +1,8 @@
use super::*;
pub(super) fn environment_selection_error_message(err: CodexErr) -> String {
pub(super) fn environment_selection_error(err: CodexErr) -> JSONRPCErrorError {
match err {
CodexErr::InvalidRequest(message) => message,
err => err.to_string(),
CodexErr::InvalidRequest(message) => invalid_request(message),
err => internal_error(format!("failed to validate environment selections: {err}")),
}
}
@@ -1299,7 +1299,7 @@ impl ThreadRequestProcessor {
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)))?;
.map_err(environment_selection_error)?;
}
Ok(environment_selections)
}
@@ -346,7 +346,7 @@ impl TurnRequestProcessor {
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)))?;
.map_err(environment_selection_error)?;
}
Ok(environment_selections)
}