use std::time::Duration;
use super::{LlmError, ProtocolClient};
use crate::config::{RoleModel, Settings};
use crate::secrets::{Resolver, SecretError, SecretSource};
#[derive(Debug, thiserror::Error)]
pub enum SetupError {
#[error("unknown provider `{0}`")]
UnknownProvider(String),
#[error("providers.{name}.base_url is not set (set {variable})")]
MissingBaseUrl {
name: String,
variable: String,
},
#[error("cannot resolve providers.{name}.api_key")]
Secret {
name: String,
#[source]
source: SecretError,
},
#[error("cannot build the client for provider `{name}`")]
Client {
name: String,
#[source]
source: LlmError,
},
}
pub async fn connect<S: SecretSource>(
settings: &Settings,
role: &RoleModel,
resolver: &Resolver<S>,
) -> Result<ProtocolClient, SetupError> {
let name = &role.provider;
let provider = settings
.providers
.get(name)
.ok_or_else(|| SetupError::UnknownProvider(name.clone()))?;
let base_url = provider
.base_url
.as_deref()
.ok_or_else(|| SetupError::MissingBaseUrl {
name: name.clone(),
variable: format!("OVERBRAINER_PROVIDERS__{}__BASE_URL", name.to_uppercase()),
})?;
let api_key = match &provider.api_key {
Some(value) => {
Some(
resolver
.resolve(value)
.await
.map_err(|source| SetupError::Secret {
name: name.clone(),
source,
})?,
)
},
None => None,
};
let timeout = Duration::from_secs(settings.pipeline.request_timeout_secs);
ProtocolClient::new(
provider.protocol,
base_url,
api_key.as_ref(),
&role.model,
timeout,
)
.map_err(|source| SetupError::Client {
name: name.clone(),
source,
})
}