#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Support {
Supported,
Unsupported,
#[default]
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ModelCapabilities {
pub tools: Support,
pub streaming: Support,
pub images: Support,
pub prompt_cache: Support,
pub structured_output: Support,
pub parallel_tool_calls: Support,
pub reasoning: Support,
}
impl ModelCapabilities {
pub const fn unknown() -> Self {
Self {
tools: Support::Unknown,
streaming: Support::Unknown,
images: Support::Unknown,
prompt_cache: Support::Unknown,
structured_output: Support::Unknown,
parallel_tool_calls: Support::Unknown,
reasoning: Support::Unknown,
}
}
pub const fn with_tools(mut self, s: Support) -> Self {
self.tools = s;
self
}
pub const fn with_streaming(mut self, s: Support) -> Self {
self.streaming = s;
self
}
pub const fn with_images(mut self, s: Support) -> Self {
self.images = s;
self
}
pub const fn with_prompt_cache(mut self, s: Support) -> Self {
self.prompt_cache = s;
self
}
pub const fn with_structured_output(mut self, s: Support) -> Self {
self.structured_output = s;
self
}
pub const fn with_parallel_tool_calls(mut self, s: Support) -> Self {
self.parallel_tool_calls = s;
self
}
pub const fn with_reasoning(mut self, s: Support) -> Self {
self.reasoning = s;
self
}
}
impl Default for ModelCapabilities {
fn default() -> Self {
Self::unknown()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct ModelInfo {
pub id: &'static str,
pub provider: &'static str,
pub name: &'static str,
pub label: &'static str,
pub context_window_tokens: Option<u32>,
pub max_output_tokens: Option<u32>,
pub capabilities: ModelCapabilities,
}
const CAPS_FULL: ModelCapabilities = ModelCapabilities {
tools: Support::Supported,
streaming: Support::Supported,
images: Support::Supported,
prompt_cache: Support::Supported,
structured_output: Support::Supported,
parallel_tool_calls: Support::Supported,
reasoning: Support::Supported,
};
const CAPS_STD: ModelCapabilities = ModelCapabilities {
parallel_tool_calls: Support::Unknown,
..CAPS_FULL
};
const CAPS_XAI: ModelCapabilities = ModelCapabilities {
tools: Support::Supported,
streaming: Support::Unknown,
images: Support::Supported,
prompt_cache: Support::Supported,
structured_output: Support::Supported,
parallel_tool_calls: Support::Unknown,
reasoning: Support::Supported,
};
pub const MODELS: &[ModelInfo] = &[
ModelInfo {
id: "openai/gpt-5.6-sol",
provider: "openai",
name: "gpt-5.6-sol",
label: "GPT-5.6 Sol",
context_window_tokens: Some(1_050_000),
max_output_tokens: Some(128_000),
capabilities: CAPS_STD,
},
ModelInfo {
id: "openai/gpt-5.6-terra",
provider: "openai",
name: "gpt-5.6-terra",
label: "GPT-5.6 Terra",
context_window_tokens: Some(1_050_000),
max_output_tokens: Some(128_000),
capabilities: CAPS_STD,
},
ModelInfo {
id: "openai/gpt-5.6-luna",
provider: "openai",
name: "gpt-5.6-luna",
label: "GPT-5.6 Luna",
context_window_tokens: Some(1_050_000),
max_output_tokens: Some(128_000),
capabilities: CAPS_STD,
},
ModelInfo {
id: "openai/gpt-5.5",
provider: "openai",
name: "gpt-5.5",
label: "GPT-5.5",
context_window_tokens: Some(1_050_000),
max_output_tokens: Some(128_000),
capabilities: CAPS_STD,
},
ModelInfo {
id: "openai/gpt-5.5-pro",
provider: "openai",
name: "gpt-5.5-pro",
label: "GPT-5.5 Pro",
context_window_tokens: Some(1_050_000),
max_output_tokens: Some(128_000),
capabilities: CAPS_STD
.with_streaming(Support::Unsupported)
.with_prompt_cache(Support::Unknown),
},
ModelInfo {
id: "openai/gpt-5.4",
provider: "openai",
name: "gpt-5.4",
label: "GPT-5.4",
context_window_tokens: Some(1_050_000),
max_output_tokens: Some(128_000),
capabilities: CAPS_STD,
},
ModelInfo {
id: "openai/gpt-5.4-pro",
provider: "openai",
name: "gpt-5.4-pro",
label: "GPT-5.4 Pro",
context_window_tokens: Some(1_050_000),
max_output_tokens: Some(128_000),
capabilities: CAPS_STD
.with_structured_output(Support::Unsupported)
.with_prompt_cache(Support::Unknown),
},
ModelInfo {
id: "openai/gpt-5.4-mini",
provider: "openai",
name: "gpt-5.4-mini",
label: "GPT-5.4 Mini",
context_window_tokens: Some(400_000),
max_output_tokens: Some(128_000),
capabilities: CAPS_STD,
},
ModelInfo {
id: "openai/gpt-5.4-nano",
provider: "openai",
name: "gpt-5.4-nano",
label: "GPT-5.4 Nano",
context_window_tokens: Some(400_000),
max_output_tokens: Some(128_000),
capabilities: CAPS_STD,
},
ModelInfo {
id: "anthropic/claude-opus-4-8",
provider: "anthropic",
name: "claude-opus-4-8",
label: "Claude Opus 4.8",
context_window_tokens: Some(1_000_000),
max_output_tokens: Some(128_000),
capabilities: CAPS_FULL,
},
ModelInfo {
id: "anthropic/claude-sonnet-5",
provider: "anthropic",
name: "claude-sonnet-5",
label: "Claude Sonnet 5",
context_window_tokens: Some(1_000_000),
max_output_tokens: Some(128_000),
capabilities: CAPS_FULL,
},
ModelInfo {
id: "anthropic/claude-opus-4-7",
provider: "anthropic",
name: "claude-opus-4-7",
label: "Claude Opus 4.7",
context_window_tokens: Some(1_000_000),
max_output_tokens: Some(128_000),
capabilities: CAPS_FULL,
},
ModelInfo {
id: "anthropic/claude-opus-4-6",
provider: "anthropic",
name: "claude-opus-4-6",
label: "Claude Opus 4.6",
context_window_tokens: Some(1_000_000),
max_output_tokens: Some(128_000),
capabilities: CAPS_FULL,
},
ModelInfo {
id: "anthropic/claude-sonnet-4-6",
provider: "anthropic",
name: "claude-sonnet-4-6",
label: "Claude Sonnet 4.6",
context_window_tokens: Some(1_000_000),
max_output_tokens: Some(128_000),
capabilities: CAPS_FULL,
},
ModelInfo {
id: "anthropic/claude-haiku-4-5-20251001",
provider: "anthropic",
name: "claude-haiku-4-5-20251001",
label: "Claude Haiku 4.5",
context_window_tokens: Some(200_000),
max_output_tokens: Some(64_000),
capabilities: CAPS_FULL,
},
ModelInfo {
id: "gemini/gemini-3.5-flash",
provider: "gemini",
name: "gemini-3.5-flash",
label: "Gemini 3.5 Flash",
context_window_tokens: Some(1_048_576),
max_output_tokens: Some(65_536),
capabilities: CAPS_FULL,
},
ModelInfo {
id: "gemini/gemini-3.1-pro-preview",
provider: "gemini",
name: "gemini-3.1-pro-preview",
label: "Gemini 3.1 Pro",
context_window_tokens: Some(1_048_576),
max_output_tokens: Some(65_536),
capabilities: CAPS_STD,
},
ModelInfo {
id: "gemini/gemini-3-flash-preview",
provider: "gemini",
name: "gemini-3-flash-preview",
label: "Gemini 3 Flash",
context_window_tokens: Some(1_048_576),
max_output_tokens: Some(65_536),
capabilities: CAPS_STD,
},
ModelInfo {
id: "xai/grok-4.5",
provider: "xai",
name: "grok-4.5",
label: "Grok 4.5",
context_window_tokens: Some(500_000),
max_output_tokens: None,
capabilities: CAPS_XAI,
},
ModelInfo {
id: "xai/grok-4.3",
provider: "xai",
name: "grok-4.3",
label: "Grok 4.3",
context_window_tokens: Some(1_000_000),
max_output_tokens: None,
capabilities: CAPS_XAI,
},
ModelInfo {
id: "xai/grok-4.20-multi-agent-beta-0309",
provider: "xai",
name: "grok-4.20-multi-agent-beta-0309",
label: "Grok 4.20 Multi-Agent",
context_window_tokens: Some(1_000_000),
max_output_tokens: None,
capabilities: CAPS_XAI.with_reasoning(Support::Unsupported),
},
ModelInfo {
id: "xai/grok-4.20-beta-0309-reasoning",
provider: "xai",
name: "grok-4.20-beta-0309-reasoning",
label: "Grok 4.20 Reasoning",
context_window_tokens: Some(1_000_000),
max_output_tokens: None,
capabilities: CAPS_XAI.with_reasoning(Support::Unsupported),
},
ModelInfo {
id: "xai/grok-4.20-beta-0309-non-reasoning",
provider: "xai",
name: "grok-4.20-beta-0309-non-reasoning",
label: "Grok 4.20",
context_window_tokens: Some(1_000_000),
max_output_tokens: None,
capabilities: CAPS_XAI.with_reasoning(Support::Unsupported),
},
];
pub fn available_models(registered_providers: &[&str]) -> Vec<&'static ModelInfo> {
MODELS
.iter()
.filter(|m| registered_providers.contains(&m.provider))
.collect()
}
pub fn spec(id: &str) -> Option<&'static ModelInfo> {
MODELS.iter().find(|m| m.id == id || m.name == id)
}