pub mod prompts;
pub mod stream;
use std::sync::Arc;
use genai::Client;
use crate::config::LlmConfig;
use crate::error::{Error, Result};
#[derive(Clone)]
pub struct AiClient {
pub client: Arc<Client>,
pub default_provider: String,
}
impl AiClient {
pub fn from_config(cfg: &LlmConfig) -> Result<Self> {
if !cfg.providers.contains_key(&cfg.default) {
return Err(Error::Config(format!(
"default provider `{}` is not in providers map",
cfg.default
)));
}
Ok(Self {
client: Arc::new(Client::default()),
default_provider: cfg.default.clone(),
})
}
pub fn resolve_provider<'a>(
&self,
cfg: &'a LlmConfig,
provider: Option<&str>,
) -> Result<(&'a str, Option<&'a str>)> {
let name = provider.unwrap_or(&self.default_provider);
let prov = cfg.providers.get(name).ok_or_else(|| {
Error::Config(format!("unknown llm provider `{name}` — check inkhaven.hjson"))
})?;
if let Some(env_var) = prov.api_key_env.as_deref() {
if std::env::var(env_var).is_err() {
return Err(Error::Config(format!(
"{env_var} not set in environment — `export {env_var}=...`"
)));
}
Ok((&prov.model, Some(env_var)))
} else {
Ok((&prov.model, None))
}
}
}