codetether_agent/tool/
mod.rs1pub mod advanced_edit;
6pub mod agent;
7pub mod avatar;
8pub mod bash;
9pub mod batch;
10pub mod codesearch;
11pub mod confirm_edit;
12pub mod confirm_multiedit;
13pub mod edit;
14pub mod file;
15pub mod image;
16pub mod invalid;
17pub mod lsp;
18pub mod mcp_bridge;
19pub mod memory;
20pub mod multiedit;
21pub mod patch;
22pub mod plan;
23pub mod podcast;
24pub mod prd;
25pub mod question;
26pub mod ralph;
27pub mod rlm;
28pub mod sandbox;
29pub mod search;
30pub mod skill;
31pub mod swarm_share;
32pub mod task;
33pub mod todo;
34pub mod undo;
35pub mod voice;
36pub mod webfetch;
37pub mod websearch;
38pub mod youtube;
39
40use anyhow::Result;
41use async_trait::async_trait;
42use serde::{Deserialize, Serialize};
43use serde_json::Value;
44use std::collections::HashMap;
45use std::sync::Arc;
46
47use crate::provider::Provider;
48pub use sandbox::{PluginManifest, PluginRegistry, SigningKey, hash_bytes, hash_file};
49
50#[async_trait]
52pub trait Tool: Send + Sync {
53 fn id(&self) -> &str;
55
56 fn name(&self) -> &str;
58
59 fn description(&self) -> &str;
61
62 fn parameters(&self) -> Value;
64
65 async fn execute(&self, args: Value) -> Result<ToolResult>;
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct ToolResult {
72 pub output: String,
73 pub success: bool,
74 #[serde(default)]
75 pub metadata: HashMap<String, Value>,
76}
77
78impl ToolResult {
79 pub fn success(output: impl Into<String>) -> Self {
80 Self {
81 output: output.into(),
82 success: true,
83 metadata: HashMap::new(),
84 }
85 }
86
87 pub fn error(message: impl Into<String>) -> Self {
88 Self {
89 output: message.into(),
90 success: false,
91 metadata: HashMap::new(),
92 }
93 }
94
95 pub fn structured_error(
99 code: &str,
100 tool: &str,
101 message: &str,
102 missing_fields: Option<Vec<&str>>,
103 example: Option<Value>,
104 ) -> Self {
105 let mut error_obj = serde_json::json!({
106 "code": code,
107 "tool": tool,
108 "message": message,
109 });
110
111 if let Some(fields) = missing_fields {
112 error_obj["missing_fields"] = serde_json::json!(fields);
113 }
114
115 if let Some(ex) = example {
116 error_obj["example"] = ex;
117 }
118
119 let output = serde_json::to_string_pretty(&serde_json::json!({
120 "error": error_obj
121 }))
122 .unwrap_or_else(|_| format!("Error: {}", message));
123
124 let mut metadata = HashMap::new();
125 metadata.insert("error_code".to_string(), serde_json::json!(code));
126 metadata.insert("tool".to_string(), serde_json::json!(tool));
127
128 Self {
129 output,
130 success: false,
131 metadata,
132 }
133 }
134
135 pub fn with_metadata(mut self, key: impl Into<String>, value: Value) -> Self {
136 self.metadata.insert(key.into(), value);
137 self
138 }
139}
140
141pub struct ToolRegistry {
143 tools: HashMap<String, Arc<dyn Tool>>,
144 plugin_registry: PluginRegistry,
145}
146
147impl std::fmt::Debug for ToolRegistry {
148 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149 f.debug_struct("ToolRegistry")
150 .field("tools", &self.tools.keys().collect::<Vec<_>>())
151 .finish()
152 }
153}
154
155impl ToolRegistry {
156 pub fn new() -> Self {
157 Self {
158 tools: HashMap::new(),
159 plugin_registry: PluginRegistry::from_env(),
160 }
161 }
162
163 pub fn plugins(&self) -> &PluginRegistry {
165 &self.plugin_registry
166 }
167
168 pub fn register(&mut self, tool: Arc<dyn Tool>) {
170 self.tools.insert(tool.id().to_string(), tool);
171 }
172
173 pub fn get(&self, id: &str) -> Option<Arc<dyn Tool>> {
175 self.tools.get(id).cloned()
176 }
177
178 pub fn list(&self) -> Vec<&str> {
180 self.tools.keys().map(|s| s.as_str()).collect()
181 }
182
183 pub fn definitions(&self) -> Vec<crate::provider::ToolDefinition> {
185 self.tools
186 .values()
187 .map(|t| crate::provider::ToolDefinition {
188 name: t.id().to_string(),
189 description: t.description().to_string(),
190 parameters: t.parameters(),
191 })
192 .collect()
193 }
194
195 pub fn with_defaults() -> Self {
197 let mut registry = Self::new();
198
199 registry.register(Arc::new(file::ReadTool::new()));
200 registry.register(Arc::new(file::WriteTool::new()));
201 registry.register(Arc::new(file::ListTool::new()));
202 registry.register(Arc::new(file::GlobTool::new()));
203 registry.register(Arc::new(search::GrepTool::new()));
204 registry.register(Arc::new(advanced_edit::AdvancedEditTool::new()));
205 registry.register(Arc::new(bash::BashTool::new()));
206 registry.register(Arc::new(lsp::LspTool::with_root(
207 std::env::current_dir()
208 .map(|p| format!("file://{}", p.display()))
209 .unwrap_or_default(),
210 )));
211 registry.register(Arc::new(webfetch::WebFetchTool::new()));
212 registry.register(Arc::new(multiedit::MultiEditTool::new()));
213 registry.register(Arc::new(websearch::WebSearchTool::new()));
214 registry.register(Arc::new(codesearch::CodeSearchTool::new()));
215 registry.register(Arc::new(patch::ApplyPatchTool::new()));
216 registry.register(Arc::new(todo::TodoReadTool::new()));
217 registry.register(Arc::new(todo::TodoWriteTool::new()));
218 registry.register(Arc::new(question::QuestionTool::new()));
219 registry.register(Arc::new(task::TaskTool::new()));
220 registry.register(Arc::new(plan::PlanEnterTool::new()));
221 registry.register(Arc::new(plan::PlanExitTool::new()));
222 registry.register(Arc::new(skill::SkillTool::new()));
223 registry.register(Arc::new(memory::MemoryTool::new()));
224 registry.register(Arc::new(ralph::RalphTool::new()));
225 registry.register(Arc::new(prd::PrdTool::new()));
226 registry.register(Arc::new(confirm_edit::ConfirmEditTool::new()));
227 registry.register(Arc::new(confirm_multiedit::ConfirmMultiEditTool::new()));
228 registry.register(Arc::new(undo::UndoTool));
229 registry.register(Arc::new(voice::VoiceTool::new()));
230 registry.register(Arc::new(podcast::PodcastTool::new()));
231 registry.register(Arc::new(youtube::YouTubeTool::new()));
232 registry.register(Arc::new(avatar::AvatarTool::new()));
233 registry.register(Arc::new(image::ImageTool::new()));
234 registry.register(Arc::new(mcp_bridge::McpBridgeTool::new()));
235 registry.register(Arc::new(invalid::InvalidTool::new()));
237 registry.register(Arc::new(agent::AgentTool::new()));
239
240 registry
241 }
242
243 pub fn with_provider(provider: Arc<dyn Provider>, model: String) -> Self {
245 let mut registry = Self::new();
246
247 registry.register(Arc::new(file::ReadTool::new()));
248 registry.register(Arc::new(file::WriteTool::new()));
249 registry.register(Arc::new(file::ListTool::new()));
250 registry.register(Arc::new(file::GlobTool::new()));
251 registry.register(Arc::new(search::GrepTool::new()));
252 registry.register(Arc::new(advanced_edit::AdvancedEditTool::new()));
253 registry.register(Arc::new(bash::BashTool::new()));
254 registry.register(Arc::new(lsp::LspTool::with_root(
255 std::env::current_dir()
256 .map(|p| format!("file://{}", p.display()))
257 .unwrap_or_default(),
258 )));
259 registry.register(Arc::new(webfetch::WebFetchTool::new()));
260 registry.register(Arc::new(multiedit::MultiEditTool::new()));
261 registry.register(Arc::new(websearch::WebSearchTool::new()));
262 registry.register(Arc::new(codesearch::CodeSearchTool::new()));
263 registry.register(Arc::new(patch::ApplyPatchTool::new()));
264 registry.register(Arc::new(todo::TodoReadTool::new()));
265 registry.register(Arc::new(todo::TodoWriteTool::new()));
266 registry.register(Arc::new(question::QuestionTool::new()));
267 registry.register(Arc::new(task::TaskTool::new()));
268 registry.register(Arc::new(plan::PlanEnterTool::new()));
269 registry.register(Arc::new(plan::PlanExitTool::new()));
270 registry.register(Arc::new(skill::SkillTool::new()));
271 registry.register(Arc::new(memory::MemoryTool::new()));
272 registry.register(Arc::new(rlm::RlmTool::new(Arc::clone(&provider), model.clone())));
273 registry.register(Arc::new(ralph::RalphTool::with_provider(provider, model)));
275 registry.register(Arc::new(prd::PrdTool::new()));
276 registry.register(Arc::new(undo::UndoTool));
277 registry.register(Arc::new(voice::VoiceTool::new()));
278 registry.register(Arc::new(podcast::PodcastTool::new()));
279 registry.register(Arc::new(youtube::YouTubeTool::new()));
280 registry.register(Arc::new(avatar::AvatarTool::new()));
281 registry.register(Arc::new(image::ImageTool::new()));
282 registry.register(Arc::new(mcp_bridge::McpBridgeTool::new()));
283 registry.register(Arc::new(invalid::InvalidTool::new()));
285 registry.register(Arc::new(agent::AgentTool::new()));
287
288 registry
289 }
290
291 pub fn with_defaults_arc() -> Arc<Self> {
295 let mut registry = Self::with_defaults();
296
297 let batch_tool = Arc::new(batch::BatchTool::new());
299 registry.register(batch_tool.clone());
300
301 let registry = Arc::new(registry);
303
304 batch_tool.set_registry(Arc::downgrade(®istry));
306
307 registry
308 }
309
310 #[allow(dead_code)]
314 pub fn with_provider_arc(provider: Arc<dyn Provider>, model: String) -> Arc<Self> {
315 let mut registry = Self::with_provider(provider, model);
316
317 let batch_tool = Arc::new(batch::BatchTool::new());
319 registry.register(batch_tool.clone());
320
321 let registry = Arc::new(registry);
323
324 batch_tool.set_registry(Arc::downgrade(®istry));
326
327 registry
328 }
329}
330
331impl Default for ToolRegistry {
332 fn default() -> Self {
333 Self::with_defaults()
334 }
335}