trae_agent_rs_core/tools/
base.rs1use crate::error::{Result, ToolError};
4use async_trait::async_trait;
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7use uuid::Uuid;
8
9#[async_trait]
11pub trait Tool: Send + Sync {
12 fn name(&self) -> &str;
14
15 fn description(&self) -> &str;
17
18 fn parameters_schema(&self) -> serde_json::Value;
20
21 async fn execute(&self, call: ToolCall) -> Result<ToolResult>;
23
24 fn requires_confirmation(&self) -> bool {
26 false
27 }
28
29 fn examples(&self) -> Vec<ToolExample> {
31 Vec::new()
32 }
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct ToolCall {
38 pub id: String,
40
41 pub name: String,
43
44 pub parameters: serde_json::Value,
46
47 pub metadata: Option<HashMap<String, serde_json::Value>>,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct ToolResult {
54 pub tool_call_id: String,
56
57 pub success: bool,
59
60 pub content: String,
62
63 pub data: Option<serde_json::Value>,
65
66 pub duration_ms: Option<u64>,
68
69 pub metadata: Option<HashMap<String, serde_json::Value>>,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct ToolExample {
76 pub description: String,
78
79 pub parameters: serde_json::Value,
81
82 pub expected_result: String,
84}
85
86pub struct ToolExecutor {
88 tools: HashMap<String, Box<dyn Tool>>,
89}
90
91impl ToolCall {
92 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 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 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 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 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 pub fn with_data(mut self, data: serde_json::Value) -> Self {
155 self.data = Some(data);
156 self
157 }
158
159 pub fn with_duration(mut self, duration_ms: u64) -> Self {
161 self.duration_ms = Some(duration_ms);
162 self
163 }
164
165 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 pub fn new() -> Self {
175 Self {
176 tools: HashMap::new(),
177 }
178 }
179
180 pub fn register_tool(&mut self, tool: Box<dyn Tool>) {
182 self.tools.insert(tool.name().to_string(), tool);
183 }
184
185 pub fn get_tool(&self, name: &str) -> Option<&dyn Tool> {
187 self.tools.get(name).map(|t| t.as_ref())
188 }
189
190 pub fn list_tools(&self) -> Vec<&str> {
192 self.tools.keys().map(|s| s.as_str()).collect()
193 }
194
195 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 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}