Skip to main content

aiway_model_protocol/
chat.rs

1use super::shared::{FinishReason, ReasoningEffort, StopToken, Usage, WebSearchContextSize};
2use derive_builder::Builder;
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use std::collections::HashMap;
6use std::fmt::Display;
7
8#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
9pub struct ChatCompletionResponse {
10    /// A unique identifier for the chat completion.
11    #[serde(skip_serializing_if = "Option::is_none")]
12    pub id: Option<String>,
13    /// A list of chat completion choices. Can be more than one if n is greater than 1.
14    pub choices: Vec<ChatCompletionChoice>,
15    /// The Unix timestamp (in seconds) of when the chat completion was created.
16    #[serde(default = "crate::shared::default_created")]
17    pub created: u32,
18    /// The model used for the chat completion.
19    #[serde(default = "default_model")]
20    pub model: String,
21    /// The service tier used for processing the request.
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub service_tier: Option<String>,
24    /// This fingerprint represents the backend configuration that the model runs with.
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub system_fingerprint: Option<String>,
27    /// The object type, which is always chat.completion.
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub object: Option<String>,
30    /// Usage statistics for the completion request.
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub usage: Option<Usage>,
33}
34
35#[cfg(feature = "stream")]
36#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
37pub struct ChatCompletionChunkResponse {
38    /// A unique identifier for the chat completion. Each chunk has the same ID.
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub id: Option<String>,
41    /// A list of chat completion choices. Can be more than one if n is greater than 1.
42    pub choices: Vec<ChatCompletionChunkChoice>,
43    /// The Unix timestamp (in seconds) of when the chat completion was created. Each chunk has the same timestamp.
44    #[serde(default = "crate::shared::default_created")]
45    pub created: u32,
46    /// The model to generate the completion.
47    #[serde(default = "default_model")]
48    pub model: String,
49    /// This fingerprint represents the backend configuration that the model runs with.
50    /// Can be used in conjunction with the seed request parameter to understand when backend changes have been made that might impact determinism.
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub system_fingerprint: Option<String>,
53    /// The object type, which is always chat.completion.chunk.
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub object: Option<String>,
56    /// An optional field that will only be present when you set stream_options: {"include_usage": true} in your request. When present, it contains a null value except for the last chunk which contains the token usage statistics for the entire request.
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub usage: Option<Usage>,
59}
60
61fn default_model() -> String {
62    "".to_string()
63}
64
65#[derive(Serialize, Deserialize, Debug, Default, Builder, Clone, PartialEq)]
66#[builder(name = "ChatCompletionParametersBuilder")]
67#[builder(setter(into, strip_option), default)]
68pub struct ChatCompletionParameters {
69    /// A list of messages comprising the conversation so far.
70    pub messages: Vec<ChatMessage>,
71    /// ID of the model to use.
72    pub model: String,
73    /// Whether or not to store the output of this chat completion request for use in our model distillation or evals products.
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub store: Option<bool>,
76    /// Constrains effort on reasoning for reasoning models.
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub reasoning_effort: Option<ReasoningEffort>,
79    /// Developer-defined tags and values used for filtering completions in the dashboard.
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub metadata: Option<HashMap<String, String>>,
82    /// Number between -2.0 and 2.0. Positive values penalize new tokens based on their existing frequency in the text so far,
83    /// decreasing the model's likelihood to repeat the same line verbatim.
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub frequency_penalty: Option<f32>,
86    /// Modify the likelihood of specified tokens appearing in the completion.
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub logit_bias: Option<HashMap<String, i32>>,
89    /// Whether to return log probabilities of the output tokens or not.
90    /// If true, returns the log probabilities of each output token returned in the 'content' of 'message'.
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub logprobs: Option<bool>,
93    /// An integer between 0 and 5 specifying the number of most likely tokens to return at each token position,
94    /// each with an associated log probability. 'logprobs' must be set to 'true' if this parameter is used.
95    #[serde(skip_serializing_if = "Option::is_none")]
96    pub top_logprobs: Option<u32>,
97    /// Max completion tokens, deprecated (still used by vllm)
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub max_tokens: Option<u32>,
100    /// An upper bound for the number of tokens that can be generated for a completion, including visible output tokens and reasoning tokens.
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub max_completion_tokens: Option<u32>,
103    /// How many chat completion choices to generate for each input message.
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub n: Option<u32>,
106    /// Output types that you would like the model to generate for this request.
107    #[serde(skip_serializing_if = "Option::is_none")]
108    pub modalities: Option<Vec<Modality>>,
109    /// Configuration for a Predicted Output, which can greatly improve response times when large parts of the model response are known ahead of time.
110    /// This is most common when you are regenerating a file with only minor changes to most of the content.
111    #[serde(skip_serializing_if = "Option::is_none")]
112    pub prediction: Option<PredictedOutput>,
113    /// Parameters for audio output. Required when audio output is requested with modalities: ["audio"].
114    #[serde(skip_serializing_if = "Option::is_none")]
115    pub audio: Option<AudioParameters>,
116    /// Number between -2.0 and 2.0. Positive values penalize new tokens based on whether they appear in the text so far,
117    /// increasing the model's likelihood to talk about new topics.
118    #[serde(skip_serializing_if = "Option::is_none")]
119    pub presence_penalty: Option<f32>,
120    /// An object specifying the format that the model must output.
121    /// Compatible with GPT-4o, GPT-4o mini, GPT-4 Turbo and all GPT-3.5 Turbo models newer than gpt-3.5-turbo-1106.
122    /// Setting to { "type": "json_schema", "json_schema": {...} } enables Structured Outputs which ensures the model will match your supplied JSON schema.
123    /// Setting to { "type": "json_object" } enables JSON mode, which ensures the message the model generates is valid JSON.
124    #[serde(skip_serializing_if = "Option::is_none")]
125    pub response_format: Option<ChatCompletionResponseFormat>,
126    /// Deprecated (still used by vllm)
127    /// This feature is in Beta. If specified, our system will make a best effort to sample deterministically,
128    /// such that repeated requests with the same seed and parameters should return the same result.
129    /// Determinism is not guaranteed, and you should refer to the system_fingerprint response parameter to monitor changes in the backend.
130    #[serde(skip_serializing_if = "Option::is_none")]
131    pub seed: Option<u32>,
132    /// Up to 4 sequences where the API will stop generating further tokens.
133    #[serde(skip_serializing_if = "Option::is_none")]
134    pub stop: Option<StopToken>,
135    /// If set, partial messages will be sent, like in ChatGPT. Tokens will be sent as data-only server-sent events
136    /// as they become available, with the stream terminated by a data: [DONE] message.
137    #[serde(skip_serializing_if = "Option::is_none")]
138    pub stream: Option<bool>,
139    /// Options for streaming response. Only set this when you set stream: true.
140    #[serde(skip_serializing_if = "Option::is_none")]
141    pub stream_options: Option<ChatCompletionStreamOptions>,
142    /// What sampling temperature to use, between 0 and 2. Higher values like 0.8 will make the output more random,
143    /// while lower values like 0.2 will make it more focused and deterministic.
144    #[serde(skip_serializing_if = "Option::is_none")]
145    pub temperature: Option<f32>,
146    /// An alternative to sampling with temperature, called nucleus sampling, where the model considers the results of the tokens with top_p probability mass.
147    /// So 0.1 means only the tokens comprising the top 10% probability mass are considered.
148    #[serde(skip_serializing_if = "Option::is_none")]
149    pub top_p: Option<f32>,
150    /// A list of tools the model may call. Currently, only functions are supported as a tool.
151    /// Use this to provide a list of functions the model may generate JSON inputs for.
152    #[serde(skip_serializing_if = "Option::is_none")]
153    pub tools: Option<Vec<ChatCompletionTool>>,
154    /// Controls which (if any) tool is called by the model. none means the model will not call any tool and instead generates a message.
155    /// auto means the model can pick between generating a message or calling one or more tools.
156    /// required means the model must call one or more tools.
157    /// Specifying a particular tool via {"type": "function", "function": {"name": "my_function"}} forces the model to call that tool.
158    #[serde(skip_serializing_if = "Option::is_none")]
159    pub tool_choice: Option<ChatCompletionToolChoice>,
160    /// Whether to enable parallel function calling during tool use.
161    #[serde(skip_serializing_if = "Option::is_none")]
162    pub parallel_tool_calls: Option<bool>,
163    /// A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies.
164    #[serde(skip_serializing_if = "Option::is_none")]
165    pub safety_identifier: Option<String>,
166    /// Used by OpenAI to cache responses for similar requests to optimize your cache hit rates.
167    #[serde(skip_serializing_if = "Option::is_none")]
168    pub prompt_cache_key: Option<String>,
169    /// This tool searches the web for relevant results to use in a response.
170    #[serde(skip_serializing_if = "Option::is_none")]
171    pub web_search_options: Option<WebSearchOptions>,
172    /// Allows to pass arbitrary json as an extra_body parameter, for specific features/openai-compatible endpoints.
173    #[serde(flatten)]
174    #[serde(skip_serializing_if = "Option::is_none")]
175    pub extra_body: Option<Value>,
176    /// Azure OpenAI and some other providers may require special query parameters to be set on the request URL.
177    /// This field allows you to specify those query parameters.
178    #[serde(skip_serializing_if = "Option::is_none")]
179    pub query_params: Option<HashMap<String, String>>,
180}
181
182#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
183pub struct ChatCompletionStreamOptions {
184    /// If set, an additional chunk will be streamed before the data: [DONE] message.
185    pub include_usage: Option<bool>,
186    #[serde(skip_serializing_if = "Option::is_none")]
187    pub continuous_usage_stats: Option<bool>,
188}
189
190#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
191pub struct ChatCompletionToolChoiceFunction {
192    /// The type of the tool. Currently, only 'function' is supported.
193    #[serde(skip_serializing_if = "Option::is_none")]
194    pub r#type: Option<ChatCompletionToolType>,
195    /// Name of the function.
196    pub function: ChatCompletionToolChoiceFunctionName,
197}
198
199#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
200pub struct ChatCompletionToolChoiceFunctionName {
201    /// Name of the function.
202    pub name: String,
203}
204
205#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
206pub struct ChatCompletionFunction {
207    /// Name of the function.
208    pub name: String,
209    /// Optional description of the function.
210    #[serde(skip_serializing_if = "Option::is_none")]
211    pub description: Option<String>,
212    /// The parameters the function takes. The model will generate JSON inputs for these parameters.
213    pub parameters: serde_json::Value,
214}
215
216#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
217#[serde(tag = "type", rename_all = "snake_case")]
218pub enum ChatCompletionResponseFormat {
219    Text,
220    JsonObject,
221    JsonSchema { json_schema: JsonSchema },
222}
223
224#[derive(Serialize, Deserialize, Debug, Default, Builder, Clone, PartialEq)]
225#[builder(name = "JsonSchemaBuilder")]
226#[builder(setter(into, strip_option), default)]
227pub struct JsonSchema {
228    /// A description of what the response format is for, used by the model to determine how to respond in the format.
229    #[serde(skip_serializing_if = "Option::is_none")]
230    description: Option<String>,
231    /// The name of the response format. Must be a-z, A-Z, 0-9, or contain underscores and dashes, with a maximum length of 64.
232    name: String,
233    /// The schema for the response format, described as a JSON Schema object.
234    #[serde(skip_serializing_if = "Option::is_none")]
235    schema: Option<serde_json::Value>,
236    /// Whether to enable strict schema adherence when generating the output.
237    #[serde(skip_serializing_if = "Option::is_none")]
238    strict: Option<bool>,
239}
240
241#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
242pub struct ChatCompletionTool {
243    /// The type of the tool. Currently, only 'function' is supported.
244    pub r#type: ChatCompletionToolType,
245    /// The name of the function to call.
246    pub function: ChatCompletionFunction,
247}
248
249#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
250#[serde(tag = "role", rename_all = "snake_case")]
251pub enum ChatMessage {
252    Developer {
253        /// The contents of the developer message.
254        content: ChatMessageContent,
255        /// An optional name for the participant. Provides the model information to differentiate between participants of the same role.
256        #[serde(skip_serializing_if = "Option::is_none")]
257        name: Option<String>,
258    },
259    System {
260        /// The contents of the system message.
261        content: ChatMessageContent,
262        /// An optional name for the participant. Provides the model information to differentiate between participants of the same role.
263        #[serde(skip_serializing_if = "Option::is_none")]
264        name: Option<String>,
265    },
266    User {
267        /// The contents of the user message.
268        content: ChatMessageContent,
269        /// An optional name for the participant. Provides the model information to differentiate between participants of the same role.
270        #[serde(skip_serializing_if = "Option::is_none")]
271        name: Option<String>,
272    },
273    Assistant {
274        /// The contents of the assistant message. Required unless tool_calls is specified.
275        #[serde(skip_serializing_if = "Option::is_none")]
276        content: Option<ChatMessageContent>,
277        /// The reasoning content by the assistant. (DeepSeek API only)
278        #[serde(skip_serializing_if = "Option::is_none")]
279        reasoning_content: Option<String>,
280        /// The refusal message by the assistant.
281        #[serde(skip_serializing_if = "Option::is_none")]
282        refusal: Option<String>,
283        /// An optional name for the participant. Provides the model information to differentiate between participants of the same role.
284        #[serde(skip_serializing_if = "Option::is_none")]
285        name: Option<String>,
286        /// Data about a previous audio response from the model.
287        #[serde(skip_serializing_if = "Option::is_none")]
288        audio: Option<AudioDataIdParameter>,
289        /// The tool calls generated by the model, such as function calls.
290        #[serde(skip_serializing_if = "Option::is_none")]
291        tool_calls: Option<Vec<ToolCall>>,
292    },
293    Tool {
294        /// The contents of the tool message.
295        content: ChatMessageContent,
296        /// Tool call that this message is responding to.
297        tool_call_id: String,
298    },
299}
300
301impl ChatMessage {
302    /// Get the ChatMessageContent data, if it exists.
303    pub fn message(&self) -> Option<&ChatMessageContent> {
304        match self {
305            ChatMessage::Developer { content, .. }
306            | ChatMessage::System { content, .. }
307            | ChatMessage::User { content, .. }
308            | ChatMessage::Assistant {
309                content: Some(content),
310                ..
311            } => Some(content),
312            ChatMessage::Assistant { content: None, .. } => None,
313            ChatMessage::Tool { .. } => None,
314        }
315    }
316
317    /// Get the content of the message as text, if it is a simple text message.
318    pub fn text(&self) -> Option<&str> {
319        match self {
320            ChatMessage::Developer { content, .. }
321            | ChatMessage::System { content, .. }
322            | ChatMessage::User { content, .. }
323            | ChatMessage::Tool { content, .. }
324            | ChatMessage::Assistant {
325                content: Some(content),
326                ..
327            } => {
328                if let ChatMessageContent::Text(text) = content {
329                    Some(text)
330                } else {
331                    None
332                }
333            }
334            ChatMessage::Assistant { content: None, .. } => None,
335        }
336    }
337
338    /// Get the name of the message sender, if it exists.
339    pub fn name(&self) -> Option<&str> {
340        match self {
341            ChatMessage::Developer { name, .. }
342            | ChatMessage::System { name, .. }
343            | ChatMessage::User { name, .. }
344            | ChatMessage::Assistant { name, .. } => name.as_deref(),
345            ChatMessage::Tool { .. } => None,
346        }
347    }
348}
349
350#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
351#[serde(tag = "role", rename_all = "snake_case")]
352pub enum DeltaChatMessage {
353    Developer {
354        /// The contents of the developer message.
355        content: ChatMessageContent,
356        /// An optional name for the participant. Provides the model information to differentiate between participants of the same role.
357        #[serde(skip_serializing_if = "Option::is_none")]
358        name: Option<String>,
359    },
360    System {
361        /// The contents of the system message.
362        content: ChatMessageContent,
363        /// An optional name for the participant. Provides the model information to differentiate between participants of the same role.
364        #[serde(skip_serializing_if = "Option::is_none")]
365        name: Option<String>,
366    },
367    User {
368        /// The contents of the user message.
369        content: ChatMessageContent,
370        /// An optional name for the participant. Provides the model information to differentiate between participants of the same role.
371        #[serde(skip_serializing_if = "Option::is_none")]
372        name: Option<String>,
373    },
374    Assistant {
375        /// The contents of the assistant message. Required unless tool_calls is specified.
376        #[serde(skip_serializing_if = "Option::is_none")]
377        content: Option<ChatMessageContent>,
378        /// The reasoning content by the assistant. (DeepSeek API only)
379        #[serde(skip_serializing_if = "Option::is_none")]
380        reasoning_content: Option<String>,
381        /// The refusal message by the assistant.
382        #[serde(skip_serializing_if = "Option::is_none")]
383        refusal: Option<String>,
384        /// An optional name for the participant. Provides the model information to differentiate between participants of the same role.
385        #[serde(skip_serializing_if = "Option::is_none")]
386        name: Option<String>,
387        /// The tool calls generated by the model, such as function calls.
388        #[serde(skip_serializing_if = "Option::is_none")]
389        tool_calls: Option<Vec<DeltaToolCall>>,
390    },
391    Tool {
392        /// The contents of the tool message.
393        content: String,
394        /// Tool call that this message is responding to.
395        tool_call_id: String,
396    },
397    #[serde(untagged)]
398    Untagged {
399        #[serde(skip_serializing_if = "Option::is_none")]
400        content: Option<ChatMessageContent>,
401        #[serde(skip_serializing_if = "Option::is_none")]
402        reasoning_content: Option<String>,
403        #[serde(skip_serializing_if = "Option::is_none")]
404        refusal: Option<String>,
405        #[serde(skip_serializing_if = "Option::is_none")]
406        name: Option<String>,
407        #[serde(skip_serializing_if = "Option::is_none")]
408        tool_calls: Option<Vec<DeltaToolCall>>,
409        #[serde(skip_serializing_if = "Option::is_none")]
410        tool_call_id: Option<String>,
411    },
412}
413
414#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
415pub struct ToolCall {
416    /// The ID of the tool call.
417    pub id: String,
418    /// The type of the tool. Currently, only function is supported.
419    pub r#type: String,
420    /// The function that the model called.
421    pub function: Function,
422}
423
424#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
425pub struct DeltaToolCall {
426    /// The index of the tool call in the list of tool calls.
427    #[serde(skip_serializing_if = "Option::is_none")]
428    pub index: Option<u32>,
429    /// /// The ID of the tool call.
430    #[serde(skip_serializing_if = "Option::is_none")]
431    pub id: Option<String>,
432    /// The type of the tool. Currently, only 'function' is supported.
433    #[serde(skip_serializing_if = "Option::is_none")]
434    pub r#type: Option<String>,
435    /// The function that the model called.
436    pub function: DeltaFunction,
437}
438
439#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
440pub struct Function {
441    /// The name of the function to call.
442    pub name: String,
443    /// The arguments to call the function with, as generated by the model in JSON format.
444    pub arguments: String,
445}
446
447#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
448pub struct DeltaFunction {
449    /// The name of the function to call.
450    #[serde(skip_serializing_if = "Option::is_none")]
451    pub name: Option<String>,
452    /// The arguments to call the function with, as generated by the model in JSON format.
453    #[serde(skip_serializing_if = "Option::is_none")]
454    pub arguments: Option<String>,
455}
456
457#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
458pub struct ChatCompletionChoice {
459    /// The index of the choice in the list of choices.
460    pub index: u32,
461    /// A chat completion message generated by the model.
462    pub message: ChatMessage,
463    /// The reason the model stopped generating tokens.
464    #[serde(skip_serializing_if = "Option::is_none")]
465    pub finish_reason: Option<FinishReason>,
466    /// Log probability information for the choice.
467    #[serde(skip_serializing_if = "Option::is_none")]
468    pub logprobs: Option<LogProps>,
469}
470
471#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
472pub struct AudioDataIdParameter {
473    /// Unique identifier for a previous audio response from the model.
474    pub id: String,
475}
476
477#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
478pub struct AudioParameters {
479    /// The voice the model uses to respond.
480    pub voice: Voice,
481    /// Specifies the output audio format.
482    pub format: AudioFormat,
483}
484
485#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
486pub struct LogProps {
487    /// A list of message content tokens with log probability information.
488    #[serde(skip_serializing_if = "Option::is_none")]
489    pub content: Option<Vec<LogPropsContent>>,
490    /// A list of message refusal tokens with log probability information.
491    #[serde(skip_serializing_if = "Option::is_none")]
492    pub refusal: Option<Vec<LogPropsContent>>,
493}
494
495#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
496pub struct LogPropsContent {
497    /// Token information
498    #[serde(flatten)]
499    pub token_info: LogProbsContentInfo,
500    /// List of the most likely tokens and their log probability, at this token position.
501    pub top_logprobs: Vec<LogProbsContentInfo>,
502}
503
504#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
505pub struct LogProbsContentInfo {
506    /// The token.
507    pub token: String,
508    /// The log probability of this token, if it is within the top 20 most likely tokens.
509    /// Otherwise, the value -9999.0 is used to signify that the token is very unlikely.
510    pub logprob: f32,
511    /// A list of integers representing the UTF-8 bytes representation of the token.
512    pub bytes: Option<Vec<u8>>,
513}
514
515#[cfg(feature = "stream")]
516#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
517pub struct ChatCompletionChunkChoice {
518    /// The index of the choice in the list of choices.
519    pub index: Option<u32>,
520    /// A chat completion delta generated by streamed model responses.
521    pub delta: DeltaChatMessage,
522    /// The reason the model stopped generating tokens.
523    #[serde(skip_serializing_if = "Option::is_none")]
524    pub finish_reason: Option<FinishReason>,
525    /// Log probability information for the choice.
526    #[serde(skip_serializing_if = "Option::is_none")]
527    pub logprobs: Option<LogProps>,
528}
529
530#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
531pub struct ImageUrlType {
532    /// Either a URL of the image or the base64 encoded image data.
533    pub url: String,
534    /// Specifies the detail level of the image.
535    #[serde(skip_serializing_if = "Option::is_none")]
536    pub detail: Option<ImageUrlDetail>,
537}
538
539#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
540pub struct PredictedOutput {
541    /// The type of the predicted content you want to provide.
542    pub r#type: PredictedOutputType,
543    /// The content that should be matched when generating a model response.
544    /// If generated tokens would match this content, the entire model response can be returned much more quickly.
545    pub content: PredictedOutputContent,
546}
547
548#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
549#[serde(untagged)]
550pub enum PredictedOutputContent {
551    String(String),
552    Array(Vec<PredictedOutputArrayPart>),
553}
554
555#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
556pub struct PredictedOutputArrayPart {
557    /// The type of the content part.
558    pub r#type: String,
559    /// The text content.
560    pub text: String,
561}
562
563#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
564#[serde(rename_all = "snake_case")]
565pub enum PredictedOutputType {
566    Content,
567}
568
569#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
570#[serde(rename_all = "snake_case")]
571pub enum Modality {
572    Text,
573    Audio,
574}
575
576#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
577#[serde(rename_all = "snake_case")]
578pub enum ImageUrlDetail {
579    Auto,
580    High,
581    Low,
582}
583
584#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
585#[serde(untagged)]
586pub enum ChatMessageContent {
587    Text(String),
588    ContentPart(Vec<ChatMessageContentPart>),
589    None,
590}
591
592#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
593#[serde(untagged)]
594pub enum ChatMessageContentPart {
595    Text(ChatMessageTextContentPart),
596    Image(ChatMessageImageContentPart),
597    Audio(ChatMessageAudioContentPart),
598}
599
600#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
601pub struct ChatMessageTextContentPart {
602    /// The type of the content part.
603    pub r#type: String,
604    /// The text content.
605    pub text: String,
606}
607
608#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
609pub struct ChatMessageImageContentPart {
610    /// The type of the content part.
611    pub r#type: String,
612    /// The text content.
613    pub image_url: ImageUrlType,
614}
615
616#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
617pub struct ChatMessageAudioContentPart {
618    /// The type of the content part. Always input_audio.
619    pub r#type: String,
620    /// The input audio data.
621    pub input_audio: InputAudioData,
622}
623
624#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
625pub struct ChatMessageImageUrl {
626    /// Either a URL of the image or the base64 encoded image data.
627    pub url: String,
628    /// Specifies the detail level of the image.
629    pub detail: String,
630}
631
632#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
633pub struct InputAudioData {
634    /// Base64 encoded audio data.
635    pub data: String,
636    /// The format of the encoded audio data. Currently supports "wav" and "mp3".
637    pub format: String,
638}
639
640#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
641pub struct WebSearchOptions {
642    /// High level guidance for the amount of context window space to use for the search.
643    #[serde(skip_serializing_if = "Option::is_none")]
644    pub search_context_size: Option<WebSearchContextSize>,
645    /// Approximate location parameters for the search.
646    #[serde(skip_serializing_if = "Option::is_none")]
647    pub user_location: Option<ApproximateUserLocation>,
648}
649
650#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
651pub struct ApproximateUserLocation {
652    pub r#type: UserLocationType,
653    /// Approximate location parameters for the search.
654    pub approximate: WebSearchUserLocation,
655}
656
657impl Display for ChatMessageContent {
658    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
659        match self {
660            ChatMessageContent::Text(text) => write!(f, "{text}"),
661            ChatMessageContent::ContentPart(tcp) => {
662                for part in tcp {
663                    write!(f, "{part:?}")?;
664                }
665                Ok(())
666            }
667            ChatMessageContent::None => write!(f, ""),
668        }
669    }
670}
671
672#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
673#[serde(rename_all = "snake_case")]
674pub enum ChatCompletionToolType {
675    Function,
676}
677
678#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
679#[serde(rename_all = "snake_case")]
680pub enum ChatCompletionToolChoice {
681    None,
682    Auto,
683    Required,
684    #[serde(untagged)]
685    ChatCompletionToolChoiceFunction(ChatCompletionToolChoiceFunction),
686}
687
688#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
689pub struct WebSearchUserLocation {
690    pub city: Option<String>,
691    pub country: Option<String>,
692    pub region: Option<String>,
693    pub timezone: Option<String>,
694}
695
696#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
697#[serde(rename_all = "snake_case")]
698pub enum UserLocationType {
699    Approximate,
700}
701
702#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
703#[serde(rename_all = "snake_case")]
704pub enum Voice {
705    Alloy,
706    Ash,
707    Ballad,
708    Coral,
709    Echo,
710    Sage,
711    Shimmer,
712    Verse,
713}
714
715#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
716#[serde(rename_all = "snake_case")]
717pub enum AudioFormat {
718    Wav,
719    Mp3,
720    Flac,
721    Opus,
722    Pcm16,
723}
724
725impl Default for ChatMessageContent {
726    fn default() -> Self {
727        ChatMessageContent::Text("".to_string())
728    }
729}
730
731impl DeltaFunction {
732    pub fn merge(&mut self, other: &Self) {
733        if self.name.is_none() && other.name.is_some() {
734            self.name.clone_from(&other.name);
735        }
736
737        if let Some(arguments) = &other.arguments {
738            if let Some(self_arguments) = &mut self.arguments {
739                self_arguments.push_str(arguments);
740            } else {
741                self.arguments = Some(arguments.clone());
742            }
743        }
744    }
745
746    pub fn is_empty(&self) -> bool {
747        self.name.is_none() && self.arguments.is_none()
748    }
749}
750
751#[cfg(test)]
752mod tests {
753    use crate::chat::{
754        ChatCompletionResponseFormat, ChatCompletionToolChoice, ChatCompletionToolChoiceFunction,
755        ChatCompletionToolChoiceFunctionName, ChatCompletionToolType, ChatMessage,
756        ChatMessageContent, ChatMessageContentPart, ChatMessageTextContentPart, JsonSchemaBuilder,
757    };
758    use serde_json;
759
760    #[test]
761    fn test_chat_completion_response_format_serialization_deserialization() {
762        let json_schema = JsonSchemaBuilder::default()
763            .description("This is a test schema".to_string())
764            .name("test_schema".to_string())
765            .schema(Some(serde_json::json!({"type": "object"})))
766            .strict(true)
767            .build()
768            .unwrap();
769
770        let response_format = ChatCompletionResponseFormat::JsonSchema { json_schema };
771
772        // Serialize the response format to a JSON string
773        let serialized = serde_json::to_string(&response_format).unwrap();
774        assert_eq!(serialized, "{\"type\":\"json_schema\",\"json_schema\":{\"description\":\"This is a test schema\",\"name\":\"test_schema\",\"schema\":{\"type\":\"object\"},\"strict\":true}}");
775
776        // Deserialize the JSON string back to a ChatCompletionResponseFormat
777        let deserialized: ChatCompletionResponseFormat = serde_json::from_str(&serialized).unwrap();
778        match deserialized {
779            ChatCompletionResponseFormat::JsonSchema { json_schema } => {
780                assert_eq!(
781                    json_schema.description,
782                    Some("This is a test schema".to_string())
783                );
784                assert_eq!(json_schema.name, "test_schema".to_string());
785                assert_eq!(
786                    json_schema.schema,
787                    Some(serde_json::json!({"type": "object"}))
788                );
789                assert_eq!(json_schema.strict, Some(true));
790            }
791            _ => panic!("Deserialized format should be JsonSchema"),
792        }
793    }
794
795    #[test]
796    fn test_chat_completion_tool_choice_required_serialization_deserialization() {
797        let tool_choice = ChatCompletionToolChoice::Required;
798
799        let serialized = serde_json::to_string(&tool_choice).unwrap();
800        assert_eq!(serialized, "\"required\"");
801
802        let deserialized: ChatCompletionToolChoice =
803            serde_json::from_str(serialized.as_str()).unwrap();
804        assert_eq!(deserialized, tool_choice)
805    }
806
807    #[test]
808    fn test_chat_completion_tool_choice_named_function_serialization_deserialization() {
809        let tool_choice = ChatCompletionToolChoice::ChatCompletionToolChoiceFunction(
810            ChatCompletionToolChoiceFunction {
811                r#type: Some(ChatCompletionToolType::Function),
812                function: ChatCompletionToolChoiceFunctionName {
813                    name: "get_current_weather".to_string(),
814                },
815            },
816        );
817
818        let serialized = serde_json::to_string(&tool_choice).unwrap();
819        assert_eq!(
820            serialized,
821            "{\"type\":\"function\",\"function\":{\"name\":\"get_current_weather\"}}"
822        );
823
824        let deserialized: ChatCompletionToolChoice =
825            serde_json::from_str(serialized.as_str()).unwrap();
826        assert_eq!(deserialized, tool_choice)
827    }
828
829    #[test]
830    fn test_chat_message_tool_content_string_serialization_deserialization() {
831        let tool_message = ChatMessage::Tool {
832            content: ChatMessageContent::Text("tool_result".to_string()),
833            tool_call_id: "tool_call_id".to_string(),
834        };
835
836        let serialized = serde_json::to_string(&tool_message).unwrap();
837        assert_eq!(
838            serialized,
839            "{\"role\":\"tool\",\"content\":\"tool_result\",\"tool_call_id\":\"tool_call_id\"}"
840        );
841
842        let deserialized: ChatMessage = serde_json::from_str(serialized.as_str()).unwrap();
843        assert_eq!(deserialized, tool_message)
844    }
845
846    #[test]
847    fn test_chat_message_tool_content_array_serialization_deserialization() {
848        let content_array = vec![ChatMessageContentPart::Text(ChatMessageTextContentPart {
849            r#type: "text".to_string(),
850            text: "tool_result".to_string(),
851        })];
852        let tool_message = ChatMessage::Tool {
853            content: ChatMessageContent::ContentPart(content_array),
854            tool_call_id: "tool_call_id".to_string(),
855        };
856
857        let serialized = serde_json::to_string(&tool_message).unwrap();
858        assert_eq!(
859            serialized,
860            "{\"role\":\"tool\",\"content\":[{\"type\":\"text\",\"text\":\"tool_result\"}],\"tool_call_id\":\"tool_call_id\"}"
861        );
862
863        let deserialized: ChatMessage = serde_json::from_str(serialized.as_str()).unwrap();
864        assert_eq!(deserialized, tool_message)
865    }
866}