feat: generate rust providers from registry

This commit is contained in:
Ishaan Jaff 2026-06-24 16:32:21 -07:00
parent 5d5dd89829
commit 9ba5a1522b
No known key found for this signature in database
6 changed files with 1240 additions and 659 deletions

View file

@ -1,6 +1,7 @@
# Adding a provider / route to litellm-rust
- Keep the route contract pure in `crates/core/src/<route>/`: define the typed request/response structs and a provider config trait with no network, env, auth, or logging.
- Add provider identity to `providers/providers.json`: `routing_name` must match Python `LlmProviders.value`; `display_name` is human-facing; `default_api_base` and `api_key_env_var` are optional provider defaults.
- Put provider-specific transforms in `crates/providers/src/<provider>/<route>/transformation.rs`, mirroring the Python provider tree and exposing a `const <PROVIDER>_<ROUTE>_CONFIG`.
- The provider config owns three pure steps: map LiteLLM params, transform the LiteLLM request into the provider request, and transform the provider response back into the LiteLLM response.
- If the provider has a reverse or normalization step, keep it pure and explicit next to the transforms; do not hide reverse mapping inside the HTTP transport.

View file

@ -9,3 +9,7 @@ repository.workspace = true
serde.workspace = true
serde_json.workspace = true
thiserror.workspace = true
[build-dependencies]
serde.workspace = true
serde_json.workspace = true

View file

