use serde::{Deserialize, Serialize};
use std::collections::HashMap;
pub use crate::models::modifiers::{CustomAuthParams, CustomConnectionData, ToolExecuteParams};
pub use crate::models::response::ToolExecutionResponse;
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ToolListParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_slugs: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub toolkit_slug: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub search: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub scopes: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tags: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub importance: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub show_deprecated: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub limit: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cursor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub toolkit_versions: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolInfo {
pub slug: String,
pub name: String,
pub description: String,
pub toolkit: ToolkitRef,
pub input_parameters: serde_json::Value,
pub output_parameters: serde_json::Value,
#[serde(default)]
pub scopes: Vec<String>,
#[serde(default)]
pub tags: Vec<String>,
pub version: String,
#[serde(default)]
pub available_versions: Vec<String>,
#[serde(default)]
pub is_deprecated: bool,
#[serde(default)]
pub no_auth: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolkitRef {
pub slug: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub logo: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolListResponse {
pub items: Vec<ToolInfo>,
#[serde(skip_serializing_if = "Option::is_none")]
pub next_cursor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub total_pages: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub current_page: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub total_items: Option<u32>,
}
pub type ToolRetrieveEnumResponse = Vec<String>;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolProxyParams {
pub endpoint: String,
pub method: HttpMethod,
#[serde(skip_serializing_if = "Option::is_none")]
pub body: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub connected_account_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parameters: Option<Vec<ProxyParameter>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_connection_data: Option<CustomConnectionData>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "UPPERCASE")]
pub enum HttpMethod {
Get,
Post,
Put,
Delete,
Patch,
Head,
Options,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProxyParameter {
pub name: String,
pub value: String,
#[serde(rename = "in")]
pub location: ParameterLocation,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ParameterLocation {
Header,
Query,
Path,
Body,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolProxyResponse {
pub data: serde_json::Value,
pub status: u16,
#[serde(skip_serializing_if = "Option::is_none")]
pub headers: Option<HashMap<String, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub binary_data: Option<String>,
pub successful: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolInputGenerationParams {
pub tool_slug: String,
pub text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_tool_description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub custom_system_prompt: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolInputGenerationResponse {
#[serde(skip_serializing_if = "Option::is_none")]
pub arguments: Option<HashMap<String, serde_json::Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
pub successful: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CustomToolDefinition {
pub slug: String,
pub name: String,
pub description: String,
pub input_schema: serde_json::Value,
#[serde(skip_serializing_if = "Option::is_none")]
pub output_schema: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub toolkit: Option<String>,
#[serde(default)]
pub requires_auth: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CustomToolExecutionRequest {
pub slug: String,
pub arguments: HashMap<String, serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub user_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub connected_account_id: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tool_execution_response_reexport() {
let response = ToolExecutionResponse {
data: serde_json::json!({"result": "success"}),
error: None,
successful: true,
log_id: Some("log_123".to_string()),
session_info: None,
};
let json = serde_json::to_string(&response).unwrap();
assert!(json.contains("success"));
assert!(json.contains("log_123"));
}
#[test]
fn test_http_method_serialization() {
let method = HttpMethod::Post;
let json = serde_json::to_string(&method).unwrap();
assert_eq!(json, "\"POST\"");
}
#[test]
fn test_parameter_location_serialization() {
let location = ParameterLocation::Header;
let json = serde_json::to_string(&location).unwrap();
assert_eq!(json, "\"header\"");
}
#[test]
fn test_tool_list_params_default() {
let params = ToolListParams::default();
assert!(params.tool_slugs.is_none());
assert!(params.toolkit_slug.is_none());
assert!(params.search.is_none());
}
#[test]
fn test_tool_execute_params_reexport() {
let mut arguments = HashMap::new();
arguments.insert("title".to_string(), serde_json::json!("Test"));
let params = ToolExecuteParams {
allow_tracing: None,
arguments,
connected_account_id: Some("ca_123".to_string()),
custom_auth_params: None,
custom_connection_data: None,
entity_id: None,
text: None,
user_id: Some("user_456".to_string()),
version: Some("1.0.0".to_string()),
dangerously_skip_version_check: Some(false),
};
let json = serde_json::to_string(¶ms).unwrap();
assert!(json.contains("ca_123"));
assert!(json.contains("user_456"));
}
#[test]
fn test_tool_proxy_params() {
let params = ToolProxyParams {
endpoint: "/api/v1/users".to_string(),
method: HttpMethod::Get,
body: None,
connected_account_id: Some("ca_123".to_string()),
parameters: Some(vec![ProxyParameter {
name: "Authorization".to_string(),
value: "Bearer token".to_string(),
location: ParameterLocation::Header,
}]),
custom_connection_data: None,
};
assert_eq!(params.method, HttpMethod::Get);
assert_eq!(params.endpoint, "/api/v1/users");
assert!(params.parameters.is_some());
}
#[test]
fn test_custom_tool_definition() {
let tool = CustomToolDefinition {
slug: "my_custom_tool".to_string(),
name: "My Custom Tool".to_string(),
description: "A custom tool for testing".to_string(),
input_schema: serde_json::json!({
"type": "object",
"properties": {
"input": {"type": "string"}
}
}),
output_schema: None,
toolkit: None,
requires_auth: false,
};
assert_eq!(tool.slug, "my_custom_tool");
assert!(!tool.requires_auth);
}
#[test]
fn test_tool_info_deserialization() {
let json = r#"{
"slug": "GITHUB_CREATE_ISSUE",
"name": "Create Issue",
"description": "Create a new issue",
"toolkit": {
"slug": "github",
"name": "GitHub"
},
"input_parameters": {},
"output_parameters": {},
"scopes": ["repo"],
"tags": ["write"],
"version": "1.0.0",
"available_versions": ["1.0.0"],
"is_deprecated": false,
"no_auth": false
}"#;
let tool: ToolInfo = serde_json::from_str(json).unwrap();
assert_eq!(tool.slug, "GITHUB_CREATE_ISSUE");
assert_eq!(tool.toolkit.slug, "github");
assert_eq!(tool.scopes.len(), 1);
}
}