use crate::agent::{deps, inputs, registry};
use crate::config::{loading::merge_agent_toml, Config};
use anyhow::{Context, Result};
pub async fn resolve_config_and_role(
tag: Option<&str>,
config: &Config,
status_cb: Option<&(dyn Fn(&str) + Send + Sync)>,
) -> Result<(Config, String)> {
let tag = tag.unwrap_or(config.default.as_str());
if tag.contains(':') {
if let Some(cb) = status_cb {
cb(&format!("Fetching agent: {tag}"));
}
let (raw_toml, tap_root) = registry::fetch_manifest(tag, &config.registry)
.await
.context(format!("Failed to fetch agent manifest for '{tag}'"))?;
let resolved_toml =
registry::resolve_capabilities(&raw_toml, &tap_root, &config.capabilities)
.context("Failed to resolve agent capabilities")?;
let resolved_toml = inputs::resolve_inputs(&resolved_toml).await?;
let resolved_toml = inputs::resolve_env_vars(&resolved_toml).await?;
deps::resolve_deps(&resolved_toml, &tap_root, status_cb).await?;
let tagged_toml = inject_role_name(&resolved_toml, tag)
.context("Failed to inject role name into agent manifest")?;
let mut merged = merge_agent_toml(config, &tagged_toml)
.context("Failed to merge agent manifest into config")?;
let base_names: std::collections::HashSet<&str> =
config.roles.iter().map(|r| r.name.as_str()).collect();
let role = merged
.roles
.iter()
.find(|r| !base_names.contains(r.name.as_str()))
.map(|r| r.name.clone())
.context(format!(
"Agent manifest for '{tag}' must define at least one new [[roles]] entry"
))?;
if let Some(tap_model) = config.taps.get(tag) {
merged.model = tap_model.clone();
crate::log_debug!("Applied tap model override: {} -> {}", tag, tap_model);
}
Ok((merged, role))
} else {
Ok((config.clone(), tag.to_string()))
}
}
fn inject_role_name(toml_str: &str, tag: &str) -> Result<String> {
let role_name = tag;
let mut value: toml::Value =
toml::from_str(toml_str).context("Failed to parse agent manifest TOML")?;
if let Some(toml::Value::Array(roles)) = value.get_mut("roles") {
if let Some(toml::Value::Table(table)) = roles.first_mut() {
table.insert(
"name".to_string(),
toml::Value::String(role_name.to_string()),
);
}
}
toml::to_string(&value).context("Failed to re-serialize agent manifest TOML")
}