Skip to main content

systemprompt_agent/models/a2a/protocol/
requests.rs

1use super::push_notification::{
2    DeleteTaskPushNotificationConfigRequest, GetTaskPushNotificationConfigRequest,
3    ListTaskPushNotificationConfigRequest, PushNotificationConfig,
4    SetTaskPushNotificationConfigRequest, TaskResubscriptionRequest,
5};
6use crate::models::a2a::jsonrpc::{JsonRpcResponse, RequestId};
7use crate::models::a2a::{AgentCard, Task, TaskState};
8use serde::{Deserialize, Serialize};
9use systemprompt_identifiers::TaskId;
10use systemprompt_models::a2a::methods;
11
12#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
13pub struct MessageSendParams {
14    pub message: crate::models::a2a::Message,
15    pub configuration: Option<MessageSendConfiguration>,
16    pub metadata: Option<serde_json::Map<String, serde_json::Value>>,
17}
18
19#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
20#[serde(rename_all = "camelCase")]
21pub struct MessageSendConfiguration {
22    pub accepted_output_modes: Option<Vec<String>>,
23    pub history_length: Option<u32>,
24    pub push_notification_config: Option<PushNotificationConfig>,
25    pub blocking: Option<bool>,
26}
27
28#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
29pub struct TaskQueryParams {
30    pub id: TaskId,
31    pub history_length: Option<u32>,
32}
33
34#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
35pub struct TaskIdParams {
36    pub id: TaskId,
37}
38
39#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
40pub struct A2aRequest {
41    pub method: String,
42    pub params: serde_json::Value,
43}
44
45#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
46#[serde(untagged)]
47pub enum A2aResponse {
48    SendMessage(SendMessageResponse),
49    GetTask(GetTaskResponse),
50    CancelTask(CancelTaskResponse),
51    GetAuthenticatedExtendedCard(GetAuthenticatedExtendedCardResponse),
52    SendStreamingMessage(SendStreamingMessageResponse),
53}
54
55pub type SendMessageResponse = JsonRpcResponse<Task>;
56pub type GetTaskResponse = JsonRpcResponse<Task>;
57pub type CancelTaskResponse = JsonRpcResponse<Task>;
58pub type GetAuthenticatedExtendedCardResponse = JsonRpcResponse<AgentCard>;
59pub type SendStreamingMessageResponse = JsonRpcResponse<Task>;
60
61#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
62pub struct A2aJsonRpcRequest {
63    pub jsonrpc: String,
64    pub method: String,
65    pub params: serde_json::Value,
66    pub id: RequestId,
67}
68
69impl A2aJsonRpcRequest {
70    pub fn parse_request(&self) -> Result<A2aRequestParams, A2aParseError> {
71        match self.method.as_str() {
72            methods::SEND_MESSAGE => {
73                let params: MessageSendParams = serde_json::from_value(self.params.clone())
74                    .map_err(|e| A2aParseError::InvalidParams {
75                        method: self.method.clone(),
76                        error: e.to_string(),
77                    })?;
78                Ok(A2aRequestParams::SendMessage(params))
79            },
80            methods::GET_TASK => {
81                let params: TaskQueryParams =
82                    serde_json::from_value(self.params.clone()).map_err(|e| {
83                        A2aParseError::InvalidParams {
84                            method: self.method.clone(),
85                            error: e.to_string(),
86                        }
87                    })?;
88                Ok(A2aRequestParams::GetTask(params))
89            },
90            methods::CANCEL_TASK => {
91                let params: TaskIdParams =
92                    serde_json::from_value(self.params.clone()).map_err(|e| {
93                        A2aParseError::InvalidParams {
94                            method: self.method.clone(),
95                            error: e.to_string(),
96                        }
97                    })?;
98                Ok(A2aRequestParams::CancelTask(params))
99            },
100            methods::GET_EXTENDED_AGENT_CARD => {
101                let params: serde_json::Value = serde_json::from_value(self.params.clone())
102                    .map_err(|e| A2aParseError::InvalidParams {
103                        method: self.method.clone(),
104                        error: e.to_string(),
105                    })?;
106                Ok(A2aRequestParams::GetAuthenticatedExtendedCard(params))
107            },
108            methods::SEND_STREAMING_MESSAGE => {
109                let params: MessageSendParams = serde_json::from_value(self.params.clone())
110                    .map_err(|e| A2aParseError::InvalidParams {
111                        method: self.method.clone(),
112                        error: e.to_string(),
113                    })?;
114                Ok(A2aRequestParams::SendStreamingMessage(params))
115            },
116            methods::SUBSCRIBE_TO_TASK => {
117                let params: TaskResubscriptionRequest = serde_json::from_value(self.params.clone())
118                    .map_err(|e| A2aParseError::InvalidParams {
119                        method: self.method.clone(),
120                        error: e.to_string(),
121                    })?;
122                Ok(A2aRequestParams::TaskResubscription(params))
123            },
124            methods::CREATE_TASK_PUSH_NOTIFICATION_CONFIG => {
125                let params: SetTaskPushNotificationConfigRequest =
126                    serde_json::from_value(self.params.clone()).map_err(|e| {
127                        A2aParseError::InvalidParams {
128                            method: self.method.clone(),
129                            error: e.to_string(),
130                        }
131                    })?;
132                Ok(A2aRequestParams::SetTaskPushNotificationConfig(params))
133            },
134            methods::GET_TASK_PUSH_NOTIFICATION_CONFIG => {
135                let params: GetTaskPushNotificationConfigRequest =
136                    serde_json::from_value(self.params.clone()).map_err(|e| {
137                        A2aParseError::InvalidParams {
138                            method: self.method.clone(),
139                            error: e.to_string(),
140                        }
141                    })?;
142                Ok(A2aRequestParams::GetTaskPushNotificationConfig(params))
143            },
144            methods::LIST_TASK_PUSH_NOTIFICATION_CONFIGS => {
145                let params: ListTaskPushNotificationConfigRequest =
146                    serde_json::from_value(self.params.clone()).map_err(|e| {
147                        A2aParseError::InvalidParams {
148                            method: self.method.clone(),
149                            error: e.to_string(),
150                        }
151                    })?;
152                Ok(A2aRequestParams::ListTaskPushNotificationConfig(params))
153            },
154            methods::DELETE_TASK_PUSH_NOTIFICATION_CONFIG => {
155                let params: DeleteTaskPushNotificationConfigRequest =
156                    serde_json::from_value(self.params.clone()).map_err(|e| {
157                        A2aParseError::InvalidParams {
158                            method: self.method.clone(),
159                            error: e.to_string(),
160                        }
161                    })?;
162                Ok(A2aRequestParams::DeleteTaskPushNotificationConfig(params))
163            },
164            _ => Err(A2aParseError::UnsupportedMethod {
165                method: self.method.clone(),
166            }),
167        }
168    }
169}
170
171#[derive(Debug, Clone, PartialEq)]
172pub enum A2aRequestParams {
173    SendMessage(MessageSendParams),
174    GetTask(TaskQueryParams),
175    CancelTask(TaskIdParams),
176    GetAuthenticatedExtendedCard(serde_json::Value),
177    SendStreamingMessage(MessageSendParams),
178    TaskResubscription(TaskResubscriptionRequest),
179    SetTaskPushNotificationConfig(SetTaskPushNotificationConfigRequest),
180    GetTaskPushNotificationConfig(GetTaskPushNotificationConfigRequest),
181    ListTaskPushNotificationConfig(ListTaskPushNotificationConfigRequest),
182    DeleteTaskPushNotificationConfig(DeleteTaskPushNotificationConfigRequest),
183}
184
185#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
186pub enum A2aParseError {
187    #[error("Unsupported method: {method}")]
188    UnsupportedMethod { method: String },
189
190    #[error("Invalid parameters for method '{method}': {error}")]
191    InvalidParams { method: String, error: String },
192}
193
194impl A2aResponse {
195    pub fn send_message(task: Task, id: RequestId) -> Self {
196        Self::SendMessage(JsonRpcResponse {
197            jsonrpc: "2.0".to_string(),
198            id,
199            result: Some(task),
200            error: None,
201        })
202    }
203
204    pub fn get_task(task: Task, id: RequestId) -> Self {
205        Self::GetTask(JsonRpcResponse {
206            jsonrpc: "2.0".to_string(),
207            id,
208            result: Some(task),
209            error: None,
210        })
211    }
212
213    pub fn cancel_task(task: Task, id: RequestId) -> Self {
214        Self::CancelTask(JsonRpcResponse {
215            jsonrpc: "2.0".to_string(),
216            id,
217            result: Some(task),
218            error: None,
219        })
220    }
221}
222
223#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
224pub struct TaskNotFoundError {
225    pub task_id: TaskId,
226    pub message: String,
227    pub code: i32,
228    pub data: serde_json::Value,
229}
230
231#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
232pub struct TaskNotCancelableError {
233    pub task_id: TaskId,
234    pub state: TaskState,
235    pub message: String,
236    pub code: i32,
237    pub data: serde_json::Value,
238}
239
240#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
241pub struct UnsupportedOperationError {
242    pub operation: String,
243    pub message: String,
244    pub code: i32,
245    pub data: serde_json::Value,
246}