use crate::catalog::BuiltinModelEntry;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum AuthMethod {
#[default]
Bearer,
#[serde(rename = "x-api-key")]
XApiKey,
#[serde(rename = "api-key")]
ApiKey,
None,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BuiltinProviderEntry {
pub id: String,
pub display_name: String,
#[serde(default)]
pub aliases: Vec<String>,
pub api: String,
pub env_key: String,
#[serde(default)]
pub extra_env_keys: Vec<String>,
#[serde(default)]
pub base_url: String,
pub auth_method: AuthMethod,
#[serde(default)]
pub extra_headers: Vec<(String, String)>,
pub category: String,
pub description: String,
#[serde(default = "default_enabled")]
pub default_enabled: bool,
}
fn default_enabled() -> bool {
true
}
impl BuiltinProviderEntry {
pub fn all_env_keys(&self) -> impl Iterator<Item = &str> {
std::iter::once(self.env_key.as_str()).chain(self.extra_env_keys.iter().map(|s| s.as_str()))
}
pub fn is_openai_compatible(&self) -> bool {
matches!(self.api.as_str(), "openai-completions" | "openai-responses")
}
}
pub fn load_builtin_providers() -> &'static [BuiltinProviderEntry] {
static CACHE: std::sync::OnceLock<&'static [BuiltinProviderEntry]> = std::sync::OnceLock::new();
CACHE.get_or_init(|| {
let providers = crate::catalog::materialize::materialize_providers();
Box::leak(providers.into_boxed_slice())
})
}
pub fn builtin_providers_count() -> usize {
load_builtin_providers().len()
}
pub fn load_builtin_models() -> &'static std::collections::BTreeMap<String, Vec<BuiltinModelEntry>>
{
static EMPTY: std::sync::OnceLock<std::collections::BTreeMap<String, Vec<BuiltinModelEntry>>> =
std::sync::OnceLock::new();
EMPTY.get_or_init(std::collections::BTreeMap::new)
}
pub fn builtin_model_count() -> usize {
0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn all_providers_have_valid_auth_method() {
for p in load_builtin_providers() {
match p.auth_method {
AuthMethod::Bearer
| AuthMethod::XApiKey
| AuthMethod::ApiKey
| AuthMethod::None => {}
}
}
}
#[test]
fn all_providers_have_non_empty_env_key() {
for p in load_builtin_providers() {
assert!(!p.env_key.is_empty(), "Provider {} has empty env_key", p.id);
}
}
#[test]
fn openai_compatible_providers_use_bearer() {
for p in load_builtin_providers() {
if p.is_openai_compatible() {
assert_eq!(
p.auth_method,
AuthMethod::Bearer,
"OpenAI-compatible provider {} should use Bearer auth",
p.id
);
}
}
}
}