Disable env-bound tools when exec server is none (#16349)

## Summary
- make `CODEX_EXEC_SERVER_URL=none` map to an explicit disabled
environment mode instead of inferring from a missing URL
- expose environment capabilities (`exec_enabled`, `filesystem_enabled`)
so tool building can gate behavior explicitly and future
multi-environment work has a clearer seam
- suppress env-backed tools when the relevant capability is unavailable,
including exec tools, `js_repl`, `apply_patch`, `list_dir`, and
`view_image`
- keep handler/runtime backstops so disabled environments still reject
execution if a tool path somehow bypasses registration

## Testing
- `just fmt`
- `cargo test -p codex-exec-server`
- `cargo test -p codex-tools
disabled_environment_omits_environment_backed_tools`
- `cargo test -p codex-tools
environment_capabilities_gate_exec_and_filesystem_tools_independently`
- remote devbox Bazel build via `codex-applied-devbox`:
`//codex-rs/cli:cli`
This commit is contained in:
starr-openai authored and GitHub committed 2026-04-06 17:22:06 -07:00
1 parent 9f737c28dd
commit a504d8f0fa
13 files changed
+258 -119

No files matched your search

+8 -5
View File
@@ -862,7 +862,7 @@ pub(crate) struct TurnContext {
pub(crate) reasoning_effort: Option<ReasoningEffortConfig>,
pub(crate) reasoning_summary: ReasoningSummaryConfig,
pub(crate) session_source: SessionSource,
pub(crate) environment: Arc<Environment>,
pub(crate) environment: Option<Arc<Environment>>,
/// The session's absolute working directory. All relative paths provided
/// by the model as well as sandbox policies are resolved against this path
/// instead of `std::env::current_dir()`.
@@ -958,6 +958,7 @@ impl TurnContext {
.with_unified_exec_shell_mode(self.tools_config.unified_exec_shell_mode.clone())
.with_web_search_config(self.tools_config.web_search_config.clone())
.with_allow_login_shell(self.tools_config.allow_login_shell)
.with_has_environment(self.tools_config.has_environment)
.with_agent_type_description(crate::agent::role::spawn_tool_spec::build(
&config.agent_roles,
));
@@ -977,7 +978,7 @@ impl TurnContext {
reasoning_effort,
reasoning_summary: self.reasoning_summary,
session_source: self.session_source.clone(),
environment: Arc::clone(&self.environment),
environment: self.environment.clone(),
cwd: self.cwd.clone(),
current_date: self.current_date.clone(),
timezone: self.timezone.clone(),
@@ -1406,7 +1407,7 @@ impl Session {
model_info: ModelInfo,
models_manager: &ModelsManager,
network: Option<NetworkProxy>,
environment: Arc<Environment>,
environment: Option<Arc<Environment>>,
sub_id: String,
js_repl: Arc<JsReplHandle>,
skills_outcome: Arc<SkillLoadOutcome>,
@@ -1439,6 +1440,7 @@ impl Session {
)
.with_web_search_config(per_turn_config.web_search_config.clone())
.with_allow_login_shell(per_turn_config.permissions.allow_login_shell)
.with_has_environment(environment.is_some())
.with_agent_type_description(crate::agent::role::spawn_tool_spec::build(
&per_turn_config.agent_roles,
));
@@ -2542,7 +2544,7 @@ impl Session {
.network_proxy
.as_ref()
.map(StartedNetworkProxy::proxy),
Arc::clone(&self.services.environment),
self.services.environment.clone(),
sub_id,
Arc::clone(&self.js_repl),
skills_outcome,
@@ -5614,6 +5616,7 @@ async fn spawn_review_thread(
)
.with_web_search_config(/*web_search_config*/ None)
.with_allow_login_shell(config.permissions.allow_login_shell)
.with_has_environment(parent_turn_context.environment.is_some())
.with_agent_type_description(crate::agent::role::spawn_tool_spec::build(
&config.agent_roles,
));
@@ -5672,7 +5675,7 @@ async fn spawn_review_thread(
reasoning_effort,
reasoning_summary,
session_source,
environment: Arc::clone(&parent_turn_context.environment),
environment: parent_turn_context.environment.clone(),
tools_config,
features: parent_turn_context.features.clone(),
ghost_snapshot: parent_turn_context.ghost_snapshot.clone(),