1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use std::collections::HashMap;
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
9#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
10#[serde(rename_all = "lowercase")]
11pub enum AudioFormat {
12    Wav,
13    Mp3,
14    Linear16,
15    Flac,
16    Mulaw,
17    Alaw,
18    Aac,
19    Opus,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
24#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
25#[serde(tag = "type", rename_all = "kebab-case")]
26pub enum Part {
27    Text(TextPart),
28    Image(ImagePart),
29    Audio(AudioPart),
30    Source(SourcePart),
31    ToolCall(ToolCallPart),
32    ToolResult(ToolResultPart),
33    Reasoning(ReasoningPart),
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
38#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
39#[serde(tag = "type", rename_all = "kebab-case")]
40pub enum PartDelta {
41    Text(TextPartDelta),
42    ToolCall(ToolCallPartDelta),
43    Image(ImagePartDelta),
44    Audio(AudioPartDelta),
45    Reasoning(ReasoningPartDelta),
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
50#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
51#[serde(tag = "role", rename_all = "lowercase")]
52pub enum Message {
53    User(UserMessage),
54    Assistant(AssistantMessage),
55    Tool(ToolMessage),
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
60#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
61#[serde(rename_all = "lowercase")]
62pub enum Modality {
63    Text,
64    Image,
65    Audio,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
76#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
77#[serde(tag = "type", rename_all = "lowercase")]
78pub enum ToolChoiceOption {
79    Auto,
82    None,
84    Required,
86    Tool(ToolChoiceTool),
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
92#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
93#[serde(tag = "type", rename_all = "lowercase")]
94pub enum ResponseFormatOption {
95    Text,
97    Json(ResponseFormatJson),
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
102#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
103#[serde(rename_all = "kebab-case")]
104pub enum LanguageModelCapability {
105    TextInput,
106    TextOutput,
107    ImageInput,
108    ImageOutput,
109    AudioInput,
110    AudioOutput,
111    FunctionCalling,
112    StructuredOutput,
113    Citation,
114    Reasoning,
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
119#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
120pub struct TextPart {
121    pub text: String,
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub citations: Option<Vec<Citation>>,
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
128#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
129pub struct ImagePart {
130    pub mime_type: String,
132    pub data: String,
134    #[serde(skip_serializing_if = "Option::is_none")]
136    pub width: Option<u32>,
137    #[serde(skip_serializing_if = "Option::is_none")]
139    pub height: Option<u32>,
140    #[serde(skip_serializing_if = "Option::is_none")]
142    pub id: Option<String>,
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
147#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
148pub struct AudioPart {
149    pub data: String,
151    pub format: AudioFormat,
153    #[serde(skip_serializing_if = "Option::is_none")]
155    pub sample_rate: Option<u32>,
156    #[serde(skip_serializing_if = "Option::is_none")]
158    pub channels: Option<u32>,
159    #[serde(skip_serializing_if = "Option::is_none")]
161    pub transcript: Option<String>,
162    #[serde(skip_serializing_if = "Option::is_none")]
164    pub id: Option<String>,
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
170#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
171pub struct SourcePart {
172    pub source: String,
174    pub title: String,
176    pub content: Vec<Part>,
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
183#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
184pub struct ToolCallPart {
185    pub tool_call_id: String,
188    pub tool_name: String,
190    pub args: Value,
192    #[serde(skip_serializing_if = "Option::is_none")]
196    pub id: Option<String>,
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
201#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
202pub struct ToolResultPart {
203    pub tool_call_id: String,
205    pub tool_name: String,
207    pub content: Vec<Part>,
209    #[serde(skip_serializing_if = "Option::is_none")]
211    pub is_error: Option<bool>,
212}
213
214#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
216#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
217pub struct ReasoningPart {
218    pub text: String,
220    #[serde(skip_serializing_if = "Option::is_none")]
222    pub signature: Option<String>,
223    #[serde(skip_serializing_if = "Option::is_none")]
225    pub id: Option<String>,
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
229#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
230pub struct Citation {
231    pub source: String,
235    #[serde(skip_serializing_if = "Option::is_none")]
239    pub title: Option<String>,
240    #[serde(skip_serializing_if = "Option::is_none")]
244    pub cited_text: Option<String>,
245    pub start_index: usize,
249    pub end_index: usize,
253}
254
255#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
257#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
258pub struct UserMessage {
259    pub content: Vec<Part>,
260}
261
262#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
264#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
265pub struct AssistantMessage {
266    pub content: Vec<Part>,
267}
268
269#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
272#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
273pub struct TextPartDelta {
274    pub text: String,
275    #[serde(skip_serializing_if = "Option::is_none")]
276    pub citation: Option<CitationDelta>,
277}
278
279#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
281#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
282pub struct CitationDelta {
283    #[serde(rename = "type")]
285    pub r#type: String,
286    #[serde(skip_serializing_if = "Option::is_none")]
288    pub source: Option<String>,
289    #[serde(skip_serializing_if = "Option::is_none")]
291    pub title: Option<String>,
292    #[serde(skip_serializing_if = "Option::is_none")]
294    pub cited_text: Option<String>,
295    #[serde(skip_serializing_if = "Option::is_none")]
297    pub start_index: Option<usize>,
298    #[serde(skip_serializing_if = "Option::is_none")]
300    pub end_index: Option<usize>,
301}
302
303#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
305#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
306pub struct ToolCallPartDelta {
307    #[serde(skip_serializing_if = "Option::is_none")]
310    pub tool_call_id: Option<String>,
311    #[serde(skip_serializing_if = "Option::is_none")]
313    pub tool_name: Option<String>,
314    #[serde(skip_serializing_if = "Option::is_none")]
316    pub args: Option<String>,
317    #[serde(skip_serializing_if = "Option::is_none")]
321    pub id: Option<String>,
322}
323
324#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
326#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
327pub struct ImagePartDelta {
328    #[serde(skip_serializing_if = "Option::is_none")]
330    pub mime_type: Option<String>,
331    #[serde(skip_serializing_if = "Option::is_none")]
333    pub data: Option<String>,
334    #[serde(skip_serializing_if = "Option::is_none")]
336    pub width: Option<u32>,
337    #[serde(skip_serializing_if = "Option::is_none")]
339    pub height: Option<u32>,
340    #[serde(skip_serializing_if = "Option::is_none")]
342    pub id: Option<String>,
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
347#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
348pub struct AudioPartDelta {
349    #[serde(skip_serializing_if = "Option::is_none")]
351    pub data: Option<String>,
352    #[serde(skip_serializing_if = "Option::is_none")]
353    pub format: Option<AudioFormat>,
354    #[serde(skip_serializing_if = "Option::is_none")]
356    pub sample_rate: Option<u32>,
357    #[serde(skip_serializing_if = "Option::is_none")]
359    pub channels: Option<u32>,
360    #[serde(skip_serializing_if = "Option::is_none")]
362    pub transcript: Option<String>,
363    #[serde(skip_serializing_if = "Option::is_none")]
365    pub id: Option<String>,
366}
367
368#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
370#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
371pub struct ReasoningPartDelta {
372    #[serde(skip_serializing_if = "Option::is_none")]
374    pub text: Option<String>,
375    #[serde(skip_serializing_if = "Option::is_none")]
377    pub signature: Option<String>,
378    #[serde(skip_serializing_if = "Option::is_none")]
380    pub id: Option<String>,
381}
382
383#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
386#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
387pub struct ContentDelta {
388    pub index: usize,
389    pub part: PartDelta,
390}
391
392pub type JSONSchema = Value;
394
395#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
397#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
398pub struct Tool {
399    pub name: String,
401    pub description: String,
403    pub parameters: JSONSchema,
406}
407
408#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
411#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
412pub struct ToolMessage {
413    pub content: Vec<Part>,
414}
415
416#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
418#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
419pub struct ModelTokensDetails {
420    #[serde(skip_serializing_if = "Option::is_none")]
421    pub text_tokens: Option<u32>,
422    #[serde(skip_serializing_if = "Option::is_none")]
423    pub cached_text_tokens: Option<u32>,
424    #[serde(skip_serializing_if = "Option::is_none")]
425    pub audio_tokens: Option<u32>,
426    #[serde(skip_serializing_if = "Option::is_none")]
427    pub cached_audio_tokens: Option<u32>,
428    #[serde(skip_serializing_if = "Option::is_none")]
429    pub image_tokens: Option<u32>,
430    #[serde(skip_serializing_if = "Option::is_none")]
431    pub cached_image_tokens: Option<u32>,
432}
433
434#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
436#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
437pub struct ModelUsage {
438    pub input_tokens: u32,
439    pub output_tokens: u32,
440    #[serde(skip_serializing_if = "Option::is_none")]
441    pub input_tokens_details: Option<ModelTokensDetails>,
442    #[serde(skip_serializing_if = "Option::is_none")]
443    pub output_tokens_details: Option<ModelTokensDetails>,
444}
445
446#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
448#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
449pub struct ModelResponse {
450    pub content: Vec<Part>,
451    #[serde(skip_serializing_if = "Option::is_none")]
452    pub usage: Option<ModelUsage>,
453    #[serde(skip_serializing_if = "Option::is_none")]
455    pub cost: Option<f64>,
456}
457
458#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
461#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
462pub struct PartialModelResponse {
463    pub delta: Option<ContentDelta>,
464    pub usage: Option<ModelUsage>,
465    pub cost: Option<f64>,
466}
467
468#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
470#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
471pub struct ToolChoiceTool {
472    pub tool_name: String,
473}
474
475#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
478#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
479pub struct ResponseFormatJson {
480    pub name: String,
482    #[serde(skip_serializing_if = "Option::is_none")]
484    pub description: Option<String>,
485    #[serde(skip_serializing_if = "Option::is_none")]
486    pub schema: Option<JSONSchema>,
487}
488
489#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
491#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
492pub struct AudioOptions {
493    #[serde(skip_serializing_if = "Option::is_none")]
495    pub format: Option<AudioFormat>,
496    #[serde(skip_serializing_if = "Option::is_none")]
498    pub voice: Option<String>,
499    #[serde(skip_serializing_if = "Option::is_none")]
501    pub language: Option<String>,
502}
503
504#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
506#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
507pub struct ReasoningOptions {
508    pub enabled: bool,
510    #[serde(skip_serializing_if = "Option::is_none")]
512    pub budget_tokens: Option<u32>,
513}
514
515#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
517#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
518pub struct LanguageModelInput {
519    #[serde(skip_serializing_if = "Option::is_none")]
522    pub system_prompt: Option<String>,
523    pub messages: Vec<Message>,
525    #[serde(skip_serializing_if = "Option::is_none")]
527    pub tools: Option<Vec<Tool>>,
528    #[serde(skip_serializing_if = "Option::is_none")]
529    pub tool_choice: Option<ToolChoiceOption>,
530    #[serde(skip_serializing_if = "Option::is_none")]
531    pub response_format: Option<ResponseFormatOption>,
532    #[serde(skip_serializing_if = "Option::is_none")]
535    pub max_tokens: Option<u32>,
536    #[serde(skip_serializing_if = "Option::is_none")]
538    pub temperature: Option<f64>,
539    #[serde(skip_serializing_if = "Option::is_none")]
543    pub top_p: Option<f64>,
544    #[serde(skip_serializing_if = "Option::is_none")]
548    pub top_k: Option<i32>,
549    #[serde(skip_serializing_if = "Option::is_none")]
552    pub presence_penalty: Option<f64>,
553    #[serde(skip_serializing_if = "Option::is_none")]
557    pub frequency_penalty: Option<f64>,
558    #[serde(skip_serializing_if = "Option::is_none")]
561    pub seed: Option<i64>,
562    #[serde(skip_serializing_if = "Option::is_none")]
564    pub modalities: Option<Vec<Modality>>,
565    #[serde(skip_serializing_if = "Option::is_none")]
568    pub metadata: Option<HashMap<String, String>>,
569    #[serde(skip_serializing_if = "Option::is_none")]
571    pub audio: Option<AudioOptions>,
572    pub reasoning: Option<ReasoningOptions>,
574    #[serde(skip_serializing_if = "Option::is_none")]
576    pub extra: Option<LanguageModelInputExtra>,
577}
578
579pub type LanguageModelInputExtra = Value;
580
581#[derive(Debug, Clone, Serialize, Deserialize)]
583#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
584pub struct LanguageModelPricing {
585    #[serde(skip_serializing_if = "Option::is_none")]
587    pub input_cost_per_text_token: Option<f64>,
588    #[serde(skip_serializing_if = "Option::is_none")]
590    pub input_cost_per_cached_text_token: Option<f64>,
591    #[serde(skip_serializing_if = "Option::is_none")]
593    pub output_cost_per_text_token: Option<f64>,
594    #[serde(skip_serializing_if = "Option::is_none")]
596    pub input_cost_per_audio_token: Option<f64>,
597    #[serde(skip_serializing_if = "Option::is_none")]
599    pub input_cost_per_cached_audio_token: Option<f64>,
600    #[serde(skip_serializing_if = "Option::is_none")]
602    pub output_cost_per_audio_token: Option<f64>,
603    #[serde(skip_serializing_if = "Option::is_none")]
605    pub input_cost_per_image_token: Option<f64>,
606    #[serde(skip_serializing_if = "Option::is_none")]
608    pub input_cost_per_cached_image_token: Option<f64>,
609    #[serde(skip_serializing_if = "Option::is_none")]
611    pub output_cost_per_image_token: Option<f64>,
612}