Skip to main content

llmsdk_provider/language_model/
tool.rs

1//! Tool definitions passed in [`super::CallOptions::tools`].
2//!
3//! Mirrors `language-model-v4-function-tool.ts`, `-provider-tool.ts`, and
4//! `-tool-choice.ts`.
5// Rust guideline compliant 2026-02-21
6
7use serde::{Deserialize, Serialize};
8
9use crate::json::{JsonObject, JsonSchema};
10use crate::shared::ProviderOptions;
11
12/// Either a client-defined function tool or a provider-defined tool.
13///
14/// Wire `type` matches ai-sdk v4 verbatim (`"function"` / `"provider"`).
15#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
16#[serde(tag = "type", rename_all = "kebab-case")]
17pub enum Tool {
18    /// Client-defined function tool.
19    #[serde(rename = "function")]
20    Function(FunctionTool),
21    /// Provider-defined tool, e.g. `OpenAI`'s `web_search_preview`.
22    #[serde(rename = "provider")]
23    Provider(ProviderTool),
24}
25
26/// Client-defined function tool with a JSON schema input.
27#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
28pub struct FunctionTool {
29    /// Unique tool name within the call.
30    pub name: String,
31    /// Optional natural-language description.
32    #[serde(default, skip_serializing_if = "Option::is_none")]
33    pub description: Option<String>,
34    /// JSON schema for the input arguments.
35    #[serde(rename = "inputSchema")]
36    pub input_schema: JsonSchema,
37    /// Example inputs to guide the model.
38    #[serde(
39        default,
40        rename = "inputExamples",
41        skip_serializing_if = "Option::is_none"
42    )]
43    pub input_examples: Option<Vec<ToolInputExample>>,
44    /// Request strict schema enforcement when the provider supports it.
45    #[serde(default, skip_serializing_if = "Option::is_none")]
46    pub strict: Option<bool>,
47    /// Provider-specific options.
48    #[serde(
49        default,
50        rename = "providerOptions",
51        skip_serializing_if = "Option::is_none"
52    )]
53    pub provider_options: Option<ProviderOptions>,
54}
55
56/// One input example for [`FunctionTool::input_examples`].
57#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
58pub struct ToolInputExample {
59    /// Example input matching the schema.
60    pub input: JsonObject,
61}
62
63/// Provider-defined tool referenced by id.
64#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
65pub struct ProviderTool {
66    /// Provider-defined tool id, e.g. `"openai.web_search_preview"`.
67    pub id: String,
68    /// Logical name within the call.
69    pub name: String,
70    /// Provider-defined arguments.
71    #[serde(default, skip_serializing_if = "Option::is_none")]
72    pub args: Option<JsonObject>,
73    /// Provider-specific options.
74    #[serde(
75        default,
76        rename = "providerOptions",
77        skip_serializing_if = "Option::is_none"
78    )]
79    pub provider_options: Option<ProviderOptions>,
80}
81
82/// How the model should choose among the configured tools.
83#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
84#[serde(tag = "type", rename_all = "kebab-case")]
85pub enum ToolChoice {
86    /// Automatic selection (may pick no tool).
87    #[default]
88    Auto,
89    /// Model must not call any tool.
90    None,
91    /// Model must call exactly one tool.
92    Required,
93    /// Model must call this specific tool.
94    Tool {
95        /// Tool name to force.
96        #[serde(rename = "toolName")]
97        tool_name: String,
98    },
99}