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)]
70#[serde(rename_all = "camelCase")]
71pub struct MessageSendParams {
72 #[serde(skip_serializing_if = "Option::is_none")]
74 pub tenant: Option<String>,
75
76 pub message: Message,
78
79 #[serde(skip_serializing_if = "Option::is_none")]
81 pub configuration: Option<SendMessageConfiguration>,
82
83 #[serde(skip_serializing_if = "Option::is_none")]
85 pub metadata: Option<serde_json::Value>,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize)]
92#[serde(rename_all = "camelCase")]
93pub struct TaskQueryParams {
94 #[serde(skip_serializing_if = "Option::is_none")]
96 pub tenant: Option<String>,
97
98 pub id: String,
100
101 #[serde(skip_serializing_if = "Option::is_none")]
103 pub history_length: Option<u32>,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize)]
112#[serde(rename_all = "camelCase")]
113pub struct TaskIdParams {
114 #[serde(skip_serializing_if = "Option::is_none")]
116 pub tenant: Option<String>,
117
118 pub id: String,
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
126#[serde(rename_all = "camelCase")]
127pub struct CancelTaskParams {
128 #[serde(skip_serializing_if = "Option::is_none")]
130 pub tenant: Option<String>,
131
132 pub id: String,
134
135 #[serde(skip_serializing_if = "Option::is_none")]
137 pub metadata: Option<serde_json::Value>,
138}
139
140#[derive(Debug, Clone, Default, Serialize, Deserialize)]
147#[serde(rename_all = "camelCase")]
148pub struct ListTasksParams {
149 #[serde(skip_serializing_if = "Option::is_none")]
151 pub tenant: Option<String>,
152
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub context_id: Option<String>,
156
157 #[serde(skip_serializing_if = "Option::is_none")]
159 pub status: Option<TaskState>,
160
161 #[serde(skip_serializing_if = "Option::is_none")]
165 pub page_size: Option<u32>,
166
167 #[serde(skip_serializing_if = "Option::is_none")]
169 pub page_token: Option<String>,
170
171 #[serde(skip_serializing_if = "Option::is_none")]
173 pub status_timestamp_after: Option<String>,
174
175 #[serde(skip_serializing_if = "Option::is_none")]
177 pub include_artifacts: Option<bool>,
178
179 #[serde(skip_serializing_if = "Option::is_none")]
181 pub history_length: Option<u32>,
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize)]
188#[serde(rename_all = "camelCase")]
189pub struct GetPushConfigParams {
190 #[serde(skip_serializing_if = "Option::is_none")]
192 pub tenant: Option<String>,
193
194 pub task_id: String,
196
197 pub id: String,
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize)]
205#[serde(rename_all = "camelCase")]
206pub struct DeletePushConfigParams {
207 #[serde(skip_serializing_if = "Option::is_none")]
209 pub tenant: Option<String>,
210
211 pub task_id: String,
213
214 pub id: String,
216}
217
218#[derive(Debug, Clone, Serialize, Deserialize)]
222#[serde(rename_all = "camelCase")]
223pub struct ListPushConfigsParams {
224 #[serde(skip_serializing_if = "Option::is_none")]
226 pub tenant: Option<String>,
227
228 pub task_id: String,
230
231 #[serde(skip_serializing_if = "Option::is_none")]
233 pub page_size: Option<u32>,
234
235 #[serde(skip_serializing_if = "Option::is_none")]
237 pub page_token: Option<String>,
238}
239
240#[derive(Debug, Clone, Serialize, Deserialize)]
244#[serde(rename_all = "camelCase")]
245pub struct GetExtendedAgentCardParams {
246 #[serde(skip_serializing_if = "Option::is_none")]
248 pub tenant: Option<String>,
249}
250
251#[cfg(test)]
254mod tests {
255 use super::*;
256 use crate::message::{MessageId, MessageRole, Part};
257
258 fn make_message() -> Message {
259 Message {
260 id: MessageId::new("msg-1"),
261 role: MessageRole::User,
262 parts: vec![Part::text("hello")],
263 task_id: None,
264 context_id: None,
265 reference_task_ids: None,
266 extensions: None,
267 metadata: None,
268 }
269 }
270
271 #[test]
272 fn message_send_params_roundtrip() {
273 let params = MessageSendParams {
274 tenant: None,
275 message: make_message(),
276 configuration: Some(SendMessageConfiguration {
277 accepted_output_modes: vec!["text/plain".into()],
278 task_push_notification_config: None,
279 history_length: Some(10),
280 return_immediately: None,
281 }),
282 metadata: None,
283 };
284 let json = serde_json::to_string(¶ms).expect("serialize");
285 let back: MessageSendParams = serde_json::from_str(&json).expect("deserialize");
286 assert_eq!(back.message.id, MessageId::new("msg-1"));
287 }
288
289 #[test]
290 fn list_tasks_params_empty_roundtrip() {
291 let params = ListTasksParams {
292 tenant: None,
293 context_id: None,
294 status: None,
295 page_size: None,
296 page_token: None,
297 status_timestamp_after: None,
298 include_artifacts: None,
299 history_length: None,
300 };
301 let json = serde_json::to_string(¶ms).expect("serialize");
302 assert_eq!(json, "{}", "empty params should serialize to {{}}");
304 }
305
306 #[test]
307 fn task_query_params_roundtrip() {
308 let params = TaskQueryParams {
309 tenant: None,
310 id: "task-1".into(),
311 history_length: Some(5),
312 };
313 let json = serde_json::to_string(¶ms).expect("serialize");
314 let back: TaskQueryParams = serde_json::from_str(&json).expect("deserialize");
315 assert_eq!(back.id, "task-1");
316 assert_eq!(back.history_length, Some(5));
317 }
318
319 #[test]
320 fn cancel_task_params_roundtrip() {
321 let params = CancelTaskParams {
322 tenant: Some("my-tenant".into()),
323 id: "task-1".into(),
324 metadata: Some(serde_json::json!({"reason": "no longer needed"})),
325 };
326 let json = serde_json::to_string(¶ms).expect("serialize");
327 let back: CancelTaskParams = serde_json::from_str(&json).expect("deserialize");
328 assert_eq!(back.id, "task-1");
329 assert_eq!(back.tenant.as_deref(), Some("my-tenant"));
330 assert!(back.metadata.is_some());
331 }
332
333 #[test]
334 fn wire_format_list_tasks_history_length() {
335 let params = ListTasksParams {
336 tenant: None,
337 context_id: None,
338 status: None,
339 page_size: None,
340 page_token: None,
341 status_timestamp_after: None,
342 include_artifacts: None,
343 history_length: Some(10),
344 };
345 let json = serde_json::to_string(¶ms).unwrap();
346 assert!(
347 json.contains("\"historyLength\":10"),
348 "historyLength must appear: {json}"
349 );
350
351 let back: ListTasksParams = serde_json::from_str(&json).unwrap();
352 assert_eq!(back.history_length, Some(10));
353 }
354
355 #[test]
356 fn wire_format_list_push_configs_params() {
357 let params = super::ListPushConfigsParams {
358 tenant: None,
359 task_id: "t1".into(),
360 page_size: Some(20),
361 page_token: None,
362 };
363 let json = serde_json::to_string(¶ms).unwrap();
364 assert!(json.contains("\"taskId\":\"t1\""));
365 assert!(json.contains("\"pageSize\":20"));
366 }
367}