From a52c91d8b59601d1b01e8ccfffc2ae0d5dde31df Mon Sep 17 00:00:00 2001 From: pakrym-oai Date: Wed, 20 May 2026 08:09:45 -0700 Subject: [PATCH] [codex] Hide deferred tools from code mode prompt (#23605) ## Why `code_mode_only_guides_all_tools_search_and_calls_deferred_app_tools` was failing because code-mode prompt generation used the same nested tool spec list for both the model-visible `exec` guide and the runtime `ALL_TOOLS` surface. That allowed deferred MCP/app tools, such as `calendar_timezone_option_99`, to leak into the `exec` description even though they should only be discoverable through `ALL_TOOLS` at runtime. ## What changed Split code-mode nested tool planning into two sets in `core/src/tools/spec_plan.rs`: - runtime nested tool specs still include deferred tools, so `tools[...]` and `ALL_TOOLS` can call them - `exec` prompt docs only render non-deferred tools, so deferred app tools stay out of the model-visible guide ## Validation - `cargo test -p codex-core --test all code_mode_only_guides_all_tools_search_and_calls_deferred_app_tools -- --nocapture` - looped the same focused test 5 additional times with `cargo test -q -p codex-core --test all code_mode_only_guides_all_tools_search_and_calls_deferred_app_tools` --- codex-rs/core/src/tools/spec_plan.rs | 30 ++++++++++++++++++---------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/codex-rs/core/src/tools/spec_plan.rs b/codex-rs/core/src/tools/spec_plan.rs index ab9d02f97c..a47ed9da34 100644 --- a/codex-rs/core/src/tools/spec_plan.rs +++ b/codex-rs/core/src/tools/spec_plan.rs @@ -367,19 +367,27 @@ fn build_code_mode_executors( return vec![]; } - let code_mode_nested_tool_specs = executors - .iter() - .filter_map(|executor| { - if executor.exposure() == ToolExposure::DirectModelOnly { - return None; - } + let mut code_mode_nested_tool_specs = Vec::new(); + let mut exec_prompt_tool_specs = Vec::new(); + for executor in executors { + let exposure = executor.exposure(); + if exposure == ToolExposure::DirectModelOnly { + continue; + } - executor.spec() - }) - .collect::>(); - let namespace_descriptions = code_mode_namespace_descriptions(&code_mode_nested_tool_specs); + let Some(spec) = executor.spec() else { + continue; + }; + + if exposure != ToolExposure::Deferred { + exec_prompt_tool_specs.push(spec.clone()); + } + code_mode_nested_tool_specs.push(spec); + } + + let namespace_descriptions = code_mode_namespace_descriptions(&exec_prompt_tool_specs); let mut enabled_tools = - collect_code_mode_exec_prompt_tool_definitions(code_mode_nested_tool_specs.iter()); + collect_code_mode_exec_prompt_tool_definitions(exec_prompt_tool_specs.iter()); enabled_tools .sort_by(|left, right| compare_code_mode_tools(left, right, &namespace_descriptions));