3c38dabefb
Co-Authored-By: Claude <noreply@anthropic.com> https://claude.ai/code/session_018zaP8vUfTAsrE38L6h6fw5
453 lines
11 KiB
Rust
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,
|
|
}
|
|
}
|