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
73 #[test]
74 fn from_jsonrpc_error() {
75 let rpc_err = JsonRpcError {
76 code: -32001,
77 message: "task not found".into(),
78 data: None,
79 };
80 let err: A2aError = rpc_err.into();
81 match err {
82 A2aError::JsonRpc { code, message } => {
83 assert_eq!(code, -32001);
84 assert_eq!(message, "task not found");
85 }
86 _ => panic!("expected JsonRpc variant"),
87 }
88 }
89
90 #[test]
91 fn error_display() {
92 let err = A2aError::Discovery {
93 url: "http://example.com".into(),
94 reason: "connection refused".into(),
95 };
96 assert_eq!(
97 err.to_string(),
98 "agent discovery failed for http://example.com: connection refused"
99 );
100
101 let err = A2aError::Stream("unexpected EOF".into());
102 assert_eq!(err.to_string(), "SSE stream error: unexpected EOF");
103 }
104
105 #[test]
106 fn security_error_display() {
107 let err = A2aError::Security("TLS required but endpoint uses HTTP".into());
108 assert_eq!(
109 err.to_string(),
110 "security policy violation: TLS required but endpoint uses HTTP"
111 );
112 }
113
114 #[test]
115 fn from_serde_json_error() {
116 let json_err = serde_json::from_str::<serde_json::Value>("invalid").unwrap_err();
117 let err: A2aError = json_err.into();
118 assert!(matches!(err, A2aError::Json(_)));
119 }
120}