Extract code-mode nested tool collection into codex-tools (#16509)

## Why
This is another small step in the `codex-core` -> `codex-tools`
migration described in `AGENTS.md`.

`core/src/tools/spec.rs` and `core/src/tools/code_mode/mod.rs` were both
hand-rolling the same pure transformation: convert visible `ToolSpec`s
into code-mode nested tool definitions, then sort and deduplicate by
tool name. That logic does not depend on core runtime state or handlers,
so keeping it in `codex-core` makes `spec.rs` harder to peel out later
than it needs to be.

## What Changed
- Add `collect_code_mode_tool_definitions()` to
`codex-rs/tools/src/code_mode.rs`.
- Reuse that helper from `codex-rs/core/src/tools/spec.rs` when
assembling the `exec` tool description.
- Reuse the same helper from `codex-rs/core/src/tools/code_mode/mod.rs`
when exposing nested tool metadata to the code-mode runtime.

This is intended to be a straight refactor with no behavior change and
no new test surface.

## Verification
- `cargo test -p codex-tools`
- `cargo test -p codex-core tools::spec::tests`
- `cargo test -p codex-core code_mode_only_`
This commit is contained in:
Michael Bolin
2026-04-01 22:17:55 -07:00
committed by GitHub
Unverified
parent cc97982bbb
commit 9f71d57a65
4 changed files with 25 additions and 17 deletions
+3 -9
View File
@@ -28,7 +28,7 @@ use crate::tools::router::ToolRouterParams;
use crate::unified_exec::resolve_max_tokens;
use codex_features::Feature;
use codex_tools::ToolSpec;
use codex_tools::tool_spec_to_code_mode_tool_definition;
use codex_tools::collect_code_mode_tool_definitions;
use codex_utils_output_truncation::TruncationPolicy;
use codex_utils_output_truncation::formatted_truncate_text_content_items_with_policy;
use codex_utils_output_truncation::truncate_function_output_items_with_policy;
@@ -244,14 +244,8 @@ pub(super) async fn build_enabled_tools(
exec: &ExecContext,
) -> Vec<codex_code_mode::ToolDefinition> {
let router = build_nested_router(exec).await;
let mut out = router
.specs()
.into_iter()
.filter_map(|spec| tool_spec_to_code_mode_tool_definition(&spec))
.collect::<Vec<_>>();
out.sort_by(|left, right| left.name.cmp(&right.name));
out.dedup_by(|left, right| left.name == right.name);
out
let specs = router.specs();
collect_code_mode_tool_definitions(&specs)
}
async fn build_nested_router(exec: &ExecContext) -> ToolRouter {
+9 -8
View File
@@ -29,6 +29,7 @@ use codex_tools::ViewImageToolOptions;
use codex_tools::WaitAgentTimeoutOptions;
use codex_tools::WebSearchToolOptions;
use codex_tools::augment_tool_spec_for_code_mode;
use codex_tools::collect_code_mode_tool_definitions;
use codex_tools::collect_tool_search_app_infos;
use codex_tools::collect_tool_suggest_entries;
use codex_tools::create_apply_patch_freeform_tool;
@@ -72,7 +73,6 @@ use codex_tools::dynamic_tool_to_responses_api_tool;
use codex_tools::mcp_tool_to_responses_api_tool;
use codex_tools::request_permissions_tool_description;
use codex_tools::request_user_input_tool_description;
use codex_tools::tool_spec_to_code_mode_tool_definition;
use std::collections::HashMap;
#[cfg(test)]
@@ -202,13 +202,14 @@ pub(crate) fn build_specs_with_discoverable_tools(
dynamic_tools,
)
.build();
let mut enabled_tools = nested_specs
.into_iter()
.filter_map(|spec| tool_spec_to_code_mode_tool_definition(&spec.spec))
.map(|tool| (tool.name, tool.description))
.collect::<Vec<_>>();
enabled_tools.sort_by(|left, right| left.0.cmp(&right.0));
enabled_tools.dedup_by(|left, right| left.0 == right.0);
let enabled_tools = collect_code_mode_tool_definitions(
nested_specs
.iter()
.map(|configured_tool| &configured_tool.spec),
)
.into_iter()
.map(|tool| (tool.name, tool.description))
.collect::<Vec<_>>();
push_tool_spec(
&mut builder,
create_code_mode_tool(&enabled_tools, config.code_mode_only_enabled),
+12
View File
@@ -37,6 +37,18 @@ pub fn tool_spec_to_code_mode_tool_definition(spec: &ToolSpec) -> Option<CodeMod
.then(|| codex_code_mode::augment_tool_definition(definition))
}
pub fn collect_code_mode_tool_definitions<'a>(
specs: impl IntoIterator<Item = &'a ToolSpec>,
) -> Vec<CodeModeToolDefinition> {
let mut tool_definitions = specs
.into_iter()
.filter_map(tool_spec_to_code_mode_tool_definition)
.collect::<Vec<_>>();
tool_definitions.sort_by(|left, right| left.name.cmp(&right.name));
tool_definitions.dedup_by(|left, right| left.name == right.name);
tool_definitions
}
pub fn create_wait_tool() -> ToolSpec {
let properties = BTreeMap::from([
(
+1
View File
@@ -42,6 +42,7 @@ pub use apply_patch_tool::ApplyPatchToolArgs;
pub use apply_patch_tool::create_apply_patch_freeform_tool;
pub use apply_patch_tool::create_apply_patch_json_tool;
pub use code_mode::augment_tool_spec_for_code_mode;
pub use code_mode::collect_code_mode_tool_definitions;
pub use code_mode::create_code_mode_tool;
pub use code_mode::create_wait_tool;
pub use code_mode::tool_spec_to_code_mode_tool_definition;