Skip to main content

rs_adk/
error.rs

1//! Error types for the agent runtime.
2
3use rs_genai::session::SessionError;
4
5/// Errors that can occur during agent execution.
6#[derive(Debug, thiserror::Error)]
7pub enum AgentError {
8    /// A wire-level session error (WebSocket, auth, setup).
9    #[error("Session error: {0}")]
10    Session(#[from] SessionError),
11
12    /// A tool execution error.
13    #[error("Tool error: {0}")]
14    Tool(#[from] ToolError),
15
16    /// The requested agent was not found in the registry.
17    #[error("Unknown agent: {0}")]
18    UnknownAgent(String),
19
20    /// The agent requested a transfer to another agent.
21    #[error("Transfer requested to agent: {0}")]
22    TransferRequested(String),
23
24    /// An agent transfer was attempted but failed.
25    #[error("Agent transfer failed: {0}")]
26    TransferFailed(String),
27
28    /// The underlying session has been closed.
29    #[error("Agent session closed")]
30    SessionClosed,
31
32    /// The operation timed out.
33    #[error("Timeout")]
34    Timeout,
35
36    /// A configuration error.
37    #[error("Configuration error: {0}")]
38    Config(String),
39
40    /// A catch-all for other errors.
41    #[error("{0}")]
42    Other(String),
43}
44
45/// Errors that can occur during tool execution.
46#[derive(Debug, Clone, thiserror::Error)]
47pub enum ToolError {
48    /// The tool's execution logic failed.
49    #[error("Tool execution failed: {0}")]
50    ExecutionFailed(String),
51
52    /// No tool with this name is registered.
53    #[error("Tool not found: {0}")]
54    NotFound(String),
55
56    /// The arguments provided to the tool were invalid.
57    #[error("Invalid arguments: {0}")]
58    InvalidArgs(String),
59
60    /// The tool call was cancelled before completion.
61    #[error("Tool cancelled")]
62    Cancelled,
63
64    /// The tool call exceeded its timeout.
65    #[error("Tool execution timed out after {0:?}")]
66    Timeout(std::time::Duration),
67
68    /// A catch-all for other tool errors.
69    #[error("{0}")]
70    Other(String),
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76    use std::time::Duration;
77
78    #[test]
79    fn agent_error_display_messages() {
80        let err = AgentError::UnknownAgent("foo".into());
81        assert_eq!(err.to_string(), "Unknown agent: foo");
82
83        let err = AgentError::TransferRequested("bar".into());
84        assert_eq!(err.to_string(), "Transfer requested to agent: bar");
85
86        let err = AgentError::TransferFailed("baz".into());
87        assert_eq!(err.to_string(), "Agent transfer failed: baz");
88
89        let err = AgentError::SessionClosed;
90        assert_eq!(err.to_string(), "Agent session closed");
91
92        let err = AgentError::Timeout;
93        assert_eq!(err.to_string(), "Timeout");
94
95        let err = AgentError::Config("bad value".into());
96        assert_eq!(err.to_string(), "Configuration error: bad value");
97
98        let err = AgentError::Other("something".into());
99        assert_eq!(err.to_string(), "something");
100    }
101
102    #[test]
103    fn agent_error_from_session_error() {
104        use rs_genai::session::SessionError;
105        use rs_genai::session::WebSocketError;
106
107        let ws_err = SessionError::WebSocket(WebSocketError::ConnectionRefused("refused".into()));
108        let agent_err: AgentError = ws_err.into();
109        let msg = agent_err.to_string();
110        assert!(msg.contains("Session error"), "got: {msg}");
111    }
112
113    #[test]
114    fn agent_error_from_tool_error() {
115        let tool_err = ToolError::NotFound("my_tool".into());
116        let agent_err: AgentError = tool_err.into();
117        let msg = agent_err.to_string();
118        assert!(msg.contains("Tool error"), "got: {msg}");
119        assert!(msg.contains("my_tool"), "got: {msg}");
120    }
121
122    #[test]
123    fn tool_error_display_messages() {
124        assert_eq!(
125            ToolError::ExecutionFailed("boom".into()).to_string(),
126            "Tool execution failed: boom"
127        );
128        assert_eq!(
129            ToolError::NotFound("x".into()).to_string(),
130            "Tool not found: x"
131        );
132        assert_eq!(
133            ToolError::InvalidArgs("bad".into()).to_string(),
134            "Invalid arguments: bad"
135        );
136        assert_eq!(ToolError::Cancelled.to_string(), "Tool cancelled");
137        assert_eq!(ToolError::Other("misc".into()).to_string(), "misc");
138    }
139
140    #[test]
141    fn tool_error_timeout_shows_duration() {
142        let err = ToolError::Timeout(Duration::from_secs(5));
143        let msg = err.to_string();
144        assert!(msg.contains("5s"), "got: {msg}");
145        assert!(msg.contains("timed out"), "got: {msg}");
146    }
147
148    #[test]
149    fn tool_error_is_clone() {
150        let err = ToolError::ExecutionFailed("test".into());
151        let cloned = err.clone();
152        assert_eq!(err.to_string(), cloned.to_string());
153
154        let err2 = ToolError::Timeout(Duration::from_millis(100));
155        let cloned2 = err2.clone();
156        assert_eq!(err2.to_string(), cloned2.to_string());
157    }
158}