Skip to main content

agent_commander/tools/
mod.rs

1//! Tool configurations and utilities
2//! Provides configuration for different CLI agents: claude, codex, opencode, agent, gemini, qwen
3
4pub mod agent;
5pub mod claude;
6pub mod codex;
7pub mod gemini;
8pub mod opencode;
9pub mod qwen;
10pub(crate) mod shell;
11
12use std::collections::HashMap;
13
14pub use agent::{AgentBuildOptions, AgentTool, AgentUsage, ErrorResult};
15pub use claude::{ClaudeBuildOptions, ClaudeTool, ClaudeUsage};
16pub use codex::{CodexBuildOptions, CodexTool, CodexUsage};
17pub use gemini::{GeminiBuildOptions, GeminiErrorResult, GeminiTool, GeminiUsage};
18pub use opencode::{OpencodeBuildOptions, OpencodeTool, OpencodeUsage};
19pub use qwen::{QwenBuildOptions, QwenErrorResult, QwenTool, QwenUsage};
20
21/// Generic tool trait
22pub trait Tool {
23    fn name(&self) -> &'static str;
24    fn display_name(&self) -> &'static str;
25    fn executable(&self) -> &'static str;
26    fn supports_json_output(&self) -> bool;
27    fn supports_json_input(&self) -> bool;
28    fn supports_system_prompt(&self) -> bool;
29    fn supports_resume(&self) -> bool;
30    fn default_model(&self) -> &'static str;
31}
32
33impl Tool for ClaudeTool {
34    fn name(&self) -> &'static str {
35        self.name
36    }
37    fn display_name(&self) -> &'static str {
38        self.display_name
39    }
40    fn executable(&self) -> &'static str {
41        self.executable
42    }
43    fn supports_json_output(&self) -> bool {
44        self.supports_json_output
45    }
46    fn supports_json_input(&self) -> bool {
47        self.supports_json_input
48    }
49    fn supports_system_prompt(&self) -> bool {
50        self.supports_system_prompt
51    }
52    fn supports_resume(&self) -> bool {
53        self.supports_resume
54    }
55    fn default_model(&self) -> &'static str {
56        self.default_model
57    }
58}
59
60impl Tool for CodexTool {
61    fn name(&self) -> &'static str {
62        self.name
63    }
64    fn display_name(&self) -> &'static str {
65        self.display_name
66    }
67    fn executable(&self) -> &'static str {
68        self.executable
69    }
70    fn supports_json_output(&self) -> bool {
71        self.supports_json_output
72    }
73    fn supports_json_input(&self) -> bool {
74        self.supports_json_input
75    }
76    fn supports_system_prompt(&self) -> bool {
77        self.supports_system_prompt
78    }
79    fn supports_resume(&self) -> bool {
80        self.supports_resume
81    }
82    fn default_model(&self) -> &'static str {
83        self.default_model
84    }
85}
86
87impl Tool for OpencodeTool {
88    fn name(&self) -> &'static str {
89        self.name
90    }
91    fn display_name(&self) -> &'static str {
92        self.display_name
93    }
94    fn executable(&self) -> &'static str {
95        self.executable
96    }
97    fn supports_json_output(&self) -> bool {
98        self.supports_json_output
99    }
100    fn supports_json_input(&self) -> bool {
101        self.supports_json_input
102    }
103    fn supports_system_prompt(&self) -> bool {
104        self.supports_system_prompt
105    }
106    fn supports_resume(&self) -> bool {
107        self.supports_resume
108    }
109    fn default_model(&self) -> &'static str {
110        self.default_model
111    }
112}
113
114impl Tool for AgentTool {
115    fn name(&self) -> &'static str {
116        self.name
117    }
118    fn display_name(&self) -> &'static str {
119        self.display_name
120    }
121    fn executable(&self) -> &'static str {
122        self.executable
123    }
124    fn supports_json_output(&self) -> bool {
125        self.supports_json_output
126    }
127    fn supports_json_input(&self) -> bool {
128        self.supports_json_input
129    }
130    fn supports_system_prompt(&self) -> bool {
131        self.supports_system_prompt
132    }
133    fn supports_resume(&self) -> bool {
134        self.supports_resume
135    }
136    fn default_model(&self) -> &'static str {
137        self.default_model
138    }
139}
140
141impl Tool for GeminiTool {
142    fn name(&self) -> &'static str {
143        self.name
144    }
145    fn display_name(&self) -> &'static str {
146        self.display_name
147    }
148    fn executable(&self) -> &'static str {
149        self.executable
150    }
151    fn supports_json_output(&self) -> bool {
152        self.supports_json_output
153    }
154    fn supports_json_input(&self) -> bool {
155        self.supports_json_input
156    }
157    fn supports_system_prompt(&self) -> bool {
158        self.supports_system_prompt
159    }
160    fn supports_resume(&self) -> bool {
161        self.supports_resume
162    }
163    fn default_model(&self) -> &'static str {
164        self.default_model
165    }
166}
167
168impl Tool for QwenTool {
169    fn name(&self) -> &'static str {
170        self.name
171    }
172    fn display_name(&self) -> &'static str {
173        self.display_name
174    }
175    fn executable(&self) -> &'static str {
176        self.executable
177    }
178    fn supports_json_output(&self) -> bool {
179        self.supports_json_output
180    }
181    fn supports_json_input(&self) -> bool {
182        self.supports_json_input
183    }
184    fn supports_system_prompt(&self) -> bool {
185        self.supports_system_prompt
186    }
187    fn supports_resume(&self) -> bool {
188        self.supports_resume
189    }
190    fn default_model(&self) -> &'static str {
191        self.default_model
192    }
193}
194
195/// Tool registry for all supported tools
196pub struct ToolRegistry {
197    tools: HashMap<&'static str, Box<dyn Tool + Send + Sync>>,
198}
199
200impl Default for ToolRegistry {
201    fn default() -> Self {
202        Self::new()
203    }
204}
205
206impl ToolRegistry {
207    /// Create a new tool registry with all supported tools
208    pub fn new() -> Self {
209        let mut tools: HashMap<&'static str, Box<dyn Tool + Send + Sync>> = HashMap::new();
210        tools.insert("claude", Box::new(ClaudeTool::default()));
211        tools.insert("codex", Box::new(CodexTool::default()));
212        tools.insert("opencode", Box::new(OpencodeTool::default()));
213        tools.insert("agent", Box::new(AgentTool::default()));
214        tools.insert("gemini", Box::new(GeminiTool::default()));
215        tools.insert("qwen", Box::new(QwenTool::default()));
216        Self { tools }
217    }
218
219    /// Get tool by name
220    pub fn get(&self, name: &str) -> Option<&(dyn Tool + Send + Sync)> {
221        self.tools.get(name).map(|t| t.as_ref())
222    }
223
224    /// Check if a tool is supported
225    pub fn is_supported(&self, name: &str) -> bool {
226        self.tools.contains_key(name)
227    }
228
229    /// List all available tool names
230    pub fn list(&self) -> Vec<&'static str> {
231        self.tools.keys().copied().collect()
232    }
233}
234
235/// Get tool configuration by name
236///
237/// # Arguments
238/// * `tool_name` - Name of the tool
239///
240/// # Returns
241/// Result with tool reference or error
242pub fn get_tool(tool_name: &str) -> Result<Box<dyn Tool + Send + Sync>, String> {
243    match tool_name {
244        "claude" => Ok(Box::new(ClaudeTool::default())),
245        "codex" => Ok(Box::new(CodexTool::default())),
246        "opencode" => Ok(Box::new(OpencodeTool::default())),
247        "agent" => Ok(Box::new(AgentTool::default())),
248        "gemini" => Ok(Box::new(GeminiTool::default())),
249        "qwen" => Ok(Box::new(QwenTool::default())),
250        _ => Err(format!(
251            "Unknown tool: {}. Available tools: claude, codex, opencode, agent, gemini, qwen",
252            tool_name
253        )),
254    }
255}
256
257/// List available tools
258pub fn list_tools() -> Vec<&'static str> {
259    vec!["claude", "codex", "opencode", "agent", "gemini", "qwen"]
260}
261
262/// Check if a tool is supported
263///
264/// # Arguments
265/// * `tool_name` - Name of the tool
266///
267/// # Returns
268/// True if tool is supported
269pub fn is_tool_supported(tool_name: &str) -> bool {
270    ["claude", "codex", "opencode", "agent", "gemini", "qwen"].contains(&tool_name)
271}
272
273// Tests are in rust/tests/tools_tests.rs