use std::{collections::BTreeSet, sync::Arc};
use mentra::a2a::A2aClient;
use super::{ConfiguredAgents, RemoteAgent, Roster, connect_each, warned};
use crate::a2a::{A2aAgent, A2aReload};
enum Fate {
Added,
Changed,
Unchanged,
}
impl ConfiguredAgents {
pub(crate) async fn reload(&self, agents: Vec<A2aAgent>) -> A2aReload {
let before = self.snapshot();
let fates: Vec<Fate> = agents
.iter()
.map(|agent| match before.get(agent.name()) {
None => Fate::Added,
Some(had) if had.agent.connects_like(agent) => Fate::Unchanged,
Some(_) => Fate::Changed,
})
.collect();
let mut report = A2aReload {
removed: before
.agents
.iter()
.map(|had| had.name())
.filter(|name| !agents.iter().any(|agent| agent.name() == *name))
.map(str::to_string)
.collect(),
..A2aReload::default()
};
let removed: BTreeSet<String> = before
.removed
.iter()
.chain(&report.removed)
.filter(|name| !agents.iter().any(|agent| agent.name() == name.as_str()))
.cloned()
.collect();
let mut fetched = Vec::with_capacity(agents.len());
for ((agent, client), fate) in connect_each(agents).await.into_iter().zip(fates) {
let name = agent.name().to_string();
match fate {
Fate::Added => report.added.push(name.clone()),
Fate::Changed => report.changed.push(name.clone()),
Fate::Unchanged => report.refreshed.push(name.clone()),
}
if client.is_err() {
report.unreachable.push(name.clone());
}
fetched.push((agent, warned(&name, client)));
}
self.swap_with(|current| Roster {
agents: fetched
.into_iter()
.map(|(agent, client)| settled(current, agent, client))
.collect(),
removed,
});
self.changed();
report
}
}
fn settled(current: &Roster, agent: A2aAgent, client: Option<Arc<A2aClient>>) -> Arc<RemoteAgent> {
if client.is_none()
&& let Some(had) = current.get(agent.name())
&& had.client.is_some()
&& had.agent.connects_like(&agent)
{
return Arc::clone(had);
}
Arc::new(RemoteAgent::new(agent, client))
}