a2a_protocol_types/
extensions.rs1use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
19#[serde(rename_all = "camelCase")]
20pub struct AgentExtension {
21 pub uri: String,
23
24 #[serde(skip_serializing_if = "Option::is_none")]
26 pub description: Option<String>,
27
28 #[serde(skip_serializing_if = "Option::is_none")]
33 pub required: Option<bool>,
34
35 #[serde(skip_serializing_if = "Option::is_none")]
37 pub params: Option<serde_json::Value>,
38}
39
40impl AgentExtension {
41 #[must_use]
43 pub fn new(uri: impl Into<String>) -> Self {
44 Self {
45 uri: uri.into(),
46 description: None,
47 required: None,
48 params: None,
49 }
50 }
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
59#[serde(rename_all = "camelCase")]
60pub struct AgentCardSignature {
61 pub protected: String,
63
64 pub signature: String,
66
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub header: Option<serde_json::Value>,
70}
71
72#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn agent_extension_minimal_roundtrip() {
80 let ext = AgentExtension::new("https://example.com/ext/v1");
81 let json = serde_json::to_string(&ext).expect("serialize");
82 assert!(json.contains("\"uri\""));
83 assert!(
84 !json.contains("\"description\""),
85 "None fields must be omitted"
86 );
87
88 let back: AgentExtension = serde_json::from_str(&json).expect("deserialize");
89 assert_eq!(back.uri, "https://example.com/ext/v1");
90 }
91
92 #[test]
93 fn agent_extension_full_roundtrip() {
94 let mut ext = AgentExtension::new("https://example.com/ext/v1");
95 ext.description = Some("Cool extension".into());
96 ext.required = Some(true);
97 ext.params = Some(serde_json::json!({"version": 2}));
98
99 let json = serde_json::to_string(&ext).expect("serialize");
100 let back: AgentExtension = serde_json::from_str(&json).expect("deserialize");
101
102 assert_eq!(back.description.as_deref(), Some("Cool extension"));
103 assert_eq!(back.required, Some(true));
104 }
105}