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    /// Tool requests the model to retry with the given hint.
85    ///
86    /// The hint is returned to the model as an error tool result so it can
87    /// self-correct and call the tool again with adjusted arguments.
88    #[error("model retry requested: {0}")]
89    ModelRetry(String),
90}
91
92/// Errors from context management operations.
93#[derive(Debug, thiserror::Error)]
94pub enum ContextError {
95    /// Compaction strategy failed.
96    #[error("compaction failed: {0}")]
97    CompactionFailed(String),
98    /// Provider error during summarization.
99    #[error("provider error during summarization: {0}")]
100    Provider(#[from] ProviderError),
101}
102
103/// Errors from the agentic loop.
104#[derive(Debug, thiserror::Error)]
105pub enum LoopError {
106    /// Provider call failed.
107    #[error("provider error: {0}")]
108    Provider(#[from] ProviderError),
109    /// Tool execution failed.
110    #[error("tool error: {0}")]
111    Tool(#[from] ToolError),
112    /// Context management failed.
113    #[error("context error: {0}")]
114    Context(#[from] ContextError),
115    /// Loop exceeded the configured turn limit.
116    #[error("max turns reached ({0})")]
117    MaxTurns(usize),
118    /// An observability hook terminated the loop.
119    #[error("terminated by hook: {0}")]
120    HookTerminated(String),
121    /// The loop was cancelled via the cancellation token.
122    #[error("cancelled")]
123    Cancelled,
124    /// A usage limit was exceeded (token budget, request limit, or tool call limit).
125    #[error("usage limit exceeded: {0}")]
126    UsageLimitExceeded(String),
127}
128
129/// Errors from durable execution operations.
130#[derive(Debug, thiserror::Error)]
131pub enum DurableError {
132    /// An activity (LLM call or tool execution) failed.
133    #[error("activity failed: {0}")]
134    ActivityFailed(String),
135    /// The workflow was cancelled.
136    #[error("workflow cancelled")]
137    Cancelled,
138    /// Timed out waiting for a signal.
139    #[error("signal timeout")]
140    SignalTimeout,
141    /// Continue-as-new was requested.
142    #[error("continue as new: {0}")]
143    ContinueAsNew(String),
144    /// Any other durable execution error.
145    #[error(transparent)]
146    Other(Box<dyn std::error::Error + Send + Sync>),
147}
148
149/// Errors from MCP operations.
150#[derive(Debug, thiserror::Error)]
151pub enum McpError {
152    /// Failed to connect to MCP server.
153    #[error("connection failed: {0}")]
154    Connection(String),
155    /// MCP initialization handshake failed.
156    #[error("initialization failed: {0}")]
157    Initialization(String),
158    /// MCP tool call failed.
159    #[error("tool call failed: {0}")]
160    ToolCall(String),
161    /// Transport-level error.
162    #[error("transport error: {0}")]
163    Transport(String),
164    /// Any other MCP error.
165    #[error(transparent)]
166    Other(Box<dyn std::error::Error + Send + Sync>),
167}
168
169/// Errors from observability hooks.
170#[derive(Debug, thiserror::Error)]
171pub enum HookError {
172    /// Hook execution failed.
173    #[error("hook failed: {0}")]
174    Failed(String),
175    /// Any other hook error.
176    #[error(transparent)]
177    Other(Box<dyn std::error::Error + Send + Sync>),
178}
179
180/// Errors from embedding provider operations.
181#[derive(Debug, thiserror::Error)]
182pub enum EmbeddingError {
183    /// Authentication/authorization failure.
184    #[error("authentication failed: {0}")]
185    Authentication(String),
186    /// Rate limited by the provider.
187    #[error("rate limited, retry after {retry_after:?}")]
188    RateLimit {
189        /// Suggested retry delay, if provided by the API.
190        retry_after: Option<std::time::Duration>,
191    },
192    /// Malformed or invalid request.
193    #[error("invalid request: {0}")]
194    InvalidRequest(String),
195    /// Network-level error (connection reset, DNS failure, etc.).
196    #[error("network error: {0}")]
197    Network(#[source] Box<dyn std::error::Error + Send + Sync>),
198    /// Any other embedding error.
199    #[error(transparent)]
200    Other(Box<dyn std::error::Error + Send + Sync>),
201}
202
203impl EmbeddingError {
204    /// Whether this error is likely transient and the request can be retried.
205    #[must_use]
206    pub fn is_retryable(&self) -> bool {
207        matches!(self, Self::RateLimit { .. } | Self::Network(_))
208    }
209}
210
211/// Errors from session storage operations.
212#[derive(Debug, thiserror::Error)]
213pub enum StorageError {
214    /// Session not found.
215    #[error("not found: {0}")]
216    NotFound(String),
217    /// Serialization/deserialization failed.
218    #[error("serialization error: {0}")]
219    Serialization(String),
220    /// I/O error during storage operation.
221    #[error("io error: {0}")]
222    Io(#[from] std::io::Error),
223    /// Any other storage error.
224    #[error(transparent)]
225    Other(Box<dyn std::error::Error + Send + Sync>),
226}
227
228/// Errors from sandbox operations.
229#[derive(Debug, thiserror::Error)]
230pub enum SandboxError {
231    /// Tool execution failed within the sandbox.
232    #[error("execution failed: {0}")]
233    ExecutionFailed(String),
234    /// Sandbox setup or teardown failed.
235    #[error("sandbox error: {0}")]
236    SetupFailed(String),
237    /// Any other sandbox error.
238    #[error(transparent)]
239    Other(Box<dyn std::error::Error + Send + Sync>),
240}