//! Built-in Agent definitions, released to the user config directory on //! first run just like built-in skills. A released definition is a regular //! user-editable file afterwards; the installer never overwrites it. use std::path::Path; use crate::config::LLMProviderConfig; mod embedded { include!(concat!(env!("OUT_DIR"), "/embedded_agents.rs")); } /// Install built-in Agent definitions into `/agents/`. Files /// that already exist (user-modified or user-created) are left untouched. pub fn install_builtin_agents(config_dir: &Path, profiles: &std::collections::HashMap) { let agents_dir = config_dir.join("agents"); if let Err(error) = std::fs::create_dir_all(&agents_dir) { tracing::warn!(dir = %agents_dir.display(), error = %error, "Failed to create agents directory"); return; } for agent in embedded::EMBEDDED_AGENTS { let path = agents_dir.join(format!("{}.md", agent.name)); if path.exists() { continue; } if let Err(error) = std::fs::write(&path, agent.content) { tracing::warn!(name = agent.name, error = %error, "Failed to install built-in Agent definition"); continue; } let profile = match profiles.get("default").cloned() { Some(profile) => profile, None => { tracing::warn!( name = agent.name, "Skipping built-in Agent validation: no 'default' provider profile configured" ); continue; } }; // Validate the released file immediately so a future catalog load // cannot fail on a broken built-in. Validation failure keeps the // file (the user can edit it) but logs loudly. match super::definition::parse_definition(&path, std::sync::Arc::new(profile)) { Ok(_) => { tracing::info!(name = agent.name, dir = %path.display(), "Installed built-in Agent definition"); } Err(error) => { tracing::warn!(name = agent.name, error = %error, "Installed built-in Agent definition failed validation"); } } } }