From 716f7b0428de021cc03bfe88c4b5fadd122edd52 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Mon, 30 Mar 2026 08:15:12 -0700 Subject: [PATCH] codex-tools: extract discovery tool specs (#16193) ## Why `core/src/tools/spec.rs` still owned the pure `tool_search` and `tool_suggest` spec builders even though that logic no longer needed `codex-core` runtime state. This change continues the `codex-tools` migration by moving the reusable discovery and suggestion spec construction out of `codex-core` so `spec.rs` is left with the core-owned policy decisions about when these tools are exposed and what metadata is available. ## What changed - Added `codex-rs/tools/src/tool_discovery.rs` with the shared `tool_search` and `tool_suggest` spec builders, plus focused unit tests in `tool_discovery_tests.rs`. - Moved the shared `DiscoverableToolAction` and `DiscoverableToolType` declarations into `codex-tools` so the `tool_suggest` handler and the extracted spec builders use the same wire-model enums. - Updated `core/src/tools/spec.rs` to translate `ToolInfo` and `DiscoverableTool` values into neutral `codex-tools` inputs and delegate the actual spec building there. - Removed the old template-based description rendering helpers from `core/src/tools/spec.rs` and deleted the now-dead helper methods in `core/src/tools/discoverable.rs`. - Updated `codex-rs/tools/README.md` to document that discovery and suggestion models/spec builders now live in `codex-tools`. ## Test plan - `cargo test -p codex-tools` - `CARGO_TARGET_DIR=/tmp/codex-core-discovery-specs cargo test -p codex-core --lib tools::spec::` - `CARGO_TARGET_DIR=/tmp/codex-core-discovery-specs cargo test -p codex-core --lib tools::handlers::tool_suggest::` - `just argument-comment-lint` ## References - #16154 - #15923 - #15928 - #15944 - #15953 - #16031 - #16047 - #16129 - #16132 - #16138 - #16141 --- codex-rs/core/src/tools/discoverable.rs | 42 +-- .../core/src/tools/handlers/tool_suggest.rs | 4 +- .../src/tools/handlers/tool_suggest_tests.rs | 2 + codex-rs/core/src/tools/spec.rs | 294 ++++-------------- codex-rs/core/src/tools/spec_tests.rs | 2 + codex-rs/tools/README.md | 2 + codex-rs/tools/src/lib.rs | 7 + codex-rs/tools/src/tool_discovery.rs | 237 ++++++++++++++ codex-rs/tools/src/tool_discovery_tests.rs | 149 +++++++++ 9 files changed, 460 insertions(+), 279 deletions(-) create mode 100644 codex-rs/tools/src/tool_discovery.rs create mode 100644 codex-rs/tools/src/tool_discovery_tests.rs diff --git a/codex-rs/core/src/tools/discoverable.rs b/codex-rs/core/src/tools/discoverable.rs index e9403918e4..78d8935aa7 100644 --- a/codex-rs/core/src/tools/discoverable.rs +++ b/codex-rs/core/src/tools/discoverable.rs @@ -1,42 +1,9 @@ use crate::plugins::PluginCapabilitySummary; use codex_app_server_protocol::AppInfo; -use serde::Deserialize; -use serde::Serialize; +use codex_tools::DiscoverableToolType; const TUI_CLIENT_NAME: &str = "codex-tui"; -#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)] -#[serde(rename_all = "snake_case")] -pub(crate) enum DiscoverableToolType { - Connector, - Plugin, -} - -impl DiscoverableToolType { - pub(crate) fn as_str(self) -> &'static str { - match self { - Self::Connector => "connector", - Self::Plugin => "plugin", - } - } -} - -#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)] -#[serde(rename_all = "snake_case")] -pub(crate) enum DiscoverableToolAction { - Install, - Enable, -} - -impl DiscoverableToolAction { - pub(crate) fn as_str(self) -> &'static str { - match self { - Self::Install => "install", - Self::Enable => "enable", - } - } -} - #[derive(Clone, Debug, PartialEq)] pub(crate) enum DiscoverableTool { Connector(Box), @@ -65,13 +32,6 @@ impl DiscoverableTool { } } - pub(crate) fn description(&self) -> Option<&str> { - match self { - Self::Connector(connector) => connector.description.as_deref(), - Self::Plugin(plugin) => plugin.description.as_deref(), - } - } - pub(crate) fn install_url(&self) -> Option<&str> { match self { Self::Connector(connector) => connector.install_url.as_deref(), diff --git a/codex-rs/core/src/tools/handlers/tool_suggest.rs b/codex-rs/core/src/tools/handlers/tool_suggest.rs index bdffbbbada..478bd2c837 100644 --- a/codex-rs/core/src/tools/handlers/tool_suggest.rs +++ b/codex-rs/core/src/tools/handlers/tool_suggest.rs @@ -8,6 +8,8 @@ use codex_app_server_protocol::McpElicitationSchema; use codex_app_server_protocol::McpServerElicitationRequest; use codex_app_server_protocol::McpServerElicitationRequestParams; use codex_rmcp_client::ElicitationAction; +use codex_tools::DiscoverableToolAction; +use codex_tools::DiscoverableToolType; use rmcp::model::RequestId; use serde::Deserialize; use serde::Serialize; @@ -21,8 +23,6 @@ use crate::tools::context::FunctionToolOutput; use crate::tools::context::ToolInvocation; use crate::tools::context::ToolPayload; use crate::tools::discoverable::DiscoverableTool; -use crate::tools::discoverable::DiscoverableToolAction; -use crate::tools::discoverable::DiscoverableToolType; use crate::tools::discoverable::filter_tool_suggest_discoverable_tools_for_client; use crate::tools::handlers::parse_arguments; use crate::tools::registry::ToolHandler; diff --git a/codex-rs/core/src/tools/handlers/tool_suggest_tests.rs b/codex-rs/core/src/tools/handlers/tool_suggest_tests.rs index 32d5061aed..c932e03145 100644 --- a/codex-rs/core/src/tools/handlers/tool_suggest_tests.rs +++ b/codex-rs/core/src/tools/handlers/tool_suggest_tests.rs @@ -8,6 +8,8 @@ use crate::plugins::test_support::write_plugins_feature_config; use crate::tools::discoverable::DiscoverablePluginInfo; use crate::tools::discoverable::filter_tool_suggest_discoverable_tools_for_client; use codex_app_server_protocol::AppInfo; +use codex_tools::DiscoverableToolAction; +use codex_tools::DiscoverableToolType; use codex_utils_absolute_path::AbsolutePathBuf; use pretty_assertions::assert_eq; use serde_json::json; diff --git a/codex-rs/core/src/tools/spec.rs b/codex-rs/core/src/tools/spec.rs index 782cb498db..6852671576 100644 --- a/codex-rs/core/src/tools/spec.rs +++ b/codex-rs/core/src/tools/spec.rs @@ -7,10 +7,7 @@ use crate::shell::Shell; use crate::shell::ShellType; use crate::tools::code_mode::PUBLIC_TOOL_NAME; use crate::tools::code_mode::WAIT_TOOL_NAME; -use crate::tools::discoverable::DiscoverablePluginInfo; use crate::tools::discoverable::DiscoverableTool; -use crate::tools::discoverable::DiscoverableToolAction; -use crate::tools::discoverable::DiscoverableToolType; use crate::tools::handlers::PLAN_TOOL; use crate::tools::handlers::TOOL_SEARCH_DEFAULT_LIMIT; use crate::tools::handlers::TOOL_SEARCH_TOOL_NAME; @@ -41,9 +38,11 @@ use codex_protocol::protocol::SandboxPolicy; use codex_protocol::protocol::SessionSource; use codex_protocol::protocol::SubAgentSource; use codex_tools::CommandToolOptions; -use codex_tools::ResponsesApiTool; +use codex_tools::DiscoverableToolType; use codex_tools::ShellToolOptions; use codex_tools::SpawnAgentToolOptions; +use codex_tools::ToolSearchAppInfo; +use codex_tools::ToolSuggestEntry; use codex_tools::ViewImageToolOptions; use codex_tools::WaitAgentTimeoutOptions; use codex_tools::augment_tool_spec_for_code_mode; @@ -71,6 +70,8 @@ use codex_tools::create_spawn_agent_tool_v1; use codex_tools::create_spawn_agent_tool_v2; use codex_tools::create_spawn_agents_on_csv_tool; use codex_tools::create_test_sync_tool; +use codex_tools::create_tool_search_tool; +use codex_tools::create_tool_suggest_tool; use codex_tools::create_view_image_tool; use codex_tools::create_wait_agent_tool_v1; use codex_tools::create_wait_agent_tool_v2; @@ -80,33 +81,17 @@ use codex_tools::dynamic_tool_to_responses_api_tool; use codex_tools::mcp_tool_to_responses_api_tool; use codex_tools::tool_spec_to_code_mode_tool_definition; use codex_utils_absolute_path::AbsolutePathBuf; -use codex_utils_template::Template; use serde::Deserialize; use serde::Serialize; use std::collections::BTreeMap; use std::collections::HashMap; use std::path::PathBuf; -use std::sync::LazyLock; pub type JsonSchema = codex_tools::JsonSchema; #[cfg(test)] pub(crate) use codex_tools::mcp_call_tool_result_output_schema; -const TOOL_SEARCH_DESCRIPTION_TEMPLATE_SOURCE: &str = - include_str!("../../templates/search_tool/tool_description.md"); -const TOOL_SEARCH_DESCRIPTION_TEMPLATE_KEY: &str = "app_descriptions"; -static TOOL_SEARCH_DESCRIPTION_TEMPLATE: LazyLock