use crate::models::ModelInfo;
use crate::tool_choice::ToolChoice;
use mcp_protocol::tool::{Tool, ToolContent};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CacheControl {
#[serde(rename = "type")]
pub cache_type: String,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct SystemMessage {
#[serde(rename = "type")]
pub message_type: String,
pub text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub cache_control: Option<CacheControl>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum SystemMessageFormat {
String(String),
Array(Vec<SystemMessage>),
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "type")]
pub enum MessageContent {
#[serde(rename = "text")]
Text { text: String },
#[serde(rename = "tool_use")]
ToolUse {
id: String,
name: String,
input: serde_json::Value,
},
#[serde(rename = "tool_result")]
ToolResult {
tool_use_id: String,
content: Vec<ToolContent>,
#[serde(skip_serializing_if = "Option::is_none")]
is_error: Option<bool>,
},
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Message {
pub role: String,
pub content: MessageContentFormat,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
pub enum MessageContentFormat {
String(String),
Structured(Vec<MessageContent>),
}
impl Message {
pub fn new_structured(role: impl Into<String>, content: Vec<MessageContent>) -> Self {
Self {
role: role.into(),
content: MessageContentFormat::Structured(content),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CompletionRequest {
pub model: String,
pub messages: Vec<Message>,
pub max_tokens: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub temperature: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub system: Option<SystemMessageFormat>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tools: Option<Vec<Tool>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_choice: Option<ToolChoice>,
#[serde(skip_serializing_if = "Option::is_none")]
pub disable_parallel_tool_use: Option<bool>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Usage {
pub input_tokens: u32,
pub output_tokens: u32,
pub cache_read_input_tokens: Option<u32>,
pub cache_creation_input_tokens: Option<u32>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CompletionResponse {
pub content: Vec<MessageContent>,
pub id: String,
pub model: String,
pub role: String,
pub stop_reason: StopReason,
pub stop_sequence: Option<String>,
#[serde(rename = "type")]
pub message_type: String,
pub usage: Usage,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum StopReason {
#[serde(rename = "end_turn")]
EndTurn,
#[serde(rename = "max_tokens")]
MaxTokens,
#[serde(rename = "stop_sequence")]
StopSequence,
#[serde(rename = "tool_use")]
ToolUse,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum AnthropicRequest {
ListModels,
GenerateCompletion { request: CompletionRequest },
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum ResponseStatus {
#[serde(rename = "Success")]
Success,
#[serde(rename = "Error")]
Error,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum AnthropicResponse {
ListModels { models: Vec<ModelInfo> },
Completion { completion: CompletionResponse },
Error { error: String },
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_deserialize_completion_request_with_system_messages() {
let json = r#"{
"model": "claude-3-7-sonnet-20250219",
"max_tokens": 1024,
"system": [
{
"type": "text",
"text": "You are an AI assistant tasked with analyzing literary works. Your goal is to provide insightful commentary on themes, characters, and writing style.\n"
},
{
"type": "text",
"text": "<the entire contents of Pride and Prejudice>",
"cache_control": {"type": "ephemeral"}
}
],
"messages": [
{
"role": "user",
"content": "Analyze the major themes in Pride and Prejudice."
}
]
}"#;
serde_json::from_str::<CompletionRequest>(json).expect("Failed to deserialize request");
}
#[test]
fn test_deserialize_completion_request_with_system_message_string() {
let json = r#"{
"model": "claude-3-7-sonnet-20250219",
"max_tokens": 1024,
"system": "You are an AI assistant tasked with analyzing literary works. Your goal is to provide insightful commentary on themes, characters, and writing style.",
"messages": [
{
"role": "user",
"content": "Analyze the major themes in Pride and Prejudice."
}
]
}"#;
serde_json::from_str::<CompletionRequest>(json).expect("Failed to deserialize request");
}
}