use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct CanonicalRequest {
#[serde(default)]
pub model: String,
#[serde(default)]
pub system: Option<Vec<Content>>,
#[serde(default)]
pub messages: Vec<Message>,
#[serde(default)]
pub tools: Vec<Tool>,
#[serde(default)]
pub tool_choice: ToolChoice,
#[serde(default)]
pub parallel_tool_calls: Option<bool>,
#[serde(default)]
pub max_tokens: Option<u32>,
#[serde(default)]
pub temperature: Option<f32>,
#[serde(default)]
pub top_p: Option<f32>,
#[serde(default)]
pub stop: Vec<String>,
#[serde(default)]
pub stream: Option<bool>,
#[serde(flatten)]
pub extra: Map<String, Value>,
}
impl CanonicalRequest {
pub fn tool_name(&self, tool_use_id: &str) -> Option<&str> {
self.messages
.iter()
.flat_map(|m| &m.content)
.find_map(|c| match c {
Content::ToolUse { id, name, .. } if id == tool_use_id => Some(name.as_str()),
_ => None,
})
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Message {
pub role: Role,
#[serde(deserialize_with = "crate::canonical::request_de::de_content_seq")]
pub content: Vec<Content>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[non_exhaustive]
pub enum Role {
System,
User,
Assistant,
Tool,
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum Content {
Text(String),
Image {
source: ImageSource,
},
ToolUse {
id: String,
name: String,
input: Value,
},
ToolResult {
tool_use_id: String,
content: Vec<Content>,
is_error: bool,
},
Thinking {
text: String,
signature: Option<String>,
},
RedactedThinking {
data: String,
},
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub enum ImageSource {
Base64 { media_type: String, data: String },
Url { url: String },
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Tool {
pub name: String,
#[serde(default)]
pub description: Option<String>,
pub input_schema: Value,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ToolChoice {
#[default]
Auto,
Any,
Tool {
name: String,
},
None,
}