Architecture of the Recovery Reviewer and Decision System in DeepSeek Reasonix

The DeepSeek Reasonix recovery system employs a two-layer Auto-Guard architecture where an independent LLM-based recovery reviewer evaluates failure evidence and emits structured verdicts, while a decision gate orchestrates episode flow, enforces token budgets, and manages persistence via side-car state files.

DeepSeek Reasonix (also referred to as DeepSeek-Reasonix) implements a sophisticated failure recovery mechanism to keep long-running autonomous agents productive and safe. The system centers on a recovery reviewer that acts as an independent, read-only evaluator of failures, paired with a decision system that orchestrates retries, pauses, and abortions based on structured verdicts returned by the reviewer.

Recovery Reviewer Implementation

The Recovery Reviewer provides an isolated LLM session dedicated to evaluating agent failures without side effects. Implemented in [internal/recovery/reviewer.go](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/recovery/reviewer.go), this component operates under strict resource constraints to prevent runaway token consumption during error analysis.

Bounded Session Configuration

Each reviewer session is instantiated with deterministic, conservative limits to ensure predictable behavior. The Session struct enforces temperature = 0 for deterministic outputs, MaxTokens = 256, and strict byte budgets for all inputs. When calling NewSessionWithSink, the system initializes a provider connection to the deepseek/recovery-reviewer model and attaches a UsageSink for telemetry tracking.

rev := recovery.NewSessionWithSink(provider, usageSink) // creates a bounded reviewer
verdict, err := rev.Review(ctx, failureEvent, evidence, proposal, taskSummary)

The session imposes a hard timeout of 30 seconds (reviewerTimeout = 30s) on all calls to provider.Stream. If the LLM fails to respond within this window or exceeds the token limit, the session returns an error immediately, triggering fallback logic in the decision gate.

Evidence Packaging and Policy

The reviewer operates against a static PolicyPrompt (approximately 2 KB) that defines its role: "You are an independent Auto plan-decision reviewer for a coding agent." All failure evidence is packaged into a FailureEvent struct containing ArgsSummary and OutputExcerpt, then clipped to configurable budgets defined by reviewerMaxEvidenceBytes and reviewerMaxTaskSummary before transmission.

fail := recovery.FailureEvent{
    ArgsSummary:   "read_file(\"config.yaml\")",
    OutputExcerpt: "permission denied",
}

Review Verdict Parsing

The reviewer returns a strictly typed ReviewVerdict containing an Outcome field (continue, pause, or abort) and a ChangeKind field (noop, retry, rewind, or ambiguous). The Review method validates JSON structure and required fields; malformed responses surface as errors that the decision system must handle through deterministic fallback rules.

Decision System and Gate Logic

While the reviewer provides recommendations, the Decision System located in [internal/recovery/decision.go](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/recovery/decision.go) executes them. This layer manages episode state, enforces global budgets, and coordinates the transition between agent execution and recovery procedures.

Gate Architecture and Budgeting

The Gate struct in [internal/recovery/gate.go](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/recovery/gate.go) serves as the primary interface between the agent and recovery logic. It wraps the reviewer session and maintains per-episode budgets including reviewerMaxTokens and reviewerMaxTotalBytes. The gate tracks the number of reviewer invocations to prevent infinite retry loops and exposes HandleFailure as the unified entry point for processing errors.

gate := recovery.NewGate(sessionID, provider, usageSink)
verdict, err := gate.HandleFailure(ctx, stepErr)

When a failure occurs, the gate captures a FailureEvent, budgets the evidence, queries the reviewer via gate.Reviewer.Review(), and produces a Decision struct via ApplyVerdict. The decision specifies one of three actions: ActionContinue (retry the step), ActionPause (halt auto-retry pending user input), or ActionAbort (terminate the episode).

Rules Engine Fallback

For scenarios where the reviewer is unavailable, times out, or returns ChangeKind: ambiguous, the system falls back to deterministic classifiers implemented in [internal/recovery/rules.go](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/recovery/rules.go). These rule-based functions analyze the failure signature—for example, detecting "method signature altered" scenarios—without LLM latency, ensuring the agent remains responsive even when the recovery reviewer service is degraded.

State Persistence

The decision system maintains crash resilience through [internal/recovery/persist.go](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/recovery/persist.go). After each verdict, the gate serializes its state to a side-car JSON file (*.recovery.json) using the types defined in [internal/recovery/types.go](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/recovery/types.go). This allows sessions to resume mid-episode using LoadGateFromDisk, restoring the exact decision point and budget consumption history.

gate := recovery.LoadGateFromDisk(sessID, sink)
return gate.Resume(ctx)

Interaction Flow Between Components

The recovery architecture follows a strict pipeline when handling agent failures:

  1. Failure Detection: When a tool or plan step errors, the gate generates a FailureEvent capturing ArgsSummary, OutputExcerpt, and context.
  2. Evidence Budgeting: The system trims failure evidence to fit reviewerMaxEvidenceBytes and combines it with the static PolicyPrompt.
  3. Reviewer Evaluation: The Gate transmits the packaged evidence to the reviewer LLM via provider.Stream, enforcing the 30-second timeout.
  4. Verdict Application: The Decision consumes the ReviewVerdict, updates episode budgets, and determines whether to modify the current proposal (e.g., rolling back to a previous plan state).
  5. Persistence: The gate writes the updated state to disk, enabling resumption after crashes or user-initiated pauses.

