use serde::{Deserialize, Serialize};
use serde_json::Map;
use super::{Metadata, ToolReturnPart};
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum CachePointTtl {
#[serde(rename = "5m")]
FiveMinutes,
#[serde(rename = "1h")]
OneHour,
}
impl CachePointTtl {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::FiveMinutes => "5m",
Self::OneHour => "1h",
}
}
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum ModelRequestPart {
SystemPrompt {
text: String,
#[serde(default, skip_serializing_if = "Map::is_empty")]
metadata: Metadata,
},
UserPrompt {
content: Vec<ContentPart>,
#[serde(default, skip_serializing_if = "Option::is_none")]
name: Option<String>,
#[serde(default, skip_serializing_if = "Map::is_empty")]
metadata: Metadata,
},
ToolReturn(ToolReturnPart),
RetryPrompt {
text: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
tool_call_id: Option<String>,
#[serde(default, skip_serializing_if = "Map::is_empty")]
metadata: Metadata,
},
Instruction {
text: String,
#[serde(default, skip_serializing_if = "Map::is_empty")]
metadata: Metadata,
},
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum ContentPart {
CachePoint {
#[serde(default, skip_serializing_if = "Option::is_none")]
ttl: Option<CachePointTtl>,
},
Text {
text: String,
},
ImageUrl {
url: String,
},
FileUrl {
url: String,
media_type: String,
},
Binary {
data: Vec<u8>,
media_type: String,
},
ResourceRef {
uri: String,
media_type: String,
resource_type: String,
#[serde(default, skip_serializing_if = "Map::is_empty")]
metadata: Metadata,
},
DataUrl {
data_url: String,
media_type: String,
},
}
impl ContentPart {
#[must_use]
pub const fn cache_point() -> Self {
Self::CachePoint { ttl: None }
}
#[must_use]
pub const fn cache_point_with_ttl(ttl: CachePointTtl) -> Self {
Self::CachePoint { ttl: Some(ttl) }
}
#[must_use]
pub fn text(text: impl Into<String>) -> Self {
Self::Text { text: text.into() }
}
#[must_use]
pub fn image_url(url: impl Into<String>) -> Self {
Self::ImageUrl { url: url.into() }
}
#[must_use]
pub fn file_url(url: impl Into<String>, media_type: impl Into<String>) -> Self {
Self::FileUrl {
url: url.into(),
media_type: media_type.into(),
}
}
#[must_use]
pub fn binary(data: impl Into<Vec<u8>>, media_type: impl Into<String>) -> Self {
Self::Binary {
data: data.into(),
media_type: media_type.into(),
}
}
#[must_use]
pub fn image_bytes(data: impl Into<Vec<u8>>, media_type: impl Into<String>) -> Self {
Self::binary(data, media_type)
}
#[must_use]
pub fn audio_bytes(data: impl Into<Vec<u8>>, media_type: impl Into<String>) -> Self {
Self::binary(data, media_type)
}
#[must_use]
pub fn video_bytes(data: impl Into<Vec<u8>>, media_type: impl Into<String>) -> Self {
Self::binary(data, media_type)
}
#[must_use]
pub fn data_url(data_url: impl Into<String>, media_type: impl Into<String>) -> Self {
Self::DataUrl {
data_url: data_url.into(),
media_type: media_type.into(),
}
}
#[must_use]
pub fn resource_ref(
uri: impl Into<String>,
media_type: impl Into<String>,
resource_type: impl Into<String>,
) -> Self {
Self::ResourceRef {
uri: uri.into(),
media_type: media_type.into(),
resource_type: resource_type.into(),
metadata: Metadata::new(),
}
}
#[must_use]
pub fn with_resource_metadata(mut self, metadata: Metadata) -> Self {
if let Self::ResourceRef {
metadata: existing, ..
} = &mut self
{
*existing = metadata;
}
self
}
}