Skip to main content

trae_agent_rs_core/tools/
base.rs

1//! Base tool traits and structures
2
3use crate::error::{Result, ToolError};
4use async_trait::async_trait;
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7use uuid::Uuid;
8
9/// Trait for all tools
10#[async_trait]
11pub trait Tool: Send + Sync {
12    /// Get the name of the tool
13    fn name(&self) -> &str;
14    
15    /// Get the description of the tool
16    fn description(&self) -> &str;
17    
18    /// Get the JSON schema for the tool's parameters
19    fn parameters_schema(&self) -> serde_json::Value;
20    
21    /// Execute the tool with the given parameters
22    async fn execute(&self, call: ToolCall) -> Result<ToolResult>;
23    
24    /// Check if the tool requires special permissions
25    fn requires_confirmation(&self) -> bool {
26        false
27    }
28    
29    /// Get examples of how to use this tool
30    fn examples(&self) -> Vec<ToolExample> {
31        Vec::new()
32    }
33}
34
35/// A call to a tool
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct ToolCall {
38    /// Unique identifier for this tool call
39    pub id: String,
40    
41    /// Name of the tool to call
42    pub name: String,
43    
44    /// Parameters to pass to the tool
45    pub parameters: serde_json::Value,
46    
47    /// Optional metadata
48    pub metadata: Option<HashMap<String, serde_json::Value>>,
49}
50
51/// Result of a tool execution
52#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct ToolResult {
54    /// ID of the tool call this is a result for
55    pub tool_call_id: String,
56    
57    /// Whether the execution was successful
58    pub success: bool,
59    
60    /// Result content
61    pub content: String,
62    
63    /// Optional structured data
64    pub data: Option<serde_json::Value>,
65    
66    /// Execution duration in milliseconds
67    pub duration_ms: Option<u64>,
68    
69    /// Optional metadata
70    pub metadata: Option<HashMap<String, serde_json::Value>>,
71}
72
73/// Example usage of a tool
74#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct ToolExample {
76    /// Description of what this example does
77    pub description: String,
78    
79    /// Example parameters
80    pub parameters: serde_json::Value,
81    
82    /// Expected result description
83    pub expected_result: String,
84}
85
86/// Tool executor that manages tool execution
87pub struct ToolExecutor {
88    tools: HashMap<String, Box<dyn Tool>>,
89}
90
91impl ToolCall {
92    /// Create a new tool call
93    pub fn new<S: Into<String>>(name: S, parameters: serde_json::Value) -> Self {
94        Self {
95            id: Uuid::new_v4().to_string(),
96            name: name.into(),
97            parameters,
98            metadata: None,
99        }
100    }
101    
102    /// Get a parameter value by key
103    pub fn get_parameter<T>(&self, key: &str) -> Result<T>
104    where
105        T: for<'de> Deserialize<'de>,
106    {
107        let value = self.parameters
108            .get(key)
109            .ok_or_else(|| ToolError::InvalidParameters {
110                message: format!("Missing parameter: {}", key),
111            })?;
112
113        serde_json::from_value(value.clone())
114            .map_err(|_| ToolError::InvalidParameters {
115                message: format!("Invalid parameter type for: {}", key),
116            }.into())
117    }
118    
119    /// Get a parameter value by key with a default
120    pub fn get_parameter_or<T>(&self, key: &str, default: T) -> T
121    where
122        T: for<'de> Deserialize<'de> + Clone,
123    {
124        self.get_parameter(key).unwrap_or(default)
125    }
126}
127
128impl ToolResult {
129    /// Create a successful result
130    pub fn success<S: Into<String>>(tool_call_id: S, content: S) -> Self {
131        Self {
132            tool_call_id: tool_call_id.into(),
133            success: true,
134            content: content.into(),
135            data: None,
136            duration_ms: None,
137            metadata: None,
138        }
139    }
140    
141    /// Create an error result
142    pub fn error<S: Into<String>>(tool_call_id: S, error: S) -> Self {
143        Self {
144            tool_call_id: tool_call_id.into(),
145            success: false,
146            content: format!("Error: {}", error.into()),
147            data: None,
148            duration_ms: None,
149            metadata: None,
150        }
151    }
152    
153    /// Set structured data
154    pub fn with_data(mut self, data: serde_json::Value) -> Self {
155        self.data = Some(data);
156        self
157    }
158    
159    /// Set execution duration
160    pub fn with_duration(mut self, duration_ms: u64) -> Self {
161        self.duration_ms = Some(duration_ms);
162        self
163    }
164    
165    /// Set metadata
166    pub fn with_metadata(mut self, metadata: HashMap<String, serde_json::Value>) -> Self {
167        self.metadata = Some(metadata);
168        self
169    }
170}
171
172impl ToolExecutor {
173    /// Create a new tool executor
174    pub fn new() -> Self {
175        Self {
176            tools: HashMap::new(),
177        }
178    }
179    
180    /// Register a tool
181    pub fn register_tool(&mut self, tool: Box<dyn Tool>) {
182        self.tools.insert(tool.name().to_string(), tool);
183    }
184    
185    /// Get a tool by name
186    pub fn get_tool(&self, name: &str) -> Option<&dyn Tool> {
187        self.tools.get(name).map(|t| t.as_ref())
188    }
189    
190    /// List all available tools
191    pub fn list_tools(&self) -> Vec<&str> {
192        self.tools.keys().map(|s| s.as_str()).collect()
193    }
194    
195    /// Execute a tool call
196    pub async fn execute(&self, call: ToolCall) -> Result<ToolResult> {
197        let tool = self.get_tool(&call.name)
198            .ok_or_else(|| ToolError::NotFound {
199                name: call.name.clone(),
200            })?;
201        
202        let start_time = std::time::Instant::now();
203        let call_id = call.id.clone();
204        let result = tool.execute(call).await;
205        let duration = start_time.elapsed().as_millis() as u64;
206
207        match result {
208            Ok(mut result) => {
209                result.duration_ms = Some(duration);
210                Ok(result)
211            }
212            Err(e) => Ok(ToolResult::error(&call_id, &e.to_string()).with_duration(duration)),
213        }
214    }
215    
216    /// Get tool definitions for LLM function calling
217    pub fn get_tool_definitions(&self) -> Vec<crate::llm::ToolDefinition> {
218        self.tools
219            .values()
220            .map(|tool| crate::llm::ToolDefinition {
221                tool_type: "function".to_string(),
222                function: crate::llm::FunctionDefinition {
223                    name: tool.name().to_string(),
224                    description: tool.description().to_string(),
225                    parameters: tool.parameters_schema(),
226                },
227            })
228            .collect()
229    }
230}
231
232impl Default for ToolExecutor {
233    fn default() -> Self {
234        Self::new()
235    }
236}