Skip to main content

RecoveryAction

Enum RecoveryAction 

Source
pub enum RecoveryAction {
    Retry {
        delay: Duration,
    },
    Skip(String),
    AskUser(String),
    Fail(String),
}
Expand description

What the framework should do after a failure.

Produced by RecoveryStrategy::decide() after the Reflector::analyze() step. Each variant maps to a different action in the agent loop — the strategy decides which one; the engine executes it.

§Variants in rough order of severity

Retry is the most permissive (try again, optionally with a correction); Skip continues past the failed step; AskUser yields control for human input; Fail terminates the operation and propagates the error. A typical strategy progresses through these as the attempt budget drains: early attempts → Retry, late attempts → Fail or AskUser.

§Equality and ordering

Derives Eq so two actions compare equal when their payloads match (same delay, same string). Useful in tests that assert a strategy picked a specific action; not meaningful for runtime prioritization — there is no Ord impl, by design.

§Example

use loopctl::reflection::RecoveryAction;
use std::time::Duration;

let action = RecoveryAction::Retry {
    delay: Duration::from_millis(500),
};
assert!(action.is_retry());
assert_eq!(action.delay(), Some(Duration::from_millis(500)));

let fail = RecoveryAction::Fail("unrecoverable".to_string());
assert!(fail.is_fail());

Variants§

§

Retry

Retry the failed operation.

Wait for delay before retrying. If the FailureAnalysis::correction that produced this action was Some, the engine applies it (substituting Correction::modified_input or swapping to Correction::alternative_tool) before re-dispatching the tool call. The strategy is responsible for choosing a sensible delay — typically backoff that grows with the attempt number.

Fields

§delay: Duration

Duration to wait before retrying, chosen by the strategy.

Strategies commonly use exponential backoff here. A delay of zero is permitted (immediate retry) but should be reserved for cases where the failure is known to be transient and the retry is cheap.

§

Skip(String)

Skip the failed operation and continue with the rest of the turn.

The framework logs the reason and moves on rather than retrying. Use when the step is optional or the failure is non-fatal — e.g., a metric-emitting tool that the agent can safely proceed without. The carried string is the human-readable reason to log.

§

AskUser(String)

Ask the user for input before continuing.

Yields control to the caller with a prompt string. The framework surfaces this in whatever interaction model it runs under (headless: prints the prompt and waits on stdin; TUI: renders a prompt and waits for input). Use when the strategy cannot decide autonomously — e.g., a permission-style failure that a human should adjudicate, or a ToolChange correction that requires a choice between plausible alternatives.

§

Fail(String)

Fail the operation and propagate the error.

No further retries — the framework should report this failure and stop the recovery loop. The carried string is the error message to surface. Use when the failure is unrecoverable, when the attempt budget is exhausted, or when a Reflector returned ReflectionError::Internal (the engine conservatively maps reflector failure to Fail).

Implementations§

Source§

impl RecoveryAction

Source

pub fn delay(&self) -> Option<Duration>

Returns the retry delay, if this is a Retry action.

Lets callers branch on the wait without a full match. Returns None for the other three variants, so a strategy can write action.delay().unwrap_or(Duration::ZERO) to default a non-retry action to immediate handling.

Source

pub fn is_retry(&self) -> bool

Returns true if this is a Retry action.

Convenience predicate; equivalent to matches!(action, RecoveryAction::Retry { .. }). Useful in engine code that gates on retry vs. non-retry without caring about the delay.

Source

pub fn is_fail(&self) -> bool

Returns true if this is a Fail action.

Convenience predicate. Engine code commonly checks this to decide whether to terminate the recovery loop and propagate the error.

Source

pub fn is_skip(&self) -> bool

Returns true if this is a Skip action.

Convenience predicate. Use to distinguish “move on silently” from the harder-failure variants when logging.

Source

pub fn is_ask_user(&self) -> bool

Returns true if this is an AskUser action.

Convenience predicate. Engine code checks this to know it must yield control to the caller (headless: stdin; TUI: prompt) rather than continue autonomously.

Trait Implementations§

Source§

impl Clone for RecoveryAction

Source§

fn clone(&self) -> RecoveryAction

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for RecoveryAction

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for RecoveryAction

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Eq for RecoveryAction

Source§

impl PartialEq for RecoveryAction

Source§

fn eq(&self, other: &RecoveryAction) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for RecoveryAction

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more