use serde::{Deserialize, Deserializer, Serialize};
fn deserialize_u64_or_string<'de, D>(deserializer: D) -> Result<u64, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(untagged)]
enum StringOrNum {
Num(u64),
Str(String),
}
match StringOrNum::deserialize(deserializer)? {
StringOrNum::Num(n) => Ok(n),
StringOrNum::Str(s) => s.parse::<u64>().map_err(serde::de::Error::custom),
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RegistrationFile {
#[serde(rename = "type")]
pub type_field: String,
pub name: String,
pub description: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub image: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub services: Vec<ServiceEndpoint>,
#[serde(default, rename = "x402Support")]
pub x402_support: bool,
#[serde(default = "default_true")]
pub active: bool,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub registrations: Vec<Registration>,
#[serde(
default,
rename = "supportedTrust",
skip_serializing_if = "Vec::is_empty"
)]
pub supported_trust: Vec<String>,
}
const fn default_true() -> bool {
true
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServiceEndpoint {
pub name: String,
pub endpoint: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub skills: Option<Vec<String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub domains: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Registration {
#[serde(rename = "agentId", deserialize_with = "deserialize_u64_or_string")]
pub agent_id: u64,
#[serde(rename = "agentRegistry")]
pub agent_registry: String,
}
#[derive(Debug, Clone)]
pub struct Feedback {
pub value: i128,
pub value_decimals: u8,
pub tag1: String,
pub tag2: String,
pub is_revoked: bool,
}
#[derive(Debug, Clone, Copy)]
pub struct ReputationSummary {
pub count: u64,
pub summary_value: i128,
pub summary_value_decimals: u8,
}
#[derive(Debug, Clone)]
pub struct ValidationStatus {
pub validator_address: alloy::primitives::Address,
pub agent_id: alloy::primitives::U256,
pub response: u8,
pub response_hash: alloy::primitives::FixedBytes<32>,
pub tag: String,
pub last_update: alloy::primitives::U256,
}
#[derive(Debug, Clone, Copy)]
pub struct ValidationSummary {
pub count: u64,
pub avg_response: u8,
}
impl RegistrationFile {
#[must_use]
pub fn new(name: impl Into<String>, description: impl Into<String>) -> Self {
Self {
type_field: "https://eips.ethereum.org/EIPS/eip-8004#registration-v1".to_owned(),
name: name.into(),
description: description.into(),
image: None,
services: Vec::new(),
x402_support: false,
active: true,
registrations: Vec::new(),
supported_trust: Vec::new(),
}
}
pub fn to_json(&self) -> Result<String, serde_json::Error> {
serde_json::to_string_pretty(self)
}
pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {
serde_json::from_str(json)
}
}