Skip to main content

oxios_kernel/resilience/
error.rs

1//! Agent run error — carries the provider error AND the agent's exported
2//! conversation state so the recovery coordinator can snapshot→restore
3//! rather than re-fork from scratch (RFC-029 §3.2, P2b).
4//!
5//! Used by `run_agent` on failure: before returning Err, the agent's
6//! `export_state()` is captured and wrapped. The supervisor's Err arm
7//! downcasts back to extract both the source error (for `classify`) and
8//! the restore state (for `ExecutionResult.restore_state`).
9
10use std::fmt;
11
12/// Error wrapper carrying the agent's exported state alongside the
13/// original provider error.
14///
15/// Implementing `std::error::Error` + `Display` makes it compatible with
16/// `anyhow::Error::downcast_ref`. The `source()` returns the original
17/// error so `classify`'s cause-chain walk still works.
18#[derive(Debug)]
19pub struct AgentRunError {
20    /// The original error (e.g. from `run_streaming()`).
21    pub source: anyhow::Error,
22    /// The agent's exported state at the point of failure, if available.
23    /// `None` when the agent failed before accumulating any state (e.g.
24    /// model-resolution error before the first LLM call).
25    pub restore_state: Option<serde_json::Value>,
26}
27
28impl AgentRunError {
29    /// Wrap a streaming error, capturing the agent's exported state.
30    pub fn wrap(source: anyhow::Error, restore_state: Option<serde_json::Value>) -> Self {
31        Self {
32            source,
33            restore_state,
34        }
35    }
36}
37
38impl fmt::Display for AgentRunError {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        write!(f, "{}", self.source)
41    }
42}
43
44impl std::error::Error for AgentRunError {
45    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
46        Some(self.source.as_ref())
47    }
48}