Skip to main content

neuron_types/
error.rs

1//! Error types for all neuron crates.
2
3use std::time::Duration;
4
5/// Errors from LLM provider operations.
6#[derive(Debug, thiserror::Error)]
7pub enum ProviderError {
8    // Retryable errors
9    /// Network-level error (connection reset, DNS failure, etc.).
10    #[error("network error: {0}")]
11    Network(#[source] Box<dyn std::error::Error + Send + Sync>),
12    /// Rate limited by the provider.
13    #[error("rate limited, retry after {retry_after:?}")]
14    RateLimit {
15        /// Suggested retry delay, if provided by the API.
16        retry_after: Option<Duration>,
17    },
18    /// Model is still loading (cold start).
19    #[error("model loading: {0}")]
20    ModelLoading(String),
21    /// Request timed out.
22    #[error("timeout after {0:?}")]
23    Timeout(Duration),
24    /// Provider service is temporarily unavailable.
25    #[error("service unavailable: {0}")]
26    ServiceUnavailable(String),
27
28    // Terminal errors
29    /// Authentication/authorization failure.
30    #[error("authentication failed: {0}")]
31    Authentication(String),
32    /// Malformed or invalid request.
33    #[error("invalid request: {0}")]
34    InvalidRequest(String),
35    /// Requested model does not exist.
36    #[error("model not found: {0}")]
37    ModelNotFound(String),
38    /// Quota or resource limit exceeded.
39    #[error("insufficient resources: {0}")]
40    InsufficientResources(String),
41
42    // Catch-all
43    /// Error during streaming.
44    #[error("stream error: {0}")]
45    StreamError(String),
46    /// Any other provider error.
47    #[error(transparent)]
48    Other(Box<dyn std::error::Error + Send + Sync>),
49}
50
51impl ProviderError {
52    /// Whether this error is likely transient and the request can be retried.
53    #[must_use]
54    pub fn is_retryable(&self) -> bool {
55        matches!(
56            self,
57            Self::Network(_)
58                | Self::RateLimit { .. }
59                | Self::ModelLoading(_)
60                | Self::Timeout(_)
61                | Self::ServiceUnavailable(_)
62        )
63    }
64}
65
66/// Errors from tool operations.
67#[derive(Debug, thiserror::Error)]
68pub enum ToolError {
69    /// Tool not found in registry.
70    #[error("tool not found: {0}")]
71    NotFound(String),
72    /// Invalid input for the tool.
73    #[error("invalid input: {0}")]
74    InvalidInput(String),
75    /// Tool execution failed.
76    #[error("execution failed: {0}")]
77    ExecutionFailed(#[source] Box<dyn std::error::Error + Send + Sync>),
78    /// Permission denied for this tool call.
79    #[error("permission denied: {0}")]
80    PermissionDenied(String),
81    /// Tool execution was cancelled.
82    #[error("cancelled")]
83    Cancelled,
84}
85
86/// Errors from context management operations.
87#[derive(Debug, thiserror::Error)]
88pub enum ContextError {
89    /// Compaction strategy failed.
90    #[error("compaction failed: {0}")]
91    CompactionFailed(String),
92    /// Provider error during summarization.
93    #[error("provider error during summarization: {0}")]
94    Provider(#[from] ProviderError),
95}
96
97/// Errors from the agentic loop.
98#[derive(Debug, thiserror::Error)]
99pub enum LoopError {
100    /// Provider call failed.
101    #[error("provider error: {0}")]
102    Provider(#[from] ProviderError),
103    /// Tool execution failed.
104    #[error("tool error: {0}")]
105    Tool(#[from] ToolError),
106    /// Context management failed.
107    #[error("context error: {0}")]
108    Context(#[from] ContextError),
109    /// Loop exceeded the configured turn limit.
110    #[error("max turns reached ({0})")]
111    MaxTurns(usize),
112    /// An observability hook terminated the loop.
113    #[error("terminated by hook: {0}")]
114    HookTerminated(String),
115}
116
117/// Errors from durable execution operations.
118#[derive(Debug, thiserror::Error)]
119pub enum DurableError {
120    /// An activity (LLM call or tool execution) failed.
121    #[error("activity failed: {0}")]
122    ActivityFailed(String),
123    /// The workflow was cancelled.
124    #[error("workflow cancelled")]
125    Cancelled,
126    /// Timed out waiting for a signal.
127    #[error("signal timeout")]
128    SignalTimeout,
129    /// Continue-as-new was requested.
130    #[error("continue as new: {0}")]
131    ContinueAsNew(String),
132    /// Any other durable execution error.
133    #[error(transparent)]
134    Other(Box<dyn std::error::Error + Send + Sync>),
135}
136
137/// Errors from MCP operations.
138#[derive(Debug, thiserror::Error)]
139pub enum McpError {
140    /// Failed to connect to MCP server.
141    #[error("connection failed: {0}")]
142    Connection(String),
143    /// MCP initialization handshake failed.
144    #[error("initialization failed: {0}")]
145    Initialization(String),
146    /// MCP tool call failed.
147    #[error("tool call failed: {0}")]
148    ToolCall(String),
149    /// Transport-level error.
150    #[error("transport error: {0}")]
151    Transport(String),
152    /// Any other MCP error.
153    #[error(transparent)]
154    Other(Box<dyn std::error::Error + Send + Sync>),
155}
156
157/// Errors from observability hooks.
158#[derive(Debug, thiserror::Error)]
159pub enum HookError {
160    /// Hook execution failed.
161    #[error("hook failed: {0}")]
162    Failed(String),
163    /// Any other hook error.
164    #[error(transparent)]
165    Other(Box<dyn std::error::Error + Send + Sync>),
166}
167
168/// Errors from session storage operations.
169#[derive(Debug, thiserror::Error)]
170pub enum StorageError {
171    /// Session not found.
172    #[error("not found: {0}")]
173    NotFound(String),
174    /// Serialization/deserialization failed.
175    #[error("serialization error: {0}")]
176    Serialization(String),
177    /// I/O error during storage operation.
178    #[error("io error: {0}")]
179    Io(#[from] std::io::Error),
180    /// Any other storage error.
181    #[error(transparent)]
182    Other(Box<dyn std::error::Error + Send + Sync>),
183}
184
185/// Errors from sub-agent operations.
186#[derive(Debug, thiserror::Error)]
187pub enum SubAgentError {
188    /// Sub-agent not found by name.
189    #[error("sub-agent not found: {0}")]
190    NotFound(String),
191    /// Maximum nesting depth exceeded.
192    #[error("max depth exceeded: {0}")]
193    MaxDepthExceeded(usize),
194    /// The sub-agent's loop failed.
195    #[error("loop error: {0}")]
196    Loop(#[from] LoopError),
197}
198
199/// Errors from sandbox operations.
200#[derive(Debug, thiserror::Error)]
201pub enum SandboxError {
202    /// Tool execution failed within the sandbox.
203    #[error("execution failed: {0}")]
204    ExecutionFailed(String),
205    /// Sandbox setup or teardown failed.
206    #[error("sandbox error: {0}")]
207    SetupFailed(String),
208    /// Any other sandbox error.
209    #[error(transparent)]
210    Other(Box<dyn std::error::Error + Send + Sync>),
211}