Initial commit

This commit is contained in:
xggz
2026-03-06 22:56:13 +08:00
commit 54d1097b41
273 changed files with 92457 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
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(),
}))
}