pub mod loader;
pub mod provider;
pub use loader::{ProviderConfigEntry, RegistryConfig};
pub use provider::{ProviderConfig, RetryConfig, SharedProviderConfig};
use serde::{Deserialize, Serialize};
use std::env;
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Config {
#[serde(skip_serializing_if = "Option::is_none")]
pub openai: Option<ProviderConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub anthropic: Option<ProviderConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deepseek: Option<ProviderConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub zhipu: Option<ProviderConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub aliyun: Option<ProviderConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub moonshot: Option<ProviderConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub volcengine: Option<ProviderConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub longcat: Option<ProviderConfig>,
}
impl Config {
pub fn from_env() -> Self {
let mut config = Config::default();
if let Ok(api_key) = env::var("OPENAI_API_KEY") {
config.openai = Some(
ProviderConfig::new(api_key)
.with_base_url(env::var("OPENAI_BASE_URL").unwrap_or_default())
.with_timeout_ms(
env::var("OPENAI_TIMEOUT_MS")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(30000),
),
);
}
if let Ok(api_key) = env::var("DEEPSEEK_API_KEY") {
config.deepseek = Some(
ProviderConfig::new(api_key)
.with_base_url(env::var("DEEPSEEK_BASE_URL").unwrap_or_default())
.with_timeout_ms(
env::var("DEEPSEEK_TIMEOUT_MS")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(30000),
),
);
}
if let Ok(api_key) = env::var("ZHIPU_API_KEY").or_else(|_| env::var("GLM_API_KEY")) {
config.zhipu = Some(
ProviderConfig::new(api_key)
.with_base_url(env::var("ZHIPU_BASE_URL").unwrap_or_default())
.with_timeout_ms(
env::var("ZHIPU_TIMEOUT_MS")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(30000),
),
);
}
if let Ok(api_key) = env::var("ALIYUN_API_KEY").or_else(|_| env::var("DASHSCOPE_API_KEY")) {
config.aliyun = Some(
ProviderConfig::new(api_key)
.with_base_url(env::var("ALIYUN_BASE_URL").unwrap_or_default())
.with_timeout_ms(
env::var("ALIYUN_TIMEOUT_MS")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(30000),
),
);
}
config
}
pub fn list_providers(&self) -> Vec<String> {
let mut providers = Vec::new();
if self.openai.is_some() {
providers.push("openai".to_string());
}
if self.anthropic.is_some() {
providers.push("anthropic".to_string());
}
if self.deepseek.is_some() {
providers.push("deepseek".to_string());
}
if self.zhipu.is_some() {
providers.push("zhipu".to_string());
}
if self.aliyun.is_some() {
providers.push("aliyun".to_string());
}
if self.moonshot.is_some() {
providers.push("moonshot".to_string());
}
if self.volcengine.is_some() {
providers.push("volcengine".to_string());
}
if self.longcat.is_some() {
providers.push("longcat".to_string());
}
providers
}
}