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