Skip to main content

a2a_rs/domain/protocols/
json_rpc.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4use crate::domain::error::A2AError;
5
6/// Standard JSON-RPC 2.0 message
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct JSONRPCMessage {
9    pub jsonrpc: String,
10    #[serde(skip_serializing_if = "Option::is_none")]
11    pub id: Option<Value>,
12}
13
14impl Default for JSONRPCMessage {
15    fn default() -> Self {
16        Self {
17            jsonrpc: "2.0".to_string(),
18            id: None,
19        }
20    }
21}
22
23/// JSON-RPC 2.0 error object
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct JSONRPCError {
26    pub code: i32,
27    pub message: String,
28    #[serde(skip_serializing_if = "Option::is_none")]
29    pub data: Option<Value>,
30}
31
32impl From<A2AError> for JSONRPCError {
33    fn from(error: A2AError) -> Self {
34        let value = error.to_jsonrpc_error();
35
36        // Extract the fields from the JSON value
37        if let Value::Object(map) = value {
38            let code = map
39                .get("code")
40                .and_then(|v| v.as_i64())
41                .map(|v| i32::try_from(v).unwrap_or(-32603))
42                .unwrap_or(-32603); // Internal error code as fallback
43
44            let message = map
45                .get("message")
46                .and_then(|v| v.as_str())
47                .unwrap_or("Internal error")
48                .to_string();
49
50            let data = map.get("data").cloned();
51
52            Self {
53                code,
54                message,
55                data,
56            }
57        } else {
58            // Fallback to internal error if the JSON structure is unexpected
59            Self {
60                code: -32603,
61                message: "Internal error".to_string(),
62                data: None,
63            }
64        }
65    }
66}
67
68/// JSON-RPC 2.0 request
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct JSONRPCRequest {
71    pub jsonrpc: String,
72    #[serde(skip_serializing_if = "Option::is_none")]
73    pub id: Option<Value>,
74    pub method: String,
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub params: Option<Value>,
77}
78
79impl JSONRPCRequest {
80    /// Create a new JSON-RPC request with the given method and parameters
81    pub fn new(method: String, params: Option<Value>) -> Self {
82        Self {
83            jsonrpc: "2.0".to_string(),
84            id: Some(Value::String(uuid::Uuid::new_v4().to_string())),
85            method,
86            params,
87        }
88    }
89
90    /// Create a new JSON-RPC request with the given method, parameters, and ID
91    pub fn with_id(method: String, params: Option<Value>, id: Value) -> Self {
92        Self {
93            jsonrpc: "2.0".to_string(),
94            id: Some(id),
95            method,
96            params,
97        }
98    }
99}
100
101/// JSON-RPC 2.0 response
102#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct JSONRPCResponse {
104    pub jsonrpc: String,
105    #[serde(skip_serializing_if = "Option::is_none")]
106    pub id: Option<Value>,
107    #[serde(skip_serializing_if = "Option::is_none")]
108    pub result: Option<Value>,
109    #[serde(skip_serializing_if = "Option::is_none")]
110    pub error: Option<JSONRPCError>,
111}
112
113impl JSONRPCResponse {
114    /// Create a successful JSON-RPC response
115    pub fn success(id: Option<Value>, result: Value) -> Self {
116        Self {
117            jsonrpc: "2.0".to_string(),
118            id,
119            result: Some(result),
120            error: None,
121        }
122    }
123
124    /// Create an error JSON-RPC response
125    pub fn error(id: Option<Value>, error: JSONRPCError) -> Self {
126        Self {
127            jsonrpc: "2.0".to_string(),
128            id,
129            result: None,
130            error: Some(error),
131        }
132    }
133}
134
135/// JSON-RPC 2.0 notification (request without id)
136#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct JSONRPCNotification {
138    pub jsonrpc: String,
139    pub method: String,
140    #[serde(skip_serializing_if = "Option::is_none")]
141    pub params: Option<Value>,
142}
143
144impl JSONRPCNotification {
145    /// Create a new JSON-RPC notification
146    pub fn new(method: String, params: Option<Value>) -> Self {
147        Self {
148            jsonrpc: "2.0".to_string(),
149            method,
150            params,
151        }
152    }
153}