1use crate::jsonrpc::JsonRpcError;
7
8#[derive(Debug, thiserror::Error)]
16#[non_exhaustive]
17pub enum A2aError {
18 #[error("HTTP request failed: {0}")]
20 Http(#[from] reqwest::Error),
21
22 #[error("JSON serialization/deserialization failed: {0}")]
24 Json(#[from] serde_json::Error),
25
26 #[error("JSON-RPC error {code}: {message}")]
32 JsonRpc { code: i32, message: String },
33
34 #[error("agent discovery failed for {url}: {reason}")]
37 Discovery { url: String, reason: String },
38
39 #[error("SSE stream error: {0}")]
41 Stream(String),
42
43 #[error("server error: {0}")]
45 Server(String),
46
47 #[error("security policy violation: {0}")]
53 Security(String),
54
55 #[error("operation timed out after {0:?}")]
57 Timeout(std::time::Duration),
58}
59
60impl From<JsonRpcError> for A2aError {
61 fn from(e: JsonRpcError) -> Self {
62 Self::JsonRpc {
63 code: e.code,
64 message: e.message,
65 }
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72 use std::assert_matches;
73
74 #[test]
75 fn from_jsonrpc_error() {
76 let rpc_err = JsonRpcError {
77 code: -32001,
78 message: "task not found".into(),
79 data: None,
80 };
81 let err: A2aError = rpc_err.into();
82 match err {
83 A2aError::JsonRpc { code, message } => {
84 assert_eq!(code, -32001);
85 assert_eq!(message, "task not found");
86 }
87 _ => panic!("expected JsonRpc variant"),
88 }
89 }
90
91 #[test]
92 fn error_display() {
93 let err = A2aError::Discovery {
94 url: "http://example.com".into(),
95 reason: "connection refused".into(),
96 };
97 assert_eq!(
98 err.to_string(),
99 "agent discovery failed for http://example.com: connection refused"
100 );
101
102 let err = A2aError::Stream("unexpected EOF".into());
103 assert_eq!(err.to_string(), "SSE stream error: unexpected EOF");
104 }
105
106 #[test]
107 fn security_error_display() {
108 let err = A2aError::Security("TLS required but endpoint uses HTTP".into());
109 assert_eq!(
110 err.to_string(),
111 "security policy violation: TLS required but endpoint uses HTTP"
112 );
113 }
114
115 #[test]
116 fn from_serde_json_error() {
117 let json_err = serde_json::from_str::<serde_json::Value>("invalid").unwrap_err();
118 let err: A2aError = json_err.into();
119 assert_matches!(err, A2aError::Json(_));
120 }
121}