1use crate::schema::to_gemini_parameters;
4use schemars::JsonSchema;
5use serde::de::DeserializeOwned;
6use serde_json::Value;
7
8#[derive(Debug, Clone)]
10pub struct ToolDef {
11 pub name: String,
12 pub description: String,
13 pub parameters: Value,
14}
15
16pub fn tool<T: JsonSchema + DeserializeOwned>(name: &str, description: &str) -> ToolDef {
18 ToolDef {
19 name: name.to_string(),
20 description: description.to_string(),
21 parameters: to_gemini_parameters::<T>(),
22 }
23}
24
25impl ToolDef {
26 pub fn to_gemini(&self) -> Value {
27 serde_json::json!({
28 "name": self.name,
29 "description": self.description,
30 "parameters": self.parameters,
31 })
32 }
33
34 pub fn to_openai(&self) -> Value {
35 serde_json::json!({
36 "type": "function",
37 "function": {
38 "name": self.name,
39 "description": self.description,
40 "parameters": self.parameters,
41 }
42 })
43 }
44
45 pub fn parse_args<T: DeserializeOwned>(&self, args: &Value) -> Result<T, serde_json::Error> {
46 serde_json::from_value(args.clone())
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 use schemars::JsonSchema;
54 use serde::{Deserialize, Serialize};
55
56 #[derive(Debug, Serialize, Deserialize, JsonSchema)]
57 struct MockTool {
58 input_path: String,
59 quality: Option<f64>,
60 }
61
62 #[test]
63 fn tool_generates_gemini_format() {
64 let t = tool::<MockTool>("mock_tool", "A mock tool");
65 let gemini = t.to_gemini();
66 assert_eq!(gemini["name"], "mock_tool");
67 assert!(gemini["parameters"]["properties"]["input_path"].is_object());
68 }
69
70 #[test]
71 fn tool_generates_openai_format() {
72 let t = tool::<MockTool>("mock_tool", "A mock tool");
73 let openai = t.to_openai();
74 assert_eq!(openai["type"], "function");
75 assert_eq!(openai["function"]["name"], "mock_tool");
76 }
77}