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