From 5c74f888147532fa7d68e6b3591174fd67170a62 Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Fri, 27 Feb 2026 23:40:49 -0500 Subject: [PATCH] Consolidate tool registration into register_core_tools All three provider profiles (Anthropic, OpenAI, Gemini) independently registered the same 7 core tools (read_file, write_file, shell, grep, glob, web_search, web_fetch). Extract a shared register_core_tools() function in tools.rs that accepts a ToolRegistry, SessionConfig (for shell timeout customization), and optional WebFetchSummarizer. Each profile now calls register_core_tools() then adds its profile-specific tools: - Anthropic: edit_file (with 120s shell timeout via config) - OpenAI: apply_patch (default 10s shell timeout) - Gemini: edit_file, read_many_files, list_dir (default 10s shell timeout) Co-Authored-By: Claude Opus 4.6 (1M context) --- crates/agent/src/lib.rs | 2 +- crates/agent/src/profiles/anthropic.rs | 14 ++------------ crates/agent/src/profiles/gemini.rs | 17 ++++++----------- crates/agent/src/profiles/openai.rs | 15 ++++----------- crates/agent/src/tools.rs | 24 ++++++++++++++++++++++-- 5 files changed, 35 insertions(+), 37 deletions(-) diff --git a/crates/agent/src/lib.rs b/crates/agent/src/lib.rs index 288d14c9d..7b2b2ed47 100644 --- a/crates/agent/src/lib.rs +++ b/crates/agent/src/lib.rs @@ -44,7 +44,7 @@ pub use subagent::{SubAgent, SubAgentEventCallback, SubAgentManager, SubAgentRes pub use tool_registry::ToolRegistry; pub use tools::{ make_edit_file_tool, make_glob_tool, make_grep_tool, make_read_file_tool, make_shell_tool, - make_shell_tool_with_config, make_write_file_tool, WebFetchSummarizer, + make_shell_tool_with_config, make_write_file_tool, register_core_tools, WebFetchSummarizer, }; pub use truncation::{truncate_lines, truncate_output, truncate_tool_output, TruncationMode}; pub use types::{AgentEvent, SessionEvent, SessionState, Turn}; diff --git a/crates/agent/src/profiles/anthropic.rs b/crates/agent/src/profiles/anthropic.rs index 017c18424..77e6d03c1 100644 --- a/crates/agent/src/profiles/anthropic.rs +++ b/crates/agent/src/profiles/anthropic.rs @@ -5,11 +5,7 @@ use crate::profiles::BaseProfile; use crate::provider_profile::{ProfileCapabilities, ProviderProfile}; use crate::skills::Skill; use crate::tool_registry::ToolRegistry; -use crate::tools::{ - make_edit_file_tool, make_glob_tool, make_grep_tool, make_read_file_tool, - make_shell_tool_with_config, make_web_fetch_tool, make_web_search_tool, make_write_file_tool, - WebFetchSummarizer, -}; +use crate::tools::{make_edit_file_tool, register_core_tools, WebFetchSummarizer}; use super::EnvContext; @@ -31,14 +27,8 @@ impl AnthropicProfile { }; let mut registry = ToolRegistry::new(); - registry.register(make_read_file_tool()); - registry.register(make_write_file_tool()); + register_core_tools(&mut registry, &config, summarizer); registry.register(make_edit_file_tool()); - registry.register(make_shell_tool_with_config(&config)); - registry.register(make_grep_tool()); - registry.register(make_glob_tool()); - registry.register(make_web_search_tool()); - registry.register(make_web_fetch_tool(summarizer)); Self { base: BaseProfile { diff --git a/crates/agent/src/profiles/gemini.rs b/crates/agent/src/profiles/gemini.rs index a702d15b8..171aa06dd 100644 --- a/crates/agent/src/profiles/gemini.rs +++ b/crates/agent/src/profiles/gemini.rs @@ -1,3 +1,4 @@ +use crate::config::SessionConfig; use crate::execution_env::ExecutionEnvironment; use crate::profiles::assemble_system_prompt; use crate::profiles::BaseProfile; @@ -5,9 +6,8 @@ use crate::provider_profile::{ProfileCapabilities, ProviderProfile}; use crate::skills::Skill; use crate::tool_registry::ToolRegistry; use crate::tools::{ - make_edit_file_tool, make_glob_tool, make_grep_tool, make_list_dir_tool, - make_read_file_tool, make_read_many_files_tool, make_shell_tool, make_web_fetch_tool, - make_web_search_tool, make_write_file_tool, WebFetchSummarizer, + make_edit_file_tool, make_list_dir_tool, make_read_many_files_tool, register_core_tools, + WebFetchSummarizer, }; use super::EnvContext; @@ -24,18 +24,13 @@ impl GeminiProfile { #[must_use] pub fn with_summarizer(model: impl Into, summarizer: Option) -> Self { + let config = SessionConfig::default(); let mut registry = ToolRegistry::new(); - registry.register(make_read_file_tool()); - registry.register(make_read_many_files_tool()); - registry.register(make_write_file_tool()); + register_core_tools(&mut registry, &config, summarizer); registry.register(make_edit_file_tool()); - registry.register(make_shell_tool()); - registry.register(make_grep_tool()); - registry.register(make_glob_tool()); + registry.register(make_read_many_files_tool()); registry.register(make_list_dir_tool()); - registry.register(make_web_search_tool()); - registry.register(make_web_fetch_tool(summarizer)); Self { base: BaseProfile { diff --git a/crates/agent/src/profiles/openai.rs b/crates/agent/src/profiles/openai.rs index 7bbce0ac4..5d80ef852 100644 --- a/crates/agent/src/profiles/openai.rs +++ b/crates/agent/src/profiles/openai.rs @@ -1,13 +1,11 @@ +use crate::config::SessionConfig; use crate::execution_env::ExecutionEnvironment; use crate::profiles::assemble_system_prompt; use crate::profiles::BaseProfile; use crate::provider_profile::{ProfileCapabilities, ProviderProfile}; use crate::skills::Skill; use crate::tool_registry::ToolRegistry; -use crate::tools::{ - make_glob_tool, make_grep_tool, make_read_file_tool, make_shell_tool, make_web_fetch_tool, - make_web_search_tool, make_write_file_tool, WebFetchSummarizer, -}; +use crate::tools::{register_core_tools, WebFetchSummarizer}; use crate::v4a_patch::make_apply_patch_tool; use super::EnvContext; @@ -25,16 +23,11 @@ impl OpenAiProfile { #[must_use] pub fn with_summarizer(model: impl Into, summarizer: Option) -> Self { + let config = SessionConfig::default(); let mut registry = ToolRegistry::new(); - registry.register(make_read_file_tool()); - registry.register(make_write_file_tool()); - registry.register(make_shell_tool()); - registry.register(make_grep_tool()); - registry.register(make_glob_tool()); + register_core_tools(&mut registry, &config, summarizer); registry.register(make_apply_patch_tool()); - registry.register(make_web_search_tool()); - registry.register(make_web_fetch_tool(summarizer)); Self { base: BaseProfile { diff --git a/crates/agent/src/tools.rs b/crates/agent/src/tools.rs index 69c698250..360b2d314 100644 --- a/crates/agent/src/tools.rs +++ b/crates/agent/src/tools.rs @@ -35,6 +35,26 @@ fn html_to_markdown(text: &str) -> String { converter.convert(text).unwrap_or_else(|_| text.to_string()) } +/// Registers the core tools shared by all provider profiles: `read_file`, `write_file`, +/// `shell`, `grep`, `glob`, `web_search`, and `web_fetch`. +/// +/// The shell tool uses `config` to set its default and max timeouts. Pass a custom +/// `SessionConfig` (e.g. with a longer `default_command_timeout_ms`) for providers +/// that need non-default shell behavior. +pub fn register_core_tools( + registry: &mut crate::tool_registry::ToolRegistry, + config: &SessionConfig, + summarizer: Option, +) { + registry.register(make_read_file_tool()); + registry.register(make_write_file_tool()); + registry.register(make_shell_tool_with_config(config)); + registry.register(make_grep_tool()); + registry.register(make_glob_tool()); + registry.register(make_web_search_tool()); + registry.register(make_web_fetch_tool(summarizer)); +} + pub(crate) fn required_str<'a>(args: &'a serde_json::Value, key: &str) -> Result<&'a str, String> { args.get(key) .and_then(|v| v.as_str()) @@ -57,7 +77,7 @@ pub fn make_read_file_tool() -> RegisteredTool { "required": ["file_path"] }), }, - executor: Arc::new(|args, env, _cancel| { + executor: Arc::new(|args, ctx| { Box::pin(async move { let file_path = required_str(&args, "file_path")?; let offset = args.get("offset").and_then(serde_json::Value::as_u64); @@ -66,7 +86,7 @@ pub fn make_read_file_tool() -> RegisteredTool { let offset_usize = offset.map(|v| v as usize); let limit_usize = limit.map(|v| v as usize); - let content = env.read_file(file_path, offset_usize, limit_usize).await?; + let content = ctx.env.read_file(file_path, offset_usize, limit_usize).await?; Ok(content) }) }),