Skip to main content

behest_runtime/
error.rs

1//! Runtime error types.
2
3use thiserror::Error;
4
5use super::run::RunId;
6
7/// Errors that can occur during runtime execution.
8///
9/// Covers provider resolution, session management, run lifecycle, policy
10/// enforcement, tool execution, storage, snapshot recovery, doom-loop
11/// detection, and input admission failures.
12#[derive(Debug, Error)]
13pub enum RuntimeError {
14    /// The requested provider was not found in the registry.
15    #[error("provider not found: {0}")]
16    ProviderNotFound(String),
17
18    /// The requested session does not exist.
19    #[error("session not found: {0}")]
20    SessionNotFound(uuid::Uuid),
21
22    /// The requested run was not found.
23    #[error("run not found: {0}")]
24    RunNotFound(RunId),
25
26    /// Operation cannot proceed because the run is in an unexpected state.
27    #[error("invalid run state: expected {expected}, got {actual}")]
28    InvalidRunState {
29        /// Expected state descriptor.
30        expected: String,
31        /// Actual state descriptor.
32        actual: String,
33    },
34
35    /// The run exceeded the maximum allowed model call iterations.
36    #[error("iteration limit exceeded: {0}")]
37    IterationLimitExceeded(usize),
38
39    /// Accumulated token usage exceeded the configured budget.
40    #[error("token budget exceeded: {used} > {limit}")]
41    TokenBudgetExceeded {
42        /// Tokens consumed so far.
43        used: usize,
44        /// Maximum allowed tokens.
45        limit: usize,
46    },
47
48    /// Estimated context size exceeds the model's maximum context window.
49    #[error("context length exceeded: model context {context}, estimated {estimated}")]
50    ContextOverflow {
51        /// Model's maximum context window size.
52        context: u32,
53        /// Estimated token usage for the full context.
54        estimated: usize,
55    },
56
57    /// Session is locked by another concurrent run.
58    #[error("session busy: {0}")]
59    SessionBusy(uuid::Uuid),
60
61    /// A tool call exceeded its configured execution timeout.
62    #[error("tool execution timeout: {tool}")]
63    ToolTimeout {
64        /// Name of the timed-out tool.
65        tool: String,
66    },
67
68    /// An error propagated from the provider layer.
69    #[error(transparent)]
70    Provider(#[from] behest_core::error::ProviderError),
71
72    /// An error propagated from the context layer.
73    #[error(transparent)]
74    Context(#[from] behest_core::error::ContextError),
75
76    /// An error propagated from the storage layer.
77    #[error(transparent)]
78    Storage(#[from] behest_core::error::StorageError),
79
80    /// An error propagated from the tool layer.
81    #[error(transparent)]
82    Tool(#[from] behest_core::error::ToolError),
83
84    /// Snapshot persistence or recovery failed.
85    #[error("recovery error: {0}")]
86    RecoveryFailed(String),
87
88    /// Doom loop detected — agent is stuck in a repetitive tool call pattern.
89    #[error("doom loop detected: {description}")]
90    DoomLoopDetected {
91        /// Human-readable description of the detected pattern.
92        description: String,
93    },
94
95    /// Input was rejected by the admission pipeline.
96    #[error("input rejected: {input_id} — {reason}")]
97    InputRejected {
98        /// Identifier of the rejected input.
99        input_id: super::input::InputId,
100        /// Reason for rejection.
101        reason: String,
102    },
103
104    /// Internal error during input admission processing.
105    #[error("input admission error: {0}")]
106    InputAdmissionFailed(String),
107}
108
109/// Result type for runtime operations.
110pub type RuntimeResult<T> = Result<T, RuntimeError>;