Skip to main content

llm_kernel/llm/
tool.rs

1//! Tool/function calling types for LLM APIs.
2//!
3//! Provides the core types for defining tools, making tool calls, and returning
4//! results — compatible with OpenAI and Anthropic function calling APIs.
5
6use serde::{Deserialize, Serialize};
7
8/// Definition of a tool/function that an LLM can invoke.
9///
10/// Describes the tool's name, purpose, and expected input schema to the model.
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct ToolDefinition {
13    /// Name of the tool (e.g. `"get_weather"`).
14    pub name: String,
15    /// Human-readable description of what the tool does.
16    pub description: String,
17    /// JSON Schema object describing the tool's input parameters.
18    pub input_schema: serde_json::Value,
19}
20
21/// A tool call requested by the LLM during generation.
22///
23/// Contains the tool name and serialized arguments as returned by the model.
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct ToolCall {
26    /// Provider-assigned ID for this tool call (used to match results).
27    pub id: String,
28    /// Name of the tool to invoke.
29    pub name: String,
30    /// JSON-encoded arguments for the tool call.
31    pub arguments: String,
32}
33
34/// Result of executing a tool call, to be sent back to the LLM.
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct ToolResult {
37    /// ID of the `ToolCall` this result corresponds to.
38    pub tool_call_id: String,
39    /// Content returned by the tool execution.
40    pub content: String,
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46    use serde_json::json;
47
48    #[test]
49    fn tool_definition_roundtrip() {
50        let def = ToolDefinition {
51            name: "get_weather".into(),
52            description: "Get current weather".into(),
53            input_schema: json!({
54                "type": "object",
55                "properties": {
56                    "location": { "type": "string" }
57                },
58                "required": ["location"]
59            }),
60        };
61        let json = serde_json::to_string(&def).unwrap();
62        let back: ToolDefinition = serde_json::from_str(&json).unwrap();
63        assert_eq!(back.name, "get_weather");
64        assert_eq!(back.description, "Get current weather");
65    }
66
67    #[test]
68    fn tool_call_roundtrip() {
69        let call = ToolCall {
70            id: "call_abc123".into(),
71            name: "search".into(),
72            arguments: r#"{"query": "rust"}"#.into(),
73        };
74        let json = serde_json::to_string(&call).unwrap();
75        let back: ToolCall = serde_json::from_str(&json).unwrap();
76        assert_eq!(back.id, "call_abc123");
77        assert_eq!(back.name, "search");
78        assert_eq!(back.arguments, r#"{"query": "rust"}"#);
79    }
80
81    #[test]
82    fn tool_result_roundtrip() {
83        let result = ToolResult {
84            tool_call_id: "call_abc123".into(),
85            content: "Found 3 results".into(),
86        };
87        let json = serde_json::to_string(&result).unwrap();
88        let back: ToolResult = serde_json::from_str(&json).unwrap();
89        assert_eq!(back.tool_call_id, "call_abc123");
90        assert_eq!(back.content, "Found 3 results");
91    }
92}