Skip to main content

sgr_agent_core/
tool.rs

1//! Tool definitions — typed Rust structs → function declarations for LLM APIs.
2
3use crate::schema::to_gemini_parameters;
4use schemars::JsonSchema;
5use serde::de::DeserializeOwned;
6use serde_json::Value;
7
8/// A tool definition ready for LLM API submission.
9#[derive(Debug, Clone)]
10pub struct ToolDef {
11    pub name: String,
12    pub description: String,
13    pub parameters: Value,
14}
15
16/// Create a tool definition from a typed struct.
17pub 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}