Code Implementation Examples

Creating a Stand-Alone Reviewer Session

The following pattern initializes a reviewer for isolated failure analysis without full gate orchestration:

import (
    "context"
    "reasonix/internal/recovery"
    "reasonix/internal/provider"
)

func exampleReviewer(ctx context.Context) error {
    // Provider targets the dedicated recovery-reviewer model
    prov := provider.NewOpenAI("deepseek/recovery-reviewer")
    sink := recovery.NewUsageSink()

    // Create bounded session with telemetry
    rev := recovery.NewSessionWithSink(prov, sink)

    fail := recovery.FailureEvent{
        ArgsSummary:   "git_push(\"main\")",
        OutputExcerpt: "rejected: non-fast-forward",
    }

    verdict, err := rev.Review(ctx, &fail, nil, recovery.Proposal{}, "")
    if err != nil {
        return err
    }

    switch verdict.Outcome {
    case "continue":
        // Proceed with retry
    case "pause":
        // Halt for manual intervention
    case "abort":
        // Terminate operation
    }
    return nil
}

Integrating Reviewer into the Decision Gate

For production agent loops, embed the reviewer within the gate to manage episode lifecycle:

func runEpisode(ctx context.Context, sessID string) error {
    prov := provider.NewOpenAI("deepseek/recovery-reviewer")
    sink := recovery.NewUsageSink()
    gate := recovery.NewGate(sessID, prov, sink)

    for {
        // Execute agent step...
        if stepErr != nil {
            verdict, err := gate.HandleFailure(ctx, stepErr)
            if err != nil {
                return err // Reviewer unavailable or budget exceeded
            }

            dec := gate.ApplyVerdict(verdict)
            switch dec.Action {
            case recovery.ActionContinue:
                continue // Retry current step
            case recovery.ActionPause:
                return fmt.Errorf("auto-retry paused; awaiting user input")
            case recovery.ActionAbort:
                return fmt.Errorf("episode aborted by reviewer decision")
            }
        }
        // Success path...
    }
}

Persisting and Resuming Recovery Sessions

To survive process restarts, persist gate state and resume execution:

func resumeEpisode(ctx context.Context, sessID string) error {
    sink := recovery.NewUsageSink()
    // Automatically loads *.recovery.json side-car file
    gate := recovery.LoadGateFromDisk(sessID, sink)
    
    // Continues from last decision point with budgets intact
    return gate.Resume(ctx)
}

Summary

  • The Recovery Reviewer in internal/recovery/reviewer.go provides an isolated, bounded LLM session (temperature 0, 256 token limit, 30s timeout) that evaluates failures through a static PolicyPrompt and returns structured ReviewVerdict objects.
  • The Decision System centers on the Gate struct in internal/recovery/gate.go, which orchestrates episode flow, enforces per-session budgets (reviewerMaxEvidenceBytes, reviewerMaxTokens), and coordinates between the agent and reviewer.
  • Fallback logic in internal/recovery/rules.go handles reviewer unavailability or ambiguous verdicts using deterministic classifiers.
  • State persistence via internal/recovery/persist.go serializes decision state to *.recovery.json files, enabling crash recovery and session resumption through LoadGateFromDisk.
  • All reviewer usage is tracked via UsageSink under the recovery-reviewer model reference for cost monitoring and telemetry.

Frequently Asked Questions

How does the recovery reviewer handle token budget overflows?

The reviewer enforces strict byte and token budgets through configuration constants (reviewerMaxEvidenceBytes, reviewerMaxTaskSummary, MaxTokens = 256). Input evidence is pre-clipped before transmission, and if the LLM response exceeds limits or the 30-second timeout fires, the Review method returns an error. The decision gate then falls back to deterministic rules in internal/recovery/rules.go rather than proceeding without reviewer guidance.

What is the difference between the Gate and the Reviewer in Reasonix?

The Reviewer (internal/recovery/reviewer.go) is a stateless, read-only LLM client that analyzes failure evidence and returns verdicts. The Gate (internal/recovery/gate.go) is a stateful orchestrator that owns the reviewer instance, manages episode budgets, persists state to disk, and translates verdicts into concrete actions (continue, pause, abort). The gate handles the lifecycle; the reviewer provides the analysis.

Can the recovery system resume after a process crash?

Yes. The decision system serializes its complete state—including current budget consumption, last verdict, and episode position—to a *.recovery.json side-car file after every significant transition. Upon restart, calling recovery.LoadGateFromDisk(sessionID, sink) restores the exact state, allowing the agent to resume from the precise decision point without re-running previous steps or re-consuming reviewer tokens.

What happens when the reviewer returns an ambiguous verdict?

When the ReviewVerdict contains ChangeKind: ambiguous, the decision system delegates to the Rules Engine in internal/recovery/rules.go. This module applies deterministic heuristics—such as detecting specific error patterns like "method signature altered"—to decide whether to retry, rewind, or abort without requiring additional LLM calls. This ensures the agent remains responsive even when the reviewer cannot provide a definitive classification.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →