Merge PR #3005: provider metadata registry
Harvested from PR #3005 by @sximelon Co-authored-by: sximelon <15710511+sximelon@users.noreply.github.com>
This commit is contained in:
+10
-54
@@ -173,8 +173,8 @@ impl ProviderKind {
|
|||||||
Self::Novita,
|
Self::Novita,
|
||||||
Self::Fireworks,
|
Self::Fireworks,
|
||||||
Self::Siliconflow,
|
Self::Siliconflow,
|
||||||
Self::SiliconflowCN,
|
|
||||||
Self::Arcee,
|
Self::Arcee,
|
||||||
|
Self::SiliconflowCN,
|
||||||
Self::Moonshot,
|
Self::Moonshot,
|
||||||
Self::Sglang,
|
Self::Sglang,
|
||||||
Self::Vllm,
|
Self::Vllm,
|
||||||
@@ -187,63 +187,19 @@ impl ProviderKind {
|
|||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn as_str(self) -> &'static str {
|
pub fn as_str(self) -> &'static str {
|
||||||
match self {
|
self.provider().id()
|
||||||
Self::Deepseek => "deepseek",
|
|
||||||
Self::NvidiaNim => "nvidia-nim",
|
|
||||||
Self::Openai => "openai",
|
|
||||||
Self::Atlascloud => "atlascloud",
|
|
||||||
Self::WanjieArk => "wanjie-ark",
|
|
||||||
Self::Volcengine => "volcengine",
|
|
||||||
Self::Openrouter => "openrouter",
|
|
||||||
Self::XiaomiMimo => "xiaomi-mimo",
|
|
||||||
Self::Novita => "novita",
|
|
||||||
Self::Fireworks => "fireworks",
|
|
||||||
Self::Siliconflow => "siliconflow",
|
|
||||||
Self::SiliconflowCN => "siliconflow-CN",
|
|
||||||
Self::Arcee => "arcee",
|
|
||||||
Self::Moonshot => "moonshot",
|
|
||||||
Self::Sglang => "sglang",
|
|
||||||
Self::Vllm => "vllm",
|
|
||||||
Self::Ollama => "ollama",
|
|
||||||
Self::Huggingface => "huggingface",
|
|
||||||
Self::Together => "together",
|
|
||||||
Self::OpenaiCodex => "openai-codex",
|
|
||||||
Self::Anthropic => "anthropic",
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn parse(value: &str) -> Option<Self> {
|
pub fn parse(value: &str) -> Option<Self> {
|
||||||
match value.trim().to_ascii_lowercase().as_str() {
|
let trimmed = value.trim();
|
||||||
"deepseek" | "deep-seek" | "deepseek-cn" | "deepseek_china" | "deepseekcn"
|
provider::all_providers()
|
||||||
| "deepseek-china" => Some(Self::Deepseek),
|
.iter()
|
||||||
"nvidia" | "nvidia-nim" | "nvidia_nim" | "nim" => Some(Self::NvidiaNim),
|
.find(|p| {
|
||||||
"openai" | "open-ai" => Some(Self::Openai),
|
trimmed.eq_ignore_ascii_case(p.id())
|
||||||
"atlascloud" | "atlas-cloud" | "atlas_cloud" | "atlas" => Some(Self::Atlascloud),
|
|| p.aliases().iter().any(|a| trimmed.eq_ignore_ascii_case(a))
|
||||||
"wanjie" | "wanjie-ark" | "wanjie_ark" | "ark-wanjie" | "ark_wanjie" | "wanjieark"
|
})
|
||||||
| "wanjie-maas" | "wanjie_maas" | "wanjiemaas" => Some(Self::WanjieArk),
|
.map(|p| p.kind())
|
||||||
"volcengine" | "volcengine-ark" | "volcengine_ark" | "ark" | "volc-ark"
|
|
||||||
| "volcengineark" => Some(Self::Volcengine),
|
|
||||||
"openrouter" | "open_router" => Some(Self::Openrouter),
|
|
||||||
"xiaomi-mimo" | "xiaomi_mimo" | "xiaomimimo" | "mimo" | "xiaomi" => {
|
|
||||||
Some(Self::XiaomiMimo)
|
|
||||||
}
|
|
||||||
"novita" => Some(Self::Novita),
|
|
||||||
"fireworks" | "fireworks-ai" => Some(Self::Fireworks),
|
|
||||||
"siliconflow" | "silicon-flow" | "silicon_flow" => Some(Self::Siliconflow),
|
|
||||||
"siliconflow-cn" | "siliconflow-CN" => Some(Self::SiliconflowCN),
|
|
||||||
"arcee" | "arcee-ai" | "arcee_ai" => Some(Self::Arcee),
|
|
||||||
"moonshot" | "moonshot-ai" | "kimi" | "kimi-k2" => Some(Self::Moonshot),
|
|
||||||
"sglang" | "sg-lang" => Some(Self::Sglang),
|
|
||||||
"vllm" | "v-llm" => Some(Self::Vllm),
|
|
||||||
"ollama" | "ollama-local" => Some(Self::Ollama),
|
|
||||||
"huggingface" | "hugging-face" | "hugging_face" | "hf" => Some(Self::Huggingface),
|
|
||||||
"together" | "together-ai" | "together_ai" => Some(Self::Together),
|
|
||||||
"anthropic" | "claude" => Some(Self::Anthropic),
|
|
||||||
"openai-codex" | "openai_codex" | "openaicodex" | "codex" | "chatgpt"
|
|
||||||
| "chatgpt-codex" | "chatgpt_codex" | "chatgptcodex" => Some(Self::OpenaiCodex),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|||||||
+110
-49
@@ -56,6 +56,11 @@ pub trait Provider: Send + Sync {
|
|||||||
/// TOML table key under `[providers.<key>]`.
|
/// TOML table key under `[providers.<key>]`.
|
||||||
fn provider_config_key(&self) -> &'static str;
|
fn provider_config_key(&self) -> &'static str;
|
||||||
|
|
||||||
|
/// Alternate names accepted during provider resolution.
|
||||||
|
fn aliases(&self) -> &'static [&'static str] {
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
|
||||||
/// Wire format used by the provider.
|
/// Wire format used by the provider.
|
||||||
fn wire(&self) -> WireFormat {
|
fn wire(&self) -> WireFormat {
|
||||||
WireFormat::ChatCompletions
|
WireFormat::ChatCompletions
|
||||||
@@ -66,16 +71,22 @@ macro_rules! provider {
|
|||||||
(
|
(
|
||||||
$struct_name:ident,
|
$struct_name:ident,
|
||||||
$kind:ident,
|
$kind:ident,
|
||||||
|
$id:literal,
|
||||||
$display_name:literal,
|
$display_name:literal,
|
||||||
$base_url:ident,
|
$base_url:ident,
|
||||||
$model:ident,
|
$model:ident,
|
||||||
[$($env_var:literal),* $(,)?],
|
[$($env_var:literal),* $(,)?],
|
||||||
$config_key:literal
|
$config_key:literal,
|
||||||
|
aliases: [$($alias:literal),* $(,)?]
|
||||||
) => {
|
) => {
|
||||||
/// Zero-sized metadata entry for this built-in provider.
|
/// Zero-sized metadata entry for this built-in provider.
|
||||||
pub struct $struct_name;
|
pub struct $struct_name;
|
||||||
|
|
||||||
impl Provider for $struct_name {
|
impl Provider for $struct_name {
|
||||||
|
fn id(&self) -> &'static str {
|
||||||
|
$id
|
||||||
|
}
|
||||||
|
|
||||||
fn kind(&self) -> ProviderKind {
|
fn kind(&self) -> ProviderKind {
|
||||||
ProviderKind::$kind
|
ProviderKind::$kind
|
||||||
}
|
}
|
||||||
@@ -99,6 +110,10 @@ macro_rules! provider {
|
|||||||
fn provider_config_key(&self) -> &'static str {
|
fn provider_config_key(&self) -> &'static str {
|
||||||
$config_key
|
$config_key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn aliases(&self) -> &'static [&'static str] {
|
||||||
|
&[$($alias),*]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -106,42 +121,51 @@ macro_rules! provider {
|
|||||||
provider!(
|
provider!(
|
||||||
Deepseek,
|
Deepseek,
|
||||||
Deepseek,
|
Deepseek,
|
||||||
|
"deepseek",
|
||||||
"DeepSeek",
|
"DeepSeek",
|
||||||
DEFAULT_DEEPSEEK_BASE_URL,
|
DEFAULT_DEEPSEEK_BASE_URL,
|
||||||
DEFAULT_DEEPSEEK_MODEL,
|
DEFAULT_DEEPSEEK_MODEL,
|
||||||
["DEEPSEEK_API_KEY"],
|
["DEEPSEEK_API_KEY"],
|
||||||
"deepseek"
|
"deepseek",
|
||||||
|
aliases: ["deep-seek", "deepseek-cn", "deepseek_china", "deepseekcn", "deepseek-china"]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
NvidiaNim,
|
NvidiaNim,
|
||||||
NvidiaNim,
|
NvidiaNim,
|
||||||
|
"nvidia-nim",
|
||||||
"NVIDIA NIM",
|
"NVIDIA NIM",
|
||||||
DEFAULT_NVIDIA_NIM_BASE_URL,
|
DEFAULT_NVIDIA_NIM_BASE_URL,
|
||||||
DEFAULT_NVIDIA_NIM_MODEL,
|
DEFAULT_NVIDIA_NIM_MODEL,
|
||||||
["NVIDIA_API_KEY", "NVIDIA_NIM_API_KEY", "DEEPSEEK_API_KEY"],
|
["NVIDIA_API_KEY", "NVIDIA_NIM_API_KEY", "DEEPSEEK_API_KEY"],
|
||||||
"nvidia_nim"
|
"nvidia_nim",
|
||||||
|
aliases: ["nvidia", "nvidia_nim", "nim"]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
Openai,
|
Openai,
|
||||||
Openai,
|
Openai,
|
||||||
|
"openai",
|
||||||
"OpenAI-compatible",
|
"OpenAI-compatible",
|
||||||
DEFAULT_OPENAI_BASE_URL,
|
DEFAULT_OPENAI_BASE_URL,
|
||||||
DEFAULT_OPENAI_MODEL,
|
DEFAULT_OPENAI_MODEL,
|
||||||
["OPENAI_API_KEY"],
|
["OPENAI_API_KEY"],
|
||||||
"openai"
|
"openai",
|
||||||
|
aliases: ["open-ai"]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
Atlascloud,
|
Atlascloud,
|
||||||
Atlascloud,
|
Atlascloud,
|
||||||
|
"atlascloud",
|
||||||
"AtlasCloud",
|
"AtlasCloud",
|
||||||
DEFAULT_ATLASCLOUD_BASE_URL,
|
DEFAULT_ATLASCLOUD_BASE_URL,
|
||||||
DEFAULT_ATLASCLOUD_MODEL,
|
DEFAULT_ATLASCLOUD_MODEL,
|
||||||
["ATLASCLOUD_API_KEY"],
|
["ATLASCLOUD_API_KEY"],
|
||||||
"atlascloud"
|
"atlascloud",
|
||||||
|
aliases: ["atlas-cloud", "atlas_cloud", "atlas"]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
WanjieArk,
|
WanjieArk,
|
||||||
WanjieArk,
|
WanjieArk,
|
||||||
|
"wanjie-ark",
|
||||||
"Wanjie Ark",
|
"Wanjie Ark",
|
||||||
DEFAULT_WANJIE_ARK_BASE_URL,
|
DEFAULT_WANJIE_ARK_BASE_URL,
|
||||||
DEFAULT_WANJIE_ARK_MODEL,
|
DEFAULT_WANJIE_ARK_MODEL,
|
||||||
@@ -150,11 +174,13 @@ provider!(
|
|||||||
"WANJIE_API_KEY",
|
"WANJIE_API_KEY",
|
||||||
"WANJIE_MAAS_API_KEY"
|
"WANJIE_MAAS_API_KEY"
|
||||||
],
|
],
|
||||||
"wanjie_ark"
|
"wanjie_ark",
|
||||||
|
aliases: ["wanjie", "wanjie_ark", "ark-wanjie", "ark_wanjie", "wanjieark", "wanjie-maas", "wanjie_maas", "wanjiemaas"]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
Volcengine,
|
Volcengine,
|
||||||
Volcengine,
|
Volcengine,
|
||||||
|
"volcengine",
|
||||||
"Volcengine Ark",
|
"Volcengine Ark",
|
||||||
DEFAULT_VOLCENGINE_BASE_URL,
|
DEFAULT_VOLCENGINE_BASE_URL,
|
||||||
DEFAULT_VOLCENGINE_MODEL,
|
DEFAULT_VOLCENGINE_MODEL,
|
||||||
@@ -163,20 +189,24 @@ provider!(
|
|||||||
"VOLCENGINE_ARK_API_KEY",
|
"VOLCENGINE_ARK_API_KEY",
|
||||||
"ARK_API_KEY"
|
"ARK_API_KEY"
|
||||||
],
|
],
|
||||||
"volcengine"
|
"volcengine",
|
||||||
|
aliases: ["volcengine-ark", "volcengine_ark", "ark", "volc-ark", "volcengineark"]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
Openrouter,
|
Openrouter,
|
||||||
Openrouter,
|
Openrouter,
|
||||||
|
"openrouter",
|
||||||
"OpenRouter",
|
"OpenRouter",
|
||||||
DEFAULT_OPENROUTER_BASE_URL,
|
DEFAULT_OPENROUTER_BASE_URL,
|
||||||
DEFAULT_OPENROUTER_MODEL,
|
DEFAULT_OPENROUTER_MODEL,
|
||||||
["OPENROUTER_API_KEY"],
|
["OPENROUTER_API_KEY"],
|
||||||
"openrouter"
|
"openrouter",
|
||||||
|
aliases: ["open_router"]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
XiaomiMimo,
|
XiaomiMimo,
|
||||||
XiaomiMimo,
|
XiaomiMimo,
|
||||||
|
"xiaomi-mimo",
|
||||||
"Xiaomi MiMo",
|
"Xiaomi MiMo",
|
||||||
DEFAULT_XIAOMI_MIMO_BASE_URL,
|
DEFAULT_XIAOMI_MIMO_BASE_URL,
|
||||||
DEFAULT_XIAOMI_MIMO_MODEL,
|
DEFAULT_XIAOMI_MIMO_MODEL,
|
||||||
@@ -187,112 +217,145 @@ provider!(
|
|||||||
"XIAOMI_API_KEY",
|
"XIAOMI_API_KEY",
|
||||||
"MIMO_API_KEY",
|
"MIMO_API_KEY",
|
||||||
],
|
],
|
||||||
"xiaomi_mimo"
|
"xiaomi_mimo",
|
||||||
|
aliases: ["xiaomi_mimo", "xiaomimimo", "mimo", "xiaomi"]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
Novita,
|
Novita,
|
||||||
Novita,
|
Novita,
|
||||||
"Novita",
|
"novita",
|
||||||
|
"Novita AI",
|
||||||
DEFAULT_NOVITA_BASE_URL,
|
DEFAULT_NOVITA_BASE_URL,
|
||||||
DEFAULT_NOVITA_MODEL,
|
DEFAULT_NOVITA_MODEL,
|
||||||
["NOVITA_API_KEY"],
|
["NOVITA_API_KEY"],
|
||||||
"novita"
|
"novita",
|
||||||
|
aliases: []
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
Fireworks,
|
Fireworks,
|
||||||
Fireworks,
|
Fireworks,
|
||||||
"Fireworks",
|
"fireworks",
|
||||||
|
"Fireworks AI",
|
||||||
DEFAULT_FIREWORKS_BASE_URL,
|
DEFAULT_FIREWORKS_BASE_URL,
|
||||||
DEFAULT_FIREWORKS_MODEL,
|
DEFAULT_FIREWORKS_MODEL,
|
||||||
["FIREWORKS_API_KEY"],
|
["FIREWORKS_API_KEY"],
|
||||||
"fireworks"
|
"fireworks",
|
||||||
|
aliases: ["fireworks-ai"]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
Siliconflow,
|
Siliconflow,
|
||||||
Siliconflow,
|
Siliconflow,
|
||||||
|
"siliconflow",
|
||||||
"SiliconFlow",
|
"SiliconFlow",
|
||||||
DEFAULT_SILICONFLOW_BASE_URL,
|
DEFAULT_SILICONFLOW_BASE_URL,
|
||||||
DEFAULT_SILICONFLOW_MODEL,
|
DEFAULT_SILICONFLOW_MODEL,
|
||||||
["SILICONFLOW_API_KEY"],
|
["SILICONFLOW_API_KEY"],
|
||||||
"siliconflow"
|
"siliconflow",
|
||||||
|
aliases: ["silicon-flow", "silicon_flow"]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
SiliconflowCN,
|
SiliconflowCN,
|
||||||
SiliconflowCN,
|
SiliconflowCN,
|
||||||
"SiliconFlow CN",
|
"siliconflow-CN",
|
||||||
|
"SiliconFlow (China)",
|
||||||
DEFAULT_SILICONFLOW_CN_BASE_URL,
|
DEFAULT_SILICONFLOW_CN_BASE_URL,
|
||||||
DEFAULT_SILICONFLOW_MODEL,
|
DEFAULT_SILICONFLOW_MODEL,
|
||||||
["SILICONFLOW_API_KEY"],
|
["SILICONFLOW_API_KEY"],
|
||||||
"siliconflow_cn"
|
"siliconflow_cn",
|
||||||
|
aliases: [
|
||||||
|
"silicon-flow-cn",
|
||||||
|
"silicon-flow-CN",
|
||||||
|
"silicon_flow_cn",
|
||||||
|
"silicon_flow_CN",
|
||||||
|
"siliconflow-china",
|
||||||
|
]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
Arcee,
|
Arcee,
|
||||||
Arcee,
|
Arcee,
|
||||||
"Arcee",
|
"arcee",
|
||||||
|
"Arcee AI",
|
||||||
DEFAULT_ARCEE_BASE_URL,
|
DEFAULT_ARCEE_BASE_URL,
|
||||||
DEFAULT_ARCEE_MODEL,
|
DEFAULT_ARCEE_MODEL,
|
||||||
["ARCEE_API_KEY"],
|
["ARCEE_API_KEY"],
|
||||||
"arcee"
|
"arcee",
|
||||||
|
aliases: ["arcee-ai", "arcee_ai"]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
Moonshot,
|
Moonshot,
|
||||||
Moonshot,
|
Moonshot,
|
||||||
"Moonshot",
|
"moonshot",
|
||||||
|
"Moonshot/Kimi",
|
||||||
DEFAULT_MOONSHOT_BASE_URL,
|
DEFAULT_MOONSHOT_BASE_URL,
|
||||||
DEFAULT_MOONSHOT_MODEL,
|
DEFAULT_MOONSHOT_MODEL,
|
||||||
["MOONSHOT_API_KEY", "KIMI_API_KEY"],
|
["MOONSHOT_API_KEY", "KIMI_API_KEY"],
|
||||||
"moonshot"
|
"moonshot",
|
||||||
|
aliases: ["moonshot-ai", "kimi", "kimi-k2"]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
Sglang,
|
Sglang,
|
||||||
Sglang,
|
Sglang,
|
||||||
|
"sglang",
|
||||||
"SGLang",
|
"SGLang",
|
||||||
DEFAULT_SGLANG_BASE_URL,
|
DEFAULT_SGLANG_BASE_URL,
|
||||||
DEFAULT_SGLANG_MODEL,
|
DEFAULT_SGLANG_MODEL,
|
||||||
["SGLANG_API_KEY"],
|
["SGLANG_API_KEY"],
|
||||||
"sglang"
|
"sglang",
|
||||||
|
aliases: ["sg-lang"]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
Vllm,
|
Vllm,
|
||||||
Vllm,
|
Vllm,
|
||||||
|
"vllm",
|
||||||
"vLLM",
|
"vLLM",
|
||||||
DEFAULT_VLLM_BASE_URL,
|
DEFAULT_VLLM_BASE_URL,
|
||||||
DEFAULT_VLLM_MODEL,
|
DEFAULT_VLLM_MODEL,
|
||||||
["VLLM_API_KEY"],
|
["VLLM_API_KEY"],
|
||||||
"vllm"
|
"vllm",
|
||||||
|
aliases: ["v-llm"]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
Ollama,
|
Ollama,
|
||||||
Ollama,
|
Ollama,
|
||||||
|
"ollama",
|
||||||
"Ollama",
|
"Ollama",
|
||||||
DEFAULT_OLLAMA_BASE_URL,
|
DEFAULT_OLLAMA_BASE_URL,
|
||||||
DEFAULT_OLLAMA_MODEL,
|
DEFAULT_OLLAMA_MODEL,
|
||||||
["OLLAMA_API_KEY"],
|
["OLLAMA_API_KEY"],
|
||||||
"ollama"
|
"ollama",
|
||||||
|
aliases: ["ollama-local"]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
Huggingface,
|
Huggingface,
|
||||||
Huggingface,
|
Huggingface,
|
||||||
|
"huggingface",
|
||||||
"Hugging Face",
|
"Hugging Face",
|
||||||
DEFAULT_HUGGINGFACE_BASE_URL,
|
DEFAULT_HUGGINGFACE_BASE_URL,
|
||||||
DEFAULT_HUGGINGFACE_MODEL,
|
DEFAULT_HUGGINGFACE_MODEL,
|
||||||
["HUGGINGFACE_API_KEY", "HF_TOKEN"],
|
["HUGGINGFACE_API_KEY", "HF_TOKEN"],
|
||||||
"huggingface"
|
"huggingface",
|
||||||
|
aliases: ["hugging-face", "hugging_face", "hf"]
|
||||||
);
|
);
|
||||||
provider!(
|
provider!(
|
||||||
Together,
|
Together,
|
||||||
Together,
|
Together,
|
||||||
|
"together",
|
||||||
"Together AI",
|
"Together AI",
|
||||||
DEFAULT_TOGETHER_BASE_URL,
|
DEFAULT_TOGETHER_BASE_URL,
|
||||||
DEFAULT_TOGETHER_MODEL,
|
DEFAULT_TOGETHER_MODEL,
|
||||||
["TOGETHER_API_KEY"],
|
["TOGETHER_API_KEY"],
|
||||||
"together"
|
"together",
|
||||||
|
aliases: ["together-ai", "together_ai"]
|
||||||
);
|
);
|
||||||
|
|
||||||
/// OpenAI Codex / ChatGPT OAuth provider using the Responses API.
|
/// OpenAI Codex / ChatGPT OAuth provider using the Responses API.
|
||||||
pub struct OpenaiCodex;
|
pub struct OpenaiCodex;
|
||||||
|
|
||||||
impl Provider for OpenaiCodex {
|
impl Provider for OpenaiCodex {
|
||||||
|
fn id(&self) -> &'static str {
|
||||||
|
"openai-codex"
|
||||||
|
}
|
||||||
|
|
||||||
fn kind(&self) -> ProviderKind {
|
fn kind(&self) -> ProviderKind {
|
||||||
ProviderKind::OpenaiCodex
|
ProviderKind::OpenaiCodex
|
||||||
}
|
}
|
||||||
@@ -317,6 +380,18 @@ impl Provider for OpenaiCodex {
|
|||||||
"openai_codex"
|
"openai_codex"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn aliases(&self) -> &'static [&'static str] {
|
||||||
|
&[
|
||||||
|
"openai_codex",
|
||||||
|
"openaicodex",
|
||||||
|
"codex",
|
||||||
|
"chatgpt",
|
||||||
|
"chatgpt-codex",
|
||||||
|
"chatgpt_codex",
|
||||||
|
"chatgptcodex",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
fn wire(&self) -> WireFormat {
|
fn wire(&self) -> WireFormat {
|
||||||
WireFormat::Responses
|
WireFormat::Responses
|
||||||
}
|
}
|
||||||
@@ -326,6 +401,10 @@ impl Provider for OpenaiCodex {
|
|||||||
pub struct Anthropic;
|
pub struct Anthropic;
|
||||||
|
|
||||||
impl Provider for Anthropic {
|
impl Provider for Anthropic {
|
||||||
|
fn id(&self) -> &'static str {
|
||||||
|
"anthropic"
|
||||||
|
}
|
||||||
|
|
||||||
fn kind(&self) -> ProviderKind {
|
fn kind(&self) -> ProviderKind {
|
||||||
ProviderKind::Anthropic
|
ProviderKind::Anthropic
|
||||||
}
|
}
|
||||||
@@ -389,8 +468,8 @@ static PROVIDER_REGISTRY: [&dyn Provider; 21] = [
|
|||||||
&NOVITA,
|
&NOVITA,
|
||||||
&FIREWORKS,
|
&FIREWORKS,
|
||||||
&SILICONFLOW,
|
&SILICONFLOW,
|
||||||
&SILICONFLOW_CN,
|
|
||||||
&ARCEE,
|
&ARCEE,
|
||||||
|
&SILICONFLOW_CN,
|
||||||
&MOONSHOT,
|
&MOONSHOT,
|
||||||
&SGLANG,
|
&SGLANG,
|
||||||
&VLLM,
|
&VLLM,
|
||||||
@@ -426,27 +505,9 @@ pub fn resolve_provider(id_or_alias: &str) -> Option<&'static dyn Provider> {
|
|||||||
/// Return metadata for a known provider kind.
|
/// Return metadata for a known provider kind.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn provider_for_kind(kind: ProviderKind) -> &'static dyn Provider {
|
pub fn provider_for_kind(kind: ProviderKind) -> &'static dyn Provider {
|
||||||
match kind {
|
PROVIDER_REGISTRY
|
||||||
ProviderKind::Deepseek => &DEEPSEEK,
|
.iter()
|
||||||
ProviderKind::NvidiaNim => &NVIDIA_NIM,
|
.find(|p| p.kind() == kind)
|
||||||
ProviderKind::Openai => &OPENAI,
|
.copied()
|
||||||
ProviderKind::Atlascloud => &ATLASCLOUD,
|
.expect("ProviderKind variant missing from PROVIDER_REGISTRY")
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+82
-103
@@ -220,126 +220,105 @@ impl ApiProvider {
|
|||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn parse(value: &str) -> Option<Self> {
|
pub fn parse(value: &str) -> Option<Self> {
|
||||||
match value.trim().to_ascii_lowercase().as_str() {
|
let trimmed = value.trim();
|
||||||
"deepseek" | "deep-seek" => Some(Self::Deepseek),
|
// ApiProvider-specific: "deepseek-cn" is a legacy variant here,
|
||||||
"deepseek-cn" | "deepseek_china" | "deepseekcn" | "deepseek-china" => {
|
// while ProviderKind treats it as a Deepseek alias.
|
||||||
Some(Self::DeepseekCN)
|
if trimmed.eq_ignore_ascii_case("deepseek-cn")
|
||||||
}
|
|| trimmed.eq_ignore_ascii_case("deepseek_china")
|
||||||
"nvidia" | "nvidia-nim" | "nvidia_nim" | "nim" => Some(Self::NvidiaNim),
|
|| trimmed.eq_ignore_ascii_case("deepseekcn")
|
||||||
"openai" | "open-ai" => Some(Self::Openai),
|
|| trimmed.eq_ignore_ascii_case("deepseek-china")
|
||||||
"atlascloud" | "atlas-cloud" | "atlas_cloud" | "atlas" => Some(Self::Atlascloud),
|
{
|
||||||
"wanjie" | "wanjie-ark" | "wanjie_ark" | "ark-wanjie" | "ark_wanjie" | "wanjieark"
|
return Some(Self::DeepseekCN);
|
||||||
| "wanjie-maas" | "wanjie_maas" | "wanjiemaas" => Some(Self::WanjieArk),
|
|
||||||
"volcengine" | "volcengine-ark" | "volcengine_ark" | "ark" | "volc-ark"
|
|
||||||
| "volcengineark" => Some(Self::Volcengine),
|
|
||||||
"openrouter" | "open_router" => Some(Self::Openrouter),
|
|
||||||
"xiaomi-mimo" | "xiaomi_mimo" | "xiaomimimo" | "mimo" | "xiaomi" => {
|
|
||||||
Some(Self::XiaomiMimo)
|
|
||||||
}
|
|
||||||
"novita" => Some(Self::Novita),
|
|
||||||
"fireworks" | "fireworks-ai" => Some(Self::Fireworks),
|
|
||||||
"siliconflow" | "silicon-flow" | "silicon_flow" => Some(Self::Siliconflow),
|
|
||||||
"siliconflow-cn" | "siliconflow-CN" | "silicon-flow-cn" | "silicon-flow-CN"
|
|
||||||
| "silicon_flow_cn" | "silicon_flow_CN" | "siliconflow-china" => {
|
|
||||||
Some(Self::SiliconflowCn)
|
|
||||||
}
|
|
||||||
"arcee" | "arcee-ai" | "arcee_ai" => Some(Self::Arcee),
|
|
||||||
"moonshot" | "moonshot-ai" | "kimi" | "kimi-k2" => Some(Self::Moonshot),
|
|
||||||
"sglang" | "sg-lang" => Some(Self::Sglang),
|
|
||||||
"vllm" | "v-llm" => Some(Self::Vllm),
|
|
||||||
"ollama" | "ollama-local" => Some(Self::Ollama),
|
|
||||||
"huggingface" | "hugging-face" | "hugging_face" | "hf" => Some(Self::Huggingface),
|
|
||||||
"together" | "together-ai" | "together_ai" => Some(Self::Together),
|
|
||||||
"anthropic" | "claude" => Some(Self::Anthropic),
|
|
||||||
"openai-codex" | "openai_codex" | "openaicodex" | "codex" | "chatgpt"
|
|
||||||
| "chatgpt-codex" | "chatgpt_codex" | "chatgptcodex" => Some(Self::OpenaiCodex),
|
|
||||||
_ => None,
|
|
||||||
}
|
}
|
||||||
|
codewhale_config::ProviderKind::parse(value).map(Self::from_kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn as_str(self) -> &'static str {
|
pub fn as_str(self) -> &'static str {
|
||||||
match self {
|
match self.kind() {
|
||||||
Self::Deepseek => "deepseek",
|
Some(kind) => kind.as_str(),
|
||||||
Self::DeepseekCN => "deepseek-cn",
|
None => "deepseek-cn",
|
||||||
Self::NvidiaNim => "nvidia-nim",
|
|
||||||
Self::Openai => "openai",
|
|
||||||
Self::Atlascloud => "atlascloud",
|
|
||||||
Self::WanjieArk => "wanjie-ark",
|
|
||||||
Self::Volcengine => "volcengine",
|
|
||||||
Self::Openrouter => "openrouter",
|
|
||||||
Self::XiaomiMimo => "xiaomi-mimo",
|
|
||||||
Self::Novita => "novita",
|
|
||||||
Self::Fireworks => "fireworks",
|
|
||||||
Self::Siliconflow => "siliconflow",
|
|
||||||
Self::SiliconflowCn => "siliconflow-CN",
|
|
||||||
Self::Arcee => "arcee",
|
|
||||||
Self::Moonshot => "moonshot",
|
|
||||||
Self::Sglang => "sglang",
|
|
||||||
Self::Vllm => "vllm",
|
|
||||||
Self::Ollama => "ollama",
|
|
||||||
Self::Huggingface => "huggingface",
|
|
||||||
Self::Together => "together",
|
|
||||||
Self::OpenaiCodex => "openai-codex",
|
|
||||||
Self::Anthropic => "anthropic",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Human-friendly label for picker UIs / status chips.
|
/// Human-friendly label for picker UIs / status chips.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn display_name(self) -> &'static str {
|
pub fn display_name(self) -> &'static str {
|
||||||
match self {
|
match self.kind() {
|
||||||
Self::Deepseek => "DeepSeek",
|
Some(kind) => kind.provider().display_name(),
|
||||||
Self::DeepseekCN => "DeepSeek (legacy alias)",
|
None => "DeepSeek (legacy alias)",
|
||||||
Self::NvidiaNim => "NVIDIA NIM",
|
|
||||||
Self::Openai => "OpenAI-compatible",
|
|
||||||
Self::Atlascloud => "AtlasCloud",
|
|
||||||
Self::WanjieArk => "Wanjie Ark",
|
|
||||||
Self::Volcengine => "Volcengine Ark",
|
|
||||||
Self::Openrouter => "OpenRouter",
|
|
||||||
Self::XiaomiMimo => "Xiaomi MiMo",
|
|
||||||
Self::Novita => "Novita AI",
|
|
||||||
Self::Fireworks => "Fireworks AI",
|
|
||||||
Self::Siliconflow => "SiliconFlow",
|
|
||||||
Self::SiliconflowCn => "SiliconFlow (China)",
|
|
||||||
Self::Arcee => "Arcee AI",
|
|
||||||
Self::Moonshot => "Moonshot/Kimi",
|
|
||||||
Self::Sglang => "SGLang",
|
|
||||||
Self::Vllm => "vLLM",
|
|
||||||
Self::Ollama => "Ollama",
|
|
||||||
Self::Huggingface => "Hugging Face",
|
|
||||||
Self::Together => "Together AI",
|
|
||||||
Self::OpenaiCodex => "OpenAI Codex (ChatGPT)",
|
|
||||||
Self::Anthropic => "Anthropic",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All providers, in the order shown in the picker.
|
/// All providers, in the order shown in the picker.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn all() -> &'static [Self] {
|
pub fn all() -> &'static [Self] {
|
||||||
&[
|
&Self::FROM_KIND_LOOKUP
|
||||||
Self::Deepseek,
|
}
|
||||||
Self::NvidiaNim,
|
|
||||||
Self::Openai,
|
/// `ApiProvider` discriminant → `ProviderKind` lookup.
|
||||||
Self::Atlascloud,
|
/// Index 1 is `None` for the legacy `DeepseekCN` variant.
|
||||||
Self::WanjieArk,
|
const KIND_LOOKUP: [Option<codewhale_config::ProviderKind>; 22] = [
|
||||||
Self::Volcengine,
|
Some(codewhale_config::ProviderKind::Deepseek),
|
||||||
Self::Openrouter,
|
None, // DeepseekCN
|
||||||
Self::XiaomiMimo,
|
Some(codewhale_config::ProviderKind::NvidiaNim),
|
||||||
Self::Novita,
|
Some(codewhale_config::ProviderKind::Openai),
|
||||||
Self::Fireworks,
|
Some(codewhale_config::ProviderKind::Atlascloud),
|
||||||
Self::Siliconflow,
|
Some(codewhale_config::ProviderKind::WanjieArk),
|
||||||
Self::SiliconflowCn,
|
Some(codewhale_config::ProviderKind::Volcengine),
|
||||||
Self::Arcee,
|
Some(codewhale_config::ProviderKind::Openrouter),
|
||||||
Self::Moonshot,
|
Some(codewhale_config::ProviderKind::XiaomiMimo),
|
||||||
Self::Sglang,
|
Some(codewhale_config::ProviderKind::Novita),
|
||||||
Self::Vllm,
|
Some(codewhale_config::ProviderKind::Fireworks),
|
||||||
Self::Ollama,
|
Some(codewhale_config::ProviderKind::Siliconflow),
|
||||||
Self::Huggingface,
|
Some(codewhale_config::ProviderKind::SiliconflowCN),
|
||||||
Self::Together,
|
Some(codewhale_config::ProviderKind::Arcee),
|
||||||
Self::OpenaiCodex,
|
Some(codewhale_config::ProviderKind::Moonshot),
|
||||||
Self::Anthropic,
|
Some(codewhale_config::ProviderKind::Sglang),
|
||||||
]
|
Some(codewhale_config::ProviderKind::Vllm),
|
||||||
|
Some(codewhale_config::ProviderKind::Ollama),
|
||||||
|
Some(codewhale_config::ProviderKind::Huggingface),
|
||||||
|
Some(codewhale_config::ProviderKind::Together),
|
||||||
|
Some(codewhale_config::ProviderKind::OpenaiCodex),
|
||||||
|
Some(codewhale_config::ProviderKind::Anthropic),
|
||||||
|
];
|
||||||
|
|
||||||
|
/// `ProviderKind` discriminant → `ApiProvider` lookup.
|
||||||
|
const FROM_KIND_LOOKUP: [Self; 21] = [
|
||||||
|
Self::Deepseek,
|
||||||
|
Self::NvidiaNim,
|
||||||
|
Self::Openai,
|
||||||
|
Self::Atlascloud,
|
||||||
|
Self::WanjieArk,
|
||||||
|
Self::Volcengine,
|
||||||
|
Self::Openrouter,
|
||||||
|
Self::XiaomiMimo,
|
||||||
|
Self::Novita,
|
||||||
|
Self::Fireworks,
|
||||||
|
Self::Siliconflow,
|
||||||
|
Self::Arcee,
|
||||||
|
Self::SiliconflowCn,
|
||||||
|
Self::Moonshot,
|
||||||
|
Self::Sglang,
|
||||||
|
Self::Vllm,
|
||||||
|
Self::Ollama,
|
||||||
|
Self::Huggingface,
|
||||||
|
Self::Together,
|
||||||
|
Self::OpenaiCodex,
|
||||||
|
Self::Anthropic,
|
||||||
|
];
|
||||||
|
|
||||||
|
/// Map to the config-level `ProviderKind`.
|
||||||
|
/// Returns `None` for the legacy `DeepseekCN` variant.
|
||||||
|
#[must_use]
|
||||||
|
pub fn kind(self) -> Option<codewhale_config::ProviderKind> {
|
||||||
|
Self::KIND_LOOKUP[self as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct from a config-level `ProviderKind`.
|
||||||
|
#[must_use]
|
||||||
|
pub fn from_kind(kind: codewhale_config::ProviderKind) -> Self {
|
||||||
|
Self::FROM_KIND_LOOKUP[kind as usize]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -505,8 +505,8 @@ mod tests {
|
|||||||
"Novita AI",
|
"Novita AI",
|
||||||
"Fireworks AI",
|
"Fireworks AI",
|
||||||
"SiliconFlow",
|
"SiliconFlow",
|
||||||
"SiliconFlow (China)",
|
|
||||||
"Arcee AI",
|
"Arcee AI",
|
||||||
|
"SiliconFlow (China)",
|
||||||
"Moonshot/Kimi",
|
"Moonshot/Kimi",
|
||||||
"SGLang",
|
"SGLang",
|
||||||
"vLLM",
|
"vLLM",
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ from pathlib import Path
|
|||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[1]
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
CONFIG_RS = ROOT / "crates" / "config" / "src" / "lib.rs"
|
CONFIG_RS = ROOT / "crates" / "config" / "src" / "lib.rs"
|
||||||
|
PROVIDER_RS = ROOT / "crates" / "config" / "src" / "provider.rs"
|
||||||
TUI_CONFIG_RS = ROOT / "crates" / "tui" / "src" / "config.rs"
|
TUI_CONFIG_RS = ROOT / "crates" / "tui" / "src" / "config.rs"
|
||||||
AGENT_RS = ROOT / "crates" / "agent" / "src" / "lib.rs"
|
AGENT_RS = ROOT / "crates" / "agent" / "src" / "lib.rs"
|
||||||
PROVIDERS_MD = ROOT / "docs" / "PROVIDERS.md"
|
PROVIDERS_MD = ROOT / "docs" / "PROVIDERS.md"
|
||||||
@@ -69,35 +70,37 @@ def extract_match_block(
|
|||||||
|
|
||||||
|
|
||||||
def provider_kind_ids(config_rs: str) -> dict[str, str]:
|
def provider_kind_ids(config_rs: str) -> dict[str, str]:
|
||||||
impl_start = require_index(
|
provider_rs = read(PROVIDER_RS)
|
||||||
config_rs, "impl ProviderKind", "crates/config/src/lib.rs"
|
pairs = re.findall(
|
||||||
|
r"provider!\(\s*\n\s*\w+,\s*\n\s*(\w+),\s*\n\s*\"([^\"]+)\"",
|
||||||
|
provider_rs,
|
||||||
)
|
)
|
||||||
block = extract_match_block(
|
ids: dict[str, str] = {variant: provider_id for variant, provider_id in pairs}
|
||||||
config_rs,
|
# OpenaiCodex and Anthropic use manual impls rather than the provider!() macro
|
||||||
"pub fn as_str(self) -> &'static str",
|
for variant_name, id_literal in [
|
||||||
"crates/config/src/lib.rs",
|
("OpenaiCodex", "openai-codex"),
|
||||||
impl_start,
|
("Anthropic", "anthropic"),
|
||||||
)
|
]:
|
||||||
pairs = re.findall(r"Self::(\w+)\s*=>\s*\"([^\"]+)\"", block)
|
match = re.search(
|
||||||
if not pairs:
|
rf'impl\s+Provider\s+for\s+{variant_name}.*?fn\s+id.*?\"({id_literal})\"',
|
||||||
raise ValueError("ProviderKind::as_str returned no providers")
|
provider_rs, re.DOTALL,
|
||||||
return {variant: provider_id for variant, provider_id in pairs}
|
)
|
||||||
|
if match:
|
||||||
|
ids[variant_name] = match.group(1)
|
||||||
|
if not ids:
|
||||||
|
raise ValueError("provider!() invocations returned no providers")
|
||||||
|
return ids
|
||||||
|
|
||||||
|
|
||||||
def api_provider_ids(tui_config_rs: str) -> dict[str, str]:
|
def api_provider_ids(tui_config_rs: str) -> dict[str, str]:
|
||||||
impl_start = require_index(
|
# ApiProvider ids derive from ProviderKind ids (via delegation to .kind().as_str())
|
||||||
tui_config_rs, "impl ApiProvider", "crates/tui/src/config.rs"
|
# plus the legacy "deepseek-cn" variant that exists only in ApiProvider.
|
||||||
)
|
variant_to_id = provider_kind_ids("")
|
||||||
block = extract_match_block(
|
# ApiProvider::SiliconflowCn maps to ProviderKind::SiliconflowCN
|
||||||
tui_config_rs,
|
if "SiliconflowCN" in variant_to_id:
|
||||||
"pub fn as_str(self) -> &'static str",
|
variant_to_id["SiliconflowCn"] = variant_to_id["SiliconflowCN"]
|
||||||
"crates/tui/src/config.rs",
|
variant_to_id["DeepseekCN"] = "deepseek-cn"
|
||||||
impl_start,
|
return variant_to_id
|
||||||
)
|
|
||||||
pairs = re.findall(r"Self::(\w+)\s*=>\s*\"([^\"]+)\"", block)
|
|
||||||
if not pairs:
|
|
||||||
raise ValueError("ApiProvider::as_str returned no providers")
|
|
||||||
return {variant: provider_id for variant, provider_id in pairs}
|
|
||||||
|
|
||||||
|
|
||||||
def provider_tables(config_rs: str) -> set[str]:
|
def provider_tables(config_rs: str) -> set[str]:
|
||||||
@@ -253,4 +256,4 @@ def main() -> int:
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
raise SystemExit(main())
|
raise SystemExit(main())
|
||||||
Reference in New Issue
Block a user