use crate::config::types::{ReasoningEffortLevel, VerbosityLevel};
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use std::sync::Arc;
use super::{Message, ToolDefinition};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct FallbackModel {
pub model: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_tokens: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub thinking: Option<AnthropicThinkingConfig>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum AnthropicThinkingConfig {
#[default]
Disabled,
Enabled {
budget_tokens: u32,
#[serde(skip_serializing_if = "Option::is_none")]
display: Option<String>,
},
Adaptive {
#[serde(skip_serializing_if = "Option::is_none")]
display: Option<String>,
},
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum PromptCacheProfile {
BudgetContinuation,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
pub enum AnthropicThinkingModeOverride {
#[default]
Inherit,
Disabled,
Adaptive,
ManualBudget(u32),
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
pub enum AnthropicThinkingDisplayOverride {
#[default]
Inherit,
Summarized,
Omitted,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
pub enum AnthropicOptionalStringOverride {
#[default]
Inherit,
Omit,
Explicit(String),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
pub enum AnthropicOptionalU32Override {
#[default]
Inherit,
Omit,
Explicit(u32),
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
pub struct AnthropicRequestOverrides {
#[serde(default)]
pub thinking_mode: AnthropicThinkingModeOverride,
#[serde(default)]
pub thinking_display: AnthropicThinkingDisplayOverride,
#[serde(default)]
pub effort: AnthropicOptionalStringOverride,
#[serde(default)]
pub task_budget_tokens: AnthropicOptionalU32Override,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct LLMRequest {
pub messages: Vec<Message>,
pub system_prompt: Option<Arc<String>>,
pub tools: Option<Arc<Vec<ToolDefinition>>>,
pub model: String,
pub max_tokens: Option<u32>,
pub temperature: Option<f32>,
pub stream: bool,
pub output_format: Option<Value>,
pub tool_choice: Option<ToolChoice>,
pub parallel_tool_calls: Option<bool>,
pub parallel_tool_config: Option<Box<ParallelToolConfig>>,
pub reasoning_effort: Option<ReasoningEffortLevel>,
pub effort: Option<String>,
pub verbosity: Option<VerbosityLevel>,
pub do_sample: Option<bool>,
pub top_p: Option<f32>,
pub top_k: Option<i32>,
pub presence_penalty: Option<f32>,
pub frequency_penalty: Option<f32>,
pub stop_sequences: Option<Vec<String>>,
pub thinking_budget: Option<u32>,
pub betas: Option<Vec<String>>,
pub context_management: Option<Value>,
pub prefill: Option<String>,
pub character_reinforcement: bool,
pub character_name: Option<String>,
pub coding_agent_settings: Option<Box<CodingAgentSettings>>,
pub metadata: Option<Value>,
pub previous_response_id: Option<String>,
pub response_store: Option<bool>,
pub responses_include: Option<Vec<String>>,
pub service_tier: Option<String>,
pub prompt_cache_key: Option<String>,
pub prompt_cache_profile: Option<PromptCacheProfile>,
pub fallbacks: Option<Vec<FallbackModel>>,
pub fallback_credit_token: Option<String>,
pub anthropic_request_overrides: Option<AnthropicRequestOverrides>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq)]
pub struct ResponsesCompactionOptions {
pub instructions: Option<String>,
pub max_output_tokens: Option<u32>,
pub reasoning_effort: Option<ReasoningEffortLevel>,
pub verbosity: Option<VerbosityLevel>,
pub responses_include: Option<Vec<String>>,
pub response_store: Option<bool>,
pub service_tier: Option<String>,
pub prompt_cache_key: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct CodingAgentSettings {
pub force_xml_tags: bool,
pub prefill_thought: bool,
pub allow_uncertainty: bool,
pub strict_grounding: bool,
pub long_context_optimization: bool,
pub use_xml_document_format: bool,
pub force_quote_grounding: bool,
pub role_specialization: Option<String>,
pub enforce_structured_thought: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
#[derive(Default)]
pub enum ToolChoice {
#[default]
Auto,
None,
Any,
Specific(SpecificToolChoice),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SpecificToolChoice {
#[serde(rename = "type")]
pub tool_type: String,
pub function: SpecificFunctionChoice,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SpecificFunctionChoice {
pub name: String,
}
impl ToolChoice {
pub fn auto() -> Self {
Self::Auto
}
pub fn none() -> Self {
Self::None
}
pub fn any() -> Self {
Self::Any
}
pub fn function(name: String) -> Self {
Self::Specific(SpecificToolChoice {
tool_type: "function".to_owned(),
function: SpecificFunctionChoice { name },
})
}
pub fn allows_parallel_tools(&self) -> bool {
match self {
Self::Auto => true,
Self::Any => true,
Self::Specific(_) => false,
Self::None => false,
}
}
pub fn description(&self) -> &'static str {
match self {
Self::Auto => "Model decides when to use tools (allows parallel)",
Self::None => "No tools will be used",
Self::Any => "At least one tool must be used (allows parallel)",
Self::Specific(_) => "Specific tool must be used (no parallel)",
}
}
const OPENAI_STYLE_PROVIDERS: &'static [&'static str] = &[
"openai",
"deepseek",
"huggingface",
"mistral",
"openrouter",
"zai",
"moonshot",
"stepfun",
"evolink",
"lmstudio",
"llamacpp",
];
#[inline]
pub fn to_provider_format(&self, provider: &str) -> Value {
if Self::OPENAI_STYLE_PROVIDERS.contains(&provider) {
return self.to_openai_format();
}
match provider {
"anthropic" => self.to_anthropic_format(),
"gemini" => self.to_gemini_format(),
_ => self.to_openai_format(), }
}
#[inline]
fn to_openai_format(&self) -> Value {
match self {
Self::Auto => json!("auto"),
Self::None => json!("none"),
Self::Any => json!("required"),
Self::Specific(choice) => json!(choice),
}
}
#[inline]
fn to_anthropic_format(&self) -> Value {
match self {
Self::Auto => json!({"type": "auto"}),
Self::None => json!({"type": "none"}),
Self::Any => json!({"type": "any"}),
Self::Specific(choice) => json!({"type": "tool", "name": &choice.function.name}),
}
}
#[inline]
fn to_gemini_format(&self) -> Value {
match self {
Self::Auto => json!({"mode": "auto"}),
Self::None => json!({"mode": "none"}),
Self::Any => json!({"mode": "any"}),
Self::Specific(choice) => {
json!({"mode": "any", "allowed_function_names": [&choice.function.name]})
}
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParallelToolConfig {
pub disable_parallel_tool_use: bool,
pub max_parallel_tools: Option<usize>,
pub encourage_parallel: bool,
}
impl Default for ParallelToolConfig {
fn default() -> Self {
Self {
disable_parallel_tool_use: false,
max_parallel_tools: Some(5), encourage_parallel: true,
}
}
}
impl ParallelToolConfig {
pub fn anthropic_optimized() -> Self {
Self {
disable_parallel_tool_use: false,
max_parallel_tools: None, encourage_parallel: true,
}
}
pub fn sequential_only() -> Self {
Self {
disable_parallel_tool_use: true,
max_parallel_tools: Some(1),
encourage_parallel: false,
}
}
}