1pub mod agent;
10pub mod bash;
11pub mod edit;
12#[cfg(test)]
13mod edit_tests;
14pub mod file;
15pub mod git;
16pub mod native;
17pub mod search;
18
19#[cfg(feature = "ares")]
20pub mod ares_bridge;
21
22use async_trait::async_trait;
23use serde_json::Value;
24use std::collections::HashMap;
25use std::sync::Arc;
26
27#[derive(Debug, Clone)]
29pub struct ToolDefinition {
30 pub name: String,
32 pub description: String,
34 pub parameters: Value,
36}
37
38#[async_trait]
40pub trait Tool: Send + Sync {
41 fn name(&self) -> &str;
43
44 fn description(&self) -> &str;
46
47 fn parameters_schema(&self) -> Value;
49
50 async fn execute(&self, args: Value) -> crate::Result<Value>;
52
53 fn to_definition(&self) -> ToolDefinition {
55 ToolDefinition {
56 name: self.name().to_string(),
57 description: self.description().to_string(),
58 parameters: self.parameters_schema(),
59 }
60 }
61}
62
63pub struct ToolRegistry {
65 tools: HashMap<String, Arc<dyn Tool>>,
66}
67
68impl ToolRegistry {
69 pub fn new() -> Self {
71 Self {
72 tools: HashMap::new(),
73 }
74 }
75
76 pub fn with_defaults(workspace_root: std::path::PathBuf) -> Self {
78 let mut registry = Self::new();
79
80 registry.register(Arc::new(file::ReadFileTool::new(workspace_root.clone())));
82 registry.register(Arc::new(file::WriteFileTool::new(workspace_root.clone())));
83 registry.register(Arc::new(file::ListDirectoryTool::new(
84 workspace_root.clone(),
85 )));
86
87 registry.register(Arc::new(edit::EditFileLinesTool::new(workspace_root.clone())));
89 registry.register(Arc::new(edit::EditFileTool::new(workspace_root.clone())));
90 registry.register(Arc::new(edit::InsertAfterTool::new(workspace_root.clone())));
91 registry.register(Arc::new(edit::AppendFileTool::new(workspace_root.clone())));
92
93 registry.register(Arc::new(native::GlobSearchTool::new(workspace_root.clone())));
95 registry.register(Arc::new(native::GrepSearchTool::new(workspace_root.clone())));
96
97 registry.register(Arc::new(bash::BashTool::new(workspace_root.clone())));
99
100 registry.register(Arc::new(git::GitStatusTool::new(workspace_root.clone())));
102 registry.register(Arc::new(git::GitDiffTool::new(workspace_root.clone())));
103 registry.register(Arc::new(git::GitAddTool::new(workspace_root.clone())));
104 registry.register(Arc::new(git::GitCommitTool::new(workspace_root.clone())));
105 registry.register(Arc::new(git::GitLogTool::new(workspace_root.clone())));
106 registry.register(Arc::new(git::GitBlameTool::new(workspace_root.clone())));
107 registry.register(Arc::new(git::GitBranchTool::new(workspace_root.clone())));
108 registry.register(Arc::new(git::GitCheckoutTool::new(workspace_root.clone())));
109 registry.register(Arc::new(git::GitStashTool::new(workspace_root.clone())));
110
111 registry.register(Arc::new(agent::SpawnAgentsTool::new(workspace_root.clone())));
113 registry.register(Arc::new(agent::SpawnAgentTool::new(workspace_root.clone())));
114
115 registry.register(Arc::new(native::RipgrepTool::new(workspace_root.clone())));
117 registry.register(Arc::new(native::FdTool::new(workspace_root.clone())));
118 registry.register(Arc::new(native::SdTool::new(workspace_root.clone())));
119 registry.register(Arc::new(native::ErdTool::new(workspace_root.clone())));
120 registry.register(Arc::new(native::MiseTool::new(workspace_root.clone())));
121 registry.register(Arc::new(native::ZoxideTool::new(workspace_root)));
122
123 registry
124 }
125
126 pub fn register(&mut self, tool: Arc<dyn Tool>) {
128 self.tools.insert(tool.name().to_string(), tool);
129 }
130
131 pub fn get(&self, name: &str) -> Option<&Arc<dyn Tool>> {
133 self.tools.get(name)
134 }
135
136 pub fn has_tool(&self, name: &str) -> bool {
138 self.tools.contains_key(name)
139 }
140
141 pub async fn execute(&self, name: &str, args: Value) -> crate::Result<Value> {
143 match self.tools.get(name) {
144 Some(tool) => tool.execute(args).await,
145 None => Err(crate::PawanError::NotFound(format!(
146 "Tool not found: {}",
147 name
148 ))),
149 }
150 }
151
152 pub fn get_definitions(&self) -> Vec<ToolDefinition> {
154 self.tools.values().map(|t| t.to_definition()).collect()
155 }
156
157 pub fn tool_names(&self) -> Vec<&str> {
159 self.tools.keys().map(|s| s.as_str()).collect()
160 }
161}
162
163impl Default for ToolRegistry {
164 fn default() -> Self {
165 Self::new()
166 }
167}