126 lines
3.3 KiB
Rust
126 lines
3.3 KiB
Rust
use std::collections::BTreeMap;
|
|
|
|
use serde::Deserialize;
|
|
|
|
use crate::acp::registry;
|
|
use crate::models::agent::AgentType;
|
|
|
|
pub const REGISTRY_URL: &str =
|
|
"https://cdn.agentclientprotocol.com/registry/v1/latest/registry.json";
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct RegistryAgent {
|
|
pub agent_type: AgentType,
|
|
pub registry_id: String,
|
|
pub name: String,
|
|
pub description: String,
|
|
pub version: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct RegistryBinaryRelease {
|
|
pub version: String,
|
|
pub archive_url: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct RegistryPayload {
|
|
agents: Vec<RegistryAgentItem>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct RegistryAgentItem {
|
|
id: String,
|
|
name: String,
|
|
description: String,
|
|
#[serde(default)]
|
|
version: Option<String>,
|
|
#[serde(default)]
|
|
distribution: RegistryDistribution,
|
|
}
|
|
|
|
#[derive(Debug, Default, Deserialize)]
|
|
struct RegistryDistribution {
|
|
#[serde(default)]
|
|
binary: BTreeMap<String, RegistryBinaryPlatformItem>,
|
|
}
|
|
|
|
#[derive(Debug, Default, Deserialize)]
|
|
struct RegistryBinaryPlatformItem {
|
|
#[serde(default, alias = "url")]
|
|
archive: String,
|
|
}
|
|
|
|
async fn fetch_registry_payload() -> Result<RegistryPayload, String> {
|
|
let response = reqwest::Client::new()
|
|
.get(REGISTRY_URL)
|
|
.send()
|
|
.await
|
|
.map_err(|e| format!("failed to fetch ACP registry: {e}"))?;
|
|
if !response.status().is_success() {
|
|
return Err(format!(
|
|
"failed to fetch ACP registry: HTTP {}",
|
|
response.status()
|
|
));
|
|
}
|
|
|
|
response
|
|
.text()
|
|
.await
|
|
.map_err(|e| format!("failed to read ACP registry response: {e}"))
|
|
.and_then(|text| {
|
|
serde_json::from_str::<RegistryPayload>(&text)
|
|
.map_err(|e| format!("failed to parse ACP registry JSON: {e}"))
|
|
})
|
|
}
|
|
|
|
pub async fn fetch_supported_agents() -> Result<Vec<RegistryAgent>, String> {
|
|
let payload = fetch_registry_payload().await?;
|
|
|
|
let mut supported = Vec::new();
|
|
for item in payload.agents {
|
|
if let Some(agent_type) = registry::from_registry_id(&item.id) {
|
|
supported.push(RegistryAgent {
|
|
agent_type,
|
|
registry_id: item.id,
|
|
name: item.name,
|
|
description: item.description,
|
|
version: item.version,
|
|
});
|
|
}
|
|
}
|
|
|
|
Ok(supported)
|
|
}
|
|
|
|
pub async fn fetch_binary_release(
|
|
agent_type: AgentType,
|
|
platform: &str,
|
|
) -> Result<Option<RegistryBinaryRelease>, String> {
|
|
let payload = fetch_registry_payload().await?;
|
|
let item = payload.agents.into_iter().find(|item| {
|
|
registry::from_registry_id(&item.id)
|
|
.map(|candidate| candidate == agent_type)
|
|
.unwrap_or(false)
|
|
});
|
|
|
|
let Some(item) = item else {
|
|
return Ok(None);
|
|
};
|
|
if item.version.as_deref().unwrap_or_default().is_empty() {
|
|
return Ok(None);
|
|
}
|
|
let platform_item = item.distribution.binary.get(platform);
|
|
let Some(platform_item) = platform_item else {
|
|
return Ok(None);
|
|
};
|
|
if platform_item.archive.is_empty() {
|
|
return Ok(None);
|
|
}
|
|
|
|
Ok(Some(RegistryBinaryRelease {
|
|
version: item.version.unwrap_or_default(),
|
|
archive_url: platform_item.archive.clone(),
|
|
}))
|
|
}
|