use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use super::openai::{
OpenAIMessage, OpenAIMessageContent, OpenAIResponseFormat, OpenAIStop, OpenAIStreamOptions, OpenAIToolCall, OpenAIToolCallDelta, OpenAIToolChoice, OpenAIToolSpec,
};
#[derive(Serialize, Debug, Clone)]
pub struct OpenRouterChatRequest {
pub messages: Vec<OpenAIMessage>,
#[serde(skip_serializing_if = "Option::is_none")]
pub model: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub models: Option<Vec<String>>,
#[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 max_tokens: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_completion_tokens: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stream: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stop: Option<OpenAIStop>,
#[serde(skip_serializing_if = "Option::is_none")]
pub presence_penalty: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub frequency_penalty: Option<f32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tools: Option<Vec<OpenAIToolSpec>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_choice: Option<OpenAIToolChoice>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parallel_tool_calls: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub response_format: Option<OpenAIResponseFormat>,
#[serde(skip_serializing_if = "Option::is_none")]
pub logit_bias: Option<HashMap<String, f32>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub logprobs: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub top_logprobs: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub n: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub seed: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub user: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stream_options: Option<OpenAIStreamOptions>,
#[serde(skip_serializing_if = "Option::is_none")]
pub modalities: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reasoning: Option<OpenRouterReasoning>,
#[serde(skip_serializing_if = "Option::is_none")]
pub provider: Option<OpenRouterProvider>,
#[serde(skip_serializing_if = "Option::is_none")]
pub plugins: Option<Vec<OpenRouterPlugin>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub session_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trace: Option<OpenRouterTrace>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cache_control: Option<OpenRouterCacheControl>,
#[serde(skip_serializing_if = "Option::is_none")]
pub image_config: Option<HashMap<String, serde_json::Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub debug: Option<OpenRouterDebugOptions>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct OpenRouterReasoning {
#[serde(skip_serializing_if = "Option::is_none")]
pub effort: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_tokens: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct OpenRouterProvider {
#[serde(skip_serializing_if = "Option::is_none")]
pub allow_fallbacks: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub require_parameters: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub data_collection: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub zdr: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub enforce_distillable_text: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub order: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub only: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ignore: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub quantizations: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_price: Option<OpenRouterMaxPrice>,
#[serde(skip_serializing_if = "Option::is_none")]
pub preferred_min_throughput: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub preferred_max_latency: Option<serde_json::Value>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct OpenRouterMaxPrice {
#[serde(skip_serializing_if = "Option::is_none")]
pub prompt: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub completion: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub image: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub audio: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub request: Option<serde_json::Value>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(tag = "id", rename_all = "kebab-case")]
pub enum OpenRouterPlugin {
#[serde(rename = "auto-router")]
AutoRouter {
#[serde(skip_serializing_if = "Option::is_none")]
enabled: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
allowed_models: Option<Vec<String>>,
},
#[serde(rename = "moderation")]
Moderation,
#[serde(rename = "web")]
Web {
#[serde(skip_serializing_if = "Option::is_none")]
enabled: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
max_results: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
search_prompt: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
engine: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
include_domains: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
exclude_domains: Option<Vec<String>>,
},
#[serde(rename = "file-parser")]
FileParser {
#[serde(skip_serializing_if = "Option::is_none")]
enabled: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pdf: Option<OpenRouterPdfParserOptions>,
},
#[serde(rename = "response-healing")]
ResponseHealing {
#[serde(skip_serializing_if = "Option::is_none")]
enabled: Option<bool>,
},
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct OpenRouterPdfParserOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub engine: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct OpenRouterTrace {
#[serde(skip_serializing_if = "Option::is_none")]
pub trace_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub trace_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub span_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub generation_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent_span_id: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct OpenRouterCacheControl {
pub r#type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub ttl: Option<String>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct OpenRouterDebugOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub echo_upstream_body: Option<bool>,
}
#[derive(Deserialize, Debug)]
pub struct OpenRouterChatResponse {
pub id: String,
pub object: String,
pub created: u64,
pub model: String,
pub choices: Vec<OpenRouterChoice>,
pub system_fingerprint: Option<String>,
pub usage: Option<OpenRouterUsage>,
}
#[derive(Deserialize, Debug)]
pub struct OpenRouterChoice {
pub index: u32,
pub message: Option<OpenRouterResponseMessage>,
pub delta: Option<OpenRouterDelta>,
pub finish_reason: Option<String>,
pub logprobs: Option<serde_json::Value>,
}
#[derive(Deserialize, Debug)]
pub struct OpenRouterResponseMessage {
pub role: String,
pub content: Option<OpenAIMessageContent>,
pub tool_calls: Option<Vec<OpenAIToolCall>>,
pub refusal: Option<String>,
pub reasoning: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct OpenRouterDelta {
pub role: Option<String>,
pub content: Option<String>,
pub reasoning: Option<String>,
pub tool_calls: Option<Vec<OpenAIToolCallDelta>>,
}
#[derive(Deserialize, Debug, Clone)]
pub struct OpenRouterUsage {
pub prompt_tokens: u32,
pub completion_tokens: u32,
pub total_tokens: u32,
pub prompt_tokens_details: Option<OpenRouterPromptTokensDetails>,
pub completion_tokens_details: Option<OpenRouterCompletionTokensDetails>,
pub cost: Option<f64>,
pub cost_details: Option<OpenRouterCostDetails>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct OpenRouterPromptTokensDetails {
pub cached_tokens: Option<u32>,
pub cache_write_tokens: Option<u32>,
pub audio_tokens: Option<u32>,
pub video_tokens: Option<u32>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct OpenRouterCompletionTokensDetails {
pub reasoning_tokens: Option<u32>,
pub audio_tokens: Option<u32>,
pub accepted_prediction_tokens: Option<u32>,
pub rejected_prediction_tokens: Option<u32>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct OpenRouterCostDetails {
pub upstream_inference_cost: Option<f64>,
pub upstream_inference_prompt_cost: Option<f64>,
pub upstream_inference_completions_cost: Option<f64>,
}
#[derive(Debug, Deserialize)]
pub struct OpenRouterModelsResponse {
pub data: Vec<OpenRouterModel>,
}
#[derive(Debug, Deserialize)]
pub struct OpenRouterModel {
pub id: String,
pub name: String,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub context_length: Option<u32>,
pub pricing: OpenRouterPricing,
pub architecture: OpenRouterArchitecture,
#[serde(default)]
pub top_provider: Option<OpenRouterTopProvider>,
#[serde(default)]
pub supported_parameters: Vec<String>,
}
#[derive(Debug, Deserialize)]
pub struct OpenRouterPricing {
#[serde(default)]
pub prompt: Option<String>,
#[serde(default)]
pub completion: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OpenRouterArchitecture {
#[serde(default)]
pub tokenizer: Option<String>,
#[serde(default)]
pub instruct_type: Option<String>,
#[serde(default)]
pub modality: Option<String>,
#[serde(default)]
pub input_modalities: Vec<String>,
#[serde(default)]
pub output_modalities: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OpenRouterTopProvider {
#[serde(default)]
pub context_length: Option<u32>,
#[serde(default)]
pub max_completion_tokens: Option<u32>,
#[serde(default)]
pub is_moderated: bool,
}