Skip to main content

runifold_agent/
error.rs

1use runifold_core::{BudgetExceeded, CheckpointError, JournalError};
2use runifold_effect::EffectExecutorError;
3use runifold_model::{ModelError, StructuredOutputErrorKind};
4use runifold_retrieval::RetrievalError;
5use runifold_tool::ToolError;
6use thiserror::Error;
7
8use crate::GatewayError;
9
10/// Failure of an agent run.
11#[derive(Debug, Error)]
12#[non_exhaustive]
13pub enum AgentError {
14    /// Model invocation failed.
15    #[error("model invocation failed: {0}")]
16    Model(#[from] ModelError),
17    /// Tool execution failed.
18    #[error("tool execution failed: {0}")]
19    Tool(#[from] ToolError),
20    /// Static or dynamic context retrieval failed.
21    #[error("agent retrieval failed: {0}")]
22    Retrieval(#[from] RetrievalError),
23    /// A shared run-tree budget was exceeded.
24    #[error("agent budget exceeded: {0}")]
25    Budget(#[from] BudgetExceeded),
26    /// Agent delegation failed.
27    #[error("agent delegation failed: {0}")]
28    Gateway(#[from] GatewayError),
29    /// Structured event recording failed.
30    #[error("agent observability failed: {0}")]
31    Journal(#[from] JournalError),
32    /// Checkpoint persistence or validation failed.
33    #[error("agent checkpoint failed: {0}")]
34    Checkpoint(#[from] CheckpointError),
35    /// Write-ahead effect coordination failed.
36    #[error("agent effect failed: {0}")]
37    Effect(#[from] EffectExecutorError),
38    /// Recovery would silently retry a possibly partial external turn.
39    #[error("checkpoint contains an ambiguous in-flight turn {turn}")]
40    AmbiguousCheckpoint {
41        /// One-based interrupted turn number.
42        turn: u32,
43    },
44    /// Agent configuration is invalid.
45    #[error("invalid agent configuration: {0}")]
46    InvalidConfig(String),
47    /// Model output violated the agent-loop protocol.
48    #[error("agent protocol error: {0}")]
49    Protocol(String),
50    /// The configured local turn bound was reached.
51    #[error("agent exceeded its local maximum of {max_turns} turns")]
52    MaxTurns {
53        /// Configured local turn bound.
54        max_turns: u32,
55    },
56    /// The model terminated before the successful local Tool-call minimum.
57    #[error(
58        "agent completed only {successful} successful local Tool calls; at least {required} required"
59    )]
60    ToolRequirementUnsatisfied {
61        /// Required successful local Tool calls.
62        required: u32,
63        /// Successful local Tool calls observed in this execution.
64        successful: u32,
65    },
66    /// The remaining shared Tool-call budget cannot satisfy the local minimum.
67    #[error(
68        "agent requires {required} successful local Tool calls but only {remaining} Tool calls remain in the shared budget"
69    )]
70    ToolRequirementExceedsBudget {
71        /// Additional successful local Tool calls still required.
72        required: u32,
73        /// Remaining shared Tool-call budget.
74        remaining: u64,
75    },
76    /// The provider exhausted bounded repairs without producing usable content.
77    #[error("model produced no usable terminal content after {attempts} repair attempts")]
78    EmptyTerminalResponse {
79        /// Repair turns completed before failing.
80        attempts: u32,
81    },
82    /// The provider exhausted bounded repairs without satisfying the Rust type.
83    #[error(
84        "structured terminal output remained unsatisfied after {attempts} repair attempts: {kind:?}"
85    )]
86    StructuredOutputUnsatisfied {
87        /// Repair turns completed before failing.
88        attempts: u32,
89        /// Stable local structured-output failure category.
90        kind: StructuredOutputErrorKind,
91        /// One-based JSON line, when available.
92        line: Option<usize>,
93        /// One-based JSON column, when available.
94        column: Option<usize>,
95    },
96    /// A tool produced output that policy forbids exposing to the model.
97    #[error("tool `{tool}` returned host-only output")]
98    ToolOutputNotVisible {
99        /// Tool name.
100        tool: String,
101    },
102}