ai_sdk_provider/language_model/content.rs
1use super::tool_result_output::ToolResultOutput;
2use crate::SharedProviderMetadata;
3use serde::{Deserialize, Serialize};
4
5/// Represents a single content element in a language model's response or message.
6///
7/// Content can take multiple forms depending on what the model generates or what is included
8/// in a message. This enum provides a unified interface for handling different types of content
9/// including text, files, tool calls, and citations.
10///
11/// # Variants
12///
13/// * `Text` - Plain text content generated by the model
14/// * `Reasoning` - Internal reasoning content from specialized reasoning models (e.g., o1)
15/// * `File` - Media content including images, audio, video, or other file types
16/// * `Source` - Citation or reference to an external source document
17/// * `ToolCall` - A tool/function call invocation from the model
18/// * `ToolResult` - The result of executing a tool or function
19///
20/// # Usage
21///
22/// Content elements are typically generated as part of a larger response and should be
23/// examined to determine the appropriate handling for each type.
24#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
25#[serde(tag = "type", rename_all = "kebab-case")]
26pub enum Content {
27 /// Plain text content generated by the model
28 Text(TextPart),
29 /// Internal reasoning content from specialized reasoning models
30 Reasoning(ReasoningPart),
31 /// Media content including images, audio, video, or other file types
32 File(FilePart),
33 /// Citation or reference to an external source document
34 Source(SourcePart),
35 /// A tool or function call invocation from the model
36 ToolCall(ToolCallPart),
37 /// The result of executing a tool or function
38 ToolResult(ToolResultPart),
39}
40
41/// Plain text content part from a language model response.
42///
43/// Represents textual content generated by the model. This is the most common content type
44/// and contains the main textual output of the language model.
45#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
46pub struct TextPart {
47 /// The actual text content
48 pub text: String,
49
50 /// Optional provider-specific metadata that may include usage information, model details,
51 /// or other provider-specific properties
52 #[serde(skip_serializing_if = "Option::is_none")]
53 pub provider_metadata: Option<SharedProviderMetadata>,
54}
55
56/// Internal reasoning content from advanced reasoning models.
57///
58/// Some specialized language models (such as o1) expose their internal reasoning process
59/// as structured content. This part contains the model's step-by-step reasoning before
60/// providing its final answer. Useful for understanding model behavior and debugging.
61///
62/// Note: Not all models support reasoning content. It will only be present when using
63/// models that are specifically designed for reasoning tasks.
64#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
65pub struct ReasoningPart {
66 /// The reasoning text describing the model's internal thought process
67 pub reasoning: String,
68
69 /// Optional provider-specific metadata
70 #[serde(skip_serializing_if = "Option::is_none")]
71 pub provider_metadata: Option<SharedProviderMetadata>,
72}
73
74/// File or media content part from a language model response.
75///
76/// Represents binary files, images, audio, video, or other media content generated or
77/// referenced by the model. The content can be provided as raw binary data or as a URL
78/// pointing to the file location.
79///
80/// # Example Use Cases
81///
82/// - Images generated by vision models
83/// - Audio files from speech synthesis models
84/// - Documents or archives created by processing models
85#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
86#[serde(rename_all = "camelCase")]
87pub struct FilePart {
88 /// File data, either as raw binary bytes or as a URL
89 pub data: super::FileData,
90
91 /// MIME type identifier (e.g., "image/jpeg", "audio/mp3", "application/pdf")
92 pub media_type: String,
93
94 /// Optional provider-specific metadata
95 #[serde(skip_serializing_if = "Option::is_none")]
96 pub provider_metadata: Option<SharedProviderMetadata>,
97}
98
99/// Citation or reference to an external source document.
100///
101/// When a model retrieves or references external sources (e.g., from a knowledge base,
102/// search results, or document repository), it includes source citations in the response.
103/// These allow you to trace the origins of information and verify facts used by the model.
104///
105/// # Fields
106///
107/// * `source_type` - The category of source (URL-based or document-based)
108/// * `id` - Unique identifier for the source within the response
109/// * `url` - Optional direct link to access the source
110/// * `title` - Optional human-readable title or name of the source
111/// * `provider_metadata` - Optional provider-specific details about the source
112#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
113#[serde(rename_all = "camelCase")]
114pub struct SourcePart {
115 /// Categorizes the source as either URL-based or document-based
116 pub source_type: SourceType,
117 /// Unique identifier for this source citation
118 pub id: String,
119
120 /// Optional URL pointing directly to the source material
121 #[serde(skip_serializing_if = "Option::is_none")]
122 pub url: Option<String>,
123
124 /// Optional descriptive title or name of the source
125 #[serde(skip_serializing_if = "Option::is_none")]
126 pub title: Option<String>,
127
128 /// Optional provider-specific metadata about the source
129 #[serde(skip_serializing_if = "Option::is_none")]
130 pub provider_metadata: Option<SharedProviderMetadata>,
131}
132
133/// Categorizes the type of source being cited.
134///
135/// Distinguishes between different source origins to help determine how to access
136/// or display the referenced material.
137///
138/// # Variants
139///
140/// * `Url` - Source is accessible via a direct HTTP/HTTPS URL
141/// * `Document` - Source is a document stored in a knowledge base or document repository
142#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
143#[serde(rename_all = "lowercase")]
144pub enum SourceType {
145 /// Source is accessible via a direct HTTP/HTTPS URL
146 Url,
147 /// Source is a document stored in a knowledge base or document repository
148 Document,
149}
150
151/// A request from the language model to invoke an external tool or function.
152///
153/// When a model detects that it needs to call a tool to accomplish a task, it emits
154/// a tool call with the tool name and arguments. The application is responsible for
155/// executing the tool and returning the results via a ToolResultPart.
156///
157/// # Fields
158///
159/// * `tool_call_id` - Unique identifier for correlating this call with its result
160/// * `tool_name` - Name of the tool to invoke (must match a provided tool definition)
161/// * `input` - Stringified JSON containing the tool arguments
162/// * `provider_executed` - If true, the provider automatically executed the tool
163/// * `dynamic` - If true, indicates a dynamic or runtime-generated tool call
164/// * `provider_metadata` - Optional provider-specific details
165///
166/// # Processing Tool Calls
167///
168/// When you receive a tool call, you should:
169/// 1. Extract the tool name and arguments
170/// 2. Locate the corresponding tool definition
171/// 3. Execute the tool with the provided arguments
172/// 4. Return a ToolResultPart with the results
173#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
174#[serde(rename_all = "camelCase")]
175pub struct ToolCallPart {
176 /// Unique identifier that correlates this tool call with its result
177 pub tool_call_id: String,
178 /// Name identifying which tool should be invoked
179 pub tool_name: String,
180 /// Stringified JSON containing the arguments for the tool
181 pub input: String,
182
183 /// Indicates whether the provider has already executed this tool
184 #[serde(skip_serializing_if = "Option::is_none")]
185 pub provider_executed: Option<bool>,
186
187 /// Indicates whether this is a dynamic or runtime-generated tool call
188 #[serde(skip_serializing_if = "Option::is_none")]
189 pub dynamic: Option<bool>,
190
191 /// Optional provider-specific metadata about the tool call
192 #[serde(skip_serializing_if = "Option::is_none")]
193 pub provider_metadata: Option<SharedProviderMetadata>,
194}
195
196/// The result of executing a tool or function in response to a model's tool call.
197///
198/// After the model requests a tool invocation via ToolCallPart, the results of that
199/// execution are communicated back through this message type. It contains the output
200/// from the tool execution, which may be text, structured data, or an error message.
201///
202/// # Fields
203///
204/// * `tool_call_id` - References the ToolCallPart this result corresponds to
205/// * `tool_name` - Name of the tool that was executed
206/// * `output` - The result from tool execution (text, structured, or error)
207/// * `preliminary` - If true, this is a partial result; more results may follow
208/// * `provider_metadata` - Optional provider-specific details about execution
209///
210/// # Including Tool Results in Messages
211///
212/// Tool results must be included in the message history when making subsequent
213/// requests, so the model can see what happened and make appropriate follow-up decisions.
214#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
215#[serde(rename_all = "camelCase")]
216pub struct ToolResultPart {
217 /// Identifier linking this result to the corresponding tool call
218 pub tool_call_id: String,
219 /// Name of the tool that was executed
220 pub tool_name: String,
221 /// The structured output or result from executing the tool
222 pub output: ToolResultOutput,
223
224 /// If true, this is a preliminary result and more results may be forthcoming
225 #[serde(skip_serializing_if = "Option::is_none")]
226 pub preliminary: Option<bool>,
227
228 /// Optional provider-specific metadata about the tool execution
229 #[serde(skip_serializing_if = "Option::is_none")]
230 pub provider_metadata: Option<SharedProviderMetadata>,
231}
232
233#[cfg(test)]
234mod tests {
235 use super::*;
236
237 #[test]
238 fn test_content_text_serialization() {
239 let content = Content::Text(TextPart {
240 text: "Hello".into(),
241 provider_metadata: None,
242 });
243 let json = serde_json::to_value(&content).unwrap();
244 assert_eq!(json["type"], "text");
245 assert_eq!(json["text"], "Hello");
246 }
247
248 #[test]
249 fn test_content_tool_call() {
250 let content = Content::ToolCall(ToolCallPart {
251 tool_call_id: "call-123".into(),
252 tool_name: "search".into(),
253 input: r#"{"query":"test"}"#.into(),
254 provider_executed: None,
255 dynamic: None,
256 provider_metadata: None,
257 });
258 let json = serde_json::to_value(&content).unwrap();
259 assert_eq!(json["type"], "tool-call");
260 assert_eq!(json["toolCallId"], "call-123");
261 assert_eq!(json["toolName"], "search");
262 }
263
264 #[test]
265 fn test_content_reasoning() {
266 let content = Content::Reasoning(ReasoningPart {
267 reasoning: "Let me think...".into(),
268 provider_metadata: None,
269 });
270 let json = serde_json::to_value(&content).unwrap();
271 assert_eq!(json["type"], "reasoning");
272 assert_eq!(json["reasoning"], "Let me think...");
273 }
274
275 #[test]
276 fn test_source_type_serialization() {
277 let source = SourcePart {
278 source_type: SourceType::Url,
279 id: "src-1".into(),
280 url: Some("https://example.com".into()),
281 title: None,
282 provider_metadata: None,
283 };
284 let json = serde_json::to_value(&source).unwrap();
285 assert_eq!(json["sourceType"], "url");
286 }
287
288 #[test]
289 fn test_tool_result_text_output() {
290 let result = ToolResultPart {
291 tool_call_id: "call-123".into(),
292 tool_name: "test_tool".into(),
293 output: ToolResultOutput::Text {
294 value: "success".into(),
295 provider_metadata: None,
296 },
297 preliminary: None,
298 provider_metadata: None,
299 };
300 let json = serde_json::to_value(&result).unwrap();
301 assert_eq!(json["toolName"], "test_tool");
302 assert_eq!(json["output"]["type"], "text");
303 assert_eq!(json["output"]["value"], "success");
304 }
305
306 #[test]
307 fn test_tool_result_error_output() {
308 let result = ToolResultPart {
309 tool_call_id: "call-123".into(),
310 tool_name: "test_tool".into(),
311 output: ToolResultOutput::ErrorText {
312 value: "error occurred".into(),
313 provider_metadata: None,
314 },
315 preliminary: None,
316 provider_metadata: None,
317 };
318 let json = serde_json::to_value(&result).unwrap();
319 assert_eq!(json["output"]["type"], "error-text");
320 assert_eq!(json["output"]["value"], "error occurred");
321 assert_eq!(json["toolName"], "test_tool");
322 }
323}