use serde::{Deserialize, Serialize};
use tracing::warn;
use super::Provider;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoleConfig {
pub provider: Provider,
pub model: String,
pub temperature: f32,
pub max_tokens: u32,
}
#[derive(Debug, Clone, Default, Deserialize)]
pub struct RoleConfigOverride {
pub provider: Option<String>,
pub model: Option<String>,
pub temperature: Option<f32>,
pub max_tokens: Option<u32>,
}
#[derive(Debug, Clone)]
pub struct RoleModels {
pub reviewer: RoleConfig,
pub verifier: RoleConfig,
pub summarizer: RoleConfig,
}
impl RoleModels {
pub fn resolve(
cli_overrides: Option<&RoleCliOverrides>,
env: &RoleEnv,
file_models: Option<&FileModels>,
) -> Self {
let reviewer = resolve_role(
cli_overrides.and_then(|c| c.reviewer_model.as_deref()),
cli_overrides.and_then(|c| c.provider.as_deref()),
env.reviewer_model.as_deref(),
env.provider.as_deref(),
file_models.and_then(|f| f.reviewer.as_ref()),
crate::llm::models::DEFAULT_REVIEWER_MODEL,
Provider::Bedrock,
0.3,
4096,
);
let verifier = resolve_role(
cli_overrides.and_then(|c| c.verifier_model.as_deref()),
cli_overrides.and_then(|c| c.provider.as_deref()),
env.verifier_model.as_deref(),
env.provider.as_deref(),
file_models.and_then(|f| f.verifier.as_ref()),
crate::llm::models::DEFAULT_VERIFIER_MODEL,
Provider::Bedrock,
1.0,
128,
);
let summarizer = resolve_role(
cli_overrides.and_then(|c| c.summarizer_model.as_deref()),
cli_overrides.and_then(|c| c.provider.as_deref()),
env.summarizer_model.as_deref(),
env.provider.as_deref(),
file_models.and_then(|f| f.summarizer.as_ref()),
crate::llm::models::DEFAULT_SUMMARIZER_MODEL,
Provider::Bedrock,
0.0,
4096,
);
Self {
reviewer,
verifier,
summarizer,
}
}
pub fn from_env(env: &RoleEnv) -> Self {
Self::resolve(None, env, None)
}
}
#[derive(Debug, Default, Clone)]
pub struct RoleCliOverrides {
pub reviewer_model: Option<String>,
pub verifier_model: Option<String>,
pub summarizer_model: Option<String>,
pub provider: Option<String>,
}
#[derive(Debug, Default, Clone)]
pub struct RoleEnv {
pub reviewer_model: Option<String>,
pub verifier_model: Option<String>,
pub summarizer_model: Option<String>,
pub provider: Option<String>,
}
impl RoleEnv {
pub fn from_env() -> Self {
Self {
reviewer_model: std::env::var("TRUSTY_REVIEW_REVIEWER_MODEL").ok(),
verifier_model: std::env::var("TRUSTY_REVIEW_VERIFIER_MODEL").ok(),
summarizer_model: std::env::var("TRUSTY_REVIEW_SUMMARIZER_MODEL").ok(),
provider: std::env::var("TRUSTY_REVIEW_PROVIDER").ok(),
}
}
}
#[derive(Debug, Default, Clone, Deserialize)]
pub struct FileModels {
pub reviewer: Option<RoleConfigOverride>,
pub verifier: Option<RoleConfigOverride>,
pub summarizer: Option<RoleConfigOverride>,
}
#[allow(clippy::too_many_arguments)]
pub(super) fn resolve_role(
cli_model: Option<&str>,
cli_provider: Option<&str>,
env_model: Option<&str>,
env_provider: Option<&str>,
file: Option<&RoleConfigOverride>,
default_model: &str,
default_provider: Provider,
default_temp: f32,
default_max_tokens: u32,
) -> RoleConfig {
let model = cli_model
.or(env_model)
.or(file.and_then(|f| f.model.as_deref()))
.unwrap_or(default_model)
.to_string();
let provider_str = cli_provider.or(env_provider);
let provider = provider_str
.and_then(|s| {
s.parse::<Provider>()
.map_err(|e| {
warn!("unrecognised provider {s:?}: {e} — using default");
})
.ok()
})
.or_else(|| {
file.and_then(|f| {
f.provider.as_deref().and_then(|s| {
s.parse::<Provider>()
.map_err(|e| {
warn!("config file provider {s:?}: {e} — using default");
})
.ok()
})
})
})
.unwrap_or(default_provider);
let temperature = file.and_then(|f| f.temperature).unwrap_or(default_temp);
let max_tokens = file
.and_then(|f| f.max_tokens)
.unwrap_or(default_max_tokens);
RoleConfig {
provider,
model,
temperature,
max_tokens,
}
}