Skip to main content

zeph_a2a/
error.rs

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