Skip to main content

llmkit_core/
tools.rs

1//! Tool/function-calling types, normalised across providers.
2
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6/// A tool the model may call, defined by a name, description, and JSON Schema.
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8pub struct Tool {
9    /// Tool name the model uses to invoke it.
10    pub name: String,
11    /// Human-readable description guiding when to use the tool.
12    #[serde(default)]
13    pub description: String,
14    /// JSON Schema for the tool's input object.
15    pub input_schema: Value,
16}
17
18impl Tool {
19    /// Build a tool from its parts.
20    pub fn new(
21        name: impl Into<String>,
22        description: impl Into<String>,
23        input_schema: Value,
24    ) -> Self {
25        Self { name: name.into(), description: description.into(), input_schema }
26    }
27
28    /// Build a tool from any type implementing [`ToolSchema`] (e.g. via the
29    /// `#[derive(ToolSchema)]` macro).
30    pub fn from_schema<T: ToolSchema>() -> Self {
31        Self {
32            name: T::tool_name().to_string(),
33            description: T::tool_description().to_string(),
34            input_schema: T::input_schema(),
35        }
36    }
37}
38
39/// How the model should choose among available tools.
40#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
41#[serde(rename_all = "snake_case")]
42pub enum ToolChoice {
43    /// Model decides whether and which tool to call.
44    #[default]
45    Auto,
46    /// Model must call at least one tool.
47    Any,
48    /// Model must not call any tool.
49    None,
50    /// Model must call the named tool.
51    Tool(String),
52}
53
54/// A tool invocation requested by the model.
55#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
56pub struct ToolCall {
57    /// Provider-assigned id, echoed back when returning the result.
58    pub id: String,
59    /// Name of the tool to invoke.
60    pub name: String,
61    /// Parsed JSON arguments.
62    pub input: Value,
63}
64
65impl ToolCall {
66    /// Construct a tool call.
67    pub fn new(id: impl Into<String>, name: impl Into<String>, input: Value) -> Self {
68        Self { id: id.into(), name: name.into(), input }
69    }
70}
71
72/// The result of executing a [`ToolCall`], returned to the model.
73#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
74pub struct ToolResult {
75    /// Id of the originating [`ToolCall`].
76    pub tool_use_id: String,
77    /// String content of the result.
78    pub content: String,
79    /// Whether the tool errored.
80    #[serde(default)]
81    pub is_error: bool,
82}
83
84impl ToolResult {
85    /// A successful tool result.
86    pub fn ok(tool_use_id: impl Into<String>, content: impl Into<String>) -> Self {
87        Self { tool_use_id: tool_use_id.into(), content: content.into(), is_error: false }
88    }
89
90    /// An errored tool result.
91    pub fn error(tool_use_id: impl Into<String>, content: impl Into<String>) -> Self {
92        Self { tool_use_id: tool_use_id.into(), content: content.into(), is_error: true }
93    }
94}
95
96/// Implemented by tool input structs to expose name, description, and schema.
97///
98/// Derive it with `#[derive(ToolSchema)]` from `llmkit-macros`.
99pub trait ToolSchema {
100    /// The tool's name.
101    fn tool_name() -> &'static str;
102    /// The tool's description.
103    fn tool_description() -> &'static str;
104    /// The JSON Schema for the tool's input.
105    fn input_schema() -> Value;
106}