// OpenAI 数据模型 use serde::{Deserialize, Serialize}; use serde_json::Value; #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct OpenAIRequest { pub model: String, #[serde(default)] pub messages: Vec, #[serde(default)] pub prompt: Option, #[serde(default)] pub stream: bool, #[serde(default)] pub n: Option, // [NEW] 支持多候选结果数量 #[serde(rename = "max_tokens")] pub max_tokens: Option, pub temperature: Option, #[serde(rename = "top_p")] pub top_p: Option, pub stop: Option, pub response_format: Option, #[serde(default)] pub tools: Option>, #[serde(rename = "tool_choice")] pub tool_choice: Option, #[serde(rename = "parallel_tool_calls")] pub parallel_tool_calls: Option, // Codex proprietary fields pub instructions: Option, pub input: Option, // [NEW] Image generation parameters (for Chat API compatibility) #[serde(default)] pub size: Option, #[serde(default)] pub quality: Option, #[serde(default, rename = "personGeneration")] pub person_generation: Option, // [NEW] Thinking/Extended Thinking 支持 (兼容 Anthropic/Claude 协议) #[serde(default)] pub thinking: Option, // [NEW] Direct imageSize support (for Gemini native parameter) #[serde(default, rename = "imageSize")] pub image_size: Option, } /// Thinking 配置 (兼容 Anthropic 和 OpenAI 扩展协议) #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct ThinkingConfig { #[serde(rename = "type")] pub thinking_type: Option, // "enabled", "disabled", or "adaptive" #[serde(rename = "budget_tokens", alias = "budgetTokens")] pub budget_tokens: Option, #[serde(skip_serializing_if = "Option::is_none")] pub effort: Option, // "low", "high", or "max" } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ResponseFormat { pub r#type: String, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(untagged)] pub enum OpenAIContent { String(String), Array(Vec), } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(tag = "type")] pub enum OpenAIContentBlock { #[serde(rename = "text", alias = "input_text")] Text { text: String }, #[serde(rename = "image_url")] ImageUrl { image_url: OpenAIImageUrl }, #[serde(rename = "audio_url")] AudioUrl { audio_url: AudioUrlContent }, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct OpenAIImageUrl { pub url: String, #[serde(skip_serializing_if = "Option::is_none")] pub detail: Option, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct AudioUrlContent { pub url: String, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct OpenAIMessage { pub role: String, #[serde(skip_serializing_if = "Option::is_none")] pub content: Option, #[serde(skip_serializing_if = "Option::is_none")] pub reasoning_content: Option, #[serde(skip_serializing_if = "Option::is_none")] pub tool_calls: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub tool_call_id: Option, #[serde(skip_serializing_if = "Option::is_none")] pub name: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ToolCall { pub id: String, pub r#type: String, pub function: ToolFunction, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ToolFunction { pub name: String, pub arguments: String, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct OpenAIResponse { pub id: String, pub object: String, pub created: u64, pub model: String, pub choices: Vec, #[serde(skip_serializing_if = "Option::is_none")] pub usage: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Choice { pub index: u32, pub message: OpenAIMessage, pub finish_reason: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct OpenAIUsage { pub prompt_tokens: u32, pub completion_tokens: u32, pub total_tokens: u32, #[serde(skip_serializing_if = "Option::is_none")] pub prompt_tokens_details: Option, #[serde(skip_serializing_if = "Option::is_none")] pub completion_tokens_details: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PromptTokensDetails { #[serde(skip_serializing_if = "Option::is_none")] pub cached_tokens: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CompletionTokensDetails { #[serde(skip_serializing_if = "Option::is_none")] pub reasoning_tokens: Option, }