@ -0,0 +1,335 @@
use std::collections::HashSet;
use std::env;
use std::fs;
use std::path::PathBuf;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct ProviderMetadataInput {
routing_name: String,
display_name: String,
default_api_base: Option<String>,
api_key_env_var: Option<String>,
}
fn rust_string(value: &str) -> String {
format!("{value:?}")
}
fn rust_option(value: Option<&str>) -> String {
value
.map(|value| format!("Some({})", rust_string(value)))
.unwrap_or_else(|| "None".to_string())
}
fn variant_name(routing_name: &str) -> String {
routing_name
.split(['_', '-', '.'])
.filter(|part| !part.is_empty())
.map(|part| {
let mut chars = part.chars();
match chars.next() {
Some(first) => {
let mut out = String::new();
out.extend(first.to_uppercase());
out.push_str(chars.as_str());
out
}
None => String::new(),
}
})
.collect()
}
fn validate_providers(providers: &[ProviderMetadataInput]) {
let mut routing_names = HashSet::new();
let mut variants = HashSet::new();
for provider in providers {
if provider.routing_name.trim().is_empty() {
panic!("provider routing_name cannot be empty");
}
if provider.display_name.trim().is_empty() {
panic!(
"provider {} has an empty display_name",
provider.routing_name
);
}
if !routing_names.insert(provider.routing_name.as_str()) {
panic!("duplicate provider routing_name: {}", provider.routing_name);
}
let variant = variant_name(&provider.routing_name);
if variant.is_empty() {
panic!(
"provider {} generated an empty Rust variant",
provider.routing_name
);
}
if !variants.insert(variant.clone()) {
panic!(
"provider {} generated duplicate Rust variant {variant}",
provider.routing_name
);
}
}
}
fn generate_provider_code(providers: &[ProviderMetadataInput]) -> String {
let variants: Vec<String> = providers
.iter()
.map(|provider| variant_name(&provider.routing_name))
.collect();
let enum_variants = variants
.iter()
.map(|variant| format!(" {variant},"))
.collect::<Vec<_>>()
.join("\n");
let all_values = variants
.iter()
.map(|variant| format!(" LlmProvider::{variant},"))
.collect::<Vec<_>>()
.join("\n");
let metadata_values = providers
.iter()
.zip(variants.iter())
.map(|(provider, variant)| {
format!(
" ProviderMetadata {{ provider: LlmProvider::{variant}, routing_name: {}, display_name: {}, default_api_base: {}, api_key_env_var: {} }},",
rust_string(&provider.routing_name),
rust_string(&provider.display_name),
rust_option(provider.default_api_base.as_deref()),
rust_option(provider.api_key_env_var.as_deref()),
)
})
.collect::<Vec<_>>()
.join("\n");
let metadata_match_arms = variants
.iter()
.enumerate()
.map(|(index, variant)| {
format!(" LlmProvider::{variant} => &Self::METADATA[{index}],")
})
.collect::<Vec<_>>()
.join("\n");
format!(
r#"// @generated by crates/core/build.rs from litellm-rust/providers/providers.json.
// Do not edit this file by hand.
use std::fmt;
use std::str::FromStr;
use crate::error::CoreError;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ProviderMetadata {{
pub provider: LlmProvider,
pub routing_name: &'static str,
pub display_name: &'static str,
pub default_api_base: Option<&'static str>,
pub api_key_env_var: Option<&'static str>,
}}
#[allow(clippy::enum_variant_names)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LlmProvider {{
{enum_variants}
}}
impl LlmProvider {{
pub const ALL: [LlmProvider; {provider_count}] = [
{all_values}
];
pub const METADATA: [ProviderMetadata; {provider_count}] = [
{metadata_values}
];
pub fn metadata(self) -> &'static ProviderMetadata {{
match self {{
{metadata_match_arms}
}}
}}
pub fn as_str(self) -> &'static str {{
self.metadata().routing_name
}}
pub fn display_name(self) -> &'static str {{
self.metadata().display_name
}}
pub fn default_api_base(self) -> Option<&'static str> {{
self.metadata().default_api_base
}}
pub fn api_key_env_var(self) -> Option<&'static str> {{
self.metadata().api_key_env_var
}}
}}
impl fmt::Display for LlmProvider {{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {{
f.write_str(self.as_str())
}}
}}
impl FromStr for LlmProvider {{
type Err = CoreError;
fn from_str(value: &str) -> Result<Self, Self::Err> {{
LlmProvider::ALL
.iter()
.copied()
.find(|provider| provider.as_str() == value)
.ok_or_else(|| CoreError::InvalidProvider(value.to_string()))
}}
}}
#[cfg(test)]
mod tests {{
use super::*;
#[derive(serde::Deserialize)]
struct RegistryProvider {{
routing_name: String,
}}
fn registry_provider_values() -> Vec<String> {{
let raw = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../providers/providers.json"
));
serde_json::from_str::<Vec<RegistryProvider>>(raw)
.expect("providers.json parses")
.into_iter()
.map(|provider| provider.routing_name)
.collect()
}}
fn python_provider_values() -> Vec<String> {{
let source = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../../litellm/types/utils.py"
));
let mut values = Vec::new();
let mut in_llm_providers = false;
for line in source.lines() {{
if line.starts_with("class LlmProviders(") {{
in_llm_providers = true;
continue;
}}
if in_llm_providers && line.starts_with("class ") {{
break;
}}
if !in_llm_providers {{
continue;
}}
let trimmed = line.trim();
let Some((name, value_expr)) = trimmed.split_once('=') else {{
continue;
}};
if !name
.trim()
.chars()
.all(|ch| ch.is_ascii_uppercase() || ch.is_ascii_digit() || ch == '_')
{{
continue;
}}
let Some(value) = value_expr.split('"').nth(1) else {{
continue;
}};
values.push(value.to_string());
}}
assert!(!values.is_empty(), "parsed Python LlmProviders values");
values
}}
#[test]
fn provider_values_match_registry_order() {{
let registry_values = registry_provider_values();
assert_eq!(LlmProvider::ALL.len(), registry_values.len());
assert_eq!(
LlmProvider::ALL
.iter()
.map(|provider| provider.as_str().to_string())
.collect::<Vec<_>>(),
registry_values
);
}}
#[test]
fn provider_registry_matches_python_llm_providers() {{
assert_eq!(registry_provider_values(), python_provider_values());
}}
#[test]
fn from_str_round_trips_all_providers() {{
for provider in LlmProvider::ALL {{
assert_eq!(LlmProvider::from_str(provider.as_str()), Ok(provider));
assert_eq!(provider.to_string(), provider.as_str());
}}
}}
#[test]
fn from_str_rejects_unknown_provider() {{
assert_eq!(
LlmProvider::from_str("not-a-provider"),
Err(CoreError::InvalidProvider("not-a-provider".to_string()))
);
}}
#[test]
fn provider_metadata_exposes_optional_defaults() {{
assert_eq!(LlmProvider::Mistral.display_name(), "Mistral");
assert_eq!(
LlmProvider::Mistral.default_api_base(),
Some("https://api.mistral.ai/v1")
);
assert_eq!(LlmProvider::Mistral.api_key_env_var(), Some("MISTRAL_API_KEY"));
}}
}}
"#,
enum_variants = enum_variants,
provider_count = providers.len(),
all_values = all_values,
metadata_values = metadata_values,
metadata_match_arms = metadata_match_arms,
)
}
fn main() {
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let providers_path = manifest_dir.join("../../providers/providers.json");
println!("cargo:rerun-if-changed={}", providers_path.display());
println!(
"cargo:rerun-if-changed={}",
manifest_dir.join("build.rs").display()
);
let raw = fs::read_to_string(&providers_path).unwrap_or_else(|err| {
panic!(
"failed to read provider registry {}: {err}",
providers_path.display()
)
});
let providers: Vec<ProviderMetadataInput> = serde_json::from_str(&raw)
.unwrap_or_else(|err| panic!("failed to parse {}: {err}", providers_path.display()));
validate_providers(&providers);
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
fs::write(
out_dir.join("provider_generated.rs"),
generate_provider_code(&providers),
)
.expect("failed to write generated provider code");
}

