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, Default, Serialize, Deserialize)]
85#[serde(rename_all = "lowercase")]
86pub enum CachePointType {
87 #[default]
88 Default,
89}
90
91#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
97pub struct CachePointBlock {
98 #[serde(rename = "type")]
99 pub r#type: CachePointType,
100}
101
102impl CachePointBlock {
103 pub fn new() -> Self {
105 Self::default()
106 }
107}
108
109#[derive(Debug, Clone)]
111#[non_exhaustive]
112pub enum ContentBlock {
113 Text(String),
114 Image(ImageBlock),
115 ToolUse(ToolUseBlock),
116 ToolResult(ToolResultBlock),
117 CachePoint(CachePointBlock),
118}
119
120impl ContentBlock {
121 pub fn as_text(&self) -> Result<&str, &Self> {
123 match self {
124 ContentBlock::Text(s) => Ok(s.as_str()),
125 _ => Err(self),
126 }
127 }
128
129 pub fn as_image(&self) -> Result<&ImageBlock, &Self> {
131 match self {
132 ContentBlock::Image(b) => Ok(b),
133 _ => Err(self),
134 }
135 }
136
137 pub fn as_tool_use(&self) -> Result<&ToolUseBlock, &Self> {
139 match self {
140 ContentBlock::ToolUse(b) => Ok(b),
141 _ => Err(self),
142 }
143 }
144
145 pub fn as_tool_result(&self) -> Result<&ToolResultBlock, &Self> {
147 match self {
148 ContentBlock::ToolResult(b) => Ok(b),
149 _ => Err(self),
150 }
151 }
152
153 pub fn as_cache_point(&self) -> Result<&CachePointBlock, &Self> {
155 match self {
156 ContentBlock::CachePoint(b) => Ok(b),
157 _ => Err(self),
158 }
159 }
160}
161
162#[derive(Debug, Clone)]
166pub struct Message {
167 pub role: ConversationRole,
168 pub content: Vec<ContentBlock>,
169}
170
171impl Message {
172 pub fn builder() -> MessageBuilder {
173 MessageBuilder::default()
174 }
175
176 pub fn role(&self) -> &ConversationRole {
177 &self.role
178 }
179
180 pub fn content(&self) -> &[ContentBlock] {
181 &self.content
182 }
183}
184
185#[derive(Default)]
186pub struct MessageBuilder {
187 role: Option<ConversationRole>,
188 content: Vec<ContentBlock>,
189}
190
191impl MessageBuilder {
192 pub fn role(mut self, role: ConversationRole) -> Self {
193 self.role = Some(role);
194 self
195 }
196
197 pub fn content(mut self, block: ContentBlock) -> Self {
198 self.content.push(block);
199 self
200 }
201
202 pub fn build(self) -> Result<Message, crate::Error> {
203 let role = self
204 .role
205 .ok_or_else(|| crate::Error::client_validation("Message.role is required"))?;
206 if self.content.is_empty() {
207 return Err(crate::Error::client_validation(
208 "Message must have at least one content block",
209 ));
210 }
211 Ok(Message {
212 role,
213 content: self.content,
214 })
215 }
216}
217
218#[derive(Debug, Clone)]
224pub struct SystemContentBlock {
225 pub text: String,
226 pub cache_point: Option<CachePointBlock>,
228}
229
230impl SystemContentBlock {
231 pub fn text(text: impl Into<String>) -> Self {
232 Self {
233 text: text.into(),
234 cache_point: None,
235 }
236 }
237
238 pub fn cache_point() -> Self {
240 Self {
241 text: String::new(),
242 cache_point: Some(CachePointBlock::new()),
243 }
244 }
245}
246
247#[derive(Debug, Clone, Default)]
250pub struct InferenceConfiguration {
251 pub max_tokens: Option<u32>,
252 pub temperature: Option<f64>,
253 pub top_p: Option<f64>,
254 pub stop_sequences: Option<Vec<String>>,
255}
256
257impl InferenceConfiguration {
258 pub fn builder() -> InferenceConfigurationBuilder {
259 InferenceConfigurationBuilder::default()
260 }
261}
262
263#[derive(Default)]
264pub struct InferenceConfigurationBuilder {
265 inner: InferenceConfiguration,
266}
267
268impl InferenceConfigurationBuilder {
269 pub fn max_tokens(mut self, v: u32) -> Self {
270 self.inner.max_tokens = Some(v);
271 self
272 }
273 pub fn temperature(mut self, v: f64) -> Self {
274 self.inner.temperature = Some(v);
275 self
276 }
277 pub fn top_p(mut self, v: f64) -> Self {
278 self.inner.top_p = Some(v);
279 self
280 }
281 pub fn stop_sequences(mut self, v: Vec<String>) -> Self {
282 self.inner.stop_sequences = Some(v);
283 self
284 }
285 pub fn build(self) -> InferenceConfiguration {
286 self.inner
287 }
288}
289
290#[derive(Debug, Clone)]
293pub struct ToolInputSchema {
294 pub json: Value,
295}
296
297#[derive(Debug, Clone)]
298pub struct ToolSpecification {
299 pub name: String,
300 pub description: Option<String>,
301 pub input_schema: ToolInputSchema,
302}
303
304#[derive(Debug, Clone)]
305pub struct Tool {
306 pub tool_spec: ToolSpecification,
307}
308
309#[derive(Debug, Clone)]
310pub enum ToolChoice {
311 Auto,
312 Any,
313 Tool { name: String },
314}
315
316#[derive(Debug, Clone)]
317pub struct ToolConfiguration {
318 pub tools: Vec<Tool>,
319 pub tool_choice: Option<ToolChoice>,
320}
321
322#[derive(Debug, Clone)]
326pub enum ConverseOutputEnum {
327 Message(Message),
328}
329
330impl ConverseOutputEnum {
331 pub fn as_message(&self) -> Result<&Message, &Self> {
333 match self {
334 ConverseOutputEnum::Message(m) => Ok(m),
335 }
337 }
338}
339
340#[derive(Debug, Clone)]
341pub struct TokenUsage {
342 pub input_tokens: u32,
343 pub output_tokens: u32,
344 pub total_tokens: u32,
345 pub cache_read_input_tokens: u32,
347 pub cache_write_input_tokens: u32,
349}
350
351#[derive(Debug, Clone)]
352pub struct Metrics {
353 pub latency_ms: u64,
354}
355
356#[derive(Debug, Clone, PartialEq, Eq)]
357pub enum StopReason {
358 EndTurn,
359 MaxTokens,
360 ToolUse,
361 StopSequence,
362 ContentFiltered,
363}
364
365impl StopReason {
366 pub(crate) fn from_finish_reason(s: &str) -> Self {
367 match s {
368 "stop" => StopReason::EndTurn,
369 "length" => StopReason::MaxTokens,
370 "tool_calls" | "function_call" => StopReason::ToolUse,
371 "content_filter" => StopReason::ContentFiltered,
372 _ => StopReason::EndTurn,
373 }
374 }
375}
376
377#[derive(Debug)]
379pub struct ConverseOutput {
380 pub(crate) output: Option<ConverseOutputEnum>,
381 pub(crate) stop_reason: StopReason,
382 pub(crate) usage: TokenUsage,
383 pub(crate) metrics: Metrics,
384}
385
386impl ConverseOutput {
387 pub fn output(&self) -> Option<&ConverseOutputEnum> {
388 self.output.as_ref()
389 }
390 pub fn stop_reason(&self) -> &StopReason {
391 &self.stop_reason
392 }
393 pub fn usage(&self) -> &TokenUsage {
394 &self.usage
395 }
396 pub fn metrics(&self) -> &Metrics {
397 &self.metrics
398 }
399}
400
401#[derive(Debug, Clone)]
404pub struct MessageStartEvent {
405 pub role: ConversationRole,
406}
407
408#[derive(Debug, Clone)]
409pub struct ContentBlockStartToolUse {
410 pub tool_use_id: String,
411 pub name: String,
412}
413
414#[derive(Debug, Clone)]
415pub enum ContentBlockStartPayload {
416 ToolUse(ContentBlockStartToolUse),
417}
418
419#[derive(Debug, Clone)]
420pub struct ContentBlockStartEvent {
421 pub content_block_index: u32,
422 pub start: ContentBlockStartPayload,
423}
424
425#[derive(Debug, Clone)]
426pub enum ContentBlockDeltaPayload {
427 Text(String),
428 ToolUse { input: String },
429}
430
431#[derive(Debug, Clone)]
432pub struct ContentBlockDeltaEvent {
433 pub content_block_index: u32,
434 pub delta: ContentBlockDeltaPayload,
435}
436
437#[derive(Debug, Clone)]
438pub struct ContentBlockStopEvent {
439 pub content_block_index: u32,
440}
441
442#[derive(Debug, Clone)]
443pub struct MessageStopEvent {
444 pub stop_reason: StopReason,
445}
446
447#[derive(Debug, Clone)]
448pub struct MetadataEvent {
449 pub usage: TokenUsage,
450 pub metrics: Metrics,
451}
452
453#[derive(Debug, Clone)]
455#[non_exhaustive]
456pub enum ConverseStreamOutput {
457 MessageStart(MessageStartEvent),
458 ContentBlockStart(ContentBlockStartEvent),
459 ContentBlockDelta(ContentBlockDeltaEvent),
460 ContentBlockStop(ContentBlockStopEvent),
461 MessageStop(MessageStopEvent),
462 Metadata(MetadataEvent),
463}