mirror of
https://github.com/openai/codex.git
synced 2026-06-01 19:02:59 +00:00
Extract tool registry planning into codex-tools (#16513)
## Why This is a larger step in the `codex-core` -> `codex-tools` migration called out in `AGENTS.md`. `codex-rs/core/src/tools/spec.rs` had become mostly pure tool-spec assembly plus handler registration. That made it hard to move more of the tool-definition layer into `codex-tools`, because the runtime binding and the crate-independent planning logic were still interleaved in one function. Splitting those concerns gives `codex-tools` ownership of the declarative registry plan while keeping `codex-core` responsible for instantiating concrete handlers. ## What Changed - Add a `codex-tools` registry-plan layer in `codex-rs/tools/src/tool_registry_plan.rs` and `codex-rs/tools/src/tool_registry_plan_types.rs`. - Move feature-gated tool-spec assembly, MCP/dynamic tool conversion, tool-search aliases, and code-mode nested-plan expansion into `codex-tools`. - Keep `codex-rs/core/src/tools/spec.rs` as the core-side adapter that maps each planned handler kind to concrete runtime handler instances. - Update `spec_tests.rs` to import the moved `codex_tools` symbols directly instead of relying on top-level `spec.rs` re-exports. 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` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16513). * #16521 * __->__ #16513
This commit is contained in:
@@ -1,79 +1,23 @@
|
||||
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::handlers::agent_jobs::BatchJobHandler;
|
||||
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::registry::ToolRegistryBuilder;
|
||||
use crate::tools::registry::tool_handler_key;
|
||||
use codex_mcp::mcp::CODEX_APPS_MCP_SERVER_NAME;
|
||||
use codex_mcp::mcp_connection_manager::ToolInfo;
|
||||
use codex_protocol::dynamic_tools::DynamicToolSpec;
|
||||
use codex_protocol::openai_models::ApplyPatchToolType;
|
||||
use codex_protocol::openai_models::ConfigShellToolType;
|
||||
use codex_tools::CommandToolOptions;
|
||||
use codex_tools::DiscoverableTool;
|
||||
use codex_tools::REQUEST_USER_INPUT_TOOL_NAME;
|
||||
use codex_tools::ShellToolOptions;
|
||||
use codex_tools::SpawnAgentToolOptions;
|
||||
use codex_tools::TOOL_SEARCH_DEFAULT_LIMIT;
|
||||
use codex_tools::TOOL_SEARCH_TOOL_NAME;
|
||||
use codex_tools::TOOL_SUGGEST_TOOL_NAME;
|
||||
use codex_tools::ToolSearchAppSource;
|
||||
use codex_tools::ToolSpec;
|
||||
use codex_tools::ToolHandlerKind;
|
||||
use codex_tools::ToolRegistryPlanAppTool;
|
||||
use codex_tools::ToolRegistryPlanParams;
|
||||
use codex_tools::ToolUserShellType;
|
||||
use codex_tools::ToolsConfig;
|
||||
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;
|
||||
use codex_tools::create_apply_patch_json_tool;
|
||||
use codex_tools::create_assign_task_tool;
|
||||
use codex_tools::create_close_agent_tool_v1;
|
||||
use codex_tools::create_close_agent_tool_v2;
|
||||
use codex_tools::create_code_mode_tool;
|
||||
use codex_tools::create_exec_command_tool;
|
||||
use codex_tools::create_image_generation_tool;
|
||||
use codex_tools::create_js_repl_reset_tool;
|
||||
use codex_tools::create_js_repl_tool;
|
||||
use codex_tools::create_list_agents_tool;
|
||||
use codex_tools::create_list_dir_tool;
|
||||
use codex_tools::create_list_mcp_resource_templates_tool;
|
||||
use codex_tools::create_list_mcp_resources_tool;
|
||||
use codex_tools::create_local_shell_tool;
|
||||
use codex_tools::create_read_mcp_resource_tool;
|
||||
use codex_tools::create_report_agent_job_result_tool;
|
||||
use codex_tools::create_request_permissions_tool;
|
||||
use codex_tools::create_request_user_input_tool;
|
||||
use codex_tools::create_resume_agent_tool;
|
||||
use codex_tools::create_send_input_tool_v1;
|
||||
use codex_tools::create_send_message_tool;
|
||||
use codex_tools::create_shell_command_tool;
|
||||
use codex_tools::create_shell_tool;
|
||||
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_update_plan_tool;
|
||||
use codex_tools::create_view_image_tool;
|
||||
use codex_tools::create_wait_agent_tool_v1;
|
||||
use codex_tools::create_wait_agent_tool_v2;
|
||||
use codex_tools::create_wait_tool;
|
||||
use codex_tools::create_web_search_tool;
|
||||
use codex_tools::create_write_stdin_tool;
|
||||
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::build_tool_registry_plan;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) use codex_tools::mcp_call_tool_result_output_schema;
|
||||
@@ -88,32 +32,6 @@ pub(crate) fn tool_user_shell_type(user_shell: &Shell) -> ToolUserShellType {
|
||||
}
|
||||
}
|
||||
|
||||
fn agent_type_description(config: &ToolsConfig) -> String {
|
||||
if config.agent_type_description.is_empty() {
|
||||
crate::agent::role::spawn_tool_spec::build(&std::collections::BTreeMap::new())
|
||||
} else {
|
||||
config.agent_type_description.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn push_tool_spec(
|
||||
builder: &mut ToolRegistryBuilder,
|
||||
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
|
||||
};
|
||||
if supports_parallel_tool_calls {
|
||||
builder.push_spec_with_parallel_support(spec, /*supports_parallel_tool_calls*/ true);
|
||||
} else {
|
||||
builder.push_spec(spec);
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds the tool registry builder while collecting tool specs for later serialization.
|
||||
#[cfg(test)]
|
||||
pub(crate) fn build_specs(
|
||||
@@ -168,10 +86,38 @@ pub(crate) fn build_specs_with_discoverable_tools(
|
||||
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 std::sync::Arc;
|
||||
|
||||
let mut builder = ToolRegistryBuilder::new();
|
||||
|
||||
let app_tool_sources = app_tools.as_ref().map(|app_tools| {
|
||||
app_tools
|
||||
.values()
|
||||
.map(|tool| ToolRegistryPlanAppTool {
|
||||
tool_name: tool.tool_name.as_str(),
|
||||
tool_namespace: tool.tool_namespace.as_str(),
|
||||
server_name: tool.server_name.as_str(),
|
||||
connector_name: tool.connector_name.as_deref(),
|
||||
connector_description: tool.connector_description.as_deref(),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
let default_agent_type_description =
|
||||
crate::agent::role::spawn_tool_spec::build(&std::collections::BTreeMap::new());
|
||||
let plan = build_tool_registry_plan(
|
||||
config,
|
||||
ToolRegistryPlanParams {
|
||||
mcp_tools: mcp_tools.as_ref(),
|
||||
app_tools: app_tool_sources.as_deref(),
|
||||
discoverable_tools: discoverable_tools.as_deref(),
|
||||
dynamic_tools,
|
||||
default_agent_type_description: &default_agent_type_description,
|
||||
wait_agent_timeouts: WaitAgentTimeoutOptions {
|
||||
default_timeout_ms: DEFAULT_WAIT_TIMEOUT_MS,
|
||||
min_timeout_ms: MIN_WAIT_TIMEOUT_MS,
|
||||
max_timeout_ms: MAX_WAIT_TIMEOUT_MS,
|
||||
},
|
||||
codex_apps_mcp_server_name: CODEX_APPS_MCP_SERVER_NAME,
|
||||
},
|
||||
);
|
||||
let shell_handler = Arc::new(ShellHandler);
|
||||
let unified_exec_handler = Arc::new(UnifiedExecHandler);
|
||||
let plan_handler = Arc::new(PlanHandler);
|
||||
@@ -185,468 +131,130 @@ pub(crate) fn build_specs_with_discoverable_tools(
|
||||
let request_user_input_handler = Arc::new(RequestUserInputHandler {
|
||||
default_mode_request_user_input: config.default_mode_request_user_input,
|
||||
});
|
||||
let mut tool_search_handler = None;
|
||||
let tool_suggest_handler = Arc::new(ToolSuggestHandler);
|
||||
let code_mode_handler = Arc::new(CodeModeExecuteHandler);
|
||||
let code_mode_wait_handler = Arc::new(CodeModeWaitHandler);
|
||||
let js_repl_handler = Arc::new(JsReplHandler);
|
||||
let js_repl_reset_handler = Arc::new(JsReplResetHandler);
|
||||
let exec_permission_approvals_enabled = config.exec_permission_approvals_enabled;
|
||||
|
||||
if config.code_mode_enabled {
|
||||
let nested_config = config.for_code_mode_nested_tools();
|
||||
let (nested_specs, _) = build_specs_with_discoverable_tools(
|
||||
&nested_config,
|
||||
mcp_tools.clone(),
|
||||
app_tools.clone(),
|
||||
/*discoverable_tools*/ None,
|
||||
dynamic_tools,
|
||||
)
|
||||
.build();
|
||||
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),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler(PUBLIC_TOOL_NAME, code_mode_handler);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_wait_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler(WAIT_TOOL_NAME, code_mode_wait_handler);
|
||||
}
|
||||
|
||||
match &config.shell_type {
|
||||
ConfigShellToolType::Default => {
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_shell_tool(ShellToolOptions {
|
||||
exec_permission_approvals_enabled,
|
||||
}),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
for spec in plan.specs {
|
||||
if spec.supports_parallel_tool_calls {
|
||||
builder.push_spec_with_parallel_support(
|
||||
spec.spec, /*supports_parallel_tool_calls*/ true,
|
||||
);
|
||||
}
|
||||
ConfigShellToolType::Local => {
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_local_shell_tool(),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
ConfigShellToolType::UnifiedExec => {
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_exec_command_tool(CommandToolOptions {
|
||||
allow_login_shell: config.allow_login_shell,
|
||||
exec_permission_approvals_enabled,
|
||||
}),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_write_stdin_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler("exec_command", unified_exec_handler.clone());
|
||||
builder.register_handler("write_stdin", unified_exec_handler);
|
||||
}
|
||||
ConfigShellToolType::Disabled => {
|
||||
// Do nothing.
|
||||
}
|
||||
ConfigShellToolType::ShellCommand => {
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_shell_command_tool(CommandToolOptions {
|
||||
allow_login_shell: config.allow_login_shell,
|
||||
exec_permission_approvals_enabled,
|
||||
}),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if config.shell_type != ConfigShellToolType::Disabled {
|
||||
// Always register shell aliases so older prompts remain compatible.
|
||||
builder.register_handler("shell", shell_handler.clone());
|
||||
builder.register_handler("container.exec", shell_handler.clone());
|
||||
builder.register_handler("local_shell", shell_handler);
|
||||
builder.register_handler("shell_command", shell_command_handler);
|
||||
}
|
||||
|
||||
if mcp_tools.is_some() {
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_list_mcp_resources_tool(),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_list_mcp_resource_templates_tool(),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_read_mcp_resource_tool(),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler("list_mcp_resources", mcp_resource_handler.clone());
|
||||
builder.register_handler("list_mcp_resource_templates", mcp_resource_handler.clone());
|
||||
builder.register_handler("read_mcp_resource", mcp_resource_handler);
|
||||
}
|
||||
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_update_plan_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler("update_plan", plan_handler);
|
||||
|
||||
if config.js_repl_enabled {
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_js_repl_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_js_repl_reset_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler("js_repl", js_repl_handler);
|
||||
builder.register_handler("js_repl_reset", js_repl_reset_handler);
|
||||
}
|
||||
|
||||
if config.request_user_input {
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_request_user_input_tool(request_user_input_tool_description(
|
||||
config.default_mode_request_user_input,
|
||||
)),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler(REQUEST_USER_INPUT_TOOL_NAME, request_user_input_handler);
|
||||
}
|
||||
|
||||
if config.request_permissions_tool_enabled {
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_request_permissions_tool(request_permissions_tool_description()),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler("request_permissions", request_permissions_handler);
|
||||
}
|
||||
|
||||
if config.search_tool
|
||||
&& let Some(app_tools) = app_tools
|
||||
{
|
||||
let search_tool_handler = Arc::new(ToolSearchHandler::new(app_tools.clone()));
|
||||
let search_app_infos = collect_tool_search_app_infos(
|
||||
app_tools.values().map(|tool| ToolSearchAppSource {
|
||||
server_name: &tool.server_name,
|
||||
connector_name: tool.connector_name.as_deref(),
|
||||
connector_description: tool.connector_description.as_deref(),
|
||||
}),
|
||||
CODEX_APPS_MCP_SERVER_NAME,
|
||||
);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_tool_search_tool(&search_app_infos, TOOL_SEARCH_DEFAULT_LIMIT),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler(TOOL_SEARCH_TOOL_NAME, search_tool_handler);
|
||||
|
||||
for tool in app_tools.values() {
|
||||
let alias_name =
|
||||
tool_handler_key(tool.tool_name.as_str(), Some(tool.tool_namespace.as_str()));
|
||||
|
||||
builder.register_handler(alias_name, mcp_handler.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if config.tool_suggest
|
||||
&& let Some(discoverable_tools) = discoverable_tools
|
||||
.as_ref()
|
||||
.filter(|tools| !tools.is_empty())
|
||||
{
|
||||
builder.push_spec_with_parallel_support(
|
||||
create_tool_suggest_tool(&collect_tool_suggest_entries(discoverable_tools)),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
);
|
||||
builder.register_handler(TOOL_SUGGEST_TOOL_NAME, tool_suggest_handler);
|
||||
}
|
||||
|
||||
if let Some(apply_patch_tool_type) = &config.apply_patch_tool_type {
|
||||
match apply_patch_tool_type {
|
||||
ApplyPatchToolType::Freeform => {
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_apply_patch_freeform_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
ApplyPatchToolType::Function => {
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_apply_patch_json_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
}
|
||||
builder.register_handler("apply_patch", apply_patch_handler);
|
||||
}
|
||||
|
||||
if config
|
||||
.experimental_supported_tools
|
||||
.iter()
|
||||
.any(|tool| tool == "list_dir")
|
||||
{
|
||||
let list_dir_handler = Arc::new(ListDirHandler);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_list_dir_tool(),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler("list_dir", list_dir_handler);
|
||||
}
|
||||
|
||||
if config
|
||||
.experimental_supported_tools
|
||||
.contains(&"test_sync_tool".to_string())
|
||||
{
|
||||
let test_sync_handler = Arc::new(TestSyncHandler);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_test_sync_tool(),
|
||||
/*supports_parallel_tool_calls*/ true,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler("test_sync_tool", test_sync_handler);
|
||||
}
|
||||
|
||||
if let Some(web_search_tool) = create_web_search_tool(WebSearchToolOptions {
|
||||
web_search_mode: config.web_search_mode,
|
||||
web_search_config: config.web_search_config.as_ref(),
|
||||
web_search_tool_type: config.web_search_tool_type,
|
||||
}) {
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
web_search_tool,
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
|
||||
if config.image_gen_tool {
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_image_generation_tool("png"),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
}
|
||||
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
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,
|
||||
);
|
||||
builder.register_handler("view_image", view_image_handler);
|
||||
|
||||
if config.collab_tools {
|
||||
if config.multi_agent_v2 {
|
||||
let agent_type_description = agent_type_description(config);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_spawn_agent_tool_v2(SpawnAgentToolOptions {
|
||||
available_models: &config.available_models,
|
||||
agent_type_description,
|
||||
}),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_send_message_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_assign_task_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_wait_agent_tool_v2(WaitAgentTimeoutOptions {
|
||||
default_timeout_ms: DEFAULT_WAIT_TIMEOUT_MS,
|
||||
min_timeout_ms: MIN_WAIT_TIMEOUT_MS,
|
||||
max_timeout_ms: MAX_WAIT_TIMEOUT_MS,
|
||||
}),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_close_agent_tool_v2(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_list_agents_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler("spawn_agent", Arc::new(SpawnAgentHandlerV2));
|
||||
builder.register_handler("send_message", Arc::new(SendMessageHandlerV2));
|
||||
builder.register_handler("assign_task", Arc::new(AssignTaskHandlerV2));
|
||||
builder.register_handler("wait_agent", Arc::new(WaitAgentHandlerV2));
|
||||
builder.register_handler("close_agent", Arc::new(CloseAgentHandlerV2));
|
||||
builder.register_handler("list_agents", Arc::new(ListAgentsHandlerV2));
|
||||
} else {
|
||||
let agent_type_description = agent_type_description(config);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_spawn_agent_tool_v1(SpawnAgentToolOptions {
|
||||
available_models: &config.available_models,
|
||||
agent_type_description,
|
||||
}),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_send_input_tool_v1(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_resume_agent_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler("resume_agent", Arc::new(ResumeAgentHandler));
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_wait_agent_tool_v1(WaitAgentTimeoutOptions {
|
||||
default_timeout_ms: DEFAULT_WAIT_TIMEOUT_MS,
|
||||
min_timeout_ms: MIN_WAIT_TIMEOUT_MS,
|
||||
max_timeout_ms: MAX_WAIT_TIMEOUT_MS,
|
||||
}),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_close_agent_tool_v1(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler("spawn_agent", Arc::new(SpawnAgentHandler));
|
||||
builder.register_handler("send_input", Arc::new(SendInputHandler));
|
||||
builder.register_handler("wait_agent", Arc::new(WaitAgentHandler));
|
||||
builder.register_handler("close_agent", Arc::new(CloseAgentHandler));
|
||||
builder.push_spec(spec.spec);
|
||||
}
|
||||
}
|
||||
|
||||
if config.agent_jobs_tools {
|
||||
let agent_jobs_handler = Arc::new(BatchJobHandler);
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_spawn_agents_on_csv_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler("spawn_agents_on_csv", agent_jobs_handler.clone());
|
||||
if config.agent_jobs_worker_tools {
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
create_report_agent_job_result_tool(),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler("report_agent_job_result", agent_jobs_handler);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(mcp_tools) = mcp_tools {
|
||||
let mut entries: Vec<(String, rmcp::model::Tool)> = mcp_tools.into_iter().collect();
|
||||
entries.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
|
||||
for (name, tool) in entries.into_iter() {
|
||||
match mcp_tool_to_responses_api_tool(name.clone(), &tool) {
|
||||
Ok(converted_tool) => {
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
ToolSpec::Function(converted_tool),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler(name, mcp_handler.clone());
|
||||
for handler in plan.handlers {
|
||||
match handler.kind {
|
||||
ToolHandlerKind::AgentJobs => {
|
||||
builder.register_handler(handler.name, Arc::new(BatchJobHandler));
|
||||
}
|
||||
ToolHandlerKind::ApplyPatch => {
|
||||
builder.register_handler(handler.name, apply_patch_handler.clone());
|
||||
}
|
||||
ToolHandlerKind::AssignTaskV2 => {
|
||||
builder.register_handler(handler.name, Arc::new(AssignTaskHandlerV2));
|
||||
}
|
||||
ToolHandlerKind::CloseAgentV1 => {
|
||||
builder.register_handler(handler.name, Arc::new(CloseAgentHandler));
|
||||
}
|
||||
ToolHandlerKind::CloseAgentV2 => {
|
||||
builder.register_handler(handler.name, Arc::new(CloseAgentHandlerV2));
|
||||
}
|
||||
ToolHandlerKind::CodeModeExecute => {
|
||||
builder.register_handler(handler.name, code_mode_handler.clone());
|
||||
}
|
||||
ToolHandlerKind::CodeModeWait => {
|
||||
builder.register_handler(handler.name, code_mode_wait_handler.clone());
|
||||
}
|
||||
ToolHandlerKind::DynamicTool => {
|
||||
builder.register_handler(handler.name, dynamic_tool_handler.clone());
|
||||
}
|
||||
ToolHandlerKind::JsRepl => {
|
||||
builder.register_handler(handler.name, js_repl_handler.clone());
|
||||
}
|
||||
ToolHandlerKind::JsReplReset => {
|
||||
builder.register_handler(handler.name, js_repl_reset_handler.clone());
|
||||
}
|
||||
ToolHandlerKind::ListAgentsV2 => {
|
||||
builder.register_handler(handler.name, Arc::new(ListAgentsHandlerV2));
|
||||
}
|
||||
ToolHandlerKind::ListDir => {
|
||||
builder.register_handler(handler.name, Arc::new(ListDirHandler));
|
||||
}
|
||||
ToolHandlerKind::Mcp => {
|
||||
builder.register_handler(handler.name, mcp_handler.clone());
|
||||
}
|
||||
ToolHandlerKind::McpResource => {
|
||||
builder.register_handler(handler.name, mcp_resource_handler.clone());
|
||||
}
|
||||
ToolHandlerKind::Plan => {
|
||||
builder.register_handler(handler.name, plan_handler.clone());
|
||||
}
|
||||
ToolHandlerKind::RequestPermissions => {
|
||||
builder.register_handler(handler.name, request_permissions_handler.clone());
|
||||
}
|
||||
ToolHandlerKind::RequestUserInput => {
|
||||
builder.register_handler(handler.name, request_user_input_handler.clone());
|
||||
}
|
||||
ToolHandlerKind::ResumeAgentV1 => {
|
||||
builder.register_handler(handler.name, Arc::new(ResumeAgentHandler));
|
||||
}
|
||||
ToolHandlerKind::SendInputV1 => {
|
||||
builder.register_handler(handler.name, Arc::new(SendInputHandler));
|
||||
}
|
||||
ToolHandlerKind::SendMessageV2 => {
|
||||
builder.register_handler(handler.name, Arc::new(SendMessageHandlerV2));
|
||||
}
|
||||
ToolHandlerKind::Shell => {
|
||||
builder.register_handler(handler.name, shell_handler.clone());
|
||||
}
|
||||
ToolHandlerKind::ShellCommand => {
|
||||
builder.register_handler(handler.name, shell_command_handler.clone());
|
||||
}
|
||||
ToolHandlerKind::SpawnAgentV1 => {
|
||||
builder.register_handler(handler.name, Arc::new(SpawnAgentHandler));
|
||||
}
|
||||
ToolHandlerKind::SpawnAgentV2 => {
|
||||
builder.register_handler(handler.name, Arc::new(SpawnAgentHandlerV2));
|
||||
}
|
||||
ToolHandlerKind::TestSync => {
|
||||
builder.register_handler(handler.name, Arc::new(TestSyncHandler));
|
||||
}
|
||||
ToolHandlerKind::ToolSearch => {
|
||||
if tool_search_handler.is_none() {
|
||||
tool_search_handler = app_tools
|
||||
.as_ref()
|
||||
.map(|app_tools| Arc::new(ToolSearchHandler::new(app_tools.clone())));
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to convert {name:?} MCP tool to OpenAI tool: {e:?}");
|
||||
if let Some(tool_search_handler) = tool_search_handler.as_ref() {
|
||||
builder.register_handler(handler.name, tool_search_handler.clone());
|
||||
}
|
||||
}
|
||||
ToolHandlerKind::ToolSuggest => {
|
||||
builder.register_handler(handler.name, tool_suggest_handler.clone());
|
||||
}
|
||||
ToolHandlerKind::UnifiedExec => {
|
||||
builder.register_handler(handler.name, unified_exec_handler.clone());
|
||||
}
|
||||
ToolHandlerKind::ViewImage => {
|
||||
builder.register_handler(handler.name, view_image_handler.clone());
|
||||
}
|
||||
ToolHandlerKind::WaitAgentV1 => {
|
||||
builder.register_handler(handler.name, Arc::new(WaitAgentHandler));
|
||||
}
|
||||
ToolHandlerKind::WaitAgentV2 => {
|
||||
builder.register_handler(handler.name, Arc::new(WaitAgentHandlerV2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !dynamic_tools.is_empty() {
|
||||
for tool in dynamic_tools {
|
||||
match dynamic_tool_to_responses_api_tool(tool) {
|
||||
Ok(converted_tool) => {
|
||||
push_tool_spec(
|
||||
&mut builder,
|
||||
ToolSpec::Function(converted_tool),
|
||||
/*supports_parallel_tool_calls*/ false,
|
||||
config.code_mode_enabled,
|
||||
);
|
||||
builder.register_handler(tool.name.clone(), dynamic_tool_handler.clone());
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
"Failed to convert dynamic tool {:?} to OpenAI tool: {e:?}",
|
||||
tool.name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
builder
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "spec_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::models_manager::model_info::with_config_overrides;
|
||||
use crate::shell::Shell;
|
||||
use crate::shell::ShellType;
|
||||
use crate::tools::ToolRouter;
|
||||
use crate::tools::registry::tool_handler_key;
|
||||
use crate::tools::router::ToolRouterParams;
|
||||
use codex_app_server_protocol::AppInfo;
|
||||
use codex_features::Feature;
|
||||
@@ -13,6 +14,7 @@ use codex_protocol::config_types::WebSearchConfig;
|
||||
use codex_protocol::config_types::WebSearchMode;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::VIEW_IMAGE_TOOL_NAME;
|
||||
use codex_protocol::openai_models::ConfigShellToolType;
|
||||
use codex_protocol::openai_models::InputModality;
|
||||
use codex_protocol::openai_models::ModelInfo;
|
||||
use codex_protocol::openai_models::ModelsResponse;
|
||||
@@ -32,6 +34,9 @@ use codex_tools::ResponsesApiWebSearchFilters;
|
||||
use codex_tools::ResponsesApiWebSearchUserLocation;
|
||||
use codex_tools::ShellCommandBackendConfig;
|
||||
use codex_tools::SpawnAgentToolOptions;
|
||||
use codex_tools::TOOL_SEARCH_TOOL_NAME;
|
||||
use codex_tools::TOOL_SUGGEST_TOOL_NAME;
|
||||
use codex_tools::ToolSpec;
|
||||
use codex_tools::ToolsConfig;
|
||||
use codex_tools::ToolsConfigParams;
|
||||
use codex_tools::UnifiedExecShellMode;
|
||||
@@ -203,6 +208,14 @@ fn spawn_agent_tool_options(config: &ToolsConfig) -> SpawnAgentToolOptions<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
fn agent_type_description(config: &ToolsConfig) -> String {
|
||||
if config.agent_type_description.is_empty() {
|
||||
crate::agent::role::spawn_tool_spec::build(&BTreeMap::new())
|
||||
} else {
|
||||
config.agent_type_description.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn wait_agent_timeout_options() -> WaitAgentTimeoutOptions {
|
||||
WaitAgentTimeoutOptions {
|
||||
default_timeout_ms: DEFAULT_WAIT_TIMEOUT_MS,
|
||||
|
||||
Reference in New Issue
Block a user