1use crate::jsonrpc::JsonRpcError;
5
6#[derive(Debug, thiserror::Error)]
7pub enum A2aError {
8 #[error("HTTP request failed: {0}")]
9 Http(#[from] reqwest::Error),
10
11 #[error("JSON serialization/deserialization failed: {0}")]
12 Json(#[from] serde_json::Error),
13
14 #[error("JSON-RPC error {code}: {message}")]
15 JsonRpc { code: i32, message: String },
16
17 #[error("agent discovery failed for {url}: {reason}")]
18 Discovery { url: String, reason: String },
19
20 #[error("SSE stream error: {0}")]
21 Stream(String),
22
23 #[error("server error: {0}")]
24 Server(String),
25
26 #[error("security policy violation: {0}")]
27 Security(String),
28}
29
30impl From<JsonRpcError> for A2aError {
31 fn from(e: JsonRpcError) -> Self {
32 Self::JsonRpc {
33 code: e.code,
34 message: e.message,
35 }
36 }
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42
43 #[test]
44 fn from_jsonrpc_error() {
45 let rpc_err = JsonRpcError {
46 code: -32001,
47 message: "task not found".into(),
48 data: None,
49 };
50 let err: A2aError = rpc_err.into();
51 match err {
52 A2aError::JsonRpc { code, message } => {
53 assert_eq!(code, -32001);
54 assert_eq!(message, "task not found");
55 }
56 _ => panic!("expected JsonRpc variant"),
57 }
58 }
59
60 #[test]
61 fn error_display() {
62 let err = A2aError::Discovery {
63 url: "http://example.com".into(),
64 reason: "connection refused".into(),
65 };
66 assert_eq!(
67 err.to_string(),
68 "agent discovery failed for http://example.com: connection refused"
69 );
70
71 let err = A2aError::Stream("unexpected EOF".into());
72 assert_eq!(err.to_string(), "SSE stream error: unexpected EOF");
73 }
74
75 #[test]
76 fn security_error_display() {
77 let err = A2aError::Security("TLS required but endpoint uses HTTP".into());
78 assert_eq!(
79 err.to_string(),
80 "security policy violation: TLS required but endpoint uses HTTP"
81 );
82 }
83
84 #[test]
85 fn from_serde_json_error() {
86 let json_err = serde_json::from_str::<serde_json::Value>("invalid").unwrap_err();
87 let err: A2aError = json_err.into();
88 assert!(matches!(err, A2aError::Json(_)));
89 }
90}