use std::path::{Path, PathBuf};
use std::sync::Arc;
use mentra::a2a::{A2aAgentTool, A2aClient};
use mentra::tool::{AudienceToolRegistration, ToolAudience};
use crate::runtime::{Bridge, Runtime};
use super::A2aAgent;
pub(crate) struct A2aConnections {
runtime: Arc<Runtime>,
claimed: Vec<String>,
registered: Vec<AudienceToolRegistration>,
root: PathBuf,
}
impl A2aConnections {
pub(crate) async fn connect(
runtime: Arc<Runtime>,
audience: &ToolAudience,
root: &Path,
agents: Vec<A2aAgent>,
) -> Self {
let mut claimed = Vec::new();
let mut registered = Vec::new();
for agent in agents {
let effective = runtime.claim_bridged(Bridge::A2a, agent.name(), root);
claimed.push(effective.clone());
let mut config = agent.into_config();
config.name = effective.clone();
match A2aClient::connect(&config).await {
Ok(client) => {
if let Some(registration) =
register(&runtime, audience, A2aAgentTool::new(Arc::new(client)))
{
runtime.record_bridged_tools(
Bridge::A2a,
&effective,
root,
vec![registration.descriptor().provider.name.clone()],
);
registered.push(registration);
}
}
Err(error) => {
eprintln!("Warning: A2A agent '{effective}' failed to connect: {error}");
}
}
}
Self {
runtime,
claimed,
registered,
root: root.to_path_buf(),
}
}
pub(crate) fn names(&self) -> &[String] {
&self.claimed
}
}
fn register(
runtime: &Runtime,
audience: &ToolAudience,
tool: A2aAgentTool,
) -> Option<AudienceToolRegistration> {
let name = tool.name().to_string();
match runtime
.mentra_runtime()
.try_register_tool_for_audience(audience.clone(), tool)
{
Ok(registration) => Some(registration),
Err(_) => {
eprintln!(
"Warning: A2A agent tool '{name}' is a name this runtime already answers to; \
it was not bridged"
);
None
}
}
}
impl Drop for A2aConnections {
fn drop(&mut self) {
self.registered.clear();
for name in self.claimed.drain(..) {
self.runtime
.release_bridged_claim(Bridge::A2a, &name, &self.root);
}
}
}