| |
| |
|
|
| use serde::{Deserialize, Serialize}; |
|
|
| |
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct ClaudeRequest { |
| pub model: String, |
| pub messages: Vec<Message>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub system: Option<SystemPrompt>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub tools: Option<Vec<Tool>>, |
| #[serde(default)] |
| pub stream: bool, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub max_tokens: Option<u32>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub temperature: Option<f32>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub top_p: Option<f32>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub top_k: Option<u32>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub thinking: Option<ThinkingConfig>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub metadata: Option<Metadata>, |
| } |
|
|
| |
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct ThinkingConfig { |
| #[serde(rename = "type")] |
| pub type_: String, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub budget_tokens: Option<u32>, |
| } |
|
|
| |
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| #[serde(untagged)] |
| pub enum SystemPrompt { |
| String(String), |
| Array(Vec<SystemBlock>), |
| } |
|
|
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct SystemBlock { |
| #[serde(rename = "type")] |
| pub block_type: String, |
| pub text: String, |
| } |
|
|
| |
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct Message { |
| pub role: String, |
| pub content: MessageContent, |
| } |
|
|
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| #[serde(untagged)] |
| pub enum MessageContent { |
| String(String), |
| Array(Vec<ContentBlock>), |
| } |
|
|
| |
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| #[serde(tag = "type")] |
| pub enum ContentBlock { |
| #[serde(rename = "text")] |
| Text { text: String }, |
|
|
| #[serde(rename = "thinking")] |
| Thinking { |
| thinking: String, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| signature: Option<String>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| cache_control: Option<serde_json::Value>, |
| }, |
|
|
| #[serde(rename = "image")] |
| Image { source: ImageSource }, |
|
|
| #[serde(rename = "tool_use")] |
| ToolUse { |
| id: String, |
| name: String, |
| input: serde_json::Value, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| signature: Option<String>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| cache_control: Option<serde_json::Value>, |
| }, |
|
|
| #[serde(rename = "tool_result")] |
| ToolResult { |
| tool_use_id: String, |
| content: serde_json::Value, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| is_error: Option<bool>, |
| }, |
|
|
| #[serde(rename = "server_tool_use")] |
| ServerToolUse { |
| id: String, |
| name: String, |
| input: serde_json::Value, |
| }, |
|
|
| #[serde(rename = "web_search_tool_result")] |
| WebSearchToolResult { |
| tool_use_id: String, |
| content: serde_json::Value, |
| }, |
|
|
| #[serde(rename = "redacted_thinking")] |
| RedactedThinking { data: String }, |
| } |
|
|
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct ImageSource { |
| #[serde(rename = "type")] |
| pub source_type: String, |
| pub media_type: String, |
| pub data: String, |
| } |
|
|
| |
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct Tool { |
| |
| #[serde(rename = "type")] |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub type_: Option<String>, |
| |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub name: Option<String>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub description: Option<String>, |
| |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub input_schema: Option<serde_json::Value>, |
| } |
|
|
| impl Tool { |
| |
| pub fn is_web_search(&self) -> bool { |
| |
| if let Some(ref t) = self.type_ { |
| if t.starts_with("web_search") { |
| return true; |
| } |
| } |
| |
| if let Some(ref n) = self.name { |
| if n == "web_search" { |
| return true; |
| } |
| } |
| false |
| } |
|
|
| |
| pub fn get_name(&self) -> String { |
| self.name.clone().unwrap_or_else(|| { |
| |
| if let Some(ref t) = self.type_ { |
| if t.starts_with("web_search") { |
| return "web_search".to_string(); |
| } |
| } |
| "unknown".to_string() |
| }) |
| } |
| } |
|
|
| |
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct Metadata { |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub user_id: Option<String>, |
| } |
|
|
| |
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct ClaudeResponse { |
| pub id: String, |
| #[serde(rename = "type")] |
| pub type_: String, |
| pub role: String, |
| pub model: String, |
| pub content: Vec<ContentBlock>, |
| pub stop_reason: String, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub stop_sequence: Option<String>, |
| pub usage: Usage, |
| } |
|
|
| |
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct Usage { |
| pub input_tokens: u32, |
| pub output_tokens: u32, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub server_tool_use: Option<serde_json::Value>, |
| } |
|
|
| |
|
|
| |
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct GeminiContent { |
| pub role: String, |
| pub parts: Vec<GeminiPart>, |
| } |
|
|
| |
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct GeminiPart { |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub text: Option<String>, |
|
|
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub thought: Option<bool>, |
|
|
| #[serde(skip_serializing_if = "Option::is_none")] |
| #[serde(rename = "thoughtSignature")] |
| pub thought_signature: Option<String>, |
|
|
| #[serde(skip_serializing_if = "Option::is_none")] |
| #[serde(rename = "functionCall")] |
| pub function_call: Option<FunctionCall>, |
|
|
| #[serde(skip_serializing_if = "Option::is_none")] |
| #[serde(rename = "functionResponse")] |
| pub function_response: Option<FunctionResponse>, |
|
|
| #[serde(skip_serializing_if = "Option::is_none")] |
| #[serde(rename = "inlineData")] |
| pub inline_data: Option<InlineData>, |
| } |
|
|
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct FunctionCall { |
| pub name: String, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub id: Option<String>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub args: Option<serde_json::Value>, |
| } |
|
|
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct FunctionResponse { |
| pub name: String, |
| pub response: serde_json::Value, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub id: Option<String>, |
| } |
|
|
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct InlineData { |
| #[serde(rename = "mimeType")] |
| pub mime_type: String, |
| pub data: String, |
| } |
|
|
| |
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct GeminiResponse { |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub candidates: Option<Vec<Candidate>>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| #[serde(rename = "usageMetadata")] |
| pub usage_metadata: Option<UsageMetadata>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| #[serde(rename = "modelVersion")] |
| pub model_version: Option<String>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| #[serde(rename = "responseId")] |
| pub response_id: Option<String>, |
| } |
|
|
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct Candidate { |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub content: Option<GeminiContent>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| #[serde(rename = "finishReason")] |
| pub finish_reason: Option<String>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub index: Option<u32>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| #[serde(rename = "groundingMetadata")] |
| pub grounding_metadata: Option<GroundingMetadata>, |
| } |
|
|
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct UsageMetadata { |
| #[serde(skip_serializing_if = "Option::is_none")] |
| #[serde(rename = "promptTokenCount")] |
| pub prompt_token_count: Option<u32>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| #[serde(rename = "candidatesTokenCount")] |
| pub candidates_token_count: Option<u32>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| #[serde(rename = "totalTokenCount")] |
| pub total_token_count: Option<u32>, |
| } |
|
|
| |
|
|
| |
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct GroundingMetadata { |
| #[serde(rename = "webSearchQueries")] |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub web_search_queries: Option<Vec<String>>, |
|
|
| #[serde(rename = "groundingChunks")] |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub grounding_chunks: Option<Vec<GroundingChunk>>, |
|
|
| #[serde(rename = "groundingSupports")] |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub grounding_supports: Option<Vec<GroundingSupport>>, |
|
|
| #[serde(rename = "searchEntryPoint")] |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub search_entry_point: Option<SearchEntryPoint>, |
| } |
|
|
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct GroundingChunk { |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub web: Option<WebSource>, |
| } |
|
|
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct WebSource { |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub uri: Option<String>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub title: Option<String>, |
| } |
|
|
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct GroundingSupport { |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub segment: Option<TextSegment>, |
| #[serde(rename = "groundingChunkIndices")] |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub grounding_chunk_indices: Option<Vec<i32>>, |
| #[serde(rename = "confidenceScores")] |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub confidence_scores: Option<Vec<f64>>, |
| } |
|
|
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct TextSegment { |
| #[serde(rename = "startIndex")] |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub start_index: Option<i32>, |
| #[serde(rename = "endIndex")] |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub end_index: Option<i32>, |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub text: Option<String>, |
| } |
|
|
| #[derive(Debug, Clone, Serialize, Deserialize)] |
| pub struct SearchEntryPoint { |
| #[serde(rename = "renderedContent")] |
| #[serde(skip_serializing_if = "Option::is_none")] |
| pub rendered_content: Option<String>, |
| } |
|
|