1use serde::{Deserialize, Serialize};
4use serde_json::Value;
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(rename_all = "lowercase")]
10pub enum ConversationRole {
11 User,
12 Assistant,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
19#[serde(rename_all = "camelCase")]
20pub struct ToolUseBlock {
21 pub tool_use_id: String,
22 pub name: String,
23 pub input: Value,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
28#[serde(rename_all = "lowercase")]
29pub enum ToolResultContent {
30 Text(String),
31 Json(Value),
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36#[serde(rename_all = "camelCase")]
37pub struct ToolResultBlock {
38 pub tool_use_id: String,
39 pub content: Vec<ToolResultContent>,
40 #[serde(skip_serializing_if = "Option::is_none")]
41 pub status: Option<String>,
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
46#[serde(rename_all = "lowercase")]
47pub enum ImageFormat {
48 Png,
49 Jpeg,
50 Gif,
51 Webp,
52}
53
54impl ImageFormat {
55 pub fn as_str(&self) -> &'static str {
57 match self {
58 ImageFormat::Png => "png",
59 ImageFormat::Jpeg => "jpeg",
60 ImageFormat::Gif => "gif",
61 ImageFormat::Webp => "webp",
62 }
63 }
64}
65
66#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
68#[serde(rename_all = "lowercase")]
69pub enum ImageSource {
70 Bytes(Vec<u8>),
72 Url(String),
74}
75
76#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
78pub struct ImageBlock {
79 pub format: ImageFormat,
80 pub source: ImageSource,
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
85#[serde(rename_all = "snake_case")]
86pub enum VideoFormat {
87 Mp4,
88 Mov,
89 Mkv,
90 Webm,
91 Flv,
92 Mpeg,
93 Mpg,
94 Wmv,
95 ThreeGp,
96}
97
98impl VideoFormat {
99 pub fn as_str(&self) -> &'static str {
101 match self {
102 VideoFormat::Mp4 => "mp4",
103 VideoFormat::Mov => "mov",
104 VideoFormat::Mkv => "mkv",
105 VideoFormat::Webm => "webm",
106 VideoFormat::Flv => "flv",
107 VideoFormat::Mpeg => "mpeg",
108 VideoFormat::Mpg => "mpg",
109 VideoFormat::Wmv => "wmv",
110 VideoFormat::ThreeGp => "three_gp",
111 }
112 }
113
114 pub fn mime_type(&self) -> &'static str {
117 match self {
118 VideoFormat::Mp4 => "video/mp4",
119 VideoFormat::Mov => "video/mov",
120 VideoFormat::Mkv => "video/x-matroska",
121 VideoFormat::Webm => "video/webm",
122 VideoFormat::Flv => "video/x-flv",
123 VideoFormat::Mpeg => "video/mpeg",
124 VideoFormat::Mpg => "video/mpg",
125 VideoFormat::Wmv => "video/wmv",
126 VideoFormat::ThreeGp => "video/3gpp",
127 }
128 }
129}
130
131#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
133#[serde(rename_all = "lowercase")]
134pub enum VideoSource {
135 Bytes(Vec<u8>),
137 Uri(String),
140}
141
142#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
144pub struct VideoBlock {
145 pub format: VideoFormat,
146 pub source: VideoSource,
147}
148
149#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
151#[serde(rename_all = "lowercase")]
152pub enum CachePointType {
153 #[default]
154 Default,
155}
156
157#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
163pub struct CachePointBlock {
164 #[serde(rename = "type")]
165 pub r#type: CachePointType,
166}
167
168impl CachePointBlock {
169 pub fn new() -> Self {
171 Self::default()
172 }
173}
174
175#[derive(Debug, Clone)]
177#[non_exhaustive]
178pub enum ContentBlock {
179 Text(String),
180 Image(ImageBlock),
181 Video(VideoBlock),
182 ToolUse(ToolUseBlock),
183 ToolResult(ToolResultBlock),
184 CachePoint(CachePointBlock),
185}
186
187impl ContentBlock {
188 pub fn as_text(&self) -> Result<&str, &Self> {
190 match self {
191 ContentBlock::Text(s) => Ok(s.as_str()),
192 _ => Err(self),
193 }
194 }
195
196 pub fn as_image(&self) -> Result<&ImageBlock, &Self> {
198 match self {
199 ContentBlock::Image(b) => Ok(b),
200 _ => Err(self),
201 }
202 }
203
204 pub fn as_video(&self) -> Result<&VideoBlock, &Self> {
206 match self {
207 ContentBlock::Video(b) => Ok(b),
208 _ => Err(self),
209 }
210 }
211
212 pub fn as_tool_use(&self) -> Result<&ToolUseBlock, &Self> {
214 match self {
215 ContentBlock::ToolUse(b) => Ok(b),
216 _ => Err(self),
217 }
218 }
219
220 pub fn as_tool_result(&self) -> Result<&ToolResultBlock, &Self> {
222 match self {
223 ContentBlock::ToolResult(b) => Ok(b),
224 _ => Err(self),
225 }
226 }
227
228 pub fn as_cache_point(&self) -> Result<&CachePointBlock, &Self> {
230 match self {
231 ContentBlock::CachePoint(b) => Ok(b),
232 _ => Err(self),
233 }
234 }
235}
236
237#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
242pub struct UploadFileOutput {
243 pub file_id: String,
244 pub upload_url: String,
246 pub uri: String,
248 pub expires_at: String,
250}
251
252#[derive(Debug, Clone, PartialEq, Eq, Default, Deserialize)]
256pub struct GeneratedImage {
257 #[serde(default)]
259 pub url: Option<String>,
260 #[serde(default)]
262 pub b64_json: Option<String>,
263 #[serde(default)]
265 pub revised_prompt: Option<String>,
266}
267
268#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Deserialize)]
271pub struct ImageGenerationUsage {
272 #[serde(default)]
273 pub input_tokens: Option<u32>,
274 #[serde(default)]
275 pub output_tokens: Option<u32>,
276 #[serde(default)]
277 pub total_tokens: Option<u32>,
278}
279
280#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
283pub struct GenerateImageOutput {
284 #[serde(default)]
286 pub created: i64,
287 pub data: Vec<GeneratedImage>,
289 #[serde(default)]
291 pub usage: Option<ImageGenerationUsage>,
292}
293
294#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
301#[serde(rename_all = "snake_case")]
302pub enum MediaResolution {
303 Low,
304 Medium,
305 High,
306 UltraHigh,
307}
308
309#[derive(Debug, Clone)]
313pub struct Message {
314 pub role: ConversationRole,
315 pub content: Vec<ContentBlock>,
316}
317
318impl Message {
319 pub fn builder() -> MessageBuilder {
320 MessageBuilder::default()
321 }
322
323 pub fn role(&self) -> &ConversationRole {
324 &self.role
325 }
326
327 pub fn content(&self) -> &[ContentBlock] {
328 &self.content
329 }
330}
331
332#[derive(Default)]
333pub struct MessageBuilder {
334 role: Option<ConversationRole>,
335 content: Vec<ContentBlock>,
336}
337
338impl MessageBuilder {
339 pub fn role(mut self, role: ConversationRole) -> Self {
340 self.role = Some(role);
341 self
342 }
343
344 pub fn content(mut self, block: ContentBlock) -> Self {
345 self.content.push(block);
346 self
347 }
348
349 pub fn build(self) -> Result<Message, crate::Error> {
350 let role = self
351 .role
352 .ok_or_else(|| crate::Error::client_validation("Message.role is required"))?;
353 if self.content.is_empty() {
354 return Err(crate::Error::client_validation(
355 "Message must have at least one content block",
356 ));
357 }
358 Ok(Message {
359 role,
360 content: self.content,
361 })
362 }
363}
364
365#[derive(Debug, Clone)]
371pub struct SystemContentBlock {
372 pub text: String,
373 pub cache_point: Option<CachePointBlock>,
375}
376
377impl SystemContentBlock {
378 pub fn text(text: impl Into<String>) -> Self {
379 Self {
380 text: text.into(),
381 cache_point: None,
382 }
383 }
384
385 pub fn cache_point() -> Self {
387 Self {
388 text: String::new(),
389 cache_point: Some(CachePointBlock::new()),
390 }
391 }
392}
393
394#[derive(Debug, Clone, Default)]
397pub struct InferenceConfiguration {
398 pub max_tokens: Option<u32>,
399 pub temperature: Option<f64>,
400 pub top_p: Option<f64>,
401 pub stop_sequences: Option<Vec<String>>,
402}
403
404impl InferenceConfiguration {
405 pub fn builder() -> InferenceConfigurationBuilder {
406 InferenceConfigurationBuilder::default()
407 }
408}
409
410#[derive(Default)]
411pub struct InferenceConfigurationBuilder {
412 inner: InferenceConfiguration,
413}
414
415impl InferenceConfigurationBuilder {
416 pub fn max_tokens(mut self, v: u32) -> Self {
417 self.inner.max_tokens = Some(v);
418 self
419 }
420 pub fn temperature(mut self, v: f64) -> Self {
421 self.inner.temperature = Some(v);
422 self
423 }
424 pub fn top_p(mut self, v: f64) -> Self {
425 self.inner.top_p = Some(v);
426 self
427 }
428 pub fn stop_sequences(mut self, v: Vec<String>) -> Self {
429 self.inner.stop_sequences = Some(v);
430 self
431 }
432 pub fn build(self) -> InferenceConfiguration {
433 self.inner
434 }
435}
436
437#[derive(Debug, Clone)]
440pub struct ToolInputSchema {
441 pub json: Value,
442}
443
444#[derive(Debug, Clone)]
445pub struct ToolSpecification {
446 pub name: String,
447 pub description: Option<String>,
448 pub input_schema: ToolInputSchema,
449}
450
451#[derive(Debug, Clone)]
452pub struct Tool {
453 pub tool_spec: ToolSpecification,
454}
455
456#[derive(Debug, Clone)]
457pub enum ToolChoice {
458 Auto,
459 Any,
460 Tool { name: String },
461}
462
463#[derive(Debug, Clone)]
464pub struct ToolConfiguration {
465 pub tools: Vec<Tool>,
466 pub tool_choice: Option<ToolChoice>,
467}
468
469#[derive(Debug, Clone)]
473pub enum ConverseOutputEnum {
474 Message(Message),
475}
476
477impl ConverseOutputEnum {
478 pub fn as_message(&self) -> Result<&Message, &Self> {
480 match self {
481 ConverseOutputEnum::Message(m) => Ok(m),
482 }
484 }
485}
486
487#[derive(Debug, Clone)]
488pub struct TokenUsage {
489 pub input_tokens: u32,
490 pub output_tokens: u32,
491 pub total_tokens: u32,
492 pub cache_read_input_tokens: u32,
494 pub cache_write_input_tokens: u32,
496}
497
498#[derive(Debug, Clone)]
499pub struct Metrics {
500 pub latency_ms: u64,
501}
502
503#[derive(Debug, Clone, PartialEq, Eq)]
504pub enum StopReason {
505 EndTurn,
506 MaxTokens,
507 ToolUse,
508 StopSequence,
509 ContentFiltered,
510}
511
512impl StopReason {
513 pub(crate) fn from_finish_reason(s: &str) -> Self {
514 match s {
515 "stop" => StopReason::EndTurn,
516 "length" => StopReason::MaxTokens,
517 "tool_calls" | "function_call" => StopReason::ToolUse,
518 "content_filter" => StopReason::ContentFiltered,
519 _ => StopReason::EndTurn,
520 }
521 }
522}
523
524#[derive(Debug)]
526pub struct ConverseOutput {
527 pub(crate) output: Option<ConverseOutputEnum>,
528 pub(crate) stop_reason: StopReason,
529 pub(crate) usage: TokenUsage,
530 pub(crate) metrics: Metrics,
531}
532
533impl ConverseOutput {
534 pub fn output(&self) -> Option<&ConverseOutputEnum> {
535 self.output.as_ref()
536 }
537 pub fn stop_reason(&self) -> &StopReason {
538 &self.stop_reason
539 }
540 pub fn usage(&self) -> &TokenUsage {
541 &self.usage
542 }
543 pub fn metrics(&self) -> &Metrics {
544 &self.metrics
545 }
546}
547
548#[derive(Debug, Clone)]
551pub struct MessageStartEvent {
552 pub role: ConversationRole,
553}
554
555#[derive(Debug, Clone)]
556pub struct ContentBlockStartToolUse {
557 pub tool_use_id: String,
558 pub name: String,
559}
560
561#[derive(Debug, Clone)]
562pub enum ContentBlockStartPayload {
563 ToolUse(ContentBlockStartToolUse),
564}
565
566#[derive(Debug, Clone)]
567pub struct ContentBlockStartEvent {
568 pub content_block_index: u32,
569 pub start: ContentBlockStartPayload,
570}
571
572#[derive(Debug, Clone)]
573pub enum ContentBlockDeltaPayload {
574 Text(String),
575 ToolUse { input: String },
576}
577
578#[derive(Debug, Clone)]
579pub struct ContentBlockDeltaEvent {
580 pub content_block_index: u32,
581 pub delta: ContentBlockDeltaPayload,
582}
583
584#[derive(Debug, Clone)]
585pub struct ContentBlockStopEvent {
586 pub content_block_index: u32,
587}
588
589#[derive(Debug, Clone)]
590pub struct MessageStopEvent {
591 pub stop_reason: StopReason,
592}
593
594#[derive(Debug, Clone)]
595pub struct MetadataEvent {
596 pub usage: TokenUsage,
597 pub metrics: Metrics,
598}
599
600#[derive(Debug, Clone)]
602#[non_exhaustive]
603pub enum ConverseStreamOutput {
604 MessageStart(MessageStartEvent),
605 ContentBlockStart(ContentBlockStartEvent),
606 ContentBlockDelta(ContentBlockDeltaEvent),
607 ContentBlockStop(ContentBlockStopEvent),
608 MessageStop(MessageStopEvent),
609 Metadata(MetadataEvent),
610}