mirror of
https://github.com/openai/codex.git
synced 2026-05-28 15:00:16 +00:00
[codex] Delete tool handler plan indirection (#21427)
## Why The spec split in the parent PR still left an intermediate registry plan that recorded `ToolHandlerKind` values and translated them into concrete handlers later. That kept tool registration dependent on static enum bookkeeping instead of registering handlers from the same code that assembles their specs. ## What Changed - Make `build_tool_registry_builder` register concrete handlers directly while adding specs. - Add small `ToolRegistryBuilder` helpers for spec augmentation and nested code-mode inspection. - Remove `ToolHandlerKind`, `ToolHandlerSpec`, and `ToolRegistryPlan`. - Update spec-plan tests to assert against the built `ToolRegistry` instead of static handler descriptors. ## Validation - `cargo check -p codex-core` - `cargo test -p codex-core tools::spec_plan::tests` - `cargo test -p codex-core tools::spec::tests` - `just fix -p codex-core`
This commit is contained in:
@@ -522,10 +522,6 @@ impl ToolRegistryBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_spec(&mut self, spec: ToolSpec) {
|
||||
self.push_spec_with_parallel_support(spec, /*supports_parallel_tool_calls*/ false);
|
||||
}
|
||||
|
||||
pub fn push_spec_with_parallel_support(
|
||||
&mut self,
|
||||
spec: ToolSpec,
|
||||
@@ -535,6 +531,20 @@ impl ToolRegistryBuilder {
|
||||
.push(ConfiguredToolSpec::new(spec, supports_parallel_tool_calls));
|
||||
}
|
||||
|
||||
pub(crate) fn push_spec(
|
||||
&mut self,
|
||||
spec: ToolSpec,
|
||||
supports_parallel_tool_calls: bool,
|
||||
code_mode_enabled: bool,
|
||||
) {
|
||||
let spec = if code_mode_enabled {
|
||||
codex_tools::augment_tool_spec_for_code_mode(spec)
|
||||
} else {
|
||||
spec
|
||||
};
|
||||
self.push_spec_with_parallel_support(spec, supports_parallel_tool_calls);
|
||||
}
|
||||
|
||||
pub fn register_handler<H>(&mut self, handler: Arc<H>)
|
||||
where
|
||||
H: ToolHandler + 'static,
|
||||
@@ -547,6 +557,10 @@ impl ToolRegistryBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn specs(&self) -> &[ConfiguredToolSpec] {
|
||||
&self.specs
|
||||
}
|
||||
|
||||
pub fn build(self) -> (Vec<ConfiguredToolSpec>, ToolRegistry) {
|
||||
let registry = ToolRegistry::new(self.handlers);
|
||||
(self.specs, registry)
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
use crate::shell::Shell;
|
||||
use crate::shell::ShellType;
|
||||
use crate::tools::handlers::agent_jobs::ReportAgentJobResultHandler;
|
||||
use crate::tools::handlers::agent_jobs::SpawnAgentsOnCsvHandler;
|
||||
use crate::tools::handlers::multi_agents_common::DEFAULT_WAIT_TIMEOUT_MS;
|
||||
use crate::tools::handlers::multi_agents_common::MAX_WAIT_TIMEOUT_MS;
|
||||
use crate::tools::handlers::multi_agents_common::MIN_WAIT_TIMEOUT_MS;
|
||||
use crate::tools::handlers::multi_agents_spec::WaitAgentTimeoutOptions;
|
||||
use crate::tools::registry::ToolRegistryBuilder;
|
||||
use crate::tools::spec_plan::build_tool_registry_plan;
|
||||
use crate::tools::spec_plan_types::ToolHandlerKind;
|
||||
use crate::tools::spec_plan::build_tool_registry_builder;
|
||||
use crate::tools::spec_plan_types::ToolNamespace;
|
||||
use crate::tools::spec_plan_types::ToolRegistryPlanDeferredTool;
|
||||
use crate::tools::spec_plan_types::ToolRegistryPlanMcpTool;
|
||||
use crate::tools::spec_plan_types::ToolRegistryPlanParams;
|
||||
use crate::tools::spec_plan_types::ToolRegistryBuildDeferredTool;
|
||||
use crate::tools::spec_plan_types::ToolRegistryBuildMcpTool;
|
||||
use crate::tools::spec_plan_types::ToolRegistryBuildParams;
|
||||
use codex_mcp::ToolInfo;
|
||||
use codex_protocol::dynamic_tools::DynamicToolSpec;
|
||||
use codex_tools::AdditionalProperties;
|
||||
@@ -22,7 +19,6 @@ use codex_tools::ResponsesApiTool;
|
||||
use codex_tools::ToolName;
|
||||
use codex_tools::ToolUserShellType;
|
||||
use codex_tools::ToolsConfig;
|
||||
use codex_tools::augment_tool_spec_for_code_mode;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
@@ -38,7 +34,7 @@ pub(crate) fn tool_user_shell_type(user_shell: &Shell) -> ToolUserShellType {
|
||||
}
|
||||
|
||||
struct McpToolPlanInputs<'a> {
|
||||
mcp_tools: Vec<ToolRegistryPlanMcpTool<'a>>,
|
||||
mcp_tools: Vec<ToolRegistryBuildMcpTool<'a>>,
|
||||
tool_namespaces: HashMap<String, ToolNamespace>,
|
||||
}
|
||||
|
||||
@@ -46,7 +42,7 @@ fn map_mcp_tools_for_plan(mcp_tools: &HashMap<String, ToolInfo>) -> McpToolPlanI
|
||||
McpToolPlanInputs {
|
||||
mcp_tools: mcp_tools
|
||||
.values()
|
||||
.map(|tool| ToolRegistryPlanMcpTool {
|
||||
.map(|tool| ToolRegistryBuildMcpTool {
|
||||
name: tool.canonical_tool_name(),
|
||||
tool: &tool.tool,
|
||||
})
|
||||
@@ -74,51 +70,15 @@ pub(crate) fn build_specs_with_discoverable_tools(
|
||||
discoverable_tools: Option<Vec<DiscoverableTool>>,
|
||||
dynamic_tools: &[DynamicToolSpec],
|
||||
) -> ToolRegistryBuilder {
|
||||
use crate::tools::handlers::ApplyPatchHandler;
|
||||
use crate::tools::handlers::CodeModeExecuteHandler;
|
||||
use crate::tools::handlers::CodeModeWaitHandler;
|
||||
use crate::tools::handlers::ContainerExecHandler;
|
||||
use crate::tools::handlers::CreateGoalHandler;
|
||||
use crate::tools::handlers::DynamicToolHandler;
|
||||
use crate::tools::handlers::ExecCommandHandler;
|
||||
use crate::tools::handlers::GetGoalHandler;
|
||||
use crate::tools::handlers::ListMcpResourceTemplatesHandler;
|
||||
use crate::tools::handlers::ListMcpResourcesHandler;
|
||||
use crate::tools::handlers::LocalShellHandler;
|
||||
use crate::tools::handlers::McpHandler;
|
||||
use crate::tools::handlers::PlanHandler;
|
||||
use crate::tools::handlers::ReadMcpResourceHandler;
|
||||
use crate::tools::handlers::RequestPermissionsHandler;
|
||||
use crate::tools::handlers::RequestPluginInstallHandler;
|
||||
use crate::tools::handlers::RequestUserInputHandler;
|
||||
use crate::tools::handlers::ShellCommandHandler;
|
||||
use crate::tools::handlers::ShellHandler;
|
||||
use crate::tools::handlers::TestSyncHandler;
|
||||
use crate::tools::handlers::ToolSearchHandler;
|
||||
use crate::tools::handlers::UnavailableToolHandler;
|
||||
use crate::tools::handlers::UpdateGoalHandler;
|
||||
use crate::tools::handlers::ViewImageHandler;
|
||||
use crate::tools::handlers::WriteStdinHandler;
|
||||
use crate::tools::handlers::multi_agents::CloseAgentHandler;
|
||||
use crate::tools::handlers::multi_agents::ResumeAgentHandler;
|
||||
use crate::tools::handlers::multi_agents::SendInputHandler;
|
||||
use crate::tools::handlers::multi_agents::SpawnAgentHandler;
|
||||
use crate::tools::handlers::multi_agents::WaitAgentHandler;
|
||||
use crate::tools::handlers::multi_agents_v2::CloseAgentHandler as CloseAgentHandlerV2;
|
||||
use crate::tools::handlers::multi_agents_v2::FollowupTaskHandler as FollowupTaskHandlerV2;
|
||||
use crate::tools::handlers::multi_agents_v2::ListAgentsHandler as ListAgentsHandlerV2;
|
||||
use crate::tools::handlers::multi_agents_v2::SendMessageHandler as SendMessageHandlerV2;
|
||||
use crate::tools::handlers::multi_agents_v2::SpawnAgentHandler as SpawnAgentHandlerV2;
|
||||
use crate::tools::handlers::multi_agents_v2::WaitAgentHandler as WaitAgentHandlerV2;
|
||||
use crate::tools::handlers::unavailable_tool_message;
|
||||
use crate::tools::tool_search_entry::build_tool_search_entries_for_config;
|
||||
|
||||
let mut builder = ToolRegistryBuilder::new();
|
||||
let mcp_tool_plan_inputs = mcp_tools.as_ref().map(map_mcp_tools_for_plan);
|
||||
let deferred_mcp_tool_sources = deferred_mcp_tools.as_ref().map(|tools| {
|
||||
tools
|
||||
.values()
|
||||
.map(|tool| ToolRegistryPlanDeferredTool {
|
||||
.map(|tool| ToolRegistryBuildDeferredTool {
|
||||
name: tool.canonical_tool_name(),
|
||||
server_name: tool.server_name.as_str(),
|
||||
connector_name: tool.connector_name.as_deref(),
|
||||
@@ -138,9 +98,19 @@ pub(crate) fn build_specs_with_discoverable_tools(
|
||||
};
|
||||
let default_wait_timeout_ms =
|
||||
DEFAULT_WAIT_TIMEOUT_MS.clamp(min_wait_timeout_ms, MAX_WAIT_TIMEOUT_MS);
|
||||
let plan = build_tool_registry_plan(
|
||||
let deferred_dynamic_tools = dynamic_tools
|
||||
.iter()
|
||||
.filter(|tool| tool.defer_loading && (config.namespace_tools || tool.namespace.is_none()))
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
let tool_search_entries = build_tool_search_entries_for_config(
|
||||
config,
|
||||
ToolRegistryPlanParams {
|
||||
deferred_mcp_tools.as_ref(),
|
||||
&deferred_dynamic_tools,
|
||||
);
|
||||
let mut builder = build_tool_registry_builder(
|
||||
config,
|
||||
ToolRegistryBuildParams {
|
||||
mcp_tools: mcp_tool_plan_inputs
|
||||
.as_ref()
|
||||
.map(|inputs| inputs.mcp_tools.as_slice()),
|
||||
@@ -156,164 +126,15 @@ pub(crate) fn build_specs_with_discoverable_tools(
|
||||
min_timeout_ms: min_wait_timeout_ms,
|
||||
max_timeout_ms: MAX_WAIT_TIMEOUT_MS,
|
||||
},
|
||||
tool_search_entries: &tool_search_entries,
|
||||
},
|
||||
);
|
||||
let deferred_dynamic_tools = dynamic_tools
|
||||
.iter()
|
||||
.filter(|tool| tool.defer_loading && (config.namespace_tools || tool.namespace.is_none()))
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
let mut existing_spec_names = plan
|
||||
.specs
|
||||
let mut existing_spec_names = builder
|
||||
.specs()
|
||||
.iter()
|
||||
.map(|configured_tool| configured_tool.name().to_string())
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
for spec in plan.specs {
|
||||
if spec.supports_parallel_tool_calls {
|
||||
builder.push_spec_with_parallel_support(
|
||||
spec.spec, /*supports_parallel_tool_calls*/ true,
|
||||
);
|
||||
} else {
|
||||
builder.push_spec(spec.spec);
|
||||
}
|
||||
}
|
||||
|
||||
for handler in plan.handlers {
|
||||
let name = handler.name;
|
||||
match handler.kind {
|
||||
ToolHandlerKind::ApplyPatch => {
|
||||
builder.register_handler(Arc::new(ApplyPatchHandler));
|
||||
}
|
||||
ToolHandlerKind::CloseAgentV1 => {
|
||||
builder.register_handler(Arc::new(CloseAgentHandler));
|
||||
}
|
||||
ToolHandlerKind::CloseAgentV2 => {
|
||||
builder.register_handler(Arc::new(CloseAgentHandlerV2));
|
||||
}
|
||||
ToolHandlerKind::CodeModeExecute => {
|
||||
builder.register_handler(Arc::new(CodeModeExecuteHandler));
|
||||
}
|
||||
ToolHandlerKind::CodeModeWait => {
|
||||
builder.register_handler(Arc::new(CodeModeWaitHandler));
|
||||
}
|
||||
ToolHandlerKind::ContainerExec => {
|
||||
builder.register_handler(Arc::new(ContainerExecHandler));
|
||||
}
|
||||
ToolHandlerKind::CreateGoal => {
|
||||
builder.register_handler(Arc::new(CreateGoalHandler));
|
||||
}
|
||||
ToolHandlerKind::DynamicTool => {
|
||||
builder.register_handler(Arc::new(DynamicToolHandler::new(name)));
|
||||
}
|
||||
ToolHandlerKind::ExecCommand => {
|
||||
builder.register_handler(Arc::new(ExecCommandHandler));
|
||||
}
|
||||
ToolHandlerKind::FollowupTaskV2 => {
|
||||
builder.register_handler(Arc::new(FollowupTaskHandlerV2));
|
||||
}
|
||||
ToolHandlerKind::GetGoal => {
|
||||
builder.register_handler(Arc::new(GetGoalHandler));
|
||||
}
|
||||
ToolHandlerKind::ListAgentsV2 => {
|
||||
builder.register_handler(Arc::new(ListAgentsHandlerV2));
|
||||
}
|
||||
ToolHandlerKind::ListMcpResources => {
|
||||
builder.register_handler(Arc::new(ListMcpResourcesHandler));
|
||||
}
|
||||
ToolHandlerKind::ListMcpResourceTemplates => {
|
||||
builder.register_handler(Arc::new(ListMcpResourceTemplatesHandler));
|
||||
}
|
||||
ToolHandlerKind::LocalShell => {
|
||||
builder.register_handler(Arc::new(LocalShellHandler));
|
||||
}
|
||||
ToolHandlerKind::Mcp => {
|
||||
builder.register_handler(Arc::new(McpHandler::new(name)));
|
||||
}
|
||||
ToolHandlerKind::Plan => {
|
||||
builder.register_handler(Arc::new(PlanHandler));
|
||||
}
|
||||
ToolHandlerKind::ReadMcpResource => {
|
||||
builder.register_handler(Arc::new(ReadMcpResourceHandler));
|
||||
}
|
||||
ToolHandlerKind::ReportAgentJobResult => {
|
||||
builder.register_handler(Arc::new(ReportAgentJobResultHandler));
|
||||
}
|
||||
ToolHandlerKind::RequestPermissions => {
|
||||
builder.register_handler(Arc::new(RequestPermissionsHandler));
|
||||
}
|
||||
ToolHandlerKind::RequestUserInput => {
|
||||
builder.register_handler(Arc::new(RequestUserInputHandler {
|
||||
available_modes: config.request_user_input_available_modes.clone(),
|
||||
}));
|
||||
}
|
||||
ToolHandlerKind::ResumeAgentV1 => {
|
||||
builder.register_handler(Arc::new(ResumeAgentHandler));
|
||||
}
|
||||
ToolHandlerKind::SendInputV1 => {
|
||||
builder.register_handler(Arc::new(SendInputHandler));
|
||||
}
|
||||
ToolHandlerKind::SendMessageV2 => {
|
||||
builder.register_handler(Arc::new(SendMessageHandlerV2));
|
||||
}
|
||||
ToolHandlerKind::Shell => {
|
||||
builder.register_handler(Arc::new(ShellHandler));
|
||||
}
|
||||
ToolHandlerKind::ShellCommand => {
|
||||
builder.register_handler(Arc::new(ShellCommandHandler::from(
|
||||
config.shell_command_backend,
|
||||
)));
|
||||
}
|
||||
ToolHandlerKind::SpawnAgentsOnCsv => {
|
||||
builder.register_handler(Arc::new(SpawnAgentsOnCsvHandler));
|
||||
}
|
||||
ToolHandlerKind::SpawnAgentV1 => {
|
||||
builder.register_handler(Arc::new(SpawnAgentHandler));
|
||||
}
|
||||
ToolHandlerKind::SpawnAgentV2 => {
|
||||
builder.register_handler(Arc::new(SpawnAgentHandlerV2));
|
||||
}
|
||||
ToolHandlerKind::TestSync => {
|
||||
builder.register_handler(Arc::new(TestSyncHandler));
|
||||
}
|
||||
ToolHandlerKind::ToolSearch => {
|
||||
let entries = build_tool_search_entries_for_config(
|
||||
config,
|
||||
deferred_mcp_tools.as_ref(),
|
||||
&deferred_dynamic_tools,
|
||||
);
|
||||
builder.register_handler(Arc::new(ToolSearchHandler::new(entries)));
|
||||
}
|
||||
ToolHandlerKind::RequestPluginInstall => {
|
||||
builder.register_handler(Arc::new(RequestPluginInstallHandler));
|
||||
}
|
||||
ToolHandlerKind::UpdateGoal => {
|
||||
builder.register_handler(Arc::new(UpdateGoalHandler));
|
||||
}
|
||||
ToolHandlerKind::ViewImage => {
|
||||
builder.register_handler(Arc::new(ViewImageHandler));
|
||||
}
|
||||
ToolHandlerKind::WaitAgentV1 => {
|
||||
builder.register_handler(Arc::new(WaitAgentHandler));
|
||||
}
|
||||
ToolHandlerKind::WaitAgentV2 => {
|
||||
builder.register_handler(Arc::new(WaitAgentHandlerV2));
|
||||
}
|
||||
ToolHandlerKind::WriteStdin => {
|
||||
builder.register_handler(Arc::new(WriteStdinHandler));
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(deferred_mcp_tools) = deferred_mcp_tools.as_ref() {
|
||||
for (_, tool) in deferred_mcp_tools.iter().filter(|(name, _)| {
|
||||
!mcp_tools
|
||||
.as_ref()
|
||||
.is_some_and(|tools| tools.contains_key(*name))
|
||||
}) {
|
||||
builder.register_handler(Arc::new(McpHandler::new(tool.canonical_tool_name())));
|
||||
}
|
||||
}
|
||||
|
||||
for unavailable_tool in unavailable_called_tools {
|
||||
let tool_name = unavailable_tool.display();
|
||||
if existing_spec_names.insert(tool_name.clone()) {
|
||||
@@ -332,12 +153,11 @@ pub(crate) fn build_specs_with_discoverable_tools(
|
||||
output_schema: None,
|
||||
defer_loading: None,
|
||||
});
|
||||
let spec = if config.code_mode_enabled {
|
||||
augment_tool_spec_for_code_mode(spec)
|
||||
} else {
|
||||
spec
|
||||
};
|
||||
builder.push_spec(spec);
|
||||
builder.push_spec(
|
||||
spec,
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
builder.register_handler(Arc::new(UnavailableToolHandler::new(unavailable_tool)));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,31 @@
|
||||
use crate::tools::code_mode::execute_spec::create_code_mode_tool;
|
||||
use crate::tools::code_mode::wait_spec::create_wait_tool;
|
||||
use crate::tools::handlers::ApplyPatchHandler;
|
||||
use crate::tools::handlers::CodeModeExecuteHandler;
|
||||
use crate::tools::handlers::CodeModeWaitHandler;
|
||||
use crate::tools::handlers::ContainerExecHandler;
|
||||
use crate::tools::handlers::CreateGoalHandler;
|
||||
use crate::tools::handlers::DynamicToolHandler;
|
||||
use crate::tools::handlers::ExecCommandHandler;
|
||||
use crate::tools::handlers::GetGoalHandler;
|
||||
use crate::tools::handlers::ListMcpResourceTemplatesHandler;
|
||||
use crate::tools::handlers::ListMcpResourcesHandler;
|
||||
use crate::tools::handlers::LocalShellHandler;
|
||||
use crate::tools::handlers::McpHandler;
|
||||
use crate::tools::handlers::PlanHandler;
|
||||
use crate::tools::handlers::ReadMcpResourceHandler;
|
||||
use crate::tools::handlers::RequestPermissionsHandler;
|
||||
use crate::tools::handlers::RequestPluginInstallHandler;
|
||||
use crate::tools::handlers::RequestUserInputHandler;
|
||||
use crate::tools::handlers::ShellCommandHandler;
|
||||
use crate::tools::handlers::ShellHandler;
|
||||
use crate::tools::handlers::TestSyncHandler;
|
||||
use crate::tools::handlers::ToolSearchHandler;
|
||||
use crate::tools::handlers::UpdateGoalHandler;
|
||||
use crate::tools::handlers::ViewImageHandler;
|
||||
use crate::tools::handlers::WriteStdinHandler;
|
||||
use crate::tools::handlers::agent_jobs::ReportAgentJobResultHandler;
|
||||
use crate::tools::handlers::agent_jobs::SpawnAgentsOnCsvHandler;
|
||||
use crate::tools::handlers::agent_jobs_spec::create_report_agent_job_result_tool;
|
||||
use crate::tools::handlers::agent_jobs_spec::create_spawn_agents_on_csv_tool;
|
||||
use crate::tools::handlers::apply_patch_spec::create_apply_patch_freeform_tool;
|
||||
@@ -10,6 +36,11 @@ use crate::tools::handlers::goal_spec::create_update_goal_tool;
|
||||
use crate::tools::handlers::mcp_resource_spec::create_list_mcp_resource_templates_tool;
|
||||
use crate::tools::handlers::mcp_resource_spec::create_list_mcp_resources_tool;
|
||||
use crate::tools::handlers::mcp_resource_spec::create_read_mcp_resource_tool;
|
||||
use crate::tools::handlers::multi_agents::CloseAgentHandler;
|
||||
use crate::tools::handlers::multi_agents::ResumeAgentHandler;
|
||||
use crate::tools::handlers::multi_agents::SendInputHandler;
|
||||
use crate::tools::handlers::multi_agents::SpawnAgentHandler;
|
||||
use crate::tools::handlers::multi_agents::WaitAgentHandler;
|
||||
use crate::tools::handlers::multi_agents_spec::SpawnAgentToolOptions;
|
||||
use crate::tools::handlers::multi_agents_spec::create_close_agent_tool_v1;
|
||||
use crate::tools::handlers::multi_agents_spec::create_close_agent_tool_v2;
|
||||
@@ -22,9 +53,14 @@ use crate::tools::handlers::multi_agents_spec::create_spawn_agent_tool_v1;
|
||||
use crate::tools::handlers::multi_agents_spec::create_spawn_agent_tool_v2;
|
||||
use crate::tools::handlers::multi_agents_spec::create_wait_agent_tool_v1;
|
||||
use crate::tools::handlers::multi_agents_spec::create_wait_agent_tool_v2;
|
||||
use crate::tools::handlers::multi_agents_v2::CloseAgentHandler as CloseAgentHandlerV2;
|
||||
use crate::tools::handlers::multi_agents_v2::FollowupTaskHandler as FollowupTaskHandlerV2;
|
||||
use crate::tools::handlers::multi_agents_v2::ListAgentsHandler as ListAgentsHandlerV2;
|
||||
use crate::tools::handlers::multi_agents_v2::SendMessageHandler as SendMessageHandlerV2;
|
||||
use crate::tools::handlers::multi_agents_v2::SpawnAgentHandler as SpawnAgentHandlerV2;
|
||||
use crate::tools::handlers::multi_agents_v2::WaitAgentHandler as WaitAgentHandlerV2;
|
||||
use crate::tools::handlers::plan_spec::create_update_plan_tool;
|
||||
use crate::tools::handlers::request_plugin_install_spec::create_request_plugin_install_tool;
|
||||
use crate::tools::handlers::request_user_input_spec::REQUEST_USER_INPUT_TOOL_NAME;
|
||||
use crate::tools::handlers::request_user_input_spec::create_request_user_input_tool;
|
||||
use crate::tools::handlers::request_user_input_spec::request_user_input_tool_description;
|
||||
use crate::tools::handlers::shell_spec::CommandToolOptions;
|
||||
@@ -43,17 +79,14 @@ use crate::tools::handlers::view_image_spec::create_view_image_tool;
|
||||
use crate::tools::hosted_spec::WebSearchToolOptions;
|
||||
use crate::tools::hosted_spec::create_image_generation_tool;
|
||||
use crate::tools::hosted_spec::create_web_search_tool;
|
||||
use crate::tools::spec_plan_types::ToolHandlerKind;
|
||||
use crate::tools::spec_plan_types::ToolRegistryPlan;
|
||||
use crate::tools::spec_plan_types::ToolRegistryPlanParams;
|
||||
use crate::tools::registry::ToolRegistryBuilder;
|
||||
use crate::tools::spec_plan_types::ToolRegistryBuildParams;
|
||||
use crate::tools::spec_plan_types::agent_type_description;
|
||||
use codex_protocol::openai_models::ApplyPatchToolType;
|
||||
use codex_protocol::openai_models::ConfigShellToolType;
|
||||
use codex_tools::REQUEST_PLUGIN_INSTALL_TOOL_NAME;
|
||||
use codex_tools::ResponsesApiNamespace;
|
||||
use codex_tools::ResponsesApiNamespaceTool;
|
||||
use codex_tools::TOOL_SEARCH_DEFAULT_LIMIT;
|
||||
use codex_tools::TOOL_SEARCH_TOOL_NAME;
|
||||
use codex_tools::ToolEnvironmentMode;
|
||||
use codex_tools::ToolName;
|
||||
use codex_tools::ToolSearchSource;
|
||||
@@ -68,12 +101,13 @@ use codex_tools::default_namespace_description;
|
||||
use codex_tools::dynamic_tool_to_loadable_tool_spec;
|
||||
use codex_tools::mcp_tool_to_responses_api_tool;
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn build_tool_registry_plan(
|
||||
pub fn build_tool_registry_builder(
|
||||
config: &ToolsConfig,
|
||||
params: ToolRegistryPlanParams<'_>,
|
||||
) -> ToolRegistryPlan {
|
||||
let mut plan = ToolRegistryPlan::new();
|
||||
params: ToolRegistryBuildParams<'_>,
|
||||
) -> ToolRegistryBuilder {
|
||||
let mut builder = ToolRegistryBuilder::new();
|
||||
let exec_permission_approvals_enabled = config.exec_permission_approvals_enabled;
|
||||
|
||||
if config.code_mode_enabled {
|
||||
@@ -92,22 +126,22 @@ pub fn build_tool_registry_plan(
|
||||
})
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
let nested_config = config.for_code_mode_nested_tools();
|
||||
let nested_plan = build_tool_registry_plan(
|
||||
let nested_builder = build_tool_registry_builder(
|
||||
&nested_config,
|
||||
ToolRegistryPlanParams {
|
||||
ToolRegistryBuildParams {
|
||||
discoverable_tools: None,
|
||||
..params
|
||||
},
|
||||
);
|
||||
let mut enabled_tools = collect_code_mode_exec_prompt_tool_definitions(
|
||||
nested_plan
|
||||
.specs
|
||||
nested_builder
|
||||
.specs()
|
||||
.iter()
|
||||
.map(|configured_tool| &configured_tool.spec),
|
||||
);
|
||||
enabled_tools
|
||||
.sort_by(|left, right| compare_code_mode_tools(left, right, &namespace_descriptions));
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_code_mode_tool(
|
||||
&enabled_tools,
|
||||
&namespace_descriptions,
|
||||
@@ -120,19 +154,13 @@ pub fn build_tool_registry_plan(
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler(
|
||||
codex_code_mode::PUBLIC_TOOL_NAME,
|
||||
ToolHandlerKind::CodeModeExecute,
|
||||
);
|
||||
plan.push_spec(
|
||||
builder.register_handler(Arc::new(CodeModeExecuteHandler));
|
||||
builder.push_spec(
|
||||
create_wait_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler(
|
||||
codex_code_mode::WAIT_TOOL_NAME,
|
||||
ToolHandlerKind::CodeModeWait,
|
||||
);
|
||||
builder.register_handler(Arc::new(CodeModeWaitHandler));
|
||||
}
|
||||
|
||||
if config.environment_mode.has_environment() {
|
||||
@@ -140,7 +168,7 @@ pub fn build_tool_registry_plan(
|
||||
matches!(config.environment_mode, ToolEnvironmentMode::Multiple);
|
||||
match &config.shell_type {
|
||||
ConfigShellToolType::Default => {
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_shell_tool(ShellToolOptions {
|
||||
exec_permission_approvals_enabled,
|
||||
}),
|
||||
@@ -149,14 +177,14 @@ pub fn build_tool_registry_plan(
|
||||
);
|
||||
}
|
||||
ConfigShellToolType::Local => {
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_local_shell_tool(),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
ConfigShellToolType::UnifiedExec => {
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_exec_command_tool_with_environment_id(
|
||||
CommandToolOptions {
|
||||
allow_login_shell: config.allow_login_shell,
|
||||
@@ -167,17 +195,17 @@ pub fn build_tool_registry_plan(
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_write_stdin_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler("exec_command", ToolHandlerKind::ExecCommand);
|
||||
plan.register_handler("write_stdin", ToolHandlerKind::WriteStdin);
|
||||
builder.register_handler(Arc::new(ExecCommandHandler));
|
||||
builder.register_handler(Arc::new(WriteStdinHandler));
|
||||
}
|
||||
ConfigShellToolType::Disabled => {}
|
||||
ConfigShellToolType::ShellCommand => {
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_shell_command_tool(CommandToolOptions {
|
||||
allow_login_shell: config.allow_login_shell,
|
||||
exec_permission_approvals_enabled,
|
||||
@@ -192,82 +220,80 @@ pub fn build_tool_registry_plan(
|
||||
if config.environment_mode.has_environment()
|
||||
&& config.shell_type != ConfigShellToolType::Disabled
|
||||
{
|
||||
plan.register_handler("shell", ToolHandlerKind::Shell);
|
||||
plan.register_handler("container.exec", ToolHandlerKind::ContainerExec);
|
||||
plan.register_handler("local_shell", ToolHandlerKind::LocalShell);
|
||||
plan.register_handler("shell_command", ToolHandlerKind::ShellCommand);
|
||||
builder.register_handler(Arc::new(ShellHandler));
|
||||
builder.register_handler(Arc::new(ContainerExecHandler));
|
||||
builder.register_handler(Arc::new(LocalShellHandler));
|
||||
builder.register_handler(Arc::new(ShellCommandHandler::from(
|
||||
config.shell_command_backend,
|
||||
)));
|
||||
}
|
||||
|
||||
if params.mcp_tools.is_some() {
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_list_mcp_resources_tool(),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_list_mcp_resource_templates_tool(),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_read_mcp_resource_tool(),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler("list_mcp_resources", ToolHandlerKind::ListMcpResources);
|
||||
plan.register_handler(
|
||||
"list_mcp_resource_templates",
|
||||
ToolHandlerKind::ListMcpResourceTemplates,
|
||||
);
|
||||
plan.register_handler("read_mcp_resource", ToolHandlerKind::ReadMcpResource);
|
||||
builder.register_handler(Arc::new(ListMcpResourcesHandler));
|
||||
builder.register_handler(Arc::new(ListMcpResourceTemplatesHandler));
|
||||
builder.register_handler(Arc::new(ReadMcpResourceHandler));
|
||||
}
|
||||
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_update_plan_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler("update_plan", ToolHandlerKind::Plan);
|
||||
builder.register_handler(Arc::new(PlanHandler));
|
||||
if config.goal_tools {
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_get_goal_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler("get_goal", ToolHandlerKind::GetGoal);
|
||||
plan.push_spec(
|
||||
builder.register_handler(Arc::new(GetGoalHandler));
|
||||
builder.push_spec(
|
||||
create_create_goal_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler("create_goal", ToolHandlerKind::CreateGoal);
|
||||
plan.push_spec(
|
||||
builder.register_handler(Arc::new(CreateGoalHandler));
|
||||
builder.push_spec(
|
||||
create_update_goal_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler("update_goal", ToolHandlerKind::UpdateGoal);
|
||||
builder.register_handler(Arc::new(UpdateGoalHandler));
|
||||
}
|
||||
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_request_user_input_tool(request_user_input_tool_description(
|
||||
&config.request_user_input_available_modes,
|
||||
)),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler(
|
||||
REQUEST_USER_INPUT_TOOL_NAME,
|
||||
ToolHandlerKind::RequestUserInput,
|
||||
);
|
||||
builder.register_handler(Arc::new(RequestUserInputHandler {
|
||||
available_modes: config.request_user_input_available_modes.clone(),
|
||||
}));
|
||||
|
||||
if config.request_permissions_tool_enabled {
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_request_permissions_tool(request_permissions_tool_description()),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler("request_permissions", ToolHandlerKind::RequestPermissions);
|
||||
builder.register_handler(Arc::new(RequestPermissionsHandler));
|
||||
}
|
||||
|
||||
let deferred_dynamic_tools = params
|
||||
@@ -303,35 +329,28 @@ pub fn build_tool_registry_plan(
|
||||
});
|
||||
}
|
||||
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_tool_search_tool(&search_source_infos, TOOL_SEARCH_DEFAULT_LIMIT),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler(TOOL_SEARCH_TOOL_NAME, ToolHandlerKind::ToolSearch);
|
||||
|
||||
if let Some(deferred_mcp_tools) = deferred_mcp_tools_for_search {
|
||||
for tool in deferred_mcp_tools {
|
||||
plan.register_handler(tool.name.clone(), ToolHandlerKind::Mcp);
|
||||
}
|
||||
}
|
||||
builder.register_handler(Arc::new(ToolSearchHandler::new(
|
||||
params.tool_search_entries.to_vec(),
|
||||
)));
|
||||
}
|
||||
|
||||
if config.tool_suggest
|
||||
&& let Some(discoverable_tools) =
|
||||
params.discoverable_tools.filter(|tools| !tools.is_empty())
|
||||
{
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_request_plugin_install_tool(&collect_request_plugin_install_entries(
|
||||
discoverable_tools,
|
||||
)),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
/*code_mode_enabled*/ false,
|
||||
);
|
||||
plan.register_handler(
|
||||
REQUEST_PLUGIN_INSTALL_TOOL_NAME,
|
||||
ToolHandlerKind::RequestPluginInstall,
|
||||
);
|
||||
builder.register_handler(Arc::new(RequestPluginInstallHandler));
|
||||
}
|
||||
|
||||
if config.environment_mode.has_environment()
|
||||
@@ -339,21 +358,21 @@ pub fn build_tool_registry_plan(
|
||||
{
|
||||
match apply_patch_tool_type {
|
||||
ApplyPatchToolType::Freeform => {
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_apply_patch_freeform_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
ApplyPatchToolType::Function => {
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_apply_patch_json_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
}
|
||||
plan.register_handler("apply_patch", ToolHandlerKind::ApplyPatch);
|
||||
builder.register_handler(Arc::new(ApplyPatchHandler));
|
||||
}
|
||||
|
||||
if config
|
||||
@@ -361,12 +380,12 @@ pub fn build_tool_registry_plan(
|
||||
.iter()
|
||||
.any(|tool| tool == "test_sync_tool")
|
||||
{
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_test_sync_tool(),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler("test_sync_tool", ToolHandlerKind::TestSync);
|
||||
builder.register_handler(Arc::new(TestSyncHandler));
|
||||
}
|
||||
|
||||
if let Some(web_search_tool) = create_web_search_tool(WebSearchToolOptions {
|
||||
@@ -374,7 +393,7 @@ pub fn build_tool_registry_plan(
|
||||
web_search_config: config.web_search_config.as_ref(),
|
||||
web_search_tool_type: config.web_search_tool_type,
|
||||
}) {
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
web_search_tool,
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
@@ -382,7 +401,7 @@ pub fn build_tool_registry_plan(
|
||||
}
|
||||
|
||||
if config.image_gen_tool {
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_image_generation_tool("png"),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
@@ -390,21 +409,21 @@ pub fn build_tool_registry_plan(
|
||||
}
|
||||
|
||||
if config.environment_mode.has_environment() {
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_view_image_tool(ViewImageToolOptions {
|
||||
can_request_original_image_detail: config.can_request_original_image_detail,
|
||||
}),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler("view_image", ToolHandlerKind::ViewImage);
|
||||
builder.register_handler(Arc::new(ViewImageHandler));
|
||||
}
|
||||
|
||||
if config.collab_tools {
|
||||
if config.multi_agent_v2 {
|
||||
let agent_type_description =
|
||||
agent_type_description(config, params.default_agent_type_description);
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_spawn_agent_tool_v2(SpawnAgentToolOptions {
|
||||
available_models: &config.available_models,
|
||||
agent_type_description,
|
||||
@@ -416,41 +435,41 @@ pub fn build_tool_registry_plan(
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_send_message_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_followup_task_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_wait_agent_tool_v2(params.wait_agent_timeouts),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_close_agent_tool_v2(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_list_agents_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler("spawn_agent", ToolHandlerKind::SpawnAgentV2);
|
||||
plan.register_handler("send_message", ToolHandlerKind::SendMessageV2);
|
||||
plan.register_handler("followup_task", ToolHandlerKind::FollowupTaskV2);
|
||||
plan.register_handler("wait_agent", ToolHandlerKind::WaitAgentV2);
|
||||
plan.register_handler("close_agent", ToolHandlerKind::CloseAgentV2);
|
||||
plan.register_handler("list_agents", ToolHandlerKind::ListAgentsV2);
|
||||
builder.register_handler(Arc::new(SpawnAgentHandlerV2));
|
||||
builder.register_handler(Arc::new(SendMessageHandlerV2));
|
||||
builder.register_handler(Arc::new(FollowupTaskHandlerV2));
|
||||
builder.register_handler(Arc::new(WaitAgentHandlerV2));
|
||||
builder.register_handler(Arc::new(CloseAgentHandlerV2));
|
||||
builder.register_handler(Arc::new(ListAgentsHandlerV2));
|
||||
} else {
|
||||
let agent_type_description =
|
||||
agent_type_description(config, params.default_agent_type_description);
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_spawn_agent_tool_v1(SpawnAgentToolOptions {
|
||||
available_models: &config.available_models,
|
||||
agent_type_description,
|
||||
@@ -462,51 +481,48 @@ pub fn build_tool_registry_plan(
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_send_input_tool_v1(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_resume_agent_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler("resume_agent", ToolHandlerKind::ResumeAgentV1);
|
||||
plan.push_spec(
|
||||
builder.register_handler(Arc::new(ResumeAgentHandler));
|
||||
builder.push_spec(
|
||||
create_wait_agent_tool_v1(params.wait_agent_timeouts),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_close_agent_tool_v1(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler("spawn_agent", ToolHandlerKind::SpawnAgentV1);
|
||||
plan.register_handler("send_input", ToolHandlerKind::SendInputV1);
|
||||
plan.register_handler("wait_agent", ToolHandlerKind::WaitAgentV1);
|
||||
plan.register_handler("close_agent", ToolHandlerKind::CloseAgentV1);
|
||||
builder.register_handler(Arc::new(SpawnAgentHandler));
|
||||
builder.register_handler(Arc::new(SendInputHandler));
|
||||
builder.register_handler(Arc::new(WaitAgentHandler));
|
||||
builder.register_handler(Arc::new(CloseAgentHandler));
|
||||
}
|
||||
}
|
||||
|
||||
if config.agent_jobs_tools {
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_spawn_agents_on_csv_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler("spawn_agents_on_csv", ToolHandlerKind::SpawnAgentsOnCsv);
|
||||
builder.register_handler(Arc::new(SpawnAgentsOnCsvHandler));
|
||||
if config.agent_jobs_worker_tools {
|
||||
plan.push_spec(
|
||||
builder.push_spec(
|
||||
create_report_agent_job_result_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
plan.register_handler(
|
||||
"report_agent_job_result",
|
||||
ToolHandlerKind::ReportAgentJobResult,
|
||||
);
|
||||
builder.register_handler(Arc::new(ReportAgentJobResultHandler));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,7 +564,7 @@ pub fn build_tool_registry_plan(
|
||||
match mcp_tool_to_responses_api_tool(&tool.name, tool.tool) {
|
||||
Ok(converted_tool) => {
|
||||
tools.push(ResponsesApiNamespaceTool::Function(converted_tool));
|
||||
plan.register_handler(tool.name, ToolHandlerKind::Mcp);
|
||||
builder.register_handler(Arc::new(McpHandler::new(tool.name)));
|
||||
}
|
||||
Err(error) => {
|
||||
let tool_name = &tool.name;
|
||||
@@ -559,8 +575,8 @@ pub fn build_tool_registry_plan(
|
||||
}
|
||||
}
|
||||
|
||||
if !tools.is_empty() {
|
||||
plan.push_spec(
|
||||
if config.namespace_tools && !tools.is_empty() {
|
||||
builder.push_spec(
|
||||
ToolSpec::Namespace(ResponsesApiNamespace {
|
||||
name: namespace,
|
||||
description,
|
||||
@@ -579,7 +595,7 @@ pub fn build_tool_registry_plan(
|
||||
Ok(loadable_tool) => {
|
||||
let handler_name = ToolName::new(tool.namespace.clone(), tool.name.clone());
|
||||
dynamic_tool_specs.push(loadable_tool);
|
||||
plan.register_handler(handler_name, ToolHandlerKind::DynamicTool);
|
||||
builder.register_handler(Arc::new(DynamicToolHandler::new(handler_name)));
|
||||
}
|
||||
Err(error) => {
|
||||
tracing::error!(
|
||||
@@ -590,19 +606,28 @@ pub fn build_tool_registry_plan(
|
||||
}
|
||||
}
|
||||
for spec in coalesce_loadable_tool_specs(dynamic_tool_specs) {
|
||||
plan.push_spec(
|
||||
spec.into(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
let spec = spec.into();
|
||||
if config.namespace_tools || !matches!(spec, ToolSpec::Namespace(_)) {
|
||||
builder.push_spec(
|
||||
spec,
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if !config.namespace_tools {
|
||||
plan.specs
|
||||
.retain(|configured_tool| !matches!(&configured_tool.spec, ToolSpec::Namespace(_)));
|
||||
if let Some(deferred_mcp_tools) = params.deferred_mcp_tools {
|
||||
for tool in deferred_mcp_tools {
|
||||
let registered_directly = params
|
||||
.mcp_tools
|
||||
.is_some_and(|mcp_tools| mcp_tools.iter().any(|direct| direct.name == tool.name));
|
||||
if !registered_directly {
|
||||
builder.register_handler(Arc::new(McpHandler::new(tool.name.clone())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plan
|
||||
builder
|
||||
}
|
||||
|
||||
fn compare_code_mode_tools(
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use super::*;
|
||||
use crate::tools::handlers::multi_agents_spec::WaitAgentTimeoutOptions;
|
||||
use crate::tools::handlers::request_user_input_spec::REQUEST_USER_INPUT_TOOL_NAME;
|
||||
use crate::tools::handlers::shell_spec::CommandToolOptions;
|
||||
use crate::tools::handlers::shell_spec::create_exec_command_tool;
|
||||
use crate::tools::spec_plan_types::ToolHandlerSpec;
|
||||
use crate::tools::registry::ToolRegistry;
|
||||
use crate::tools::spec_plan_types::ToolNamespace;
|
||||
use crate::tools::spec_plan_types::ToolRegistryPlanDeferredTool;
|
||||
use crate::tools::spec_plan_types::ToolRegistryPlanMcpTool;
|
||||
use crate::tools::spec_plan_types::ToolRegistryBuildDeferredTool;
|
||||
use crate::tools::spec_plan_types::ToolRegistryBuildMcpTool;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_features::Feature;
|
||||
use codex_features::Features;
|
||||
@@ -29,10 +30,12 @@ use codex_tools::FreeformTool;
|
||||
use codex_tools::JsonSchema;
|
||||
use codex_tools::JsonSchemaPrimitiveType;
|
||||
use codex_tools::JsonSchemaType;
|
||||
use codex_tools::REQUEST_PLUGIN_INSTALL_TOOL_NAME;
|
||||
use codex_tools::ResponsesApiNamespaceTool;
|
||||
use codex_tools::ResponsesApiTool;
|
||||
use codex_tools::ResponsesApiWebSearchFilters;
|
||||
use codex_tools::ResponsesApiWebSearchUserLocation;
|
||||
use codex_tools::TOOL_SEARCH_TOOL_NAME;
|
||||
use codex_tools::ToolEnvironmentMode;
|
||||
use codex_tools::ToolName;
|
||||
use codex_tools::ToolsConfigParams;
|
||||
@@ -1244,7 +1247,7 @@ fn namespace_specs_are_hidden_when_namespace_tools_are_disabled() {
|
||||
});
|
||||
tools_config.namespace_tools = false;
|
||||
|
||||
let (tools, handlers) = build_specs(
|
||||
let (tools, registry) = build_specs(
|
||||
&tools_config,
|
||||
Some(HashMap::from([(
|
||||
ToolName::namespaced("mcp__sample__", "echo"),
|
||||
@@ -1255,10 +1258,7 @@ fn namespace_specs_are_hidden_when_namespace_tools_are_disabled() {
|
||||
);
|
||||
|
||||
assert_lacks_tool_name(&tools, "mcp__sample__");
|
||||
assert!(handlers.contains(&ToolHandlerSpec {
|
||||
name: ToolName::namespaced("mcp__sample__", "echo"),
|
||||
kind: ToolHandlerKind::Mcp,
|
||||
}));
|
||||
assert!(registry.has_handler(&ToolName::namespaced("mcp__sample__", "echo")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1412,7 +1412,7 @@ fn search_tool_description_lists_each_mcp_source_once() {
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
});
|
||||
|
||||
let (tools, handlers) = build_specs(
|
||||
let (tools, registry) = build_specs(
|
||||
&tools_config,
|
||||
Some(HashMap::from([
|
||||
(
|
||||
@@ -1477,14 +1477,11 @@ fn search_tool_description_lists_each_mcp_source_once() {
|
||||
assert!(description.contains("- rmcp: Remote memory tools."));
|
||||
assert!(!description.contains("mcp__rmcp__echo"));
|
||||
|
||||
assert!(handlers.contains(&ToolHandlerSpec {
|
||||
name: ToolName::namespaced("mcp__codex_apps__calendar", "_create_event"),
|
||||
kind: ToolHandlerKind::Mcp,
|
||||
}));
|
||||
assert!(handlers.contains(&ToolHandlerSpec {
|
||||
name: ToolName::namespaced("mcp__rmcp__", "echo"),
|
||||
kind: ToolHandlerKind::Mcp,
|
||||
}));
|
||||
assert!(registry.has_handler(&ToolName::namespaced(
|
||||
"mcp__codex_apps__calendar",
|
||||
"_create_event",
|
||||
)));
|
||||
assert!(registry.has_handler(&ToolName::namespaced("mcp__rmcp__", "echo")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1578,7 +1575,7 @@ fn search_tool_is_hidden_when_only_deferred_namespace_tools_are_available() {
|
||||
});
|
||||
tools_config.namespace_tools = false;
|
||||
|
||||
let (tools, handlers) = build_specs(
|
||||
let (tools, registry) = build_specs(
|
||||
&tools_config,
|
||||
/*mcp_tools*/ None,
|
||||
Some(vec![deferred_mcp_tool(
|
||||
@@ -1592,10 +1589,7 @@ fn search_tool_is_hidden_when_only_deferred_namespace_tools_are_available() {
|
||||
);
|
||||
|
||||
assert_lacks_tool_name(&tools, TOOL_SEARCH_TOOL_NAME);
|
||||
assert!(!handlers.contains(&ToolHandlerSpec {
|
||||
name: ToolName::plain(TOOL_SEARCH_TOOL_NAME),
|
||||
kind: ToolHandlerKind::ToolSearch,
|
||||
}));
|
||||
assert!(!registry.has_handler(&ToolName::plain(TOOL_SEARCH_TOOL_NAME)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1639,7 +1633,7 @@ fn search_tool_registers_for_deferred_dynamic_tools() {
|
||||
},
|
||||
];
|
||||
|
||||
let (tools, handlers) = build_specs(
|
||||
let (tools, registry) = build_specs(
|
||||
&tools_config,
|
||||
/*mcp_tools*/ None,
|
||||
/*deferred_mcp_tools*/ None,
|
||||
@@ -1670,18 +1664,9 @@ fn search_tool_registers_for_deferred_dynamic_tools() {
|
||||
let dynamic_tool = find_namespace_function_tool(&tools, "codex_app", tool_name);
|
||||
assert_eq!(dynamic_tool.defer_loading, Some(true));
|
||||
}
|
||||
assert!(handlers.contains(&ToolHandlerSpec {
|
||||
name: ToolName::plain(TOOL_SEARCH_TOOL_NAME),
|
||||
kind: ToolHandlerKind::ToolSearch,
|
||||
}));
|
||||
assert!(handlers.contains(&ToolHandlerSpec {
|
||||
name: ToolName::namespaced("codex_app", "automation_update"),
|
||||
kind: ToolHandlerKind::DynamicTool,
|
||||
}));
|
||||
assert!(handlers.contains(&ToolHandlerSpec {
|
||||
name: ToolName::namespaced("codex_app", "automation_list"),
|
||||
kind: ToolHandlerKind::DynamicTool,
|
||||
}));
|
||||
assert!(registry.has_handler(&ToolName::plain(TOOL_SEARCH_TOOL_NAME)));
|
||||
assert!(registry.has_handler(&ToolName::namespaced("codex_app", "automation_update")));
|
||||
assert!(registry.has_handler(&ToolName::namespaced("codex_app", "automation_list")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1718,7 +1703,7 @@ fn search_tool_keeps_plain_deferred_dynamic_tools_when_namespace_tools_are_disab
|
||||
},
|
||||
];
|
||||
|
||||
let (tools, handlers) = build_specs(
|
||||
let (tools, registry) = build_specs(
|
||||
&tools_config,
|
||||
/*mcp_tools*/ None,
|
||||
/*deferred_mcp_tools*/ None,
|
||||
@@ -1727,10 +1712,7 @@ fn search_tool_keeps_plain_deferred_dynamic_tools_when_namespace_tools_are_disab
|
||||
|
||||
assert_contains_tool_names(&tools, &[TOOL_SEARCH_TOOL_NAME, "plain_dynamic"]);
|
||||
assert_lacks_tool_name(&tools, "codex_app");
|
||||
assert!(handlers.contains(&ToolHandlerSpec {
|
||||
name: ToolName::plain(TOOL_SEARCH_TOOL_NAME),
|
||||
kind: ToolHandlerKind::ToolSearch,
|
||||
}));
|
||||
assert!(registry.has_handler(&ToolName::plain(TOOL_SEARCH_TOOL_NAME)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1862,17 +1844,14 @@ fn request_plugin_install_description_lists_discoverable_tools() {
|
||||
})),
|
||||
];
|
||||
|
||||
let (tools, handlers) = build_specs_with_discoverable_tools(
|
||||
let (tools, registry) = build_specs_with_discoverable_tools(
|
||||
&tools_config,
|
||||
/*mcp_tools*/ None,
|
||||
/*deferred_mcp_tools*/ None,
|
||||
Some(discoverable_tools),
|
||||
&[],
|
||||
);
|
||||
assert!(handlers.contains(&ToolHandlerSpec {
|
||||
name: ToolName::plain(REQUEST_PLUGIN_INSTALL_TOOL_NAME),
|
||||
kind: ToolHandlerKind::RequestPluginInstall,
|
||||
}));
|
||||
assert!(registry.has_handler(&ToolName::plain(REQUEST_PLUGIN_INSTALL_TOOL_NAME)));
|
||||
|
||||
let request_plugin_install = find_tool(&tools, REQUEST_PLUGIN_INSTALL_TOOL_NAME);
|
||||
let ToolSpec::Function(ResponsesApiTool {
|
||||
@@ -2225,9 +2204,9 @@ fn search_capable_model_info() -> ModelInfo {
|
||||
fn build_specs<'a>(
|
||||
config: &ToolsConfig,
|
||||
mcp_tools: Option<HashMap<ToolName, rmcp::model::Tool>>,
|
||||
deferred_mcp_tools: Option<Vec<ToolRegistryPlanDeferredTool<'a>>>,
|
||||
deferred_mcp_tools: Option<Vec<ToolRegistryBuildDeferredTool<'a>>>,
|
||||
dynamic_tools: &[DynamicToolSpec],
|
||||
) -> (Vec<ConfiguredToolSpec>, Vec<ToolHandlerSpec>) {
|
||||
) -> (Vec<ConfiguredToolSpec>, ToolRegistry) {
|
||||
build_specs_with_discoverable_tools(
|
||||
config,
|
||||
mcp_tools,
|
||||
@@ -2240,10 +2219,10 @@ fn build_specs<'a>(
|
||||
fn build_specs_with_discoverable_tools<'a>(
|
||||
config: &ToolsConfig,
|
||||
mcp_tools: Option<HashMap<ToolName, rmcp::model::Tool>>,
|
||||
deferred_mcp_tools: Option<Vec<ToolRegistryPlanDeferredTool<'a>>>,
|
||||
deferred_mcp_tools: Option<Vec<ToolRegistryBuildDeferredTool<'a>>>,
|
||||
discoverable_tools: Option<Vec<DiscoverableTool>>,
|
||||
dynamic_tools: &[DynamicToolSpec],
|
||||
) -> (Vec<ConfiguredToolSpec>, Vec<ToolHandlerSpec>) {
|
||||
) -> (Vec<ConfiguredToolSpec>, ToolRegistry) {
|
||||
build_specs_with_optional_tool_namespaces(
|
||||
config,
|
||||
mcp_tools,
|
||||
@@ -2257,23 +2236,23 @@ fn build_specs_with_discoverable_tools<'a>(
|
||||
fn build_specs_with_optional_tool_namespaces<'a>(
|
||||
config: &ToolsConfig,
|
||||
mcp_tools: Option<HashMap<ToolName, rmcp::model::Tool>>,
|
||||
deferred_mcp_tools: Option<Vec<ToolRegistryPlanDeferredTool<'a>>>,
|
||||
deferred_mcp_tools: Option<Vec<ToolRegistryBuildDeferredTool<'a>>>,
|
||||
tool_namespaces: Option<HashMap<String, ToolNamespace>>,
|
||||
discoverable_tools: Option<Vec<DiscoverableTool>>,
|
||||
dynamic_tools: &[DynamicToolSpec],
|
||||
) -> (Vec<ConfiguredToolSpec>, Vec<ToolHandlerSpec>) {
|
||||
) -> (Vec<ConfiguredToolSpec>, ToolRegistry) {
|
||||
let mcp_tool_inputs = mcp_tools.as_ref().map(|mcp_tools| {
|
||||
mcp_tools
|
||||
.iter()
|
||||
.map(|(name, tool)| ToolRegistryPlanMcpTool {
|
||||
.map(|(name, tool)| ToolRegistryBuildMcpTool {
|
||||
name: name.clone(),
|
||||
tool,
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
let plan = build_tool_registry_plan(
|
||||
let builder = build_tool_registry_builder(
|
||||
config,
|
||||
ToolRegistryPlanParams {
|
||||
ToolRegistryBuildParams {
|
||||
mcp_tools: mcp_tool_inputs.as_deref(),
|
||||
deferred_mcp_tools: deferred_mcp_tools.as_deref(),
|
||||
tool_namespaces: tool_namespaces.as_ref(),
|
||||
@@ -2281,9 +2260,10 @@ fn build_specs_with_optional_tool_namespaces<'a>(
|
||||
dynamic_tools,
|
||||
default_agent_type_description: DEFAULT_AGENT_TYPE_DESCRIPTION,
|
||||
wait_agent_timeouts: wait_agent_timeout_options(),
|
||||
tool_search_entries: &[],
|
||||
},
|
||||
);
|
||||
(plan.specs, plan.handlers)
|
||||
builder.build()
|
||||
}
|
||||
|
||||
fn mcp_tool(name: &str, description: &str, input_schema: serde_json::Value) -> rmcp::model::Tool {
|
||||
@@ -2397,8 +2377,8 @@ fn deferred_mcp_tool<'a>(
|
||||
server_name: &'a str,
|
||||
connector_name: Option<&'a str>,
|
||||
description: Option<&'a str>,
|
||||
) -> ToolRegistryPlanDeferredTool<'a> {
|
||||
ToolRegistryPlanDeferredTool {
|
||||
) -> ToolRegistryBuildDeferredTool<'a> {
|
||||
ToolRegistryBuildDeferredTool {
|
||||
name: ToolName::namespaced(tool_namespace, tool_name),
|
||||
server_name,
|
||||
connector_name,
|
||||
|
||||
@@ -1,75 +1,20 @@
|
||||
use crate::tools::handlers::multi_agents_spec::WaitAgentTimeoutOptions;
|
||||
use codex_protocol::dynamic_tools::DynamicToolSpec;
|
||||
use codex_tools::ConfiguredToolSpec;
|
||||
use codex_tools::DiscoverableTool;
|
||||
use codex_tools::ToolName;
|
||||
use codex_tools::ToolSpec;
|
||||
use codex_tools::ToolsConfig;
|
||||
use codex_tools::augment_tool_spec_for_code_mode;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ToolHandlerKind {
|
||||
ApplyPatch,
|
||||
CloseAgentV1,
|
||||
CloseAgentV2,
|
||||
CodeModeExecute,
|
||||
CodeModeWait,
|
||||
ContainerExec,
|
||||
CreateGoal,
|
||||
DynamicTool,
|
||||
ExecCommand,
|
||||
FollowupTaskV2,
|
||||
GetGoal,
|
||||
ListAgentsV2,
|
||||
ListMcpResourceTemplates,
|
||||
ListMcpResources,
|
||||
LocalShell,
|
||||
Mcp,
|
||||
Plan,
|
||||
ReadMcpResource,
|
||||
ReportAgentJobResult,
|
||||
RequestPluginInstall,
|
||||
RequestPermissions,
|
||||
RequestUserInput,
|
||||
ResumeAgentV1,
|
||||
SendInputV1,
|
||||
SendMessageV2,
|
||||
Shell,
|
||||
ShellCommand,
|
||||
SpawnAgentsOnCsv,
|
||||
SpawnAgentV1,
|
||||
SpawnAgentV2,
|
||||
TestSync,
|
||||
ToolSearch,
|
||||
UpdateGoal,
|
||||
ViewImage,
|
||||
WaitAgentV1,
|
||||
WaitAgentV2,
|
||||
WriteStdin,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ToolHandlerSpec {
|
||||
pub name: ToolName,
|
||||
pub kind: ToolHandlerKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ToolRegistryPlan {
|
||||
pub specs: Vec<ConfiguredToolSpec>,
|
||||
pub handlers: Vec<ToolHandlerSpec>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ToolRegistryPlanParams<'a> {
|
||||
pub mcp_tools: Option<&'a [ToolRegistryPlanMcpTool<'a>]>,
|
||||
pub deferred_mcp_tools: Option<&'a [ToolRegistryPlanDeferredTool<'a>]>,
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ToolRegistryBuildParams<'a> {
|
||||
pub mcp_tools: Option<&'a [ToolRegistryBuildMcpTool<'a>]>,
|
||||
pub deferred_mcp_tools: Option<&'a [ToolRegistryBuildDeferredTool<'a>]>,
|
||||
pub tool_namespaces: Option<&'a HashMap<String, ToolNamespace>>,
|
||||
pub discoverable_tools: Option<&'a [DiscoverableTool]>,
|
||||
pub dynamic_tools: &'a [DynamicToolSpec],
|
||||
pub default_agent_type_description: &'a str,
|
||||
pub wait_agent_timeouts: WaitAgentTimeoutOptions,
|
||||
pub tool_search_entries: &'a [crate::tools::tool_search_entry::ToolSearchEntry],
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@@ -82,50 +27,19 @@ pub struct ToolNamespace {
|
||||
/// while registering its runtime handler with the canonical namespace/name
|
||||
/// identity.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ToolRegistryPlanMcpTool<'a> {
|
||||
pub struct ToolRegistryBuildMcpTool<'a> {
|
||||
pub name: ToolName,
|
||||
pub tool: &'a rmcp::model::Tool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ToolRegistryPlanDeferredTool<'a> {
|
||||
pub struct ToolRegistryBuildDeferredTool<'a> {
|
||||
pub name: ToolName,
|
||||
pub server_name: &'a str,
|
||||
pub connector_name: Option<&'a str>,
|
||||
pub description: Option<&'a str>,
|
||||
}
|
||||
|
||||
impl ToolRegistryPlan {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
specs: Vec::new(),
|
||||
handlers: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn push_spec(
|
||||
&mut self,
|
||||
spec: ToolSpec,
|
||||
supports_parallel_tool_calls: bool,
|
||||
code_mode_enabled: bool,
|
||||
) {
|
||||
let spec = if code_mode_enabled {
|
||||
augment_tool_spec_for_code_mode(spec)
|
||||
} else {
|
||||
spec
|
||||
};
|
||||
self.specs
|
||||
.push(ConfiguredToolSpec::new(spec, supports_parallel_tool_calls));
|
||||
}
|
||||
|
||||
pub(crate) fn register_handler(&mut self, name: impl Into<ToolName>, kind: ToolHandlerKind) {
|
||||
self.handlers.push(ToolHandlerSpec {
|
||||
name: name.into(),
|
||||
kind,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn agent_type_description(
|
||||
config: &ToolsConfig,
|
||||
default_agent_type_description: &str,
|
||||
|
||||
Reference in New Issue
Block a user