use std::sync::OnceLock;
use anyhow::Result;
use objects::object::{Attribution, Principal};
use repo::Repository;
type HarnessProbe = fn(&Repository) -> (Option<String>, Option<String>);
static HARNESS_PROBE: OnceLock<HarnessProbe> = OnceLock::new();
pub fn install_harness_probe(probe: HarnessProbe) {
let _ = HARNESS_PROBE.set(probe);
}
fn current_process_harness(repo: &Repository) -> (Option<String>, Option<String>) {
HARNESS_PROBE
.get()
.map_or_else(|| (None, None), |probe| probe(repo))
}
pub fn clean_attribution_value(value: String) -> Option<String> {
let trimmed = value.trim();
if trimmed.is_empty() || trimmed.eq_ignore_ascii_case("unknown") {
None
} else {
Some(value)
}
}
pub fn resolve_principal(repo: &Repository, user_config: &config::UserConfig) -> Result<Principal> {
Ok(verbs::resolve_principal(repo, user_config.principal_pair())?.principal)
}
pub fn resolve_attribution(
repo: &Repository,
user_config: &config::UserConfig,
) -> Result<Attribution> {
let principal = resolve_principal(repo, user_config)?;
let (harness_provider_raw, harness_model_raw) = current_process_harness(repo);
let harness_provider = harness_provider_raw.and_then(clean_attribution_value);
let harness_model = harness_model_raw.and_then(clean_attribution_value);
let agent_provider = std::env::var("HEDDLE_AGENT_PROVIDER")
.ok()
.and_then(clean_attribution_value)
.or(harness_provider)
.or_else(|| {
user_config
.agent
.provider
.clone()
.and_then(clean_attribution_value)
})
.or_else(|| {
repo.config()
.agent
.provider
.clone()
.and_then(clean_attribution_value)
});
let agent_model = std::env::var("HEDDLE_AGENT_MODEL")
.ok()
.and_then(clean_attribution_value)
.or(harness_model)
.or_else(|| {
user_config
.agent
.model
.clone()
.and_then(clean_attribution_value)
})
.or_else(|| {
repo.config()
.agent
.model
.clone()
.and_then(clean_attribution_value)
});
match (agent_provider, agent_model) {
(Some(provider), Some(model)) => {
let agent = objects::object::Agent::new(provider, model);
Ok(Attribution::with_agent(principal, agent))
}
_ => Ok(Attribution::human(principal)),
}
}