a3s_code_core/tools/builtin/
mod.rs1pub(crate) mod bash;
7pub mod batch;
8mod code_intelligence;
9mod edit;
10mod generate_object;
11pub(crate) mod git;
12mod glob_tool;
13mod grep;
14mod ls;
15mod patch;
16mod read;
17mod web_fetch;
18mod web_search;
19mod write;
20
21use super::registry::ToolRegistry;
22use std::sync::Arc;
23
24pub(crate) fn safe_http_source_url(value: &str) -> Option<String> {
27 let mut url = reqwest::Url::parse(value.trim()).ok()?;
28 if !matches!(url.scheme(), "http" | "https") || url.host_str()?.is_empty() {
29 return None;
30 }
31 url.set_username("").ok()?;
32 url.set_password(None).ok()?;
33 url.set_query(None);
34 url.set_fragment(None);
35 Some(url.to_string())
36}
37
38pub fn register_builtins(
48 registry: &ToolRegistry,
49 capabilities: &crate::workspace::WorkspaceCapabilities,
50) {
51 if capabilities.read {
52 registry.register_builtin(Arc::new(read::ReadTool));
53 registry.register_builtin(Arc::new(ls::LsTool));
54 }
55 if capabilities.write {
56 registry.register_builtin(Arc::new(write::WriteTool));
57 }
58 if capabilities.read && capabilities.write {
59 registry.register_builtin(Arc::new(edit::EditTool));
60 registry.register_builtin(Arc::new(patch::PatchTool));
61 }
62 if capabilities.exec {
63 registry.register_builtin(Arc::new(bash::BashTool));
64 }
65 if capabilities.search {
66 registry.register_builtin(Arc::new(grep::GrepTool));
67 registry.register_builtin(Arc::new(glob_tool::GlobTool));
68 }
69 if capabilities.code_intelligence {
70 code_intelligence::register(registry);
71 }
72 if capabilities.git {
73 registry.register_builtin(Arc::new(git::GitTool));
74 }
75 registry.register_builtin(Arc::new(web_fetch::WebFetchTool));
76 registry.register_builtin(Arc::new(web_search::WebSearchTool::new()));
77}
78
79pub fn register_batch(registry: &Arc<ToolRegistry>) {
81 registry.register_builtin(Arc::new(batch::BatchTool::new(Arc::clone(registry))));
82}
83
84pub fn register_program(registry: &Arc<ToolRegistry>) {
86 register_program_with_catalog(
87 registry,
88 crate::program::ProgramCatalog::with_builtin_programs(),
89 );
90}
91
92pub fn register_program_with_catalog(
94 registry: &Arc<ToolRegistry>,
95 catalog: crate::program::ProgramCatalog,
96) {
97 registry.register_builtin(Arc::new(crate::tools::ProgramTool::with_catalog(
98 Arc::clone(registry),
99 catalog,
100 )));
101}
102
103pub fn register_task(
109 registry: &Arc<ToolRegistry>,
110 llm_client: Arc<dyn crate::llm::LlmClient>,
111 agent_registry: Arc<crate::subagent::AgentRegistry>,
112 workspace: String,
113) {
114 register_task_with_mcp(
115 registry,
116 llm_client,
117 agent_registry,
118 workspace,
119 None,
120 None,
121 None,
122 );
123}
124
125pub fn register_task_with_mcp(
133 registry: &Arc<ToolRegistry>,
134 llm_client: Arc<dyn crate::llm::LlmClient>,
135 agent_registry: Arc<crate::subagent::AgentRegistry>,
136 workspace: String,
137 mcp_manager: Option<Arc<crate::mcp::manager::McpManager>>,
138 parent_context: Option<crate::child_run::ChildRunContext>,
139 subagent_tracker: Option<Arc<crate::subagent_task_tracker::InMemorySubagentTaskTracker>>,
140) {
141 register_task_with_mcp_managers(
142 registry,
143 llm_client,
144 agent_registry,
145 workspace,
146 mcp_manager.into_iter().collect(),
147 parent_context,
148 subagent_tracker,
149 );
150}
151
152pub fn register_task_with_mcp_managers(
157 registry: &Arc<ToolRegistry>,
158 llm_client: Arc<dyn crate::llm::LlmClient>,
159 agent_registry: Arc<crate::subagent::AgentRegistry>,
160 workspace: String,
161 mcp_managers: Vec<Arc<crate::mcp::manager::McpManager>>,
162 parent_context: Option<crate::child_run::ChildRunContext>,
163 subagent_tracker: Option<Arc<crate::subagent_task_tracker::InMemorySubagentTaskTracker>>,
164) {
165 use crate::tools::task::{ParallelTaskTool, TaskExecutor, TaskTool};
166 let mut executor =
167 TaskExecutor::with_mcp_managers(agent_registry, llm_client, workspace, mcp_managers);
168 if let Some(ctx) = parent_context {
169 executor = executor.with_parent_context(ctx);
170 }
171 if let Some(tracker) = subagent_tracker {
172 executor = executor.with_subagent_tracker(tracker);
173 }
174 let executor = Arc::new(executor);
175 registry.register_builtin(Arc::new(TaskTool::new(Arc::clone(&executor))));
176 registry.register_builtin(Arc::new(ParallelTaskTool::new(Arc::clone(&executor))));
177}
178
179pub(crate) fn register_skill(
181 registry: &Arc<ToolRegistry>,
182 llm_client: Arc<dyn crate::llm::LlmClient>,
183 skill_registry: Arc<crate::skills::SkillRegistry>,
184 tool_executor: Arc<crate::tools::ToolExecutor>,
185 base_config: crate::agent::AgentConfig,
186) {
187 use crate::tools::skill::{SearchSkillsTool, SkillTool};
188 registry.register_builtin(Arc::new(SearchSkillsTool::new(Arc::clone(&skill_registry))));
189 registry.register_builtin(Arc::new(SkillTool::new(
190 skill_registry,
191 llm_client,
192 tool_executor,
193 base_config,
194 )));
195}
196
197pub fn register_generate_object(
202 registry: &Arc<ToolRegistry>,
203 llm_client: Arc<dyn crate::llm::LlmClient>,
204) {
205 registry.register_builtin(Arc::new(generate_object::GenerateObjectTool::new(
206 llm_client,
207 )));
208}
209
210#[cfg(test)]
211mod tests {
212 use super::safe_http_source_url;
213
214 #[test]
215 fn safe_source_url_removes_credentials_query_and_fragment() {
216 assert_eq!(
217 safe_http_source_url(
218 "HTTPS://user:password@Example.COM/report?access_token=secret#section"
219 )
220 .as_deref(),
221 Some("https://example.com/report")
222 );
223 assert!(safe_http_source_url("file:///tmp/source").is_none());
224 }
225}