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}
125
126/// Errors from durable execution operations.
127#[derive(Debug, thiserror::Error)]
128pub enum DurableError {
129    /// An activity (LLM call or tool execution) failed.
130    #[error("activity failed: {0}")]
131    ActivityFailed(String),
132    /// The workflow was cancelled.
133    #[error("workflow cancelled")]
134    Cancelled,
135    /// Timed out waiting for a signal.
136    #[error("signal timeout")]
137    SignalTimeout,
138    /// Continue-as-new was requested.
139    #[error("continue as new: {0}")]
140    ContinueAsNew(String),
141    /// Any other durable execution error.
142    #[error(transparent)]
143    Other(Box<dyn std::error::Error + Send + Sync>),
144}
145
146/// Errors from MCP operations.
147#[derive(Debug, thiserror::Error)]
148pub enum McpError {
149    /// Failed to connect to MCP server.
150    #[error("connection failed: {0}")]
151    Connection(String),
152    /// MCP initialization handshake failed.
153    #[error("initialization failed: {0}")]
154    Initialization(String),
155    /// MCP tool call failed.
156    #[error("tool call failed: {0}")]
157    ToolCall(String),
158    /// Transport-level error.
159    #[error("transport error: {0}")]
160    Transport(String),
161    /// Any other MCP error.
162    #[error(transparent)]
163    Other(Box<dyn std::error::Error + Send + Sync>),
164}
165
166/// Errors from observability hooks.
167#[derive(Debug, thiserror::Error)]
168pub enum HookError {
169    /// Hook execution failed.
170    #[error("hook failed: {0}")]
171    Failed(String),
172    /// Any other hook error.
173    #[error(transparent)]
174    Other(Box<dyn std::error::Error + Send + Sync>),
175}
176
177/// Errors from embedding provider operations.
178#[derive(Debug, thiserror::Error)]
179pub enum EmbeddingError {
180    /// Authentication/authorization failure.
181    #[error("authentication failed: {0}")]
182    Authentication(String),
183    /// Rate limited by the provider.
184    #[error("rate limited, retry after {retry_after:?}")]
185    RateLimit {
186        /// Suggested retry delay, if provided by the API.
187        retry_after: Option<std::time::Duration>,
188    },
189    /// Malformed or invalid request.
190    #[error("invalid request: {0}")]
191    InvalidRequest(String),
192    /// Network-level error (connection reset, DNS failure, etc.).
193    #[error("network error: {0}")]
194    Network(#[source] Box<dyn std::error::Error + Send + Sync>),
195    /// Any other embedding error.
196    #[error(transparent)]
197    Other(Box<dyn std::error::Error + Send + Sync>),
198}
199
200impl EmbeddingError {
201    /// Whether this error is likely transient and the request can be retried.
202    #[must_use]
203    pub fn is_retryable(&self) -> bool {
204        matches!(self, Self::RateLimit { .. } | Self::Network(_))
205    }
206}
207
208/// Errors from session storage operations.
209#[derive(Debug, thiserror::Error)]
210pub enum StorageError {
211    /// Session not found.
212    #[error("not found: {0}")]
213    NotFound(String),
214    /// Serialization/deserialization failed.
215    #[error("serialization error: {0}")]
216    Serialization(String),
217    /// I/O error during storage operation.
218    #[error("io error: {0}")]
219    Io(#[from] std::io::Error),
220    /// Any other storage error.
221    #[error(transparent)]
222    Other(Box<dyn std::error::Error + Send + Sync>),
223}
224
225
226/// Errors from sandbox operations.
227#[derive(Debug, thiserror::Error)]
228pub enum SandboxError {
229    /// Tool execution failed within the sandbox.
230    #[error("execution failed: {0}")]
231    ExecutionFailed(String),
232    /// Sandbox setup or teardown failed.
233    #[error("sandbox error: {0}")]
234    SetupFailed(String),
235    /// Any other sandbox error.
236    #[error(transparent)]
237    Other(Box<dyn std::error::Error + Send + Sync>),
238}