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#[allow(clippy::struct_excessive_bools)]
102#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
103#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
104pub struct LanguageModelCapabilities {
105 pub text_input: bool,
106 pub text_output: bool,
107 pub image_input: bool,
108 pub image_output: bool,
109 pub audio_input: bool,
110 pub audio_output: bool,
111 pub function_calling: bool,
112 pub structured_output: bool,
113 pub citation: bool,
114 pub reasoning: bool,
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")]
195 pub signature: Option<String>,
196 #[serde(skip_serializing_if = "Option::is_none")]
200 pub id: Option<String>,
201}
202
203#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
205#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
206pub struct ToolResultPart {
207 pub tool_call_id: String,
209 pub tool_name: String,
211 pub content: Vec<Part>,
213 #[serde(skip_serializing_if = "Option::is_none")]
215 pub is_error: Option<bool>,
216}
217
218#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
220#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
221pub struct ReasoningPart {
222 pub text: String,
224 #[serde(skip_serializing_if = "Option::is_none")]
226 pub signature: Option<String>,
227 #[serde(skip_serializing_if = "Option::is_none")]
229 pub id: Option<String>,
230}
231
232#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
233#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
234pub struct Citation {
235 pub source: String,
239 #[serde(skip_serializing_if = "Option::is_none")]
243 pub title: Option<String>,
244 #[serde(skip_serializing_if = "Option::is_none")]
248 pub cited_text: Option<String>,
249 pub start_index: usize,
253 pub end_index: usize,
257}
258
259#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
261#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
262pub struct UserMessage {
263 pub content: Vec<Part>,
264}
265
266#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
268#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
269pub struct AssistantMessage {
270 pub content: Vec<Part>,
271}
272
273#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
276#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
277pub struct TextPartDelta {
278 pub text: String,
279 #[serde(skip_serializing_if = "Option::is_none")]
280 pub citation: Option<CitationDelta>,
281}
282
283#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
285#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
286pub struct CitationDelta {
287 #[serde(rename = "type")]
289 pub r#type: String,
290 #[serde(skip_serializing_if = "Option::is_none")]
292 pub source: Option<String>,
293 #[serde(skip_serializing_if = "Option::is_none")]
295 pub title: Option<String>,
296 #[serde(skip_serializing_if = "Option::is_none")]
298 pub cited_text: Option<String>,
299 #[serde(skip_serializing_if = "Option::is_none")]
301 pub start_index: Option<usize>,
302 #[serde(skip_serializing_if = "Option::is_none")]
304 pub end_index: Option<usize>,
305}
306
307#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
309#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
310pub struct ToolCallPartDelta {
311 #[serde(skip_serializing_if = "Option::is_none")]
314 pub tool_call_id: Option<String>,
315 #[serde(skip_serializing_if = "Option::is_none")]
317 pub tool_name: Option<String>,
318 #[serde(skip_serializing_if = "Option::is_none")]
320 pub args: Option<String>,
321 #[serde(skip_serializing_if = "Option::is_none")]
324 pub signature: Option<String>,
325 #[serde(skip_serializing_if = "Option::is_none")]
329 pub id: Option<String>,
330}
331
332#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
334#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
335pub struct ImagePartDelta {
336 #[serde(skip_serializing_if = "Option::is_none")]
338 pub mime_type: Option<String>,
339 #[serde(skip_serializing_if = "Option::is_none")]
341 pub data: Option<String>,
342 #[serde(skip_serializing_if = "Option::is_none")]
344 pub width: Option<u32>,
345 #[serde(skip_serializing_if = "Option::is_none")]
347 pub height: Option<u32>,
348 #[serde(skip_serializing_if = "Option::is_none")]
350 pub id: Option<String>,
351}
352
353#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
355#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
356pub struct AudioPartDelta {
357 #[serde(skip_serializing_if = "Option::is_none")]
359 pub data: Option<String>,
360 #[serde(skip_serializing_if = "Option::is_none")]
361 pub format: Option<AudioFormat>,
362 #[serde(skip_serializing_if = "Option::is_none")]
364 pub sample_rate: Option<u32>,
365 #[serde(skip_serializing_if = "Option::is_none")]
367 pub channels: Option<u32>,
368 #[serde(skip_serializing_if = "Option::is_none")]
370 pub transcript: Option<String>,
371 #[serde(skip_serializing_if = "Option::is_none")]
373 pub id: Option<String>,
374}
375
376#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
378#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
379pub struct ReasoningPartDelta {
380 #[serde(skip_serializing_if = "Option::is_none")]
382 pub text: Option<String>,
383 #[serde(skip_serializing_if = "Option::is_none")]
385 pub signature: Option<String>,
386 #[serde(skip_serializing_if = "Option::is_none")]
388 pub id: Option<String>,
389}
390
391#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
394#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
395pub struct ContentDelta {
396 pub index: usize,
397 pub part: PartDelta,
398}
399
400pub type JSONSchema = Value;
402
403#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
405#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
406pub struct Tool {
407 pub name: String,
409 pub description: String,
411 pub parameters: JSONSchema,
414}
415
416#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
419#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
420pub struct ToolMessage {
421 pub content: Vec<Part>,
422}
423
424#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
426#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
427pub struct ModelTokensDetails {
428 #[serde(skip_serializing_if = "Option::is_none")]
429 pub text_tokens: Option<u32>,
430 #[serde(skip_serializing_if = "Option::is_none")]
431 pub cached_text_tokens: Option<u32>,
432 #[serde(skip_serializing_if = "Option::is_none")]
433 pub audio_tokens: Option<u32>,
434 #[serde(skip_serializing_if = "Option::is_none")]
435 pub cached_audio_tokens: Option<u32>,
436 #[serde(skip_serializing_if = "Option::is_none")]
437 pub image_tokens: Option<u32>,
438 #[serde(skip_serializing_if = "Option::is_none")]
439 pub cached_image_tokens: Option<u32>,
440}
441
442#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
444#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
445pub struct ModelUsage {
446 pub input_tokens: u32,
447 pub output_tokens: u32,
448 #[serde(skip_serializing_if = "Option::is_none")]
449 pub input_tokens_details: Option<ModelTokensDetails>,
450 #[serde(skip_serializing_if = "Option::is_none")]
451 pub output_tokens_details: Option<ModelTokensDetails>,
452}
453
454#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
456#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
457pub struct ModelResponse {
458 pub content: Vec<Part>,
459 #[serde(skip_serializing_if = "Option::is_none")]
460 pub usage: Option<ModelUsage>,
461 #[serde(skip_serializing_if = "Option::is_none")]
463 pub cost: Option<f64>,
464}
465
466#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
469#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
470pub struct PartialModelResponse {
471 pub delta: Option<ContentDelta>,
472 pub usage: Option<ModelUsage>,
473 pub cost: Option<f64>,
474}
475
476#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
478#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
479pub struct ToolChoiceTool {
480 pub tool_name: String,
481}
482
483#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
486#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
487pub struct ResponseFormatJson {
488 pub name: String,
490 #[serde(skip_serializing_if = "Option::is_none")]
492 pub description: Option<String>,
493 #[serde(skip_serializing_if = "Option::is_none")]
494 pub schema: Option<JSONSchema>,
495}
496
497#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
499#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
500pub struct AudioOptions {
501 #[serde(skip_serializing_if = "Option::is_none")]
503 pub format: Option<AudioFormat>,
504 #[serde(skip_serializing_if = "Option::is_none")]
506 pub voice: Option<String>,
507 #[serde(skip_serializing_if = "Option::is_none")]
509 pub language: Option<String>,
510}
511
512#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
514#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
515pub struct ReasoningOptions {
516 pub enabled: bool,
518 #[serde(skip_serializing_if = "Option::is_none")]
520 pub budget_tokens: Option<u32>,
521}
522
523#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq)]
525#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
526pub struct LanguageModelInput {
527 #[serde(skip_serializing_if = "Option::is_none")]
530 pub system_prompt: Option<String>,
531 pub messages: Vec<Message>,
533 #[serde(skip_serializing_if = "Option::is_none")]
535 pub tools: Option<Vec<Tool>>,
536 #[serde(skip_serializing_if = "Option::is_none")]
537 pub tool_choice: Option<ToolChoiceOption>,
538 #[serde(skip_serializing_if = "Option::is_none")]
539 pub response_format: Option<ResponseFormatOption>,
540 #[serde(skip_serializing_if = "Option::is_none")]
543 pub max_tokens: Option<u32>,
544 #[serde(skip_serializing_if = "Option::is_none")]
546 pub temperature: Option<f64>,
547 #[serde(skip_serializing_if = "Option::is_none")]
551 pub top_p: Option<f64>,
552 #[serde(skip_serializing_if = "Option::is_none")]
556 pub top_k: Option<i32>,
557 #[serde(skip_serializing_if = "Option::is_none")]
560 pub presence_penalty: Option<f64>,
561 #[serde(skip_serializing_if = "Option::is_none")]
565 pub frequency_penalty: Option<f64>,
566 #[serde(skip_serializing_if = "Option::is_none")]
569 pub seed: Option<i64>,
570 #[serde(skip_serializing_if = "Option::is_none")]
572 pub modalities: Option<Vec<Modality>>,
573 #[serde(skip_serializing_if = "Option::is_none")]
576 pub metadata: Option<HashMap<String, String>>,
577 #[serde(skip_serializing_if = "Option::is_none")]
579 pub audio: Option<AudioOptions>,
580 pub reasoning: Option<ReasoningOptions>,
582}
583
584#[derive(Debug, Clone, Serialize, Deserialize)]
586#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
587pub struct LanguageModelPricing {
588 #[serde(skip_serializing_if = "Option::is_none")]
590 pub input_cost_per_text_token: Option<f64>,
591 #[serde(skip_serializing_if = "Option::is_none")]
593 pub input_cost_per_cached_text_token: Option<f64>,
594 #[serde(skip_serializing_if = "Option::is_none")]
596 pub output_cost_per_text_token: Option<f64>,
597 #[serde(skip_serializing_if = "Option::is_none")]
599 pub input_cost_per_audio_token: Option<f64>,
600 #[serde(skip_serializing_if = "Option::is_none")]
602 pub input_cost_per_cached_audio_token: Option<f64>,
603 #[serde(skip_serializing_if = "Option::is_none")]
605 pub output_cost_per_audio_token: Option<f64>,
606 #[serde(skip_serializing_if = "Option::is_none")]
608 pub input_cost_per_image_token: Option<f64>,
609 #[serde(skip_serializing_if = "Option::is_none")]
611 pub input_cost_per_cached_image_token: Option<f64>,
612 #[serde(skip_serializing_if = "Option::is_none")]
614 pub output_cost_per_image_token: Option<f64>,
615}