agent_sdk/
builtin_tools.rs1use std::sync::Arc;
34use tokio::sync::RwLock;
35
36use agent_sdk_tools::tools::ToolRegistry;
37
38use crate::primitive_tools::{BashTool, EditTool, GlobTool, GrepTool, ReadTool, WriteTool};
39use crate::todo::{TodoReadTool, TodoState, TodoWriteTool};
40#[cfg(feature = "web")]
41use crate::web::{LinkFetchTool, SearchProvider, WebSearchTool};
42use crate::{AgentCapabilities, Environment};
43
44pub struct BuiltinToolsConfig<E: Environment + 'static> {
58 pub environment: Arc<E>,
60 pub capabilities: AgentCapabilities,
62 pub todo_state: Option<Arc<RwLock<TodoState>>>,
64 #[cfg(feature = "web")]
68 pub link_fetch: bool,
69}
70
71pub fn register_builtin_tools<Ctx, E>(
78 registry: &mut ToolRegistry<Ctx>,
79 config: BuiltinToolsConfig<E>,
80) where
81 Ctx: Send + Sync + 'static,
82 E: Environment + 'static,
83{
84 register_primitives(registry, config.environment, config.capabilities);
85
86 if let Some(state) = config.todo_state {
87 register_todo_tools(registry, state);
88 }
89
90 #[cfg(feature = "web")]
91 if config.link_fetch {
92 register_link_fetch(registry);
93 }
94}
95
96pub fn register_primitives<Ctx, E>(
99 registry: &mut ToolRegistry<Ctx>,
100 environment: Arc<E>,
101 capabilities: AgentCapabilities,
102) where
103 Ctx: Send + Sync + 'static,
104 E: Environment + 'static,
105{
106 registry.register(ReadTool::new(
107 Arc::clone(&environment),
108 capabilities.clone(),
109 ));
110 registry.register(WriteTool::new(
111 Arc::clone(&environment),
112 capabilities.clone(),
113 ));
114 registry.register(EditTool::new(
115 Arc::clone(&environment),
116 capabilities.clone(),
117 ));
118 registry.register(BashTool::new(
119 Arc::clone(&environment),
120 capabilities.clone(),
121 ));
122 registry.register(GlobTool::new(
123 Arc::clone(&environment),
124 capabilities.clone(),
125 ));
126 registry.register(GrepTool::new(environment, capabilities));
127}
128
129pub fn register_todo_tools<Ctx>(registry: &mut ToolRegistry<Ctx>, state: Arc<RwLock<TodoState>>)
131where
132 Ctx: Send + Sync + 'static,
133{
134 registry.register(TodoReadTool::new(Arc::clone(&state)));
135 registry.register(TodoWriteTool::new(state));
136}
137
138#[cfg(feature = "web")]
141pub fn register_link_fetch<Ctx>(registry: &mut ToolRegistry<Ctx>)
142where
143 Ctx: Send + Sync + 'static,
144{
145 registry.register(LinkFetchTool::new());
146}
147
148#[cfg(feature = "web")]
154pub fn register_web_search<Ctx, P>(registry: &mut ToolRegistry<Ctx>, provider: P)
155where
156 Ctx: Send + Sync + 'static,
157 P: SearchProvider + 'static,
158{
159 registry.register(WebSearchTool::new(provider));
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165 use crate::InMemoryFileSystem;
166
167 #[cfg(feature = "web")]
168 #[test]
169 fn register_builtin_tools_wires_primitives_and_todo_and_fetch() {
170 let fs = Arc::new(InMemoryFileSystem::new("/workspace"));
171 let todo = Arc::new(RwLock::new(TodoState::new()));
172 let mut registry = ToolRegistry::<()>::new();
173
174 register_builtin_tools(
175 &mut registry,
176 BuiltinToolsConfig {
177 environment: fs,
178 capabilities: AgentCapabilities::full_access(),
179 todo_state: Some(todo),
180 link_fetch: true,
181 },
182 );
183
184 for expected in [
185 "read",
186 "write",
187 "edit",
188 "bash",
189 "glob",
190 "grep",
191 "todo_read",
192 "todo_write",
193 "link_fetch",
194 ] {
195 assert!(
196 registry.get(expected).is_some(),
197 "expected '{expected}' registered",
198 );
199 }
200 }
201
202 #[test]
203 fn register_primitives_registers_exactly_six_tools() {
204 let fs = Arc::new(InMemoryFileSystem::new("/workspace"));
205 let mut registry = ToolRegistry::<()>::new();
206 register_primitives(&mut registry, fs, AgentCapabilities::read_only());
207
208 for expected in ["read", "write", "edit", "bash", "glob", "grep"] {
209 assert!(
210 registry.get(expected).is_some(),
211 "expected '{expected}' registered",
212 );
213 }
214 }
215
216 #[test]
217 fn builtin_tools_config_skips_optional_families_when_unset() {
218 let fs = Arc::new(InMemoryFileSystem::new("/workspace"));
219 let mut registry = ToolRegistry::<()>::new();
220 register_builtin_tools(
221 &mut registry,
222 BuiltinToolsConfig {
223 environment: fs,
224 capabilities: AgentCapabilities::full_access(),
225 todo_state: None,
226 #[cfg(feature = "web")]
227 link_fetch: false,
228 },
229 );
230
231 assert!(registry.get("read").is_some());
232 assert!(registry.get("todo_read").is_none());
233 assert!(registry.get("link_fetch").is_none());
234 }
235}