From 9ba5a1522b445d2cf206c7c86d6c081f5cecd97c Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 24 Jun 2026 16:32:21 -0700 Subject: [PATCH] feat: generate rust providers from registry --- litellm-rust/ADDING_A_PROVIDER.md | 1 + litellm-rust/crates/core/Cargo.toml | 4 + litellm-rust/crates/core/build.rs | 335 +++++++ .../crates/core/src/providers/provider.rs | 660 +------------ litellm-rust/providers/README.md | 21 + litellm-rust/providers/providers.json | 878 ++++++++++++++++++ 6 files changed, 1240 insertions(+), 659 deletions(-) create mode 100644 litellm-rust/crates/core/build.rs create mode 100644 litellm-rust/providers/README.md create mode 100644 litellm-rust/providers/providers.json diff --git a/litellm-rust/ADDING_A_PROVIDER.md b/litellm-rust/ADDING_A_PROVIDER.md index f9a725c833a..ac454727c8a 100644 --- a/litellm-rust/ADDING_A_PROVIDER.md +++ b/litellm-rust/ADDING_A_PROVIDER.md @@ -1,6 +1,7 @@ # Adding a provider / route to litellm-rust - Keep the route contract pure in `crates/core/src//`: 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///transformation.rs`, mirroring the Python provider tree and exposing a `const __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. diff --git a/litellm-rust/crates/core/Cargo.toml b/litellm-rust/crates/core/Cargo.toml index e54002fe5e8..c3b16431b36 100644 --- a/litellm-rust/crates/core/Cargo.toml +++ b/litellm-rust/crates/core/Cargo.toml @@ -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 diff --git a/litellm-rust/crates/core/build.rs b/litellm-rust/crates/core/build.rs new file mode 100644 index 00000000000..e31152c2035 --- /dev/null +++ b/litellm-rust/crates/core/build.rs @@ -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, + api_key_env_var: Option, +} + +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 = providers + .iter() + .map(|provider| variant_name(&provider.routing_name)) + .collect(); + + let enum_variants = variants + .iter() + .map(|variant| format!(" {variant},")) + .collect::>() + .join("\n"); + + let all_values = variants + .iter() + .map(|variant| format!(" LlmProvider::{variant},")) + .collect::>() + .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::>() + .join("\n"); + + let metadata_match_arms = variants + .iter() + .enumerate() + .map(|(index, variant)| { + format!(" LlmProvider::{variant} => &Self::METADATA[{index}],") + }) + .collect::>() + .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 {{ + 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 {{ + let raw = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../../providers/providers.json" + )); + serde_json::from_str::>(raw) + .expect("providers.json parses") + .into_iter() + .map(|provider| provider.routing_name) + .collect() + }} + + fn python_provider_values() -> Vec {{ + 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::>(), + 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 = 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"); +} diff --git a/litellm-rust/crates/core/src/providers/provider.rs b/litellm-rust/crates/core/src/providers/provider.rs index f14152aae18..c0a511d10bb 100644 --- a/litellm-rust/crates/core/src/providers/provider.rs +++ b/litellm-rust/crates/core/src/providers/provider.rs @@ -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 { - 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::>(), - 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")); diff --git a/litellm-rust/providers/README.md b/litellm-rust/providers/README.md new file mode 100644 index 00000000000..0191656373e --- /dev/null +++ b/litellm-rust/providers/README.md @@ -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///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`. diff --git a/litellm-rust/providers/providers.json b/litellm-rust/providers/providers.json new file mode 100644 index 00000000000..60e2c3e8bc4 --- /dev/null +++ b/litellm-rust/providers/providers.json @@ -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 + } +]