use std::time::Duration;
use secrecy::SecretString;
use serde::{Deserialize, Serialize};
use crate::provider::{ModelName, ProviderId};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ProviderType {
#[cfg(feature = "openai")]
OpenAi,
#[cfg(feature = "anthropic")]
Anthropic,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProviderConfig {
#[serde(default)]
pub provider_type: Option<ProviderType>,
pub base_url: String,
#[serde(default)]
pub model: Option<ModelName>,
#[serde(default)]
pub models: Vec<ModelName>,
#[serde(default)]
pub compaction_model: Option<ModelName>,
#[serde(default)]
pub api_key: Option<String>,
#[serde(default)]
pub organization: Option<String>,
#[serde(default = "default_timeout_secs")]
pub timeout_secs: u64,
#[serde(default = "default_connect_timeout_secs")]
pub connect_timeout_secs: u64,
#[serde(default = "default_max_retries")]
pub max_retries: usize,
}
impl ProviderConfig {
#[must_use]
pub fn new(base_url: impl Into<String>) -> Self {
Self {
provider_type: None,
base_url: base_url.into(),
model: None,
models: Vec::new(),
compaction_model: None,
api_key: None,
organization: None,
timeout_secs: default_timeout_secs(),
connect_timeout_secs: default_connect_timeout_secs(),
max_retries: default_max_retries(),
}
}
#[must_use]
pub fn with_provider_type(mut self, provider_type: ProviderType) -> Self {
self.provider_type = Some(provider_type);
self
}
#[must_use]
pub fn with_model(mut self, model: impl Into<ModelName>) -> Self {
self.model = Some(model.into());
self
}
#[must_use]
pub fn with_api_key(mut self, api_key: impl Into<String>) -> Self {
self.api_key = Some(api_key.into());
self
}
#[must_use]
pub fn resolve_api_key(&self) -> Option<SecretString> {
self.api_key.as_ref().and_then(|key| {
if let Some(var_name) = key.strip_prefix("env:") {
std::env::var(var_name)
.ok()
.map(|s| SecretString::new(s.into_boxed_str()))
} else {
Some(SecretString::new(key.clone().into_boxed_str()))
}
})
}
#[must_use]
pub fn to_http_config(&self, id: ProviderId) -> crate::provider::ProviderHttpConfig {
crate::provider::ProviderHttpConfig {
id,
base_url: self.base_url.clone(),
api_key: self.resolve_api_key(),
organization: self.organization.clone(),
timeout: Duration::from_secs(self.timeout_secs),
connect_timeout: Duration::from_secs(self.connect_timeout_secs),
max_retries: self.max_retries,
}
}
}
const fn default_timeout_secs() -> u64 {
60
}
const fn default_connect_timeout_secs() -> u64 {
10
}
const fn default_max_retries() -> usize {
2
}