Skip to main content

a3s_code_core/tools/builtin/
mod.rs

1//! Native Rust implementations of all built-in tools
2//!
3//! These replace the previous `a3s-tools` binary backend with direct Rust
4//! implementations that execute in-process. Each tool implements the `Tool` trait.
5
6pub(crate) mod bash;
7pub mod batch;
8mod edit;
9mod generate_object;
10pub(crate) mod git;
11mod glob_tool;
12mod grep;
13mod ls;
14mod patch;
15mod read;
16mod web_fetch;
17mod web_search;
18mod write;
19
20use super::registry::ToolRegistry;
21use std::sync::Arc;
22
23/// Register all baseline built-in tools with the registry, gated by
24/// workspace capabilities.
25///
26/// Tools whose required capability is missing are not registered, so the model
27/// never sees a tool the backend cannot service. `web_fetch` and `web_search`
28/// have no workspace capability and are always registered.
29///
30/// Note: `batch` is NOT registered here — it requires an `Arc<ToolRegistry>`
31/// and must be registered after the registry is wrapped in an Arc.
32pub fn register_builtins(
33    registry: &ToolRegistry,
34    capabilities: &crate::workspace::WorkspaceCapabilities,
35) {
36    if capabilities.read {
37        registry.register_builtin(Arc::new(read::ReadTool));
38        registry.register_builtin(Arc::new(ls::LsTool));
39    }
40    if capabilities.write {
41        registry.register_builtin(Arc::new(write::WriteTool));
42    }
43    if capabilities.read && capabilities.write {
44        registry.register_builtin(Arc::new(edit::EditTool));
45        registry.register_builtin(Arc::new(patch::PatchTool));
46    }
47    if capabilities.exec {
48        registry.register_builtin(Arc::new(bash::BashTool));
49    }
50    if capabilities.search {
51        registry.register_builtin(Arc::new(grep::GrepTool));
52        registry.register_builtin(Arc::new(glob_tool::GlobTool));
53    }
54    if capabilities.git {
55        registry.register_builtin(Arc::new(git::GitTool));
56    }
57    registry.register_builtin(Arc::new(web_fetch::WebFetchTool));
58    registry.register_builtin(Arc::new(web_search::WebSearchTool::new()));
59}
60
61/// Register the batch tool. Must be called after the registry is wrapped in Arc.
62pub fn register_batch(registry: &Arc<ToolRegistry>) {
63    registry.register_builtin(Arc::new(batch::BatchTool::new(Arc::clone(registry))));
64}
65
66/// Register the programmatic tool calling wrapper.
67pub fn register_program(registry: &Arc<ToolRegistry>) {
68    register_program_with_catalog(
69        registry,
70        crate::program::ProgramCatalog::with_builtin_programs(),
71    );
72}
73
74/// Register the programmatic tool calling wrapper with a custom catalog.
75pub fn register_program_with_catalog(
76    registry: &Arc<ToolRegistry>,
77    catalog: crate::program::ProgramCatalog,
78) {
79    registry.register_builtin(Arc::new(crate::tools::ProgramTool::with_catalog(
80        Arc::clone(registry),
81        catalog,
82    )));
83}
84
85/// Register the task delegation tools (task, parallel_task).
86///
87/// Must be called after the registry is wrapped in Arc. Requires an LLM client
88/// and the workspace path so child agent loops can be spawned inline.
89/// Optionally accepts an MCP manager so child sessions inherit MCP tools.
90pub fn register_task(
91    registry: &Arc<ToolRegistry>,
92    llm_client: Arc<dyn crate::llm::LlmClient>,
93    agent_registry: Arc<crate::subagent::AgentRegistry>,
94    workspace: String,
95) {
96    register_task_with_mcp(
97        registry,
98        llm_client,
99        agent_registry,
100        workspace,
101        None,
102        None,
103        None,
104    );
105}
106
107/// Register the task delegation tools with optional MCP manager and parent context.
108///
109/// When `mcp_manager` is provided, delegated child sessions will have access
110/// to all MCP tools from connected servers.
111/// When `parent_context` is provided, child runs inherit parent capabilities.
112/// When `subagent_tracker` is provided, each task registers a
113/// `CancellationToken` against it so callers can cancel by `task_id`.
114pub fn register_task_with_mcp(
115    registry: &Arc<ToolRegistry>,
116    llm_client: Arc<dyn crate::llm::LlmClient>,
117    agent_registry: Arc<crate::subagent::AgentRegistry>,
118    workspace: String,
119    mcp_manager: Option<Arc<crate::mcp::manager::McpManager>>,
120    parent_context: Option<crate::child_run::ChildRunContext>,
121    subagent_tracker: Option<Arc<crate::subagent_task_tracker::InMemorySubagentTaskTracker>>,
122) {
123    use crate::tools::task::{ParallelTaskTool, TaskExecutor, TaskTool};
124    let mut executor = match mcp_manager {
125        Some(mcp) => TaskExecutor::with_mcp(agent_registry, llm_client, workspace, mcp),
126        None => TaskExecutor::new(agent_registry, llm_client, workspace),
127    };
128    if let Some(ctx) = parent_context {
129        executor = executor.with_parent_context(ctx);
130    }
131    if let Some(tracker) = subagent_tracker {
132        executor = executor.with_subagent_tracker(tracker);
133    }
134    let executor = Arc::new(executor);
135    registry.register_builtin(Arc::new(TaskTool::new(Arc::clone(&executor))));
136    registry.register_builtin(Arc::new(ParallelTaskTool::new(Arc::clone(&executor))));
137}
138
139/// Register the Skill tool for skill-based tool access control.
140pub(crate) fn register_skill(
141    registry: &Arc<ToolRegistry>,
142    llm_client: Arc<dyn crate::llm::LlmClient>,
143    skill_registry: Arc<crate::skills::SkillRegistry>,
144    tool_executor: Arc<crate::tools::ToolExecutor>,
145    base_config: crate::agent::AgentConfig,
146) {
147    use crate::tools::skill::{SearchSkillsTool, SkillTool};
148    registry.register_builtin(Arc::new(SearchSkillsTool::new(Arc::clone(&skill_registry))));
149    registry.register_builtin(Arc::new(SkillTool::new(
150        skill_registry,
151        llm_client,
152        tool_executor,
153        base_config,
154    )));
155}
156
157/// Register the `generate_object` tool for structured JSON output.
158///
159/// Must be called after the registry is wrapped in Arc. Requires an LLM client
160/// so the tool can make its own LLM calls for object generation.
161pub fn register_generate_object(
162    registry: &Arc<ToolRegistry>,
163    llm_client: Arc<dyn crate::llm::LlmClient>,
164) {
165    registry.register_builtin(Arc::new(generate_object::GenerateObjectTool::new(
166        llm_client,
167    )));
168}