use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AgentExtension {
pub uri: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub required: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub params: Option<serde_json::Value>,
}
impl AgentExtension {
#[must_use]
pub fn new(uri: impl Into<String>) -> Self {
Self {
uri: uri.into(),
description: None,
required: None,
params: None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct AgentCardSignature {
pub protected: String,
pub signature: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub header: Option<serde_json::Value>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn agent_extension_minimal_roundtrip() {
let ext = AgentExtension::new("https://example.com/ext/v1");
let json = serde_json::to_string(&ext).expect("serialize");
assert!(json.contains("\"uri\""));
assert!(
!json.contains("\"description\""),
"None fields must be omitted"
);
let back: AgentExtension = serde_json::from_str(&json).expect("deserialize");
assert_eq!(back.uri, "https://example.com/ext/v1");
}
#[test]
fn agent_extension_full_roundtrip() {
let mut ext = AgentExtension::new("https://example.com/ext/v1");
ext.description = Some("Cool extension".into());
ext.required = Some(true);
ext.params = Some(serde_json::json!({"version": 2}));
let json = serde_json::to_string(&ext).expect("serialize");
let back: AgentExtension = serde_json::from_str(&json).expect("deserialize");
assert_eq!(back.description.as_deref(), Some("Cool extension"));
assert_eq!(back.required, Some(true));
}
}