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