1use serde::{Deserialize, Serialize};
26use std::collections::HashMap;
27
28pub use crate::models::modifiers::{CustomAuthParams, CustomConnectionData, ToolExecuteParams};
30pub use crate::models::response::ToolExecutionResponse;
31
32#[derive(Debug, Clone, Default, Serialize, Deserialize)]
34pub struct ToolListParams {
35 #[serde(skip_serializing_if = "Option::is_none")]
37 pub tool_slugs: Option<Vec<String>>,
38
39 #[serde(skip_serializing_if = "Option::is_none")]
41 pub toolkit_slug: Option<String>,
42
43 #[serde(skip_serializing_if = "Option::is_none")]
45 pub search: Option<String>,
46
47 #[serde(skip_serializing_if = "Option::is_none")]
49 pub scopes: Option<Vec<String>>,
50
51 #[serde(skip_serializing_if = "Option::is_none")]
53 pub tags: Option<Vec<String>>,
54
55 #[serde(skip_serializing_if = "Option::is_none")]
57 pub importance: Option<String>,
58
59 #[serde(skip_serializing_if = "Option::is_none")]
61 pub show_deprecated: Option<bool>,
62
63 #[serde(skip_serializing_if = "Option::is_none")]
65 pub limit: Option<u32>,
66
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub cursor: Option<String>,
70
71 #[serde(skip_serializing_if = "Option::is_none")]
73 pub toolkit_versions: Option<String>,
74}
75
76#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct ToolInfo {
79 pub slug: String,
81
82 pub name: String,
84
85 pub description: String,
87
88 pub toolkit: ToolkitRef,
90
91 pub input_parameters: serde_json::Value,
93
94 pub output_parameters: serde_json::Value,
96
97 #[serde(default)]
99 pub scopes: Vec<String>,
100
101 #[serde(default)]
103 pub tags: Vec<String>,
104
105 pub version: String,
107
108 #[serde(default)]
110 pub available_versions: Vec<String>,
111
112 #[serde(default)]
114 pub is_deprecated: bool,
115
116 #[serde(default)]
118 pub no_auth: bool,
119}
120
121#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct ToolkitRef {
124 pub slug: String,
126
127 #[serde(skip_serializing_if = "Option::is_none")]
129 pub name: Option<String>,
130
131 #[serde(skip_serializing_if = "Option::is_none")]
133 pub logo: Option<String>,
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct ToolListResponse {
139 pub items: Vec<ToolInfo>,
141
142 #[serde(skip_serializing_if = "Option::is_none")]
144 pub next_cursor: Option<String>,
145
146 #[serde(skip_serializing_if = "Option::is_none")]
148 pub total_pages: Option<u32>,
149
150 #[serde(skip_serializing_if = "Option::is_none")]
152 pub current_page: Option<u32>,
153
154 #[serde(skip_serializing_if = "Option::is_none")]
156 pub total_items: Option<u32>,
157}
158
159pub type ToolRetrieveEnumResponse = Vec<String>;
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct ToolProxyParams {
167 pub endpoint: String,
169
170 pub method: HttpMethod,
172
173 #[serde(skip_serializing_if = "Option::is_none")]
175 pub body: Option<serde_json::Value>,
176
177 #[serde(skip_serializing_if = "Option::is_none")]
179 pub connected_account_id: Option<String>,
180
181 #[serde(skip_serializing_if = "Option::is_none")]
183 pub parameters: Option<Vec<ProxyParameter>>,
184
185 #[serde(skip_serializing_if = "Option::is_none")]
187 pub custom_connection_data: Option<CustomConnectionData>,
188}
189
190#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
192#[serde(rename_all = "UPPERCASE")]
193pub enum HttpMethod {
194 Get,
195 Post,
196 Put,
197 Delete,
198 Patch,
199 Head,
200 Options,
201}
202
203#[derive(Debug, Clone, Serialize, Deserialize)]
205pub struct ProxyParameter {
206 pub name: String,
208
209 pub value: String,
211
212 #[serde(rename = "in")]
214 pub location: ParameterLocation,
215}
216
217#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
219#[serde(rename_all = "lowercase")]
220pub enum ParameterLocation {
221 Header,
223
224 Query,
226
227 Path,
229
230 Body,
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct ToolProxyResponse {
237 pub data: serde_json::Value,
239
240 pub status: u16,
242
243 #[serde(skip_serializing_if = "Option::is_none")]
245 pub headers: Option<HashMap<String, String>>,
246
247 #[serde(skip_serializing_if = "Option::is_none")]
249 pub binary_data: Option<String>,
250
251 pub successful: bool,
253
254 #[serde(skip_serializing_if = "Option::is_none")]
256 pub error: Option<String>,
257}
258
259#[derive(Debug, Clone, Serialize, Deserialize)]
261pub struct ToolInputGenerationParams {
262 pub tool_slug: String,
264
265 pub text: String,
267
268 #[serde(skip_serializing_if = "Option::is_none")]
270 pub custom_tool_description: Option<String>,
271
272 #[serde(skip_serializing_if = "Option::is_none")]
274 pub custom_system_prompt: Option<String>,
275}
276
277#[derive(Debug, Clone, Serialize, Deserialize)]
279pub struct ToolInputGenerationResponse {
280 #[serde(skip_serializing_if = "Option::is_none")]
282 pub arguments: Option<HashMap<String, serde_json::Value>>,
283
284 #[serde(skip_serializing_if = "Option::is_none")]
286 pub error: Option<String>,
287
288 pub successful: bool,
290}
291
292#[derive(Debug, Clone, Serialize, Deserialize)]
294pub struct CustomToolDefinition {
295 pub slug: String,
297
298 pub name: String,
300
301 pub description: String,
303
304 pub input_schema: serde_json::Value,
306
307 #[serde(skip_serializing_if = "Option::is_none")]
309 pub output_schema: Option<serde_json::Value>,
310
311 #[serde(skip_serializing_if = "Option::is_none")]
313 pub toolkit: Option<String>,
314
315 #[serde(default)]
317 pub requires_auth: bool,
318}
319
320#[derive(Debug, Clone, Serialize, Deserialize)]
322pub struct CustomToolExecutionRequest {
323 pub slug: String,
325
326 pub arguments: HashMap<String, serde_json::Value>,
328
329 #[serde(skip_serializing_if = "Option::is_none")]
331 pub user_id: Option<String>,
332
333 #[serde(skip_serializing_if = "Option::is_none")]
335 pub connected_account_id: Option<String>,
336}
337
338#[cfg(test)]
342mod tests {
343 use super::*;
344
345 #[test]
346 fn test_tool_execution_response_reexport() {
347 let response = ToolExecutionResponse {
349 data: serde_json::json!({"result": "success"}),
350 error: None,
351 successful: true,
352 log_id: Some("log_123".to_string()),
353 session_info: None,
354 };
355
356 let json = serde_json::to_string(&response).unwrap();
357 assert!(json.contains("success"));
358 assert!(json.contains("log_123"));
359 }
360
361 #[test]
362 fn test_http_method_serialization() {
363 let method = HttpMethod::Post;
364 let json = serde_json::to_string(&method).unwrap();
365 assert_eq!(json, "\"POST\"");
366 }
367
368 #[test]
369 fn test_parameter_location_serialization() {
370 let location = ParameterLocation::Header;
371 let json = serde_json::to_string(&location).unwrap();
372 assert_eq!(json, "\"header\"");
373 }
374
375 #[test]
376 fn test_tool_list_params_default() {
377 let params = ToolListParams::default();
378 assert!(params.tool_slugs.is_none());
379 assert!(params.toolkit_slug.is_none());
380 assert!(params.search.is_none());
381 }
382
383 #[test]
384 fn test_tool_execute_params_reexport() {
385 let mut arguments = HashMap::new();
387 arguments.insert("title".to_string(), serde_json::json!("Test"));
388
389 let params = ToolExecuteParams {
390 allow_tracing: None,
391 arguments,
392 connected_account_id: Some("ca_123".to_string()),
393 custom_auth_params: None,
394 custom_connection_data: None,
395 entity_id: None,
396 text: None,
397 user_id: Some("user_456".to_string()),
398 version: Some("1.0.0".to_string()),
399 dangerously_skip_version_check: Some(false),
400 };
401
402 let json = serde_json::to_string(¶ms).unwrap();
403 assert!(json.contains("ca_123"));
404 assert!(json.contains("user_456"));
405 }
406
407 #[test]
408 fn test_tool_proxy_params() {
409 let params = ToolProxyParams {
410 endpoint: "/api/v1/users".to_string(),
411 method: HttpMethod::Get,
412 body: None,
413 connected_account_id: Some("ca_123".to_string()),
414 parameters: Some(vec![ProxyParameter {
415 name: "Authorization".to_string(),
416 value: "Bearer token".to_string(),
417 location: ParameterLocation::Header,
418 }]),
419 custom_connection_data: None,
420 };
421
422 assert_eq!(params.method, HttpMethod::Get);
423 assert_eq!(params.endpoint, "/api/v1/users");
424 assert!(params.parameters.is_some());
425 }
426
427 #[test]
428 fn test_custom_tool_definition() {
429 let tool = CustomToolDefinition {
430 slug: "my_custom_tool".to_string(),
431 name: "My Custom Tool".to_string(),
432 description: "A custom tool for testing".to_string(),
433 input_schema: serde_json::json!({
434 "type": "object",
435 "properties": {
436 "input": {"type": "string"}
437 }
438 }),
439 output_schema: None,
440 toolkit: None,
441 requires_auth: false,
442 };
443
444 assert_eq!(tool.slug, "my_custom_tool");
445 assert!(!tool.requires_auth);
446 }
447
448 #[test]
449 fn test_tool_info_deserialization() {
450 let json = r#"{
451 "slug": "GITHUB_CREATE_ISSUE",
452 "name": "Create Issue",
453 "description": "Create a new issue",
454 "toolkit": {
455 "slug": "github",
456 "name": "GitHub"
457 },
458 "input_parameters": {},
459 "output_parameters": {},
460 "scopes": ["repo"],
461 "tags": ["write"],
462 "version": "1.0.0",
463 "available_versions": ["1.0.0"],
464 "is_deprecated": false,
465 "no_auth": false
466 }"#;
467
468 let tool: ToolInfo = serde_json::from_str(json).unwrap();
469 assert_eq!(tool.slug, "GITHUB_CREATE_ISSUE");
470 assert_eq!(tool.toolkit.slug, "github");
471 assert_eq!(tool.scopes.len(), 1);
472 }
473}