1use serde::{Deserialize, Serialize};
24
25use crate::message::Message;
26use crate::push::TaskPushNotificationConfig;
27use crate::task::TaskState;
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
33#[serde(rename_all = "camelCase")]
34pub struct SendMessageConfiguration {
35 pub accepted_output_modes: Vec<String>,
37
38 #[serde(skip_serializing_if = "Option::is_none")]
40 pub task_push_notification_config: Option<TaskPushNotificationConfig>,
41
42 #[serde(skip_serializing_if = "Option::is_none")]
44 pub history_length: Option<u32>,
45
46 #[serde(skip_serializing_if = "Option::is_none")]
49 pub return_immediately: Option<bool>,
50}
51
52impl Default for SendMessageConfiguration {
53 fn default() -> Self {
54 Self {
55 accepted_output_modes: vec!["text/plain".to_owned()],
56 task_push_notification_config: None,
57 history_length: None,
58 return_immediately: None,
59 }
60 }
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
67#[serde(rename_all = "camelCase")]
68pub struct MessageSendParams {
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub tenant: Option<String>,
72
73 pub message: Message,
75
76 #[serde(skip_serializing_if = "Option::is_none")]
81 pub context_id: Option<String>,
82
83 #[serde(skip_serializing_if = "Option::is_none")]
85 pub configuration: Option<SendMessageConfiguration>,
86
87 #[serde(skip_serializing_if = "Option::is_none")]
89 pub metadata: Option<serde_json::Value>,
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
96#[serde(rename_all = "camelCase")]
97pub struct TaskQueryParams {
98 #[serde(skip_serializing_if = "Option::is_none")]
100 pub tenant: Option<String>,
101
102 pub id: String,
104
105 #[serde(skip_serializing_if = "Option::is_none")]
107 pub history_length: Option<u32>,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize)]
116#[serde(rename_all = "camelCase")]
117pub struct TaskIdParams {
118 #[serde(skip_serializing_if = "Option::is_none")]
120 pub tenant: Option<String>,
121
122 pub id: String,
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize)]
130#[serde(rename_all = "camelCase")]
131pub struct CancelTaskParams {
132 #[serde(skip_serializing_if = "Option::is_none")]
134 pub tenant: Option<String>,
135
136 pub id: String,
138
139 #[serde(skip_serializing_if = "Option::is_none")]
141 pub metadata: Option<serde_json::Value>,
142}
143
144#[derive(Debug, Clone, Default, Serialize, Deserialize)]
151#[serde(rename_all = "camelCase")]
152pub struct ListTasksParams {
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub tenant: Option<String>,
156
157 #[serde(skip_serializing_if = "Option::is_none")]
159 pub context_id: Option<String>,
160
161 #[serde(skip_serializing_if = "Option::is_none")]
163 pub status: Option<TaskState>,
164
165 #[serde(skip_serializing_if = "Option::is_none")]
169 pub page_size: Option<u32>,
170
171 #[serde(skip_serializing_if = "Option::is_none")]
173 pub page_token: Option<String>,
174
175 #[serde(skip_serializing_if = "Option::is_none")]
177 pub status_timestamp_after: Option<String>,
178
179 #[serde(skip_serializing_if = "Option::is_none")]
181 pub include_artifacts: Option<bool>,
182
183 #[serde(skip_serializing_if = "Option::is_none")]
185 pub history_length: Option<u32>,
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize)]
192#[serde(rename_all = "camelCase")]
193pub struct GetPushConfigParams {
194 #[serde(skip_serializing_if = "Option::is_none")]
196 pub tenant: Option<String>,
197
198 pub task_id: String,
200
201 pub id: String,
203}
204
205#[derive(Debug, Clone, Serialize, Deserialize)]
209#[serde(rename_all = "camelCase")]
210pub struct DeletePushConfigParams {
211 #[serde(skip_serializing_if = "Option::is_none")]
213 pub tenant: Option<String>,
214
215 pub task_id: String,
217
218 pub id: String,
220}
221
222#[derive(Debug, Clone, Serialize, Deserialize)]
226#[serde(rename_all = "camelCase")]
227pub struct ListPushConfigsParams {
228 #[serde(skip_serializing_if = "Option::is_none")]
230 pub tenant: Option<String>,
231
232 pub task_id: String,
234
235 #[serde(skip_serializing_if = "Option::is_none")]
237 pub page_size: Option<u32>,
238
239 #[serde(skip_serializing_if = "Option::is_none")]
241 pub page_token: Option<String>,
242}
243
244#[derive(Debug, Clone, Serialize, Deserialize)]
248#[serde(rename_all = "camelCase")]
249pub struct GetExtendedAgentCardParams {
250 #[serde(skip_serializing_if = "Option::is_none")]
252 pub tenant: Option<String>,
253}
254
255#[cfg(test)]
258mod tests {
259 use super::*;
260 use crate::message::{MessageId, MessageRole, Part};
261
262 fn make_message() -> Message {
263 Message {
264 id: MessageId::new("msg-1"),
265 role: MessageRole::User,
266 parts: vec![Part::text("hello")],
267 task_id: None,
268 context_id: None,
269 reference_task_ids: None,
270 extensions: None,
271 metadata: None,
272 }
273 }
274
275 #[test]
276 fn message_send_params_roundtrip() {
277 let params = MessageSendParams {
278 tenant: None,
279 context_id: None,
280 message: make_message(),
281 configuration: Some(SendMessageConfiguration {
282 accepted_output_modes: vec!["text/plain".into()],
283 task_push_notification_config: None,
284 history_length: Some(10),
285 return_immediately: None,
286 }),
287 metadata: None,
288 };
289 let json = serde_json::to_string(¶ms).expect("serialize");
290 let back: MessageSendParams = serde_json::from_str(&json).expect("deserialize");
291 assert_eq!(back.message.id, MessageId::new("msg-1"));
292 }
293
294 #[test]
295 fn list_tasks_params_empty_roundtrip() {
296 let params = ListTasksParams {
297 tenant: None,
298 context_id: None,
299 status: None,
300 page_size: None,
301 page_token: None,
302 status_timestamp_after: None,
303 include_artifacts: None,
304 history_length: None,
305 };
306 let json = serde_json::to_string(¶ms).expect("serialize");
307 assert_eq!(json, "{}", "empty params should serialize to {{}}");
309 }
310
311 #[test]
312 fn task_query_params_roundtrip() {
313 let params = TaskQueryParams {
314 tenant: None,
315 id: "task-1".into(),
316 history_length: Some(5),
317 };
318 let json = serde_json::to_string(¶ms).expect("serialize");
319 let back: TaskQueryParams = serde_json::from_str(&json).expect("deserialize");
320 assert_eq!(back.id, "task-1");
321 assert_eq!(back.history_length, Some(5));
322 }
323
324 #[test]
325 fn cancel_task_params_roundtrip() {
326 let params = CancelTaskParams {
327 tenant: Some("my-tenant".into()),
328 id: "task-1".into(),
329 metadata: Some(serde_json::json!({"reason": "no longer needed"})),
330 };
331 let json = serde_json::to_string(¶ms).expect("serialize");
332 let back: CancelTaskParams = serde_json::from_str(&json).expect("deserialize");
333 assert_eq!(back.id, "task-1");
334 assert_eq!(back.tenant.as_deref(), Some("my-tenant"));
335 assert!(back.metadata.is_some());
336 }
337
338 #[test]
339 fn wire_format_list_tasks_history_length() {
340 let params = ListTasksParams {
341 tenant: None,
342 context_id: None,
343 status: None,
344 page_size: None,
345 page_token: None,
346 status_timestamp_after: None,
347 include_artifacts: None,
348 history_length: Some(10),
349 };
350 let json = serde_json::to_string(¶ms).unwrap();
351 assert!(
352 json.contains("\"historyLength\":10"),
353 "historyLength must appear: {json}"
354 );
355
356 let back: ListTasksParams = serde_json::from_str(&json).unwrap();
357 assert_eq!(back.history_length, Some(10));
358 }
359
360 #[test]
361 fn wire_format_list_push_configs_params() {
362 let params = super::ListPushConfigsParams {
363 tenant: None,
364 task_id: "t1".into(),
365 page_size: Some(20),
366 page_token: None,
367 };
368 let json = serde_json::to_string(¶ms).unwrap();
369 assert!(json.contains("\"taskId\":\"t1\""));
370 assert!(json.contains("\"pageSize\":20"));
371 }
372}