View file

@ -1,659 +1 @@
use std::fmt;
use std::str::FromStr;
use crate::error::CoreError;
#[allow(clippy::enum_variant_names)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LlmProvider {
Openai,
Chatgpt,
OpenaiLike,
JinaAi,
Xai,
Zai,
CustomOpenai,
TextCompletionOpenai,
Cohere,
CohereChat,
Clarifai,
Anthropic,
AnthropicText,
Bytez,
Replicate,
Reducto,
Runwayml,
AwsPolly,
Huggingface,
TogetherAi,
Openrouter,
Datarobot,
VertexAi,
VertexAiBeta,
Gemini,
Ai21,
Baseten,
BlackForestLabs,
Azure,
AzureText,
AzureAi,
Sagemaker,
SagemakerChat,
SagemakerNova,
Bedrock,
Vllm,
NlpCloud,
Petals,
Oobabooga,
Ollama,
OllamaChat,
Deepinfra,
Perplexity,
Mistral,
Milvus,
Groq,
A2a,
Gigachat,
NvidiaNim,
NvidiaRiva,
Soniox,
Cerebras,
Ai21Chat,
Volcengine,
Codestral,
TextCompletionCodestral,
Dashscope,
Modelscope,
Moonshot,
Publicai,
V0,
Morph,
LambdaAi,
Inception,
TextCompletionInception,
Deepseek,
Sambanova,
Maritalk,
Voyage,
Cloudflare,
Xinference,
FireworksAi,
Friendliai,
FeatherlessAi,
Watsonx,
WatsonxText,
Triton,
Predibase,
Databricks,
Empower,
Github,
Ragflow,
Compactifai,
DockerModelRunner,
Custom,
LitellmProxy,
HostedVllm,
Llamafile,
LmStudio,
Galadriel,
Nebius,
Infinity,
Deepgram,
Elevenlabs,
Novita,
AiohttpOpenai,
Langfuse,
Humanloop,
Topaz,
Sap,
Assemblyai,
CharityEngine,
GithubCopilot,
Snowflake,
GradientAi,
MetaLlama,
Nscale,
PgVector,
S3Vectors,
Helicone,
Hyperbolic,
Recraft,
FalAi,
Stability,
Heroku,
Aiml,
Cometapi,
Oci,
AutoRouter,
VercelAiGateway,
Dotprompt,
Manus,
Wandb,
Ovhcloud,
Scaleway,
Lemonade,
AmazonNova,
A2aAgent,
Langgraph,
Langflow,
Minimax,
Synthetic,
Apertis,
NanoGpt,
Poe,
Chutes,
Neosantara,
Parasail,
XiaomiMimo,
Tensormesh,
Libertai,
Pinstripes,
Darkbloom,
LitellmAgent,
Cursor,
BedrockMantle,
}
impl LlmProvider {
#[allow(clippy::too_many_lines)]
pub fn as_str(self) -> &'static str {
match self {
LlmProvider::Openai => "openai",
LlmProvider::Chatgpt => "chatgpt",
LlmProvider::OpenaiLike => "openai_like",
LlmProvider::JinaAi => "jina_ai",
LlmProvider::Xai => "xai",
LlmProvider::Zai => "zai",
LlmProvider::CustomOpenai => "custom_openai",
LlmProvider::TextCompletionOpenai => "text-completion-openai",
LlmProvider::Cohere => "cohere",
LlmProvider::CohereChat => "cohere_chat",
LlmProvider::Clarifai => "clarifai",
LlmProvider::Anthropic => "anthropic",
LlmProvider::AnthropicText => "anthropic_text",
LlmProvider::Bytez => "bytez",
LlmProvider::Replicate => "replicate",
LlmProvider::Reducto => "reducto",
LlmProvider::Runwayml => "runwayml",
LlmProvider::AwsPolly => "aws_polly",
LlmProvider::Huggingface => "huggingface",
LlmProvider::TogetherAi => "together_ai",
LlmProvider::Openrouter => "openrouter",
LlmProvider::Datarobot => "datarobot",
LlmProvider::VertexAi => "vertex_ai",
LlmProvider::VertexAiBeta => "vertex_ai_beta",
LlmProvider::Gemini => "gemini",
LlmProvider::Ai21 => "ai21",
LlmProvider::Baseten => "baseten",
LlmProvider::BlackForestLabs => "black_forest_labs",
LlmProvider::Azure => "azure",
LlmProvider::AzureText => "azure_text",
LlmProvider::AzureAi => "azure_ai",
LlmProvider::Sagemaker => "sagemaker",
LlmProvider::SagemakerChat => "sagemaker_chat",
LlmProvider::SagemakerNova => "sagemaker_nova",
LlmProvider::Bedrock => "bedrock",
LlmProvider::Vllm => "vllm",
LlmProvider::NlpCloud => "nlp_cloud",
LlmProvider::Petals => "petals",
LlmProvider::Oobabooga => "oobabooga",
LlmProvider::Ollama => "ollama",
LlmProvider::OllamaChat => "ollama_chat",
LlmProvider::Deepinfra => "deepinfra",
LlmProvider::Perplexity => "perplexity",
LlmProvider::Mistral => "mistral",
LlmProvider::Milvus => "milvus",
LlmProvider::Groq => "groq",
LlmProvider::A2a => "a2a",
LlmProvider::Gigachat => "gigachat",
LlmProvider::NvidiaNim => "nvidia_nim",
LlmProvider::NvidiaRiva => "nvidia_riva",
LlmProvider::Soniox => "soniox",
LlmProvider::Cerebras => "cerebras",
LlmProvider::Ai21Chat => "ai21_chat",
LlmProvider::Volcengine => "volcengine",
LlmProvider::Codestral => "codestral",
LlmProvider::TextCompletionCodestral => "text-completion-codestral",
LlmProvider::Dashscope => "dashscope",
LlmProvider::Modelscope => "modelscope",
LlmProvider::Moonshot => "moonshot",
LlmProvider::Publicai => "publicai",
LlmProvider::V0 => "v0",
LlmProvider::Morph => "morph",
LlmProvider::LambdaAi => "lambda_ai",
LlmProvider::Inception => "inception",
LlmProvider::TextCompletionInception => "text-completion-inception",
LlmProvider::Deepseek => "deepseek",
LlmProvider::Sambanova => "sambanova",
LlmProvider::Maritalk => "maritalk",
LlmProvider::Voyage => "voyage",
LlmProvider::Cloudflare => "cloudflare",
LlmProvider::Xinference => "xinference",
LlmProvider::FireworksAi => "fireworks_ai",
LlmProvider::Friendliai => "friendliai",
LlmProvider::FeatherlessAi => "featherless_ai",
LlmProvider::Watsonx => "watsonx",
LlmProvider::WatsonxText => "watsonx_text",
LlmProvider::Triton => "triton",
LlmProvider::Predibase => "predibase",
LlmProvider::Databricks => "databricks",
LlmProvider::Empower => "empower",
LlmProvider::Github => "github",
LlmProvider::Ragflow => "ragflow",
LlmProvider::Compactifai => "compactifai",
LlmProvider::DockerModelRunner => "docker_model_runner",
LlmProvider::Custom => "custom",
LlmProvider::LitellmProxy => "litellm_proxy",
LlmProvider::HostedVllm => "hosted_vllm",
LlmProvider::Llamafile => "llamafile",
LlmProvider::LmStudio => "lm_studio",
LlmProvider::Galadriel => "galadriel",
LlmProvider::Nebius => "nebius",
LlmProvider::Infinity => "infinity",
LlmProvider::Deepgram => "deepgram",
LlmProvider::Elevenlabs => "elevenlabs",
LlmProvider::Novita => "novita",
LlmProvider::AiohttpOpenai => "aiohttp_openai",
LlmProvider::Langfuse => "langfuse",
LlmProvider::Humanloop => "humanloop",
LlmProvider::Topaz => "topaz",
LlmProvider::Sap => "sap",
LlmProvider::Assemblyai => "assemblyai",
LlmProvider::CharityEngine => "charity_engine",
LlmProvider::GithubCopilot => "github_copilot",
LlmProvider::Snowflake => "snowflake",
LlmProvider::GradientAi => "gradient_ai",
LlmProvider::MetaLlama => "meta_llama",
LlmProvider::Nscale => "nscale",
LlmProvider::PgVector => "pg_vector",
LlmProvider::S3Vectors => "s3_vectors",
LlmProvider::Helicone => "helicone",
LlmProvider::Hyperbolic => "hyperbolic",
LlmProvider::Recraft => "recraft",
LlmProvider::FalAi => "fal_ai",
LlmProvider::Stability => "stability",
LlmProvider::Heroku => "heroku",
LlmProvider::Aiml => "aiml",
LlmProvider::Cometapi => "cometapi",
LlmProvider::Oci => "oci",
LlmProvider::AutoRouter => "auto_router",
LlmProvider::VercelAiGateway => "vercel_ai_gateway",
LlmProvider::Dotprompt => "dotprompt",
LlmProvider::Manus => "manus",
LlmProvider::Wandb => "wandb",
LlmProvider::Ovhcloud => "ovhcloud",
LlmProvider::Scaleway => "scaleway",
LlmProvider::Lemonade => "lemonade",
LlmProvider::AmazonNova => "amazon_nova",
LlmProvider::A2aAgent => "a2a_agent",
LlmProvider::Langgraph => "langgraph",
LlmProvider::Langflow => "langflow",
LlmProvider::Minimax => "minimax",
LlmProvider::Synthetic => "synthetic",
LlmProvider::Apertis => "apertis",
LlmProvider::NanoGpt => "nano-gpt",
LlmProvider::Poe => "poe",
LlmProvider::Chutes => "chutes",
LlmProvider::Neosantara => "neosantara",
LlmProvider::Parasail => "parasail",
LlmProvider::XiaomiMimo => "xiaomi_mimo",
LlmProvider::Tensormesh => "tensormesh",
LlmProvider::Libertai => "libertai",
LlmProvider::Pinstripes => "pinstripes",
LlmProvider::Darkbloom => "darkbloom",
LlmProvider::LitellmAgent => "litellm_agent",
LlmProvider::Cursor => "cursor",
LlmProvider::BedrockMantle => "bedrock_mantle",
}
}
#[allow(clippy::too_many_lines)]
pub const ALL: [LlmProvider; 146] = [
LlmProvider::Openai,
LlmProvider::Chatgpt,
LlmProvider::OpenaiLike,
LlmProvider::JinaAi,
LlmProvider::Xai,
LlmProvider::Zai,
LlmProvider::CustomOpenai,
LlmProvider::TextCompletionOpenai,
LlmProvider::Cohere,
LlmProvider::CohereChat,
LlmProvider::Clarifai,
LlmProvider::Anthropic,
LlmProvider::AnthropicText,
LlmProvider::Bytez,
LlmProvider::Replicate,
LlmProvider::Reducto,
LlmProvider::Runwayml,
LlmProvider::AwsPolly,
LlmProvider::Huggingface,
LlmProvider::TogetherAi,
LlmProvider::Openrouter,
LlmProvider::Datarobot,
LlmProvider::VertexAi,
LlmProvider::VertexAiBeta,
LlmProvider::Gemini,
LlmProvider::Ai21,
LlmProvider::Baseten,
LlmProvider::BlackForestLabs,
LlmProvider::Azure,
LlmProvider::AzureText,
LlmProvider::AzureAi,
LlmProvider::Sagemaker,
LlmProvider::SagemakerChat,
LlmProvider::SagemakerNova,
LlmProvider::Bedrock,
LlmProvider::Vllm,
LlmProvider::NlpCloud,
LlmProvider::Petals,
LlmProvider::Oobabooga,
LlmProvider::Ollama,
LlmProvider::OllamaChat,
LlmProvider::Deepinfra,
LlmProvider::Perplexity,
LlmProvider::Mistral,
LlmProvider::Milvus,
LlmProvider::Groq,
LlmProvider::A2a,
LlmProvider::Gigachat,
LlmProvider::NvidiaNim,
LlmProvider::NvidiaRiva,
LlmProvider::Soniox,
LlmProvider::Cerebras,
LlmProvider::Ai21Chat,
LlmProvider::Volcengine,
LlmProvider::Codestral,
LlmProvider::TextCompletionCodestral,
LlmProvider::Dashscope,
LlmProvider::Modelscope,
LlmProvider::Moonshot,
LlmProvider::Publicai,
LlmProvider::V0,
LlmProvider::Morph,
LlmProvider::LambdaAi,
LlmProvider::Inception,
LlmProvider::TextCompletionInception,
LlmProvider::Deepseek,
LlmProvider::Sambanova,
LlmProvider::Maritalk,
LlmProvider::Voyage,
LlmProvider::Cloudflare,
LlmProvider::Xinference,
LlmProvider::FireworksAi,
LlmProvider::Friendliai,
LlmProvider::FeatherlessAi,
LlmProvider::Watsonx,
LlmProvider::WatsonxText,
LlmProvider::Triton,
LlmProvider::Predibase,
LlmProvider::Databricks,
LlmProvider::Empower,
LlmProvider::Github,
LlmProvider::Ragflow,
LlmProvider::Compactifai,
LlmProvider::DockerModelRunner,
LlmProvider::Custom,
LlmProvider::LitellmProxy,
LlmProvider::HostedVllm,
LlmProvider::Llamafile,
LlmProvider::LmStudio,
LlmProvider::Galadriel,
LlmProvider::Nebius,
LlmProvider::Infinity,
LlmProvider::Deepgram,
LlmProvider::Elevenlabs,
LlmProvider::Novita,
LlmProvider::AiohttpOpenai,
LlmProvider::Langfuse,
LlmProvider::Humanloop,
LlmProvider::Topaz,
LlmProvider::Sap,
LlmProvider::Assemblyai,
LlmProvider::CharityEngine,
LlmProvider::GithubCopilot,
LlmProvider::Snowflake,
LlmProvider::GradientAi,
LlmProvider::MetaLlama,
LlmProvider::Nscale,
LlmProvider::PgVector,
LlmProvider::S3Vectors,
LlmProvider::Helicone,
LlmProvider::Hyperbolic,
LlmProvider::Recraft,
LlmProvider::FalAi,
LlmProvider::Stability,
LlmProvider::Heroku,
LlmProvider::Aiml,
LlmProvider::Cometapi,
LlmProvider::Oci,
LlmProvider::AutoRouter,
LlmProvider::VercelAiGateway,
LlmProvider::Dotprompt,
LlmProvider::Manus,
LlmProvider::Wandb,
LlmProvider::Ovhcloud,
LlmProvider::Scaleway,
LlmProvider::Lemonade,
LlmProvider::AmazonNova,
LlmProvider::A2aAgent,
LlmProvider::Langgraph,
LlmProvider::Langflow,
LlmProvider::Minimax,
LlmProvider::Synthetic,
LlmProvider::Apertis,
LlmProvider::NanoGpt,
LlmProvider::Poe,
LlmProvider::Chutes,
LlmProvider::Neosantara,
LlmProvider::Parasail,
LlmProvider::XiaomiMimo,
LlmProvider::Tensormesh,
LlmProvider::Libertai,
LlmProvider::Pinstripes,
LlmProvider::Darkbloom,
LlmProvider::LitellmAgent,
LlmProvider::Cursor,
LlmProvider::BedrockMantle,
];
}
impl fmt::Display for LlmProvider {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl FromStr for LlmProvider {
type Err = CoreError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
LlmProvider::ALL
.iter()
.copied()
.find(|provider| provider.as_str() == value)
.ok_or_else(|| CoreError::InvalidProvider(value.to_string()))
}
}
#[cfg(test)]
mod tests {
use super::*;
const PYTHON_LLM_PROVIDER_VALUES: &[&str] = &[
"openai",
"chatgpt",
"openai_like",
"jina_ai",
"xai",
"zai",
"custom_openai",
"text-completion-openai",
"cohere",
"cohere_chat",
"clarifai",
"anthropic",
"anthropic_text",
"bytez",
"replicate",
"reducto",
"runwayml",
"aws_polly",
"huggingface",
"together_ai",
"openrouter",
"datarobot",
"vertex_ai",
"vertex_ai_beta",
"gemini",
"ai21",
"baseten",
"black_forest_labs",
"azure",
"azure_text",
"azure_ai",
"sagemaker",
"sagemaker_chat",
"sagemaker_nova",
"bedrock",
"vllm",
"nlp_cloud",
"petals",
"oobabooga",
"ollama",
"ollama_chat",
"deepinfra",
"perplexity",
"mistral",
"milvus",
"groq",
"a2a",
"gigachat",
"nvidia_nim",
"nvidia_riva",
"soniox",
"cerebras",
"ai21_chat",
"volcengine",
"codestral",
"text-completion-codestral",
"dashscope",
"modelscope",
"moonshot",
"publicai",
"v0",
"morph",
"lambda_ai",
"inception",
"text-completion-inception",
"deepseek",
"sambanova",
"maritalk",
"voyage",
"cloudflare",
"xinference",
"fireworks_ai",
"friendliai",
"featherless_ai",
"watsonx",
"watsonx_text",
"triton",
"predibase",
"databricks",
"empower",
"github",
"ragflow",
"compactifai",
"docker_model_runner",
"custom",
"litellm_proxy",
"hosted_vllm",
"llamafile",
"lm_studio",
"galadriel",
"nebius",
"infinity",
"deepgram",
"elevenlabs",
"novita",
"aiohttp_openai",
"langfuse",
"humanloop",
"topaz",
"sap",
"assemblyai",
"charity_engine",
"github_copilot",
"snowflake",
"gradient_ai",
"meta_llama",
"nscale",
"pg_vector",
"s3_vectors",
"helicone",
"hyperbolic",
"recraft",
"fal_ai",
"stability",
"heroku",
"aiml",
"cometapi",
"oci",
"auto_router",
"vercel_ai_gateway",
"dotprompt",
"manus",
"wandb",
"ovhcloud",
"scaleway",
"lemonade",
"amazon_nova",
"a2a_agent",
"langgraph",
"langflow",
"minimax",
"synthetic",
"apertis",
"nano-gpt",
"poe",
"chutes",
"neosantara",
"parasail",
"xiaomi_mimo",
"tensormesh",
"libertai",
"pinstripes",
"darkbloom",
"litellm_agent",
"cursor",
"bedrock_mantle",
];
#[test]
fn provider_values_match_python_enum_order() {
assert_eq!(LlmProvider::ALL.len(), 146);
assert_eq!(
LlmProvider::ALL
.iter()
.map(|provider| provider.as_str())
.collect::<Vec<_>>(),
PYTHON_LLM_PROVIDER_VALUES
);
}
#[test]
fn from_str_round_trips_all_providers() {
for provider in LlmProvider::ALL {
assert_eq!(LlmProvider::from_str(provider.as_str()), Ok(provider));
assert_eq!(provider.to_string(), provider.as_str());
}
}
#[test]
fn from_str_rejects_unknown_provider() {
assert_eq!(
LlmProvider::from_str("not-a-provider"),
Err(CoreError::InvalidProvider("not-a-provider".to_string()))
);
}
}
include!(concat!(env!("OUT_DIR"), "/provider_generated.rs"));

View file

@ -0,0 +1,21 @@
# Rust Provider Registry
`providers.json` is the source of truth for provider identity in `litellm-rust`.
`crates/core/build.rs` reads it at compile time and generates the typed
`LlmProvider` enum plus static provider metadata. Runtime code does not parse
this JSON.
To add a provider:
- Add a `providers.json` entry with `routing_name` matching Python
`LlmProviders.value` in `litellm/types/utils.py`.
- Set `display_name` to the human-readable provider name for docs/errors.
- Set `default_api_base` to a stable provider-level default base URL, or `null`
when it is unknown, dynamic, or route-specific.
- Set `api_key_env_var` to the canonical LiteLLM env var, or `null` when there
is no single provider-level key.
- Put request/response logic under
`crates/providers/src/<provider>/<route>/transformation.rs`; do not put
transforms, signing logic, or secrets in this registry.
- Run `cargo test -p litellm-core --locked`; it verifies the Rust registry stays
in parity with Python `LlmProviders`.

View file

@ -0,0 +1,878 @@
[
{
"routing_name": "openai",
"display_name": "OpenAI",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "chatgpt",
"display_name": "ChatGPT",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "openai_like",
"display_name": "OpenAI Like",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "jina_ai",
"display_name": "Jina AI",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "xai",
"display_name": "xAI",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "zai",
"display_name": "Z.ai",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "custom_openai",
"display_name": "Custom OpenAI",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "text-completion-openai",
"display_name": "Text Completion OpenAI",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "cohere",
"display_name": "Cohere",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "cohere_chat",
"display_name": "Cohere Chat",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "clarifai",
"display_name": "Clarifai",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "anthropic",
"display_name": "Anthropic",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "anthropic_text",
"display_name": "Anthropic Text",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "bytez",
"display_name": "Bytez",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "replicate",
"display_name": "Replicate",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "reducto",
"display_name": "Reducto",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "runwayml",
"display_name": "Runwayml",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "aws_polly",
"display_name": "AWS Polly",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "huggingface",
"display_name": "Hugging Face",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "together_ai",
"display_name": "Together AI",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "openrouter",
"display_name": "Openrouter",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "datarobot",
"display_name": "Datarobot",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "vertex_ai",
"display_name": "Vertex AI",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "vertex_ai_beta",
"display_name": "Vertex AI Beta",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "gemini",
"display_name": "Gemini",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "ai21",
"display_name": "AI21",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "baseten",
"display_name": "Baseten",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "black_forest_labs",
"display_name": "Black Forest Labs",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "azure",
"display_name": "Azure",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "azure_text",
"display_name": "Azure Text",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "azure_ai",
"display_name": "Azure AI",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "sagemaker",
"display_name": "Sagemaker",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "sagemaker_chat",
"display_name": "Sagemaker Chat",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "sagemaker_nova",
"display_name": "Sagemaker Nova",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "bedrock",
"display_name": "Bedrock",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "vllm",
"display_name": "vLLM",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "nlp_cloud",
"display_name": "NLP Cloud",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "petals",
"display_name": "Petals",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "oobabooga",
"display_name": "Oobabooga",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "ollama",
"display_name": "Ollama",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "ollama_chat",
"display_name": "Ollama Chat",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "deepinfra",
"display_name": "Deepinfra",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "perplexity",
"display_name": "Perplexity",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "mistral",
"display_name": "Mistral",
"default_api_base": "https://api.mistral.ai/v1",
"api_key_env_var": "MISTRAL_API_KEY"
},
{
"routing_name": "milvus",
"display_name": "Milvus",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "groq",
"display_name": "Groq",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "a2a",
"display_name": "A2A",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "gigachat",
"display_name": "Gigachat",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "nvidia_nim",
"display_name": "NVIDIA NIM",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "nvidia_riva",
"display_name": "NVIDIA Riva",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "soniox",
"display_name": "Soniox",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "cerebras",
"display_name": "Cerebras",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "ai21_chat",
"display_name": "AI21 Chat",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "volcengine",
"display_name": "Volcengine",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "codestral",
"display_name": "Codestral",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "text-completion-codestral",
"display_name": "Text Completion Codestral",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "dashscope",
"display_name": "Dashscope",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "modelscope",
"display_name": "Modelscope",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "moonshot",
"display_name": "Moonshot",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "publicai",
"display_name": "Publicai",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "v0",
"display_name": "v0",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "morph",
"display_name": "Morph",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "lambda_ai",
"display_name": "Lambda AI",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "inception",
"display_name": "Inception",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "text-completion-inception",
"display_name": "Text Completion Inception",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "deepseek",
"display_name": "Deepseek",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "sambanova",
"display_name": "Sambanova",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "maritalk",
"display_name": "Maritalk",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "voyage",
"display_name": "Voyage",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "cloudflare",
"display_name": "Cloudflare",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "xinference",
"display_name": "Xinference",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "fireworks_ai",
"display_name": "Fireworks AI",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "friendliai",
"display_name": "Friendliai",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "featherless_ai",
"display_name": "Featherless AI",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "watsonx",
"display_name": "Watsonx",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "watsonx_text",
"display_name": "Watsonx Text",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "triton",
"display_name": "Triton",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "predibase",
"display_name": "Predibase",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "databricks",
"display_name": "Databricks",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "empower",
"display_name": "Empower",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "github",
"display_name": "GitHub",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "ragflow",
"display_name": "Ragflow",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "compactifai",
"display_name": "Compactifai",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "docker_model_runner",
"display_name": "Docker Model Runner",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "custom",
"display_name": "Custom",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "litellm_proxy",
"display_name": "LiteLLM Proxy",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "hosted_vllm",
"display_name": "Hosted vLLM",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "llamafile",
"display_name": "Llamafile",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "lm_studio",
"display_name": "LM Studio",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "galadriel",
"display_name": "Galadriel",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "nebius",
"display_name": "Nebius",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "infinity",
"display_name": "Infinity",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "deepgram",
"display_name": "Deepgram",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "elevenlabs",
"display_name": "Elevenlabs",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "novita",
"display_name": "Novita",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "aiohttp_openai",
"display_name": "AIOHTTP OpenAI",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "langfuse",
"display_name": "Langfuse",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "humanloop",
"display_name": "Humanloop",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "topaz",
"display_name": "Topaz",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "sap",
"display_name": "Sap Generative AI Hub",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "assemblyai",
"display_name": "Assemblyai",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "charity_engine",
"display_name": "Charity Engine",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "github_copilot",
"display_name": "GitHub Copilot",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "snowflake",
"display_name": "Snowflake",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "gradient_ai",
"display_name": "Gradient AI",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "meta_llama",
"display_name": "Llama",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "nscale",
"display_name": "Nscale",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "pg_vector",
"display_name": "Pg Vector",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "s3_vectors",
"display_name": "S3 Vectors",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "helicone",
"display_name": "Helicone",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "hyperbolic",
"display_name": "Hyperbolic",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "recraft",
"display_name": "Recraft",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "fal_ai",
"display_name": "Fal AI",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "stability",
"display_name": "Stability",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "heroku",
"display_name": "Heroku",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "aiml",
"display_name": "Aiml",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "cometapi",
"display_name": "Cometapi",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "oci",
"display_name": "OCI",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "auto_router",
"display_name": "Auto Router",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "vercel_ai_gateway",
"display_name": "Vercel AI Gateway",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "dotprompt",
"display_name": "Dotprompt",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "manus",
"display_name": "Manus",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "wandb",
"display_name": "Wandb",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "ovhcloud",
"display_name": "OVHcloud",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "scaleway",
"display_name": "Scaleway",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "lemonade",
"display_name": "Lemonade",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "amazon_nova",
"display_name": "Amazon Nova",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "a2a_agent",
"display_name": "A2A Agent",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "langgraph",
"display_name": "Langgraph",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "langflow",
"display_name": "Langflow",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "minimax",
"display_name": "Minimax",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "synthetic",
"display_name": "Synthetic",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "apertis",
"display_name": "Apertis",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "nano-gpt",
"display_name": "NanoGPT",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "poe",
"display_name": "Poe",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "chutes",
"display_name": "Chutes",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "neosantara",
"display_name": "Neosantara",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "parasail",
"display_name": "Parasail",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "xiaomi_mimo",
"display_name": "Xiaomi MiMo",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "tensormesh",
"display_name": "Tensormesh",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "libertai",
"display_name": "Libertai",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "pinstripes",
"display_name": "Pinstripes",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "darkbloom",
"display_name": "Darkbloom",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "litellm_agent",
"display_name": "LiteLLM Agent",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "cursor",
"display_name": "Cursor",
"default_api_base": null,
"api_key_env_var": null
},
{
"routing_name": "bedrock_mantle",
"display_name": "Bedrock Mantle",
"default_api_base": null,
"api_key_env_var": null
}
]