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