Files
codewhale/crates/config/src/provider.rs
T

453 lines
11 KiB
Rust

//! Built-in provider metadata.
//!
//! This module is a metadata foundation for collapsing provider drift over
//! time. It deliberately does not mutate request bodies or choose fallback
//! providers; runtime routing remains in `ConfigToml::resolve_runtime_options`.
use super::{
DEFAULT_ARCEE_BASE_URL, DEFAULT_ARCEE_MODEL, DEFAULT_ATLASCLOUD_BASE_URL,
DEFAULT_ATLASCLOUD_MODEL, DEFAULT_DEEPSEEK_BASE_URL, DEFAULT_DEEPSEEK_MODEL,
DEFAULT_FIREWORKS_BASE_URL, DEFAULT_FIREWORKS_MODEL, DEFAULT_HUGGINGFACE_BASE_URL,
DEFAULT_HUGGINGFACE_MODEL, DEFAULT_MOONSHOT_BASE_URL, DEFAULT_MOONSHOT_MODEL,
DEFAULT_NOVITA_BASE_URL, DEFAULT_NOVITA_MODEL, DEFAULT_NVIDIA_NIM_BASE_URL,
DEFAULT_NVIDIA_NIM_MODEL, DEFAULT_OLLAMA_BASE_URL, DEFAULT_OLLAMA_MODEL,
DEFAULT_OPENAI_BASE_URL, DEFAULT_OPENAI_CODEX_BASE_URL, DEFAULT_OPENAI_CODEX_MODEL,
DEFAULT_OPENAI_MODEL, DEFAULT_OPENROUTER_BASE_URL, DEFAULT_OPENROUTER_MODEL,
DEFAULT_SGLANG_BASE_URL, DEFAULT_SGLANG_MODEL, DEFAULT_SILICONFLOW_BASE_URL,
DEFAULT_SILICONFLOW_CN_BASE_URL, DEFAULT_SILICONFLOW_MODEL, DEFAULT_TOGETHER_BASE_URL,
DEFAULT_TOGETHER_MODEL, DEFAULT_VLLM_BASE_URL, DEFAULT_VLLM_MODEL, DEFAULT_VOLCENGINE_BASE_URL,
DEFAULT_VOLCENGINE_MODEL, DEFAULT_WANJIE_ARK_BASE_URL, DEFAULT_WANJIE_ARK_MODEL,
DEFAULT_XIAOMI_MIMO_BASE_URL, DEFAULT_XIAOMI_MIMO_MODEL, ProviderKind,
};
/// Wire protocol spoken by a provider.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WireFormat {
/// OpenAI-compatible `/v1/chat/completions` style payloads.
ChatCompletions,
/// OpenAI Responses API (`/responses`).
Responses,
/// Native Anthropic Messages API (`/v1/messages`).
AnthropicMessages,
}
/// Static metadata for a built-in model provider.
pub trait Provider: Send + Sync {
/// Provider enum variant represented by this entry.
fn kind(&self) -> ProviderKind;
/// Canonical provider identifier.
fn id(&self) -> &'static str {
self.kind().as_str()
}
/// Human-readable provider label for UIs and diagnostics.
fn display_name(&self) -> &'static str;
/// Default base URL used when no config/env/CLI override is present.
fn default_base_url(&self) -> &'static str;
/// Default model used when no config/env/CLI override is present.
fn default_model(&self) -> &'static str;
/// Environment variable candidates used for this provider's API key.
fn env_vars(&self) -> &'static [&'static str];
/// TOML table key under `[providers.<key>]`.
fn provider_config_key(&self) -> &'static str;
/// Wire format used by the provider.
fn wire(&self) -> WireFormat {
WireFormat::ChatCompletions
}
}
macro_rules! provider {
(
$struct_name:ident,
$kind:ident,
$display_name:literal,
$base_url:ident,
$model:ident,
[$($env_var:literal),* $(,)?],
$config_key:literal
) => {
/// Zero-sized metadata entry for this built-in provider.
pub struct $struct_name;
impl Provider for $struct_name {
fn kind(&self) -> ProviderKind {
ProviderKind::$kind
}
fn display_name(&self) -> &'static str {
$display_name
}
fn default_base_url(&self) -> &'static str {
$base_url
}
fn default_model(&self) -> &'static str {
$model
}
fn env_vars(&self) -> &'static [&'static str] {
&[$($env_var),*]
}
fn provider_config_key(&self) -> &'static str {
$config_key
}
}
};
}
provider!(
Deepseek,
Deepseek,
"DeepSeek",
DEFAULT_DEEPSEEK_BASE_URL,
DEFAULT_DEEPSEEK_MODEL,
["DEEPSEEK_API_KEY"],
"deepseek"
);
provider!(
NvidiaNim,
NvidiaNim,
"NVIDIA NIM",
DEFAULT_NVIDIA_NIM_BASE_URL,
DEFAULT_NVIDIA_NIM_MODEL,
["NVIDIA_API_KEY", "NVIDIA_NIM_API_KEY", "DEEPSEEK_API_KEY"],
"nvidia_nim"
);
provider!(
Openai,
Openai,
"OpenAI-compatible",
DEFAULT_OPENAI_BASE_URL,
DEFAULT_OPENAI_MODEL,
["OPENAI_API_KEY"],
"openai"
);
provider!(
Atlascloud,
Atlascloud,
"AtlasCloud",
DEFAULT_ATLASCLOUD_BASE_URL,
DEFAULT_ATLASCLOUD_MODEL,
["ATLASCLOUD_API_KEY"],
"atlascloud"
);
provider!(
WanjieArk,
WanjieArk,
"Wanjie Ark",
DEFAULT_WANJIE_ARK_BASE_URL,
DEFAULT_WANJIE_ARK_MODEL,
[
"WANJIE_ARK_API_KEY",
"WANJIE_API_KEY",
"WANJIE_MAAS_API_KEY"
],
"wanjie_ark"
);
provider!(
Volcengine,
Volcengine,
"Volcengine Ark",
DEFAULT_VOLCENGINE_BASE_URL,
DEFAULT_VOLCENGINE_MODEL,
[
"VOLCENGINE_API_KEY",
"VOLCENGINE_ARK_API_KEY",
"ARK_API_KEY"
],
"volcengine"
);
provider!(
Openrouter,
Openrouter,
"OpenRouter",
DEFAULT_OPENROUTER_BASE_URL,
DEFAULT_OPENROUTER_MODEL,
["OPENROUTER_API_KEY"],
"openrouter"
);
provider!(
XiaomiMimo,
XiaomiMimo,
"Xiaomi MiMo",
DEFAULT_XIAOMI_MIMO_BASE_URL,
DEFAULT_XIAOMI_MIMO_MODEL,
[
"XIAOMI_MIMO_TOKEN_PLAN_API_KEY",
"MIMO_TOKEN_PLAN_API_KEY",
"XIAOMI_MIMO_API_KEY",
"XIAOMI_API_KEY",
"MIMO_API_KEY",
],
"xiaomi_mimo"
);
provider!(
Novita,
Novita,
"Novita",
DEFAULT_NOVITA_BASE_URL,
DEFAULT_NOVITA_MODEL,
["NOVITA_API_KEY"],
"novita"
);
provider!(
Fireworks,
Fireworks,
"Fireworks",
DEFAULT_FIREWORKS_BASE_URL,
DEFAULT_FIREWORKS_MODEL,
["FIREWORKS_API_KEY"],
"fireworks"
);
provider!(
Siliconflow,
Siliconflow,
"SiliconFlow",
DEFAULT_SILICONFLOW_BASE_URL,
DEFAULT_SILICONFLOW_MODEL,
["SILICONFLOW_API_KEY"],
"siliconflow"
);
provider!(
SiliconflowCN,
SiliconflowCN,
"SiliconFlow CN",
DEFAULT_SILICONFLOW_CN_BASE_URL,
DEFAULT_SILICONFLOW_MODEL,
["SILICONFLOW_API_KEY"],
"siliconflow"
);
provider!(
Arcee,
Arcee,
"Arcee",
DEFAULT_ARCEE_BASE_URL,
DEFAULT_ARCEE_MODEL,
["ARCEE_API_KEY"],
"arcee"
);
provider!(
Moonshot,
Moonshot,
"Moonshot",
DEFAULT_MOONSHOT_BASE_URL,
DEFAULT_MOONSHOT_MODEL,
["MOONSHOT_API_KEY", "KIMI_API_KEY"],
"moonshot"
);
provider!(
Sglang,
Sglang,
"SGLang",
DEFAULT_SGLANG_BASE_URL,
DEFAULT_SGLANG_MODEL,
["SGLANG_API_KEY"],
"sglang"
);
provider!(
Vllm,
Vllm,
"vLLM",
DEFAULT_VLLM_BASE_URL,
DEFAULT_VLLM_MODEL,
["VLLM_API_KEY"],
"vllm"
);
provider!(
Ollama,
Ollama,
"Ollama",
DEFAULT_OLLAMA_BASE_URL,
DEFAULT_OLLAMA_MODEL,
["OLLAMA_API_KEY"],
"ollama"
);
provider!(
Huggingface,
Huggingface,
"Hugging Face",
DEFAULT_HUGGINGFACE_BASE_URL,
DEFAULT_HUGGINGFACE_MODEL,
["HUGGINGFACE_API_KEY", "HF_TOKEN"],
"huggingface"
);
provider!(
Together,
Together,
"Together AI",
DEFAULT_TOGETHER_BASE_URL,
DEFAULT_TOGETHER_MODEL,
["TOGETHER_API_KEY"],
"together"
);
/// OpenAI Codex / ChatGPT OAuth provider using the Responses API.
pub struct OpenaiCodex;
impl Provider for OpenaiCodex {
fn kind(&self) -> ProviderKind {
ProviderKind::OpenaiCodex
}
fn display_name(&self) -> &'static str {
"OpenAI Codex (ChatGPT)"
}
fn default_base_url(&self) -> &'static str {
DEFAULT_OPENAI_CODEX_BASE_URL
}
fn default_model(&self) -> &'static str {
DEFAULT_OPENAI_CODEX_MODEL
}
fn env_vars(&self) -> &'static [&'static str] {
&["OPENAI_CODEX_ACCESS_TOKEN", "CODEX_ACCESS_TOKEN"]
}
fn provider_config_key(&self) -> &'static str {
"openai_codex"
}
fn wire(&self) -> WireFormat {
WireFormat::Responses
}
}
/// Native Anthropic Messages API provider (#3014).
pub struct Anthropic;
impl Provider for Anthropic {
fn kind(&self) -> ProviderKind {
ProviderKind::Anthropic
}
fn display_name(&self) -> &'static str {
"Anthropic"
}
fn default_base_url(&self) -> &'static str {
crate::DEFAULT_ANTHROPIC_BASE_URL
}
fn default_model(&self) -> &'static str {
crate::DEFAULT_ANTHROPIC_MODEL
}
fn env_vars(&self) -> &'static [&'static str] {
&["ANTHROPIC_API_KEY"]
}
fn provider_config_key(&self) -> &'static str {
"anthropic"
}
fn wire(&self) -> WireFormat {
WireFormat::AnthropicMessages
}
}
static DEEPSEEK: Deepseek = Deepseek;
static NVIDIA_NIM: NvidiaNim = NvidiaNim;
static OPENAI: Openai = Openai;
static ATLASCLOUD: Atlascloud = Atlascloud;
static WANJIE_ARK: WanjieArk = WanjieArk;
static VOLCENGINE: Volcengine = Volcengine;
static OPENROUTER: Openrouter = Openrouter;
static XIAOMI_MIMO: XiaomiMimo = XiaomiMimo;
static NOVITA: Novita = Novita;
static FIREWORKS: Fireworks = Fireworks;
static SILICONFLOW: Siliconflow = Siliconflow;
static SILICONFLOW_CN: SiliconflowCN = SiliconflowCN;
static ARCEE: Arcee = Arcee;
static MOONSHOT: Moonshot = Moonshot;
static SGLANG: Sglang = Sglang;
static VLLM: Vllm = Vllm;
static OLLAMA: Ollama = Ollama;
static HUGGINGFACE: Huggingface = Huggingface;
static TOGETHER: Together = Together;
static OPENAI_CODEX: OpenaiCodex = OpenaiCodex;
static ANTHROPIC: Anthropic = Anthropic;
static PROVIDER_REGISTRY: [&dyn Provider; 21] = [
&DEEPSEEK,
&NVIDIA_NIM,
&OPENAI,
&ATLASCLOUD,
&WANJIE_ARK,
&VOLCENGINE,
&OPENROUTER,
&XIAOMI_MIMO,
&NOVITA,
&FIREWORKS,
&SILICONFLOW,
&SILICONFLOW_CN,
&ARCEE,
&MOONSHOT,
&SGLANG,
&VLLM,
&OLLAMA,
&HUGGINGFACE,
&TOGETHER,
&OPENAI_CODEX,
&ANTHROPIC,
];
/// Return all built-in provider metadata entries in `ProviderKind::ALL` order.
#[must_use]
pub fn all_providers() -> &'static [&'static dyn Provider] {
&PROVIDER_REGISTRY
}
/// Find a provider by canonical id only.
#[must_use]
pub fn lookup_provider(id: &str) -> Option<&'static dyn Provider> {
let id = id.trim();
all_providers()
.iter()
.copied()
.find(|provider| provider.id() == id)
}
/// Resolve a provider by canonical id or supported legacy alias.
#[must_use]
pub fn resolve_provider(id_or_alias: &str) -> Option<&'static dyn Provider> {
ProviderKind::parse(id_or_alias).map(provider_for_kind)
}
/// Return metadata for a known provider kind.
#[must_use]
pub fn provider_for_kind(kind: ProviderKind) -> &'static dyn Provider {
match kind {
ProviderKind::Deepseek => &DEEPSEEK,
ProviderKind::NvidiaNim => &NVIDIA_NIM,
ProviderKind::Openai => &OPENAI,
ProviderKind::Atlascloud => &ATLASCLOUD,
ProviderKind::WanjieArk => &WANJIE_ARK,
ProviderKind::Volcengine => &VOLCENGINE,
ProviderKind::Openrouter => &OPENROUTER,
ProviderKind::XiaomiMimo => &XIAOMI_MIMO,
ProviderKind::Novita => &NOVITA,
ProviderKind::Fireworks => &FIREWORKS,
ProviderKind::Siliconflow => &SILICONFLOW,
ProviderKind::SiliconflowCN => &SILICONFLOW_CN,
ProviderKind::Arcee => &ARCEE,
ProviderKind::Moonshot => &MOONSHOT,
ProviderKind::Sglang => &SGLANG,
ProviderKind::Vllm => &VLLM,
ProviderKind::Ollama => &OLLAMA,
ProviderKind::Huggingface => &HUGGINGFACE,
ProviderKind::Together => &TOGETHER,
ProviderKind::OpenaiCodex => &OPENAI_CODEX,
ProviderKind::Anthropic => &ANTHROPIC,
}
}