use super::cache::PromptCacheRetention;
use super::model::Model;
use super::{GenerateOptions, Message};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GenerateRequest {
#[serde(skip)]
pub model: Model,
pub messages: Vec<Message>,
#[serde(flatten)]
pub options: GenerateOptions,
#[serde(skip_serializing_if = "Option::is_none")]
pub provider_options: Option<ProviderOptions>,
#[serde(skip_serializing_if = "Option::is_none")]
pub telemetry_metadata: Option<HashMap<String, String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "provider", rename_all = "lowercase")]
pub enum ProviderOptions {
Anthropic(AnthropicOptions),
OpenAI(OpenAIOptions),
Google(GoogleOptions),
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AnthropicOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub thinking: Option<ThinkingOptions>,
#[serde(skip_serializing_if = "Option::is_none")]
pub effort: Option<ReasoningEffort>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThinkingOptions {
pub budget_tokens: u32,
}
impl ThinkingOptions {
pub fn new(budget_tokens: u32) -> Self {
Self {
budget_tokens: budget_tokens.max(1024),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "api_type", rename_all = "lowercase")]
pub enum OpenAIApiConfig {
Completions(CompletionsConfig),
Responses(ResponsesConfig),
}
impl Default for OpenAIApiConfig {
fn default() -> Self {
OpenAIApiConfig::Completions(CompletionsConfig::default())
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CompletionsConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub prompt_cache_key: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prompt_cache_retention: Option<PromptCacheRetention>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ResponsesConfig {
#[serde(skip_serializing_if = "Option::is_none")]
pub reasoning_effort: Option<ReasoningEffort>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reasoning_summary: Option<ReasoningSummary>,
#[serde(skip_serializing_if = "Option::is_none")]
pub session_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub service_tier: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cache_retention: Option<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct OpenAIOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub api_config: Option<OpenAIApiConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub system_message_mode: Option<SystemMessageMode>,
#[serde(skip_serializing_if = "Option::is_none")]
pub store: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub user: Option<String>,
}
impl OpenAIOptions {
pub fn completions() -> Self {
Self {
api_config: Some(OpenAIApiConfig::Completions(CompletionsConfig::default())),
..Default::default()
}
}
pub fn responses() -> Self {
Self {
api_config: Some(OpenAIApiConfig::Responses(ResponsesConfig::default())),
..Default::default()
}
}
pub fn responses_with_reasoning(effort: ReasoningEffort) -> Self {
Self {
api_config: Some(OpenAIApiConfig::Responses(ResponsesConfig {
reasoning_effort: Some(effort),
..Default::default()
})),
..Default::default()
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SystemMessageMode {
System,
Developer,
Remove,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ReasoningEffort {
Low,
Medium,
High,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ReasoningSummary {
Auto,
Detailed,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct GoogleOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub thinking_budget: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cached_content: Option<String>,
}
impl GenerateRequest {
pub fn new(model: Model, messages: Vec<Message>) -> Self {
Self {
model,
messages,
options: GenerateOptions::default(),
provider_options: None,
telemetry_metadata: None,
}
}
pub fn with_provider_options(mut self, options: ProviderOptions) -> Self {
self.provider_options = Some(options);
self
}
pub fn with_telemetry_metadata(mut self, metadata: HashMap<String, String>) -> Self {
self.telemetry_metadata = Some(metadata);
self
}
}