use polyc_controller::Agent;
use serde::Deserialize as _;
pub const MANIFEST_PATH: &str = "manifests/base/agents.yaml";
const RAW: &str = include_str!("../agents.yaml");
#[derive(Debug, thiserror::Error)]
pub enum CatalogError {
#[error("parse agent document {index} in {MANIFEST_PATH}: {source}")]
Parse {
index: usize,
#[source]
source: yaml_serde::Error,
},
#[error("agent document {index} in {MANIFEST_PATH} has no metadata.name")]
MissingName {
index: usize,
},
}
pub fn shipped() -> Result<Vec<Agent>, CatalogError> {
decode(RAW)
}
fn decode(raw: &str) -> Result<Vec<Agent>, CatalogError> {
yaml_serde::Deserializer::from_str(raw)
.enumerate()
.map(|(index, doc)| {
let agent =
Agent::deserialize(doc).map_err(|source| CatalogError::Parse { index, source })?;
if agent.metadata.name.is_none() {
return Err(CatalogError::MissingName { index });
}
Ok(agent)
})
.collect()
}
#[must_use]
pub fn find<'a>(agents: &'a [Agent], name: &str) -> Option<&'a Agent> {
agents
.iter()
.find(|agent| agent.metadata.name.as_deref() == Some(name))
}
#[must_use]
pub fn name(agent: &Agent) -> &str {
agent
.metadata
.name
.as_deref()
.expect("polyc_agent_catalog::shipped guarantees every agent is named")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_and_null_catalog_documents_are_not_skipped() {
let first = RAW.split("---").nth(1).expect("first agent document");
for empty in ["", "null\n"] {
let raw = format!("---{first}---\n{empty}---{first}");
assert!(matches!(
decode(&raw),
Err(CatalogError::Parse { index: 1, .. })
));
}
let second = first.replacen("name: assistant", "name: second", 1);
let raw = format!("---{first}---{second}");
let agents = decode(&raw).expect("two agents");
assert_eq!(agents.len(), 2);
assert_eq!(name(&agents[0]), "assistant");
assert_eq!(name(&agents[1]), "second");
}
#[test]
fn the_shipped_catalog_parses_and_every_agent_is_named() {
let agents = shipped().expect("the shipped catalog must parse");
assert!(!agents.is_empty(), "the shipped catalog must ship agents");
for agent in &agents {
assert!(agent.metadata.name.is_some());
}
}
#[test]
fn the_shipped_catalog_ships_the_deployment_default_assistant() {
let agents = shipped().expect("the shipped catalog must parse");
assert!(
find(&agents, "assistant").is_some(),
"manifests/base/agents.yaml must ship an agent named assistant \
(POLYCHROME_DEFAULT_AGENT)"
);
}
}