xai_openapi/
tools.rs

1//! Tool and function call types for xAI API.
2
3use serde::{Deserialize, Serialize};
4
5use crate::prelude::*;
6
7use crate::common::Annotation;
8
9/// Definition of one tool that the model can call.
10#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
11#[serde(tag = "type", rename_all = "snake_case")]
12pub enum Tool {
13    /// A function tool that the model can call.
14    Function {
15        /// Definition of tool call available to the model.
16        function: FunctionDefinition,
17    },
18    /// Live search tool.
19    LiveSearch {
20        /// Search sources.
21        sources: Vec<crate::search::SearchSource>,
22    },
23}
24
25impl Default for Tool {
26    fn default() -> Self {
27        Tool::Function {
28            function: FunctionDefinition::default(),
29        }
30    }
31}
32
33/// Definition of the tool call made available to the model.
34#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
35pub struct FunctionDefinition {
36    /// The name of the function.
37    pub name: String,
38
39    /// A JSON schema describing the function parameters.
40    pub parameters: serde_json::Value,
41
42    /// A description of the function to indicate to the model when to call it.
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub description: Option<String>,
45
46    /// Not supported. Only maintained for compatibility reasons.
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub strict: Option<bool>,
49}
50
51/// A tool call made by the model.
52#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
53pub struct ToolCall {
54    /// A unique ID of the tool call generated by xAI.
55    pub id: String,
56
57    /// Function to call for the tool call.
58    pub function: Function,
59
60    /// Index of the tool call.
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub index: Option<i32>,
63
64    /// Type of tool call.
65    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
66    pub tool_type: Option<String>,
67}
68
69/// Function call details.
70#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
71pub struct Function {
72    /// Name of the function.
73    pub name: String,
74
75    /// Arguments available to the function.
76    pub arguments: String,
77}
78
79/// Function name for tool choice.
80#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
81pub struct FunctionChoice {
82    /// Name of the function.
83    pub name: String,
84}
85
86/// Parameter to control how model chooses the tools.
87#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
88#[serde(untagged)]
89pub enum ToolChoice {
90    /// Controls tool access by the model.
91    /// `"none"` makes model ignore tools, `"auto"` lets the model automatically decide,
92    /// `"required"` forces model to pick a tool to call.
93    Mode(String),
94    /// Specific function to use.
95    Specific {
96        /// Type is always `"function"`.
97        #[serde(rename = "type")]
98        tool_type: String,
99        /// Name of the function to use.
100        #[serde(skip_serializing_if = "Option::is_none")]
101        function: Option<FunctionChoice>,
102    },
103}
104
105impl Default for ToolChoice {
106    fn default() -> Self {
107        ToolChoice::Mode("auto".to_string())
108    }
109}
110
111/// A tool call to run a function (for Responses API).
112#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
113pub struct FunctionToolCall {
114    /// The type of the function tool call.
115    #[serde(rename = "type")]
116    pub call_type: String,
117
118    /// The unique ID of the function tool call generated by the model.
119    pub call_id: String,
120
121    /// The name of the function.
122    pub name: String,
123
124    /// The arguments to pass to the function, as a JSON string.
125    pub arguments: String,
126
127    /// The unique ID of the function tool call.
128    #[serde(skip_serializing_if = "Option::is_none")]
129    pub id: Option<String>,
130
131    /// Status of the item. One of `completed`, `in_progress` or `incomplete`.
132    #[serde(skip_serializing_if = "Option::is_none")]
133    pub status: Option<String>,
134}
135
136/// The output of a function tool call.
137#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
138pub struct FunctionToolCallOutput {
139    /// The type of the function tool call, which is always `function_call_output`.
140    #[serde(rename = "type")]
141    pub output_type: String,
142
143    /// The unique ID of the function tool call generated by the model.
144    pub call_id: String,
145
146    /// The output of the function tool call, as a JSON string.
147    pub output: String,
148}
149
150/// The output of a web search tool call.
151#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
152pub struct WebSearchCall {
153    /// The type of the web search tool call. Always `web_search_call`.
154    #[serde(rename = "type")]
155    pub call_type: String,
156
157    /// An object describing the specific action taken in this web search call.
158    pub action: WebSearchAction,
159
160    /// The unique ID of the web search tool call.
161    #[serde(skip_serializing_if = "Option::is_none")]
162    pub id: Option<String>,
163
164    /// The status of the web search tool call.
165    #[serde(skip_serializing_if = "Option::is_none")]
166    pub status: Option<String>,
167}
168
169/// Web search action.
170#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
171#[serde(tag = "type", rename_all = "snake_case")]
172pub enum WebSearchAction {
173    /// Action type "search" - Performs a web search query.
174    Search {
175        /// The search query.
176        query: String,
177        /// The sources used in the search.
178        #[serde(skip_serializing_if = "Option::is_none")]
179        sources: Option<Vec<WebSearchSource>>,
180    },
181    /// Action type `open_page` - Opens a specific URL from search results.
182    OpenPage {
183        /// The URL of the page to open.
184        url: String,
185    },
186    /// Action type "find" - Searches for a pattern within a loaded page.
187    Find {
188        /// The source of the page to search in.
189        source: WebSearchSource,
190        /// The pattern or text to search for within the page.
191        pattern: String,
192    },
193}
194
195impl Default for WebSearchAction {
196    fn default() -> Self {
197        WebSearchAction::Search {
198            query: String::new(),
199            sources: None,
200        }
201    }
202}
203
204/// Web search source.
205#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
206pub struct WebSearchSource {
207    /// The type of source.
208    #[serde(rename = "type")]
209    pub source_type: String,
210
211    /// The URL of the source.
212    #[serde(skip_serializing_if = "Option::is_none")]
213    pub url: Option<String>,
214}
215
216/// Web search options.
217#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
218pub struct WebSearchOptions {
219    /// This field included for compatibility reason with `OpenAI`'s API.
220    #[serde(skip_serializing_if = "Option::is_none")]
221    pub search_context_size: Option<String>,
222
223    /// Only included for compatibility.
224    #[serde(skip_serializing_if = "Option::is_none")]
225    pub filters: Option<serde_json::Value>,
226
227    /// Only included for compatibility.
228    #[serde(skip_serializing_if = "Option::is_none")]
229    pub user_location: Option<serde_json::Value>,
230}
231
232/// Web search filters.
233#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
234pub struct WebSearchFilters {
235    /// List of website domains to restrict search results to.
236    #[serde(skip_serializing_if = "Option::is_none")]
237    pub allowed_domains: Option<Vec<String>>,
238
239    /// List of website domains to exclude from search results.
240    #[serde(skip_serializing_if = "Option::is_none")]
241    pub excluded_domains: Option<Vec<String>>,
242}
243
244/// The output of a file search tool call.
245#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
246pub struct FileSearchCall {
247    /// The type of the file search tool call. Always `file_search_call`.
248    #[serde(rename = "type")]
249    pub call_type: String,
250
251    /// The queries used to search for files.
252    pub queries: Vec<String>,
253
254    /// The results of the file search tool call.
255    pub results: Vec<FileSearchResult>,
256
257    /// The unique ID of the file search tool call.
258    #[serde(skip_serializing_if = "Option::is_none")]
259    pub id: Option<String>,
260
261    /// The status of the file search tool call.
262    #[serde(skip_serializing_if = "Option::is_none")]
263    pub status: Option<String>,
264}
265
266/// A file search result.
267#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
268pub struct FileSearchResult {
269    /// The file ID of the file search result.
270    pub file_id: String,
271
272    /// The filename of the file search result.
273    pub filename: String,
274
275    /// The score of the file search result.
276    pub score: f64,
277
278    /// The text of the file search result.
279    pub text: String,
280}
281
282/// The output of a code interpreter tool call.
283#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
284pub struct CodeInterpreterCall {
285    /// The type of the code interpreter tool call. Always `code_interpreter_call`.
286    #[serde(rename = "type")]
287    pub call_type: String,
288
289    /// The outputs of the code interpreter tool call.
290    pub outputs: Vec<CodeInterpreterOutput>,
291
292    /// The code of the code interpreter tool call.
293    #[serde(skip_serializing_if = "Option::is_none")]
294    pub code: Option<String>,
295
296    /// The unique ID of the code interpreter tool call.
297    #[serde(skip_serializing_if = "Option::is_none")]
298    pub id: Option<String>,
299
300    /// The status of the code interpreter tool call.
301    #[serde(skip_serializing_if = "Option::is_none")]
302    pub status: Option<String>,
303}
304
305/// Output of a code interpreter tool call.
306#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
307#[serde(tag = "type", rename_all = "snake_case")]
308pub enum CodeInterpreterOutput {
309    /// Log output from code interpreter.
310    Logs {
311        /// The output of the code interpreter tool call.
312        logs: String,
313    },
314    /// Image output from code interpreter.
315    Image {
316        /// The URL of the generated image.
317        url: String,
318    },
319}
320
321impl Default for CodeInterpreterOutput {
322    fn default() -> Self {
323        CodeInterpreterOutput::Logs {
324            logs: String::new(),
325        }
326    }
327}
328
329/// The output of a MCP tool call.
330#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
331pub struct McpCall {
332    /// The type of the MCP tool call. Always `mcp_call`.
333    #[serde(rename = "type")]
334    pub call_type: String,
335
336    /// The name of the tool that was run.
337    pub name: String,
338
339    /// The label of the MCP server running the tool.
340    pub server_label: String,
341
342    /// A JSON string of the arguments passed to the tool.
343    pub arguments: String,
344
345    /// The output of the MCP tool call.
346    pub output: String,
347
348    /// The unique ID of the MCP tool call.
349    #[serde(skip_serializing_if = "Option::is_none")]
350    pub id: Option<String>,
351
352    /// The error message of the MCP tool call.
353    #[serde(skip_serializing_if = "Option::is_none")]
354    pub error: Option<String>,
355
356    /// The status of the MCP tool call.
357    #[serde(skip_serializing_if = "Option::is_none")]
358    pub status: Option<String>,
359}
360
361/// The output of a custom tool call.
362#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
363pub struct CustomToolCall {
364    /// The type of the custom tool call.
365    #[serde(rename = "type")]
366    pub call_type: String,
367
368    /// The unique ID of the function tool call generated by the model.
369    pub call_id: String,
370
371    /// An identifier used to map this custom tool call to a tool call output.
372    pub name: String,
373
374    /// The status of the custom tool call.
375    pub id: String,
376
377    /// The unique ID of the custom tool call.
378    #[serde(skip_serializing_if = "Option::is_none")]
379    pub input: Option<String>,
380
381    /// Status of the item. One of `completed`, `in_progress` or `incomplete`.
382    #[serde(skip_serializing_if = "Option::is_none")]
383    pub status: Option<String>,
384}
385
386/// Definition of one tool that the model can call (for Responses API).
387#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
388#[serde(tag = "type", rename_all = "snake_case")]
389pub enum ModelTool {
390    /// A function that the model can call.
391    Function {
392        /// The name of the function.
393        name: String,
394        /// A JSON schema describing the function parameters.
395        parameters: serde_json::Value,
396        /// A description of the function.
397        #[serde(skip_serializing_if = "Option::is_none")]
398        description: Option<String>,
399        /// Not supported. Only maintained for compatibility reasons.
400        #[serde(skip_serializing_if = "Option::is_none")]
401        strict: Option<bool>,
402    },
403    /// Search the web.
404    WebSearch {
405        /// List of website domains to allow in the search results.
406        #[serde(skip_serializing_if = "Option::is_none")]
407        allowed_domains: Option<Vec<String>>,
408        /// List of website domains to exclude from the search results.
409        #[serde(skip_serializing_if = "Option::is_none")]
410        excluded_domains: Option<Vec<String>>,
411        /// Enable image understanding during web search.
412        #[serde(skip_serializing_if = "Option::is_none")]
413        enable_image_understanding: Option<bool>,
414        /// Control whether the web search tool fetches live content or uses only cached content.
415        #[serde(skip_serializing_if = "Option::is_none")]
416        external_web_access: Option<bool>,
417        /// Filters to apply to the search results.
418        #[serde(skip_serializing_if = "Option::is_none")]
419        filters: Option<WebSearchFilters>,
420        /// High level guidance for the amount of context window space to use.
421        #[serde(skip_serializing_if = "Option::is_none")]
422        search_context_size: Option<String>,
423        /// The user location to use for the search.
424        #[serde(skip_serializing_if = "Option::is_none")]
425        user_location: Option<serde_json::Value>,
426    },
427    /// Search X.
428    XSearch {
429        /// List of X Handles of the users from whom to consider the posts.
430        #[serde(skip_serializing_if = "Option::is_none")]
431        allowed_x_handles: Option<Vec<String>>,
432        /// List of X Handles of the users from whom to exclude the posts.
433        #[serde(skip_serializing_if = "Option::is_none")]
434        excluded_x_handles: Option<Vec<String>>,
435        /// Enable image understanding during X search.
436        #[serde(skip_serializing_if = "Option::is_none")]
437        enable_image_understanding: Option<bool>,
438        /// Enable video understanding during X search.
439        #[serde(skip_serializing_if = "Option::is_none")]
440        enable_video_understanding: Option<bool>,
441        /// Date from which to consider the results.
442        #[serde(skip_serializing_if = "Option::is_none")]
443        from_date: Option<String>,
444        /// Date up to which to consider the results.
445        #[serde(skip_serializing_if = "Option::is_none")]
446        to_date: Option<String>,
447    },
448    /// Search the knowledge bases.
449    FileSearch {
450        /// List of vector store IDs to search within.
451        vector_store_ids: Vec<String>,
452        /// Maximum number of results.
453        #[serde(skip_serializing_if = "Option::is_none")]
454        max_num_results: Option<i32>,
455        /// A filter to apply.
456        #[serde(skip_serializing_if = "Option::is_none")]
457        filters: Option<serde_json::Value>,
458        /// Ranking options for search.
459        #[serde(skip_serializing_if = "Option::is_none")]
460        ranking_options: Option<serde_json::Value>,
461    },
462    /// Execute code.
463    CodeInterpreter {
464        /// The code interpreter container.
465        #[serde(skip_serializing_if = "Option::is_none")]
466        container: Option<serde_json::Value>,
467    },
468    /// A remote MCP server to use.
469    Mcp {
470        /// The label of the MCP server.
471        server_label: String,
472        /// The URL of the MCP server.
473        server_url: String,
474        /// Allowed tools.
475        #[serde(skip_serializing_if = "Option::is_none")]
476        allowed_tools: Option<Vec<String>>,
477        /// Authorization token.
478        #[serde(skip_serializing_if = "Option::is_none")]
479        authorization: Option<String>,
480        /// Connector ID.
481        #[serde(skip_serializing_if = "Option::is_none")]
482        connector_id: Option<String>,
483        /// Additional headers.
484        #[serde(skip_serializing_if = "Option::is_none")]
485        headers: Option<HashMap<String, String>>,
486        /// Whether to require approval.
487        #[serde(skip_serializing_if = "Option::is_none")]
488        require_approval: Option<String>,
489        /// Server description.
490        #[serde(skip_serializing_if = "Option::is_none")]
491        server_description: Option<String>,
492    },
493}
494
495impl Default for ModelTool {
496    fn default() -> Self {
497        ModelTool::Function {
498            name: String::new(),
499            parameters: serde_json::Value::Null,
500            description: None,
501            strict: None,
502        }
503    }
504}
505
506/// Parameter to control how model chooses the tools (for Responses API).
507#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
508#[serde(untagged)]
509pub enum ModelToolChoice {
510    /// Controls tool access by the model.
511    Mode(String),
512    /// Specific function to use.
513    Specific {
514        /// Type is always `"function"`.
515        #[serde(rename = "type")]
516        tool_type: String,
517        /// Name of the function to use.
518        name: String,
519    },
520}
521
522impl Default for ModelToolChoice {
523    fn default() -> Self {
524        ModelToolChoice::Mode("auto".to_string())
525    }
526}
527
528/// Text output from the model.
529#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
530pub struct OutputText {
531    /// The type of the output. Always `output_text`.
532    #[serde(rename = "type")]
533    pub output_type: String,
534
535    /// The text output from the model.
536    pub text: String,
537
538    /// Citations.
539    pub annotations: Vec<Annotation>,
540
541    /// The log probabilities of each output token returned.
542    #[serde(skip_serializing_if = "Option::is_none")]
543    pub logprobs: Option<Vec<crate::chat::TokenLogProb>>,
544}
545
546/// Refusal output from the model.
547#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
548pub struct OutputRefusal {
549    /// The type of the output. Always `refusal`.
550    #[serde(rename = "type")]
551    pub output_type: String,
552
553    /// The reason for the refusal.
554    pub refusal: String,
555}
556
557/// Output message content.
558#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
559#[serde(tag = "type", rename_all = "snake_case")]
560pub enum OutputMessageContent {
561    /// Text output.
562    OutputText {
563        /// The text output from the model.
564        text: String,
565        /// Citations.
566        annotations: Vec<Annotation>,
567        /// The log probabilities of each output token.
568        #[serde(skip_serializing_if = "Option::is_none")]
569        logprobs: Option<Vec<crate::chat::TokenLogProb>>,
570    },
571    /// Refusal output.
572    Refusal {
573        /// The reason for the refusal.
574        refusal: String,
575    },
576}
577
578impl Default for OutputMessageContent {
579    fn default() -> Self {
580        OutputMessageContent::OutputText {
581            text: String::new(),
582            annotations: Vec::new(),
583            logprobs: None,
584        }
585    }
586}