1use serde::{Deserialize, Serialize};
22
23use crate::message::Message;
24use crate::push::TaskPushNotificationConfig;
25use crate::task::TaskState;
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(rename_all = "camelCase")]
32pub struct SendMessageConfiguration {
33 pub accepted_output_modes: Vec<String>,
35
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub task_push_notification_config: Option<TaskPushNotificationConfig>,
39
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub history_length: Option<u32>,
43
44 #[serde(skip_serializing_if = "Option::is_none")]
47 pub return_immediately: Option<bool>,
48}
49
50impl Default for SendMessageConfiguration {
51 fn default() -> Self {
52 Self {
53 accepted_output_modes: vec!["text/plain".to_owned()],
54 task_push_notification_config: None,
55 history_length: None,
56 return_immediately: None,
57 }
58 }
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
65#[serde(rename_all = "camelCase")]
66pub struct MessageSendParams {
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub tenant: Option<String>,
70
71 pub message: Message,
73
74 #[serde(skip_serializing_if = "Option::is_none")]
76 pub configuration: Option<SendMessageConfiguration>,
77
78 #[serde(skip_serializing_if = "Option::is_none")]
80 pub metadata: Option<serde_json::Value>,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
87#[serde(rename_all = "camelCase")]
88pub struct TaskQueryParams {
89 #[serde(skip_serializing_if = "Option::is_none")]
91 pub tenant: Option<String>,
92
93 pub id: String,
95
96 #[serde(skip_serializing_if = "Option::is_none")]
98 pub history_length: Option<u32>,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
107#[serde(rename_all = "camelCase")]
108pub struct TaskIdParams {
109 #[serde(skip_serializing_if = "Option::is_none")]
111 pub tenant: Option<String>,
112
113 pub id: String,
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize)]
121#[serde(rename_all = "camelCase")]
122pub struct CancelTaskParams {
123 #[serde(skip_serializing_if = "Option::is_none")]
125 pub tenant: Option<String>,
126
127 pub id: String,
129
130 #[serde(skip_serializing_if = "Option::is_none")]
132 pub metadata: Option<serde_json::Value>,
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
142#[serde(rename_all = "camelCase")]
143pub struct ListTasksParams {
144 #[serde(skip_serializing_if = "Option::is_none")]
146 pub tenant: Option<String>,
147
148 #[serde(skip_serializing_if = "Option::is_none")]
150 pub context_id: Option<String>,
151
152 #[serde(skip_serializing_if = "Option::is_none")]
154 pub status: Option<TaskState>,
155
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub page_size: Option<u32>,
159
160 #[serde(skip_serializing_if = "Option::is_none")]
162 pub page_token: Option<String>,
163
164 #[serde(skip_serializing_if = "Option::is_none")]
166 pub status_timestamp_after: Option<String>,
167
168 #[serde(skip_serializing_if = "Option::is_none")]
170 pub include_artifacts: Option<bool>,
171
172 #[serde(skip_serializing_if = "Option::is_none")]
174 pub history_length: Option<u32>,
175}
176
177#[derive(Debug, Clone, Serialize, Deserialize)]
181#[serde(rename_all = "camelCase")]
182pub struct GetPushConfigParams {
183 #[serde(skip_serializing_if = "Option::is_none")]
185 pub tenant: Option<String>,
186
187 pub task_id: String,
189
190 pub id: String,
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize)]
198#[serde(rename_all = "camelCase")]
199pub struct DeletePushConfigParams {
200 #[serde(skip_serializing_if = "Option::is_none")]
202 pub tenant: Option<String>,
203
204 pub task_id: String,
206
207 pub id: String,
209}
210
211#[derive(Debug, Clone, Serialize, Deserialize)]
215#[serde(rename_all = "camelCase")]
216pub struct ListPushConfigsParams {
217 #[serde(skip_serializing_if = "Option::is_none")]
219 pub tenant: Option<String>,
220
221 pub task_id: String,
223
224 #[serde(skip_serializing_if = "Option::is_none")]
226 pub page_size: Option<u32>,
227
228 #[serde(skip_serializing_if = "Option::is_none")]
230 pub page_token: Option<String>,
231}
232
233#[derive(Debug, Clone, Serialize, Deserialize)]
237#[serde(rename_all = "camelCase")]
238pub struct GetExtendedAgentCardParams {
239 #[serde(skip_serializing_if = "Option::is_none")]
241 pub tenant: Option<String>,
242}
243
244#[cfg(test)]
247mod tests {
248 use super::*;
249 use crate::message::{MessageId, MessageRole, Part};
250
251 fn make_message() -> Message {
252 Message {
253 id: MessageId::new("msg-1"),
254 role: MessageRole::User,
255 parts: vec![Part::text("hello")],
256 task_id: None,
257 context_id: None,
258 reference_task_ids: None,
259 extensions: None,
260 metadata: None,
261 }
262 }
263
264 #[test]
265 fn message_send_params_roundtrip() {
266 let params = MessageSendParams {
267 tenant: None,
268 message: make_message(),
269 configuration: Some(SendMessageConfiguration {
270 accepted_output_modes: vec!["text/plain".into()],
271 task_push_notification_config: None,
272 history_length: Some(10),
273 return_immediately: None,
274 }),
275 metadata: None,
276 };
277 let json = serde_json::to_string(¶ms).expect("serialize");
278 let back: MessageSendParams = serde_json::from_str(&json).expect("deserialize");
279 assert_eq!(back.message.id, MessageId::new("msg-1"));
280 }
281
282 #[test]
283 fn list_tasks_params_empty_roundtrip() {
284 let params = ListTasksParams {
285 tenant: None,
286 context_id: None,
287 status: None,
288 page_size: None,
289 page_token: None,
290 status_timestamp_after: None,
291 include_artifacts: None,
292 history_length: None,
293 };
294 let json = serde_json::to_string(¶ms).expect("serialize");
295 assert_eq!(json, "{}", "empty params should serialize to {{}}");
297 }
298
299 #[test]
300 fn task_query_params_roundtrip() {
301 let params = TaskQueryParams {
302 tenant: None,
303 id: "task-1".into(),
304 history_length: Some(5),
305 };
306 let json = serde_json::to_string(¶ms).expect("serialize");
307 let back: TaskQueryParams = serde_json::from_str(&json).expect("deserialize");
308 assert_eq!(back.id, "task-1");
309 assert_eq!(back.history_length, Some(5));
310 }
311
312 #[test]
313 fn cancel_task_params_roundtrip() {
314 let params = CancelTaskParams {
315 tenant: Some("my-tenant".into()),
316 id: "task-1".into(),
317 metadata: Some(serde_json::json!({"reason": "no longer needed"})),
318 };
319 let json = serde_json::to_string(¶ms).expect("serialize");
320 let back: CancelTaskParams = serde_json::from_str(&json).expect("deserialize");
321 assert_eq!(back.id, "task-1");
322 assert_eq!(back.tenant.as_deref(), Some("my-tenant"));
323 assert!(back.metadata.is_some());
324 }
325
326 #[test]
327 fn wire_format_list_tasks_history_length() {
328 let params = ListTasksParams {
329 tenant: None,
330 context_id: None,
331 status: None,
332 page_size: None,
333 page_token: None,
334 status_timestamp_after: None,
335 include_artifacts: None,
336 history_length: Some(10),
337 };
338 let json = serde_json::to_string(¶ms).unwrap();
339 assert!(
340 json.contains("\"historyLength\":10"),
341 "historyLength must appear: {json}"
342 );
343
344 let back: ListTasksParams = serde_json::from_str(&json).unwrap();
345 assert_eq!(back.history_length, Some(10));
346 }
347
348 #[test]
349 fn wire_format_list_push_configs_params() {
350 let params = super::ListPushConfigsParams {
351 tenant: None,
352 task_id: "t1".into(),
353 page_size: Some(20),
354 page_token: None,
355 };
356 let json = serde_json::to_string(¶ms).unwrap();
357 assert!(json.contains("\"taskId\":\"t1\""));
358 assert!(json.contains("\"pageSize\":20"));
359 }
360}