use crate::Provider;
use crate::model_profile::catalog::ModelTier;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum OpenAiReasoningMode {
Standard,
Pro,
}
impl OpenAiReasoningMode {
pub const fn as_wire_str(self) -> &'static str {
match self {
Self::Standard => "standard",
Self::Pro => "pro",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum OpenAiReasoningContext {
Auto,
CurrentTurn,
AllTurns,
}
impl OpenAiReasoningContext {
pub const fn as_wire_str(self) -> &'static str {
match self {
Self::Auto => "auto",
Self::CurrentTurn => "current_turn",
Self::AllTurns => "all_turns",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum OpenAiTextVerbosity {
Low,
Medium,
High,
}
impl OpenAiTextVerbosity {
pub const fn as_wire_str(self) -> &'static str {
match self {
Self::Low => "low",
Self::Medium => "medium",
Self::High => "high",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum OpenAiPromptCacheMode {
Implicit,
Explicit,
}
impl OpenAiPromptCacheMode {
pub const fn as_wire_str(self) -> &'static str {
match self {
Self::Implicit => "implicit",
Self::Explicit => "explicit",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, schemars::JsonSchema)]
pub enum OpenAiPromptCacheTtl {
#[serde(rename = "30m")]
ThirtyMinutes,
}
impl OpenAiPromptCacheTtl {
pub const fn as_wire_str(self) -> &'static str {
match self {
Self::ThirtyMinutes => "30m",
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct OpenAiResponsesParamCapabilities {
pub reasoning_modes: &'static [OpenAiReasoningMode],
pub reasoning_contexts: &'static [OpenAiReasoningContext],
pub text_verbosity_levels: &'static [OpenAiTextVerbosity],
pub prompt_cache_modes: &'static [OpenAiPromptCacheMode],
pub prompt_cache_ttls: &'static [OpenAiPromptCacheTtl],
pub supports_in_memory_prompt_cache_retention: bool,
}
#[derive(Debug, Clone, Copy)]
pub struct ModelCapabilities {
pub id: &'static str,
pub provider: Provider,
pub display_name: &'static str,
pub tier: ModelTier,
pub model_family: &'static str,
pub context_window: u32,
pub max_output_tokens: u32,
pub context_window_beta: Option<BetaValue<u32>>,
pub max_output_tokens_beta: Option<BetaValue<u32>>,
pub vision: bool,
pub image_tool_results: bool,
pub inline_video: bool,
pub realtime: bool,
pub realtime_supports_provider_managed_turns: bool,
pub realtime_supports_explicit_commit: bool,
pub realtime_interrupt_supported: bool,
pub realtime_transcript_supported: bool,
pub transcription_companion_model: Option<&'static str>,
pub image_generation: bool,
pub supports_temperature: bool,
pub supports_top_p: bool,
pub supports_top_k: bool,
pub thinking: ThinkingSupport,
pub supports_reasoning: bool,
pub effort_levels: &'static [EffortLevel],
pub openai_responses_params: Option<OpenAiResponsesParamCapabilities>,
pub supports_web_search: bool,
pub supports_inference_geo: bool,
pub supports_compaction: bool,
pub supports_structured_output: bool,
pub supports_legacy_penalties: bool,
pub supports_thinking_budget_legacy: bool,
pub beta_headers: &'static [BetaHeader],
pub call_timeout_secs: Option<u64>,
}
#[derive(Debug, Clone, Copy)]
pub struct BetaValue<T: 'static> {
pub header: &'static str,
pub value: T,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BetaFeature {
Compaction,
StructuredOutput,
InterleavedThinking,
}
impl BetaFeature {
pub const fn as_wire_str(self) -> &'static str {
match self {
BetaFeature::Compaction => "compaction",
BetaFeature::StructuredOutput => "structured_output",
BetaFeature::InterleavedThinking => "interleaved_thinking",
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct BetaHeader {
pub feature: BetaFeature,
pub header_name: &'static str,
pub header_value: &'static str,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ThinkingSupport {
None,
AnthropicEnabledOnly,
AnthropicAdaptiveOnly,
AnthropicAdaptiveAndEnabled,
GeminiThinkingLevel,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum EffortLevel {
None,
Minimal,
Low,
Medium,
High,
Xhigh,
Max,
}
impl EffortLevel {
pub const fn as_wire_str(self) -> &'static str {
match self {
EffortLevel::None => "none",
EffortLevel::Minimal => "minimal",
EffortLevel::Low => "low",
EffortLevel::Medium => "medium",
EffortLevel::High => "high",
EffortLevel::Xhigh => "xhigh",
EffortLevel::Max => "max",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn beta_feature_wire_labels_are_pinned_projections() {
assert_eq!(BetaFeature::Compaction.as_wire_str(), "compaction");
assert_eq!(
BetaFeature::StructuredOutput.as_wire_str(),
"structured_output"
);
assert_eq!(
BetaFeature::InterleavedThinking.as_wire_str(),
"interleaved_thinking"
);
}
#[test]
fn effort_level_wire_values_are_pinned_projections() {
assert_eq!(EffortLevel::None.as_wire_str(), "none");
assert_eq!(EffortLevel::Minimal.as_wire_str(), "minimal");
assert_eq!(EffortLevel::Low.as_wire_str(), "low");
assert_eq!(EffortLevel::Medium.as_wire_str(), "medium");
assert_eq!(EffortLevel::High.as_wire_str(), "high");
assert_eq!(EffortLevel::Xhigh.as_wire_str(), "xhigh");
assert_eq!(EffortLevel::Max.as_wire_str(), "max");
}
#[test]
fn openai_responses_parameter_wire_values_are_pinned() {
assert_eq!(OpenAiReasoningMode::Standard.as_wire_str(), "standard");
assert_eq!(OpenAiReasoningMode::Pro.as_wire_str(), "pro");
assert_eq!(OpenAiReasoningContext::Auto.as_wire_str(), "auto");
assert_eq!(
OpenAiReasoningContext::CurrentTurn.as_wire_str(),
"current_turn"
);
assert_eq!(OpenAiReasoningContext::AllTurns.as_wire_str(), "all_turns");
assert_eq!(OpenAiTextVerbosity::High.as_wire_str(), "high");
assert_eq!(OpenAiPromptCacheMode::Explicit.as_wire_str(), "explicit");
assert_eq!(OpenAiPromptCacheTtl::ThirtyMinutes.as_wire_str(), "30m");
}
}