use serde_json::Value;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Role {
System,
User,
Assistant,
Tool,
}
impl Role {
pub const fn as_str(self) -> &'static str {
match self {
Self::System => "system",
Self::User => "user",
Self::Assistant => "assistant",
Self::Tool => "tool",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ImageDetail {
Auto,
Low,
High,
}
impl ImageDetail {
pub const fn as_str(self) -> &'static str {
match self {
Self::Auto => "auto",
Self::Low => "low",
Self::High => "high",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CacheTtl {
FiveMinutes,
OneHour,
}
impl CacheTtl {
pub const fn as_str(self) -> &'static str {
match self {
Self::FiveMinutes => "5m",
Self::OneHour => "1h",
}
}
#[must_use]
pub fn parse(value: &str) -> Option<Self> {
match value {
"5m" => Some(Self::FiveMinutes),
"1h" => Some(Self::OneHour),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct CacheControl {
pub ttl: Option<CacheTtl>,
}
impl CacheControl {
pub const EPHEMERAL: Self = Self { ttl: None };
#[must_use]
pub const fn with_ttl(ttl: CacheTtl) -> Self {
Self { ttl: Some(ttl) }
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SystemBlock {
pub text: String,
pub cache_control: Option<CacheControl>,
}
impl SystemBlock {
#[must_use]
pub fn text(text: impl Into<String>) -> Self {
Self {
text: text.into(),
cache_control: None,
}
}
}
#[derive(Debug, Clone)]
pub enum ImageSource {
Base64 {
media_type: String,
data: String,
detail: Option<ImageDetail>,
},
Url {
url: String,
detail: Option<ImageDetail>,
},
}
#[derive(Debug, Clone)]
pub enum CanonicalContent {
Text {
text: String,
cache_control: Option<CacheControl>,
},
Image {
source: ImageSource,
cache_control: Option<CacheControl>,
},
ToolUse {
id: String,
name: String,
input: Value,
signature: Option<String>,
cache_control: Option<CacheControl>,
},
ToolResult {
tool_use_id: String,
content: Vec<Self>,
is_error: bool,
structured_content: Option<Value>,
meta: Option<Value>,
cache_control: Option<CacheControl>,
},
Thinking {
text: String,
signature: Option<String>,
id: Option<String>,
encrypted_content: Option<String>,
},
}
impl CanonicalContent {
#[must_use]
pub fn text(text: impl Into<String>) -> Self {
Self::Text {
text: text.into(),
cache_control: None,
}
}
#[must_use]
pub const fn image(source: ImageSource) -> Self {
Self::Image {
source,
cache_control: None,
}
}
#[must_use]
pub const fn cache_control(&self) -> Option<CacheControl> {
match self {
Self::Text { cache_control, .. }
| Self::Image { cache_control, .. }
| Self::ToolUse { cache_control, .. }
| Self::ToolResult { cache_control, .. } => *cache_control,
Self::Thinking { .. } => None,
}
}
}
#[derive(Debug, Clone)]
pub struct CanonicalMessage {
pub role: Role,
pub content: Vec<CanonicalContent>,
}