protocol_droid/domain/a2a/
extended_agent_card.rs1use std::collections::BTreeMap;
49
50use serde::{Deserialize, Serialize};
51
52use super::agent_card::AgentCard;
53
54#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
58pub struct GetExtendedAgentCardRequest {
59 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
68 pub metadata: BTreeMap<String, serde_json::Value>,
69}
70
71impl GetExtendedAgentCardRequest {
72 #[must_use]
74 pub const fn new() -> Self {
75 Self {
76 metadata: BTreeMap::new(),
77 }
78 }
79}
80
81#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
85#[serde(transparent)]
86pub struct GetExtendedAgentCardResponse(pub AgentCard);
87
88impl From<AgentCard> for GetExtendedAgentCardResponse {
89 fn from(card: AgentCard) -> Self {
90 Self(card)
91 }
92}
93
94impl std::ops::Deref for GetExtendedAgentCardResponse {
95 type Target = AgentCard;
96
97 fn deref(&self) -> &Self::Target {
98 &self.0
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::{GetExtendedAgentCardRequest, GetExtendedAgentCardResponse};
105 use crate::domain::a2a::agent_card::AgentCardBuilder;
106
107 type TestError = Box<dyn std::error::Error>;
108
109 #[test]
110 fn request_serialises_as_empty_object() -> Result<(), TestError> {
111 let request = GetExtendedAgentCardRequest::new();
112 let value = serde_json::to_value(&request)?;
113 let obj = value
114 .as_object()
115 .ok_or("a GetExtendedAgentCardRequest must serialise to a JSON object")?;
116 assert!(obj.is_empty(), "expected `{{}}`, got {value}");
117 Ok(())
118 }
119
120 #[test]
121 fn response_serialises_as_card_object() -> Result<(), TestError> {
122 let interface = crate::domain::a2a::agent_card::AgentInterface {
123 url: url::Url::parse("https://example.com/a2a/v1")
124 .map_err(|e| -> Box<dyn std::error::Error> { Box::new(e) })?,
125 protocol_binding: crate::domain::a2a::agent_card::JSONRPC.clone(),
126 protocol_version: crate::domain::a2a::A2aVersion::V1_0,
127 tenant: None,
128 };
129 let card = AgentCardBuilder::new()
130 .with_name("test-agent")
131 .with_description("An A2A test agent.")
132 .with_version("0.1.0")
133 .with_interface(interface)
134 .with_input_mode("text/plain")
135 .with_output_mode("text/plain")
136 .build()
137 .map_err(|e| -> Box<dyn std::error::Error> { Box::new(e) })?;
138 let response = GetExtendedAgentCardResponse::from(card);
139 let value = serde_json::to_value(&response)?;
140 let obj = value
141 .as_object()
142 .ok_or("a GetExtendedAgentCardResponse must serialise to a JSON object")?;
143 assert_eq!(
147 obj.get("name").and_then(serde_json::Value::as_str),
148 Some("test-agent")
149 );
150 Ok(())
151 }
152
153 #[test]
154 fn response_from_card_via_into_works() -> Result<(), TestError> {
155 let interface = crate::domain::a2a::agent_card::AgentInterface {
156 url: url::Url::parse("https://example.com/a2a/v1")
157 .map_err(|e| -> Box<dyn std::error::Error> { Box::new(e) })?,
158 protocol_binding: crate::domain::a2a::agent_card::JSONRPC.clone(),
159 protocol_version: crate::domain::a2a::A2aVersion::V1_0,
160 tenant: None,
161 };
162 let card = AgentCardBuilder::new()
163 .with_name("test-agent")
164 .with_description("An A2A test agent.")
165 .with_version("0.1.0")
166 .with_interface(interface)
167 .with_input_mode("text/plain")
168 .with_output_mode("text/plain")
169 .build()
170 .map_err(|e| -> Box<dyn std::error::Error> { Box::new(e) })?;
171 let response: GetExtendedAgentCardResponse = card.clone().into();
172 assert_eq!(response.0, card);
173 Ok(())
174 }
175}