a2a_protocol_types/
responses.rs1use serde::{Deserialize, Serialize};
16
17use crate::agent_card::AgentCard;
18use crate::message::Message;
19use crate::task::Task;
20
21#[non_exhaustive]
29#[derive(Debug, Clone, Serialize, Deserialize)]
30#[serde(rename_all = "camelCase")]
31pub enum SendMessageResponse {
32 Task(Task),
34
35 Message(Message),
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize)]
43#[serde(rename_all = "camelCase")]
44pub struct TaskListResponse {
45 pub tasks: Vec<Task>,
47
48 #[serde(skip_serializing_if = "Option::is_none")]
50 pub next_page_token: Option<String>,
51
52 #[serde(skip_serializing_if = "Option::is_none")]
54 pub page_size: Option<u32>,
55
56 #[serde(skip_serializing_if = "Option::is_none")]
58 pub total_size: Option<u32>,
59}
60
61impl TaskListResponse {
62 #[must_use]
64 pub const fn new(tasks: Vec<Task>) -> Self {
65 Self {
66 tasks,
67 next_page_token: None,
68 page_size: None,
69 total_size: None,
70 }
71 }
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
78#[serde(rename_all = "camelCase")]
79pub struct ListPushConfigsResponse {
80 pub configs: Vec<crate::push::TaskPushNotificationConfig>,
82
83 #[serde(skip_serializing_if = "Option::is_none")]
85 pub next_page_token: Option<String>,
86}
87
88pub type AuthenticatedExtendedCardResponse = AgentCard;
95
96#[cfg(test)]
99mod tests {
100 use super::*;
101 use crate::message::{MessageId, MessageRole, Part};
102 use crate::task::{ContextId, TaskId, TaskState, TaskStatus};
103
104 fn make_task() -> Task {
105 Task {
106 id: TaskId::new("t1"),
107 context_id: ContextId::new("c1"),
108 status: TaskStatus::new(TaskState::Completed),
109 history: None,
110 artifacts: None,
111 metadata: None,
112 }
113 }
114
115 fn make_message() -> Message {
116 Message {
117 id: MessageId::new("m1"),
118 role: MessageRole::Agent,
119 parts: vec![Part::text("hi")],
120 task_id: None,
121 context_id: None,
122 reference_task_ids: None,
123 extensions: None,
124 metadata: None,
125 }
126 }
127
128 #[test]
129 fn send_message_response_task_variant() {
130 let resp = SendMessageResponse::Task(make_task());
131 let json = serde_json::to_string(&resp).expect("serialize");
132 assert!(
133 !json.contains("\"kind\""),
134 "v1.0 should not have kind: {json}"
135 );
136
137 let back: SendMessageResponse = serde_json::from_str(&json).expect("deserialize");
138 assert!(matches!(back, SendMessageResponse::Task(_)));
139 }
140
141 #[test]
142 fn send_message_response_message_variant() {
143 let resp = SendMessageResponse::Message(make_message());
144 let json = serde_json::to_string(&resp).expect("serialize");
145 assert!(
146 !json.contains("\"kind\""),
147 "v1.0 should not have kind: {json}"
148 );
149
150 let back: SendMessageResponse = serde_json::from_str(&json).expect("deserialize");
151 assert!(matches!(back, SendMessageResponse::Message(_)));
152 }
153
154 #[test]
155 fn task_list_response_roundtrip() {
156 let resp = TaskListResponse {
157 tasks: vec![make_task()],
158 next_page_token: Some("cursor-abc".into()),
159 page_size: Some(10),
160 total_size: Some(1),
161 };
162 let json = serde_json::to_string(&resp).expect("serialize");
163 assert!(json.contains("\"nextPageToken\":\"cursor-abc\""));
164
165 let back: TaskListResponse = serde_json::from_str(&json).expect("deserialize");
166 assert_eq!(back.tasks.len(), 1);
167 assert_eq!(back.next_page_token.as_deref(), Some("cursor-abc"));
168 }
169
170 #[test]
171 fn task_list_response_no_token_omitted() {
172 let resp = TaskListResponse::new(vec![]);
173 let json = serde_json::to_string(&resp).expect("serialize");
174 assert!(
175 !json.contains("\"nextPageToken\""),
176 "token should be absent: {json}"
177 );
178 }
179}