Skip to main content

systemprompt_agent/models/a2a/protocol/
requests.rs

1//! A2A JSON-RPC request and response envelopes.
2//!
3//! Defines the typed parameter shapes for each A2A method, the
4//! [`A2aJsonRpcRequest`] wire envelope and its
5//! [`A2aJsonRpcRequest::parse_request`] dispatcher into [`A2aRequestParams`],
6//! the [`A2aResponse`] result variants, and the protocol error payloads.
7//!
8//! Copyright (c) systemprompt.io — Business Source License 1.1.
9//! See <https://systemprompt.io> for licensing details.
10
11use crate::models::a2a::jsonrpc::{JsonRpcResponse, RequestId};
12use crate::models::a2a::{AgentCard, Task, TaskState};
13use serde::{Deserialize, Serialize};
14use systemprompt_identifiers::TaskId;
15use systemprompt_models::a2a::methods;
16
17#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
18pub struct MessageSendParams {
19    pub message: crate::models::a2a::Message,
20    pub configuration: Option<MessageSendConfiguration>,
21    pub metadata: Option<serde_json::Map<String, serde_json::Value>>,
22}
23
24#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
25#[serde(rename_all = "camelCase")]
26pub struct MessageSendConfiguration {
27    pub accepted_output_modes: Option<Vec<String>>,
28    pub history_length: Option<u32>,
29    pub blocking: Option<bool>,
30}
31
32#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
33pub struct TaskQueryParams {
34    pub id: TaskId,
35    pub history_length: Option<u32>,
36}
37
38#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
39pub struct TaskIdParams {
40    pub id: TaskId,
41}
42
43#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
44pub struct A2aRequest {
45    pub method: String,
46    pub params: serde_json::Value,
47}
48
49#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
50#[serde(untagged)]
51pub enum A2aResponse {
52    SendMessage(SendMessageResponse),
53    GetTask(GetTaskResponse),
54    CancelTask(CancelTaskResponse),
55    GetAuthenticatedExtendedCard(GetAuthenticatedExtendedCardResponse),
56    SendStreamingMessage(SendStreamingMessageResponse),
57}
58
59pub type SendMessageResponse = JsonRpcResponse<Task>;
60pub type GetTaskResponse = JsonRpcResponse<Task>;
61pub type CancelTaskResponse = JsonRpcResponse<Task>;
62pub type GetAuthenticatedExtendedCardResponse = JsonRpcResponse<AgentCard>;
63pub type SendStreamingMessageResponse = JsonRpcResponse<Task>;
64
65#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
66pub struct A2aJsonRpcRequest {
67    pub jsonrpc: String,
68    pub method: String,
69    pub params: serde_json::Value,
70    pub id: RequestId,
71}
72
73impl A2aJsonRpcRequest {
74    pub fn parse_request(&self) -> Result<A2aRequestParams, A2aParseError> {
75        match self.method.as_str() {
76            methods::SEND_MESSAGE => Ok(A2aRequestParams::SendMessage(self.parse_params()?)),
77            methods::GET_TASK => Ok(A2aRequestParams::GetTask(self.parse_params()?)),
78            methods::CANCEL_TASK => Ok(A2aRequestParams::CancelTask(self.parse_params()?)),
79            methods::GET_EXTENDED_AGENT_CARD => Ok(A2aRequestParams::GetAuthenticatedExtendedCard(
80                self.parse_params()?,
81            )),
82            methods::SEND_STREAMING_MESSAGE => {
83                Ok(A2aRequestParams::SendStreamingMessage(self.parse_params()?))
84            },
85            methods::SUBSCRIBE_TO_TASK => {
86                Ok(A2aRequestParams::TaskResubscription(self.parse_params()?))
87            },
88            _ => Err(A2aParseError::UnsupportedMethod {
89                method: self.method.clone(),
90            }),
91        }
92    }
93
94    fn parse_params<T: serde::de::DeserializeOwned>(&self) -> Result<T, A2aParseError> {
95        serde_json::from_value(self.params.clone()).map_err(|e| A2aParseError::InvalidParams {
96            method: self.method.clone(),
97            error: e.to_string(),
98        })
99    }
100}
101
102#[derive(Debug, Clone, PartialEq)]
103pub enum A2aRequestParams {
104    SendMessage(MessageSendParams),
105    GetTask(TaskQueryParams),
106    CancelTask(TaskIdParams),
107    GetAuthenticatedExtendedCard(serde_json::Value),
108    SendStreamingMessage(MessageSendParams),
109    TaskResubscription(TaskResubscriptionRequest),
110}
111
112#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
113pub struct TaskResubscriptionRequest {
114    pub task_id: TaskId,
115}
116
117#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
118pub enum A2aParseError {
119    #[error("Unsupported method: {method}")]
120    UnsupportedMethod { method: String },
121
122    #[error("Invalid parameters for method '{method}': {error}")]
123    InvalidParams { method: String, error: String },
124}
125
126impl A2aResponse {
127    pub fn send_message(task: Task, id: RequestId) -> Self {
128        Self::SendMessage(JsonRpcResponse {
129            jsonrpc: "2.0".to_owned(),
130            id,
131            result: Some(task),
132            error: None,
133        })
134    }
135
136    pub fn get_task(task: Task, id: RequestId) -> Self {
137        Self::GetTask(JsonRpcResponse {
138            jsonrpc: "2.0".to_owned(),
139            id,
140            result: Some(task),
141            error: None,
142        })
143    }
144
145    pub fn cancel_task(task: Task, id: RequestId) -> Self {
146        Self::CancelTask(JsonRpcResponse {
147            jsonrpc: "2.0".to_owned(),
148            id,
149            result: Some(task),
150            error: None,
151        })
152    }
153}
154
155#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
156pub struct TaskNotFoundError {
157    pub task_id: TaskId,
158    pub message: String,
159    pub code: i32,
160    pub data: serde_json::Value,
161}
162
163#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
164pub struct TaskNotCancelableError {
165    pub task_id: TaskId,
166    pub state: TaskState,
167    pub message: String,
168    pub code: i32,
169    pub data: serde_json::Value,
170}
171
172#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
173pub struct UnsupportedOperationError {
174    pub operation: String,
175    pub message: String,
176    pub code: i32,
177    pub data: serde_json::Value,
178}