1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
5#[serde(rename_all = "snake_case")]
6pub enum ToolCategory {
7 FileSystem,
8 Web,
9 Shell,
10 Memory,
11 Knowledge,
12 Browser,
13 Agent,
14 Schedule,
15 Event,
16 Media,
17 SourceControl,
18 Container,
19 Data,
20 CodeAnalysis,
21 Archive,
22 Template,
23 Crypto,
24 Plugin,
25}
26
27impl std::fmt::Display for ToolCategory {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 match self {
30 Self::FileSystem => write!(f, "filesystem"),
31 Self::Web => write!(f, "web"),
32 Self::Shell => write!(f, "shell"),
33 Self::Memory => write!(f, "memory"),
34 Self::Knowledge => write!(f, "knowledge"),
35 Self::Browser => write!(f, "browser"),
36 Self::Agent => write!(f, "agent"),
37 Self::Schedule => write!(f, "schedule"),
38 Self::Event => write!(f, "event"),
39 Self::Media => write!(f, "media"),
40 Self::SourceControl => write!(f, "source_control"),
41 Self::Container => write!(f, "container"),
42 Self::Data => write!(f, "data"),
43 Self::CodeAnalysis => write!(f, "code_analysis"),
44 Self::Archive => write!(f, "archive"),
45 Self::Template => write!(f, "template"),
46 Self::Crypto => write!(f, "crypto"),
47 Self::Plugin => write!(f, "plugin"),
48 }
49 }
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct ToolDefinition {
55 pub name: String,
57 pub description: String,
59 pub input_schema: serde_json::Value,
61 pub category: ToolCategory,
63}
64
65#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct ToolResult {
68 pub success: bool,
70 pub output: serde_json::Value,
72 pub error: Option<String>,
74 pub duration_ms: u64,
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn test_tool_category_display_all() {
84 assert_eq!(ToolCategory::FileSystem.to_string(), "filesystem");
85 assert_eq!(ToolCategory::Web.to_string(), "web");
86 assert_eq!(ToolCategory::Shell.to_string(), "shell");
87 assert_eq!(ToolCategory::Memory.to_string(), "memory");
88 assert_eq!(ToolCategory::Knowledge.to_string(), "knowledge");
89 assert_eq!(ToolCategory::Browser.to_string(), "browser");
90 assert_eq!(ToolCategory::Agent.to_string(), "agent");
91 assert_eq!(ToolCategory::Schedule.to_string(), "schedule");
92 assert_eq!(ToolCategory::Event.to_string(), "event");
93 assert_eq!(ToolCategory::Media.to_string(), "media");
94 assert_eq!(ToolCategory::SourceControl.to_string(), "source_control");
95 assert_eq!(ToolCategory::Container.to_string(), "container");
96 assert_eq!(ToolCategory::Data.to_string(), "data");
97 assert_eq!(ToolCategory::CodeAnalysis.to_string(), "code_analysis");
98 assert_eq!(ToolCategory::Archive.to_string(), "archive");
99 assert_eq!(ToolCategory::Template.to_string(), "template");
100 assert_eq!(ToolCategory::Crypto.to_string(), "crypto");
101 assert_eq!(ToolCategory::Plugin.to_string(), "plugin");
102 }
103
104 #[test]
105 fn test_tool_category_serde_roundtrip() {
106 let categories = vec![
107 ToolCategory::FileSystem,
108 ToolCategory::Web,
109 ToolCategory::Shell,
110 ToolCategory::Memory,
111 ToolCategory::Knowledge,
112 ToolCategory::Browser,
113 ToolCategory::Agent,
114 ToolCategory::Schedule,
115 ToolCategory::Event,
116 ToolCategory::Media,
117 ToolCategory::SourceControl,
118 ToolCategory::Container,
119 ToolCategory::Data,
120 ToolCategory::CodeAnalysis,
121 ToolCategory::Archive,
122 ToolCategory::Template,
123 ToolCategory::Crypto,
124 ToolCategory::Plugin,
125 ];
126 for cat in &categories {
127 let json = serde_json::to_string(cat).expect("serialize");
128 let deser: ToolCategory = serde_json::from_str(&json).expect("deserialize");
129 assert_eq!(&deser, cat);
130 }
131 }
132
133 #[test]
134 fn test_tool_category_serde_values() {
135 assert_eq!(
136 serde_json::to_string(&ToolCategory::FileSystem).unwrap(),
137 "\"file_system\""
138 );
139 assert_eq!(
140 serde_json::to_string(&ToolCategory::SourceControl).unwrap(),
141 "\"source_control\""
142 );
143 assert_eq!(
144 serde_json::to_string(&ToolCategory::CodeAnalysis).unwrap(),
145 "\"code_analysis\""
146 );
147 }
148
149 #[test]
150 fn test_tool_definition_serde() {
151 let def = ToolDefinition {
152 name: "read_file".to_string(),
153 description: "Read a file from disk".to_string(),
154 input_schema: serde_json::json!({
155 "type": "object",
156 "properties": {
157 "path": {"type": "string"}
158 },
159 "required": ["path"]
160 }),
161 category: ToolCategory::FileSystem,
162 };
163 let json = serde_json::to_string(&def).expect("serialize");
164 let deser: ToolDefinition = serde_json::from_str(&json).expect("deserialize");
165 assert_eq!(deser.name, "read_file");
166 assert_eq!(deser.category, ToolCategory::FileSystem);
167 }
168
169 #[test]
170 fn test_tool_result_success() {
171 let result = ToolResult {
172 success: true,
173 output: serde_json::json!({"data": "hello"}),
174 error: None,
175 duration_ms: 50,
176 };
177 let json = serde_json::to_string(&result).expect("serialize");
178 let deser: ToolResult = serde_json::from_str(&json).expect("deserialize");
179 assert!(deser.success);
180 assert!(deser.error.is_none());
181 assert_eq!(deser.duration_ms, 50);
182 }
183
184 #[test]
185 fn test_tool_result_failure() {
186 let result = ToolResult {
187 success: false,
188 output: serde_json::Value::Null,
189 error: Some("file not found".to_string()),
190 duration_ms: 5,
191 };
192 assert!(!result.success);
193 assert_eq!(result.error.as_deref(), Some("file not found"));
194 }
195
196 #[test]
197 fn test_tool_category_equality() {
198 assert_eq!(ToolCategory::Web, ToolCategory::Web);
199 assert_ne!(ToolCategory::Web, ToolCategory::Shell);
200 }
201
202 #[test]
203 fn test_tool_category_hash() {
204 let mut set = std::collections::HashSet::new();
205 set.insert(ToolCategory::Web);
206 set.insert(ToolCategory::Shell);
207 set.insert(ToolCategory::Web);
208 assert_eq!(set.len(), 2);
209 }
210}