1use thiserror::Error;
2
3#[derive(Error, Debug)]
5pub enum AgentError {
6 #[error("Configuration error: {0}")]
7 Config(String),
8
9 #[error("OpenAI API error: {0}")]
10 OpenAI(#[from] async_openai::error::OpenAIError),
11
12 #[error("Serialization error: {0}")]
13 Serialization(#[from] serde_json::Error),
14
15 #[error("Validation error: {0}")]
16 Validation(String),
17
18 #[error("Tool execution error: {0}")]
19 ToolExecution(String),
20
21 #[error("Tool not found: {0}")]
22 ToolNotFound(String),
23
24 #[error("Invalid function call: {0}")]
25 InvalidFunctionCall(String),
26
27 #[error("Timeout error: {0}")]
28 Timeout(String),
29
30 #[error("Maximum iterations exceeded: {0}")]
31 MaxIterations(usize),
32
33 #[error("Rate limit exceeded: retry after {retry_after}s")]
34 RateLimit { retry_after: u64 },
35
36 #[error("Unknown error: {0}")]
37 Unknown(String),
38}
39
40pub type Result<T> = std::result::Result<T, AgentError>;
42
43impl AgentError {
44 pub fn is_retryable(&self) -> bool {
46 match self {
47 AgentError::OpenAI(openai_err) => {
48 matches!(openai_err, async_openai::error::OpenAIError::ApiError(_))
49 }
50 AgentError::Validation(_) => true,
51 AgentError::RateLimit { .. } => true,
52 AgentError::Timeout(_) => true,
53 _ => false,
54 }
55 }
56
57 pub fn error_code(&self) -> &'static str {
59 match self {
60 AgentError::Config(_) => "CONFIG_ERROR",
61 AgentError::OpenAI(_) => "OPENAI_ERROR",
62 AgentError::Serialization(_) => "SERIALIZATION_ERROR",
63 AgentError::Validation(_) => "VALIDATION_ERROR",
64 AgentError::ToolExecution(_) => "TOOL_EXECUTION_ERROR",
65 AgentError::ToolNotFound(_) => "TOOL_NOT_FOUND",
66 AgentError::InvalidFunctionCall(_) => "INVALID_FUNCTION_CALL",
67 AgentError::Timeout(_) => "TIMEOUT_ERROR",
68 AgentError::MaxIterations(_) => "MAX_ITERATIONS_EXCEEDED",
69 AgentError::RateLimit { .. } => "RATE_LIMIT_ERROR",
70 AgentError::Unknown(_) => "UNKNOWN_ERROR",
71 }
72 }
73
74 pub fn to_error_payload(&self) -> serde_json::Value {
76 serde_json::json!({
77 "error": {
78 "code": self.error_code(),
79 "message": self.to_string(),
80 "retryable": self.is_retryable()
81 }
82 })
83 }
84}