use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ToolCall {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
pub name: String,
pub arguments: std::collections::HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ContentBlock {
Text { text: String },
ImageBase64 {
data: String,
media_type: String,
},
ImageUrl {
url: String,
#[serde(default = "default_detail")]
detail: String,
},
VideoPath {
path: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
fps: Option<f32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
max_frames: Option<u32>,
},
VideoUrl {
url: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
fps: Option<f32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
max_frames: Option<u32>,
},
VideoBase64 {
data: String,
media_type: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
fps: Option<f32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
max_frames: Option<u32>,
},
AudioPath {
path: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
sample_rate: Option<u32>,
},
AudioUrl {
url: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
sample_rate: Option<u32>,
},
AudioBase64 {
data: String,
media_type: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
sample_rate: Option<u32>,
},
}
impl ContentBlock {
pub fn is_video(&self) -> bool {
matches!(
self,
ContentBlock::VideoPath { .. }
| ContentBlock::VideoUrl { .. }
| ContentBlock::VideoBase64 { .. }
)
}
pub fn is_audio(&self) -> bool {
matches!(
self,
ContentBlock::AudioPath { .. }
| ContentBlock::AudioUrl { .. }
| ContentBlock::AudioBase64 { .. }
)
}
}
fn default_detail() -> String {
"auto".to_string()
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "role", rename_all = "snake_case")]
pub enum Message {
System { content: String },
User { content: String },
UserMultimodal { content: Vec<ContentBlock> },
Assistant {
#[serde(default)]
content: String,
#[serde(default)]
tool_calls: Vec<ToolCall>,
},
ToolResult {
tool_use_id: String,
content: String,
},
ProviderOutputItems {
protocol: String,
items: Vec<serde_json::Value>,
},
}