Skip to content

Epic: Resume Interrupted/Incomplete Flows (Continue after timeout, stop, or failure) #47

Description

@maddes8cht

Description

A flow interrupted in any form – agent timeout, token budget exhaustion, manual stop, max_loops_reached, agent error, missing state update – is markable as incomplete and therefore resumable. The user inspects the stored termination reason, can disable specific reasons, and continues the same flow – optionally with a new timeout (and, if needed, a new max_loops).

Design principle: any state with termination_reason != "completed" is potentially resumable; a configurable filter decides which reasons are allowed. There is deliberately no flow-level timeout – the per-agent subprocess timeout stays the only time bound.

Checkpoint (file & lifecycle)

  • Naming rule identical to the run log: <log_dir>/openloop-run-{name}-{ts}.json (same stem as the .log, same directory). --resume <log-or-json> derives the counterpart by swapping the extension.
  • Contains the full state (WorkflowState.to_json(), incl. payload/meta), the agent position (phase, iteration, agent_index), and a full copy of the flow definition – resume always runs with the unmodified definition, independent of later edits to workflows/*.json or agents/*.md.
  • Written atomically (tmp+rename) after every successful agent merge and at every interruption point (with the termination_reason).
  • Deleted automatically on successful completion – the presence of a checkpoint file is a reliable "resumable run exists" probe.

Resume semantics

  • Resume continues at the last completed agent boundary: the interrupted agent re-runs from scratch in a fresh opencode session.
  • Mid-iteration resume does not re-increment the iteration (the interrupted iteration continues at agent_index); a max_loops_reached state resumes at the next iteration with a raised bound.
  • Resume is itself re-resumable: the checkpoint is overwritten at every boundary, so repeated interruptions form an idempotent continuation chain.

Resumable reasons (config resume_reasons)

Default: all except "completed"stopped, max_loops_reached, agent_error:<name>, timeout:<name>, missing_state:<name>. Users disable reasons they consider non-resumable.

Distinct timeout handling

RunResult gains timed_out: bool; the engine records timeout:<agent_name>:<seconds> instead of the generic agent_error:<name>, so the used timeout survives into the checkpoint for review and adjustment.

Resume invocation

  • CLI: --resume <log|json>; mutually exclusive with --workflow (the definition comes from the checkpoint). Combined with --timeout <new> (required knob), --max-loops <new> (required for max_loops_reached resumes), and existing --opencode-defaults / --workdir / --init-script.
  • Log: resume appends to the same log file (with a <resume> marker) to keep the 1:1 log↔checkpoint pairing.
  • GUI: Continue button lists resumable runs (checkpoint files in log_dir), shows stored reason + timeout + iteration/phase, allows adjusting timeout/max-loops, relaunches with restored state.

Sub-Issues (ToDo)

Scope

  • In: resume mechanism, timeout + max-loops override, reason filter, GUI continue.
  • Out: flow-level timeout (stays per-agent only), token-budget enforcement (see Future), opencode session reuse (fresh session on resume).
  • Known limitation (documented): re-running an interrupted agent may re-apply side effects from before the crash – agents should treat payload as an accumulated journal.

Future (separate issue): Token budget

opencode run exposes no per-run budget flag; opencode stats is aggregate. A future token_budget config key could sum per-run usage from opencode session data and abort the loop on overflow – plugging directly into this resume mechanism as another interruption reason.

Prerequisites

Reuses existing building blocks: WorkflowState.to_json()/from_json() (core/state.py:20-39), cooperative stop_event, meta writes (core/engine.py:418-436), log-dir resolution (core/engine.py:270-278), per-agent timeout (core/runner.py:148).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions