adk_server/a2a/
jsonrpc.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4/// JSON-RPC 2.0 Request
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct JsonRpcRequest {
7    pub jsonrpc: String,
8    pub method: String,
9    #[serde(default)]
10    pub params: Option<Value>,
11    pub id: Option<Value>,
12}
13
14/// JSON-RPC 2.0 Response
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct JsonRpcResponse {
17    pub jsonrpc: String,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub result: Option<Value>,
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub error: Option<JsonRpcError>,
22    pub id: Option<Value>,
23}
24
25impl JsonRpcResponse {
26    pub fn success(id: Option<Value>, result: Value) -> Self {
27        Self { jsonrpc: "2.0".to_string(), result: Some(result), error: None, id }
28    }
29
30    pub fn error(id: Option<Value>, error: JsonRpcError) -> Self {
31        Self { jsonrpc: "2.0".to_string(), result: None, error: Some(error), id }
32    }
33}
34
35/// JSON-RPC 2.0 Error
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct JsonRpcError {
38    pub code: i32,
39    pub message: String,
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub data: Option<Value>,
42}
43
44impl JsonRpcError {
45    pub fn parse_error(message: impl Into<String>) -> Self {
46        Self { code: -32700, message: message.into(), data: None }
47    }
48
49    pub fn invalid_request(message: impl Into<String>) -> Self {
50        Self { code: -32600, message: message.into(), data: None }
51    }
52
53    pub fn method_not_found(method: &str) -> Self {
54        Self { code: -32601, message: format!("Method not found: {}", method), data: None }
55    }
56
57    pub fn invalid_params(message: impl Into<String>) -> Self {
58        Self { code: -32602, message: message.into(), data: None }
59    }
60
61    pub fn internal_error(message: impl Into<String>) -> Self {
62        Self { code: -32603, message: message.into(), data: None }
63    }
64
65    /// Create an internal error with sanitized message for production.
66    /// Logs the detailed error but returns a generic message to the client.
67    pub fn internal_error_sanitized(error: &dyn std::fmt::Display, expose_details: bool) -> Self {
68        if expose_details {
69            Self::internal_error(error.to_string())
70        } else {
71            // Log the actual error for debugging
72            tracing::error!(error = %error, "Internal server error");
73            Self::internal_error("Internal server error")
74        }
75    }
76}
77
78/// A2A Protocol Methods
79pub mod methods {
80    pub const MESSAGE_SEND: &str = "message/send";
81    pub const MESSAGE_SEND_STREAM: &str = "message/stream";
82    pub const TASKS_GET: &str = "tasks/get";
83    pub const TASKS_CANCEL: &str = "tasks/cancel";
84}
85
86/// Parameters for message/send method
87#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct MessageSendParams {
89    pub message: super::Message,
90    #[serde(skip_serializing_if = "Option::is_none")]
91    pub config: Option<MessageSendConfig>,
92}
93
94/// Configuration for message send
95#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct MessageSendConfig {
97    #[serde(skip_serializing_if = "Option::is_none", rename = "acceptedOutputModes")]
98    pub accepted_output_modes: Option<Vec<String>>,
99    #[serde(skip_serializing_if = "Option::is_none")]
100    pub blocking: Option<bool>,
101    #[serde(skip_serializing_if = "Option::is_none", rename = "historyLength")]
102    pub history_length: Option<u32>,
103}
104
105/// Parameters for tasks/get method
106#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct TasksGetParams {
108    #[serde(rename = "taskId")]
109    pub task_id: String,
110    #[serde(skip_serializing_if = "Option::is_none", rename = "historyLength")]
111    pub history_length: Option<u32>,
112}
113
114/// Parameters for tasks/cancel method
115#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct TasksCancelParams {
117    #[serde(rename = "taskId")]
118    pub task_id: String,
119}
120
121/// Task representation returned by A2A
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct Task {
124    pub id: String,
125    #[serde(skip_serializing_if = "Option::is_none", rename = "contextId")]
126    pub context_id: Option<String>,
127    pub status: super::TaskStatus,
128    #[serde(skip_serializing_if = "Option::is_none")]
129    pub artifacts: Option<Vec<super::Artifact>>,
130    #[serde(skip_serializing_if = "Option::is_none")]
131    pub history: Option<Vec<super::Message>>,
132}
133
134#[cfg(test)]
135mod tests {
136    use super::*;
137
138    #[test]
139    fn test_jsonrpc_request_parse() {
140        let json = r#"{"jsonrpc":"2.0","method":"message/send","params":{},"id":1}"#;
141        let req: JsonRpcRequest = serde_json::from_str(json).unwrap();
142        assert_eq!(req.method, "message/send");
143        assert_eq!(req.id, Some(Value::Number(1.into())));
144    }
145
146    #[test]
147    fn test_jsonrpc_response_success() {
148        let resp =
149            JsonRpcResponse::success(Some(Value::Number(1.into())), Value::String("ok".into()));
150        assert!(resp.result.is_some());
151        assert!(resp.error.is_none());
152    }
153
154    #[test]
155    fn test_jsonrpc_response_error() {
156        let resp = JsonRpcResponse::error(
157            Some(Value::Number(1.into())),
158            JsonRpcError::method_not_found("unknown"),
159        );
160        assert!(resp.result.is_none());
161        assert!(resp.error.is_some());
162        assert_eq!(resp.error.unwrap().code, -32601);
163    }
164}