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>;