1use thiserror::Error;
7
8#[derive(Debug, Error)]
10pub enum ReactError {
11 #[error("LLM Error: {0}")]
13 Llm(Box<LlmError>),
14 #[error("Tool Error: {0}")]
16 Tool(#[from] ToolError),
17 #[error("Parse Error: {0}")]
19 Parse(#[from] ParseError),
20 #[error("Agent Error: {0}")]
22 Agent(#[from] AgentError),
23 #[error("Config Error: {0}")]
25 Config(Box<ConfigError>),
26 #[cfg(feature = "mcp")]
28 #[error("MCP Error: {0}")]
29 Mcp(#[from] McpError),
30 #[error("Memory Error: {0}")]
32 Memory(Box<MemoryError>),
33 #[error("Sandbox Error: {0}")]
35 Sandbox(#[from] SandboxError),
36 #[cfg(feature = "channels")]
38 #[error("Channel Error: {0}")]
39 Channel(#[from] ChannelError),
40 #[error("IO Error: {0}")]
42 Io(#[from] std::io::Error),
43 #[error("{0}")]
45 Other(String),
46}
47
48#[derive(Debug, Error)]
50pub enum MemoryError {
51 #[error("IO error: {0}")]
53 IoError(String),
54 #[error("Serialization error: {0}")]
56 SerializationError(String),
57 #[error("Memory '{0}' not found")]
59 NotFound(String),
60 #[error("Unsupported operation: {0}")]
62 Unsupported(String),
63}
64
65impl From<std::io::Error> for MemoryError {
66 fn from(err: std::io::Error) -> Self {
67 MemoryError::IoError(err.to_string())
68 }
69}
70
71#[derive(Debug, Error)]
73pub enum LlmError {
74 #[error("Network error: {0}")]
76 NetworkError(String),
77 #[error("API error (status {status}): {message}")]
79 ApiError {
80 status: u16,
82 message: String,
84 },
85 #[error("Invalid response: {0}")]
87 InvalidResponse(String),
88 #[error("Empty response from LLM")]
90 EmptyResponse,
91 #[error("Serialization error: {0}")]
93 SerializationError(String),
94}
95
96#[derive(Debug, Error)]
98pub enum ToolError {
99 #[error("Tool '{0}' not found")]
101 NotFound(String),
102 #[error("Missing parameter: {0}")]
104 MissingParameter(String),
105 #[error("Invalid parameter '{name}': {message}")]
107 InvalidParameter {
108 name: String,
110 message: String,
112 },
113 #[error("Tool '{tool}' execution failed: {message}")]
115 ExecutionFailed {
116 tool: String,
118 message: String,
120 },
121 #[error("Tool '{0}' execution timed out")]
123 Timeout(String),
124 #[error("Invalid path: {path} ({reason})")]
126 InvalidPath {
127 path: String,
129 reason: String,
131 },
132 #[error("Access denied: {path} ({reason})")]
134 AccessDenied {
135 path: String,
137 reason: String,
139 },
140 #[error("File too large: {size} bytes (max: {max} bytes)")]
142 FileTooLarge {
143 size: u64,
145 max: u64,
147 },
148}
149
150#[derive(Debug, Error)]
152pub enum ParseError {
153 #[error("Invalid Thought: {0}")]
155 InvalidThought(String),
156 #[error("Invalid Action: {0}")]
158 InvalidAction(String),
159 #[error("Invalid Action Input: {0}")]
161 InvalidActionInput(String),
162 #[error("JSON parse error: {0}")]
164 JsonError(#[from] serde_json::Error),
165 #[error("Unexpected format: {0}")]
167 UnexpectedFormat(String),
168}
169
170#[derive(Debug, Error)]
172pub enum AgentError {
173 #[error("Max iterations exceeded: {0}")]
175 MaxIterationsExceeded(usize),
176 #[error("No tools available")]
178 NoToolsAvailable,
179 #[error("Initialization failed: {0}")]
181 InitializationFailed(String),
182 #[error("Execution interrupted")]
184 Interrupted,
185 #[error("No response from LLM (model: {model}, agent: {agent})")]
187 NoResponse {
188 model: String,
190 agent: String,
192 },
193 #[error("Token limit exceeded")]
195 TokenLimitExceeded,
196 #[error("Permission denied: {0}")]
198 PermissionDenied(String),
199 #[error("Hook error: {0}")]
201 HookError(String),
202 #[error("Subagent error: {0}")]
204 SubagentError(String),
205 #[error("Timeout: {0}")]
207 Timeout(String),
208 #[error("Context limit exceeded: {0}")]
210 ContextLimitExceeded(String),
211}
212
213#[cfg(feature = "mcp")]
215#[derive(Debug, Error)]
216pub enum McpError {
217 #[error("Connection failed: {0}")]
219 ConnectionFailed(String),
220 #[error("Initialization failed: {0}")]
222 InitializationFailed(String),
223 #[error("Protocol error: {0}")]
225 ProtocolError(String),
226 #[error("Tool call failed: {0}")]
228 ToolCallFailed(String),
229 #[error("MCP transport closed unexpectedly")]
231 TransportClosed,
232}
233
234#[derive(Debug, Error)]
236pub enum SandboxError {
237 #[error("Sandbox unavailable: {0}")]
239 Unavailable(String),
240 #[error("Sandbox start failed: {0}")]
242 StartFailed(String),
243 #[error("Sandbox timeout: {0}")]
245 Timeout(String),
246 #[error("Resource exceeded: {0}")]
248 ResourceExceeded(String),
249 #[error("Permission denied: {0}")]
251 PermissionDenied(String),
252 #[error("IO error: {0}")]
254 IoError(String),
255}
256
257#[cfg(feature = "channels")]
259#[derive(Debug, Error)]
260pub enum ChannelError {
261 #[error("Network error: {0}")]
263 NetworkError(String),
264 #[error("API error (status {status}): {message}")]
266 ApiError {
267 status: u16,
269 message: String,
271 },
272 #[error("Auth error: {0}")]
274 AuthError(String),
275 #[error("Connection error: {0}")]
277 ConnectionError(String),
278 #[error("Send error: {0}")]
280 SendError(String),
281 #[error("Invalid config: {0}")]
283 InvalidConfig(String),
284 #[error("Channel error: {0}")]
286 Other(String),
287}
288
289#[derive(Debug, Error)]
291pub enum ConfigError {
292 #[error("Failed to parse environment variable: {0}")]
294 EnvParseError(String),
295 #[error("Model '{0}' missing required config: {1}")]
297 MissingConfig(String, String),
298 #[error("Invalid environment variable format: {0}")]
300 EnvFormatError(String),
301 #[error("Model '{0}' mismatched config error: {1}")]
303 UnMatchConfigError(String, String),
304 #[error("No configuration found for model: {0}")]
306 NotFindModelError(String),
307 #[error("Config file error: {0}")]
309 ConfigFileError(String),
310}
311
312impl From<LlmError> for ReactError {
315 fn from(err: LlmError) -> Self {
316 ReactError::Llm(Box::new(err))
317 }
318}
319
320impl From<ConfigError> for ReactError {
321 fn from(err: ConfigError) -> Self {
322 ReactError::Config(Box::new(err))
323 }
324}
325
326impl From<MemoryError> for ReactError {
327 fn from(err: MemoryError) -> Self {
328 ReactError::Memory(Box::new(err))
329 }
330}
331
332impl From<serde_json::Error> for ReactError {
333 fn from(err: serde_json::Error) -> Self {
334 ReactError::Parse(ParseError::JsonError(err))
335 }
336}
337
338#[cfg(feature = "reqwest")]
339impl From<reqwest::Error> for ReactError {
340 fn from(err: reqwest::Error) -> Self {
341 if err.is_timeout() {
342 ReactError::Llm(Box::new(LlmError::NetworkError(
343 "Request timeout".to_string(),
344 )))
345 } else if err.is_connect() {
346 ReactError::Llm(Box::new(LlmError::NetworkError(format!(
347 "Connection failed: {}",
348 err
349 ))))
350 } else {
351 ReactError::Llm(Box::new(LlmError::NetworkError(err.to_string())))
352 }
353 }
354}
355
356pub type Result<T> = std::result::Result<T, ReactError>;