use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct PeerSummary {
pub id: String,
pub description: String,
}
pub struct PeerDirectory {
peers: Vec<PeerSummary>,
}
impl PeerDirectory {
pub fn new(peers: Vec<PeerSummary>) -> Arc<Self> {
Arc::new(Self { peers })
}
pub fn render_for(&self, self_id: &str, allowed_delegates: &[String]) -> Option<String> {
let others: Vec<&PeerSummary> = self.peers.iter().filter(|p| p.id != self_id).collect();
if others.is_empty() {
return None;
}
let mut out = String::from("# PEERS\n");
out.push_str("Other agents you can reach via `delegate({agent_id, task, ...})`:\n\n");
for p in others {
let reachable = allowed_delegates.is_empty()
|| allowed_delegates
.iter()
.any(|pat| match pat.strip_suffix('*') {
Some(stem) => p.id.starts_with(stem),
None => pat == &p.id,
});
let mark = if reachable { "✓" } else { "✗" };
if p.description.is_empty() {
out.push_str(&format!("- {mark} `{}`\n", p.id));
} else {
out.push_str(&format!("- {mark} `{}` — {}\n", p.id, p.description.trim()));
}
}
Some(out)
}
pub fn is_empty(&self) -> bool {
self.peers.is_empty()
}
pub fn peers(&self) -> &[PeerSummary] {
&self.peers
}
}
#[cfg(test)]
mod tests {
use super::*;
fn peer(id: &str, desc: &str) -> PeerSummary {
PeerSummary {
id: id.into(),
description: desc.into(),
}
}
#[test]
fn renders_others_with_reachability_marks() {
let dir = PeerDirectory::new(vec![
peer("boss", "decides strategy"),
peer("ventas", "handles sales"),
peer("soporte_lvl1", "first-line support"),
]);
let block = dir
.render_for("boss", &["ventas".into(), "soporte_*".into()])
.expect("block exists");
assert!(block.contains("# PEERS"));
assert!(!block.contains("`boss`"), "self must be filtered out");
assert!(block.contains("✓ `ventas`"));
assert!(block.contains("✓ `soporte_lvl1`"));
}
#[test]
fn empty_allowlist_marks_everything_reachable() {
let dir = PeerDirectory::new(vec![peer("a", ""), peer("b", "desc b")]);
let block = dir.render_for("a", &[]).expect("block");
assert!(block.contains("✓ `b`"));
assert!(block.contains("desc b"));
}
#[test]
fn unreachable_peers_marked() {
let dir = PeerDirectory::new(vec![peer("a", ""), peer("b", ""), peer("c", "")]);
let block = dir.render_for("a", &["b".into()]).expect("block");
assert!(block.contains("✓ `b`"));
assert!(block.contains("✗ `c`"));
}
#[test]
fn single_agent_has_no_peers_block() {
let dir = PeerDirectory::new(vec![peer("alone", "")]);
assert!(dir.render_for("alone", &[]).is_none());
}
}