Skip to content
Changelog

Cancelled runs now say where they stopped

September 23, 20261 min read

Agno's cancellation_stage lets a client hide runs that never started without reading the run's content, and the AgentOS run API schemas carry it too. Clients used to match that content against cancelled before execution. That string covered one case. A run cancelled while it waited for a worker slot said cancelled while queued for a slot, and a non-durable background run cancelled in the same spot had no content at all.

cancellation_stage is a CancellationStage enum with three values. PENDING means the run never started. EXECUTING means Agno stopped the run mid-execution and kept its partial output. PAUSED means the run was waiting for a human-in-the-loop continuation.

Which cancellation_stage Agno writes for a CANCELLED run. A run that was queued or waiting for a concurrency slot and never started gets PENDING. A run cancelled while running, with partial output kept, gets EXECUTING, which also covers a retry waiting out its backoff. A run paused for a human-in-the-loop continuation gets PAUSED, which also covers a rejected step with on_reject="cancel". An event-loop shutdown, a dropped stream, or a run saved before the field existed gets no stage, which means unknown. Hide a cancelled run only when the stage is PENDING.

A missing stage means unknown. Runs saved before this change carry no stage, and neither do task-level interrupts such as an event-loop shutdown or a disconnected streaming task. Hide a cancelled run only when the stage is PENDING, and treat every other value, including no value, as a run worth showing:

from agno.run import CancellationStage, RunStatus
from agno.run.agent import RunOutput
 
 
def show_in_history(run: RunOutput) -> bool:
    if run.status != RunStatus.cancelled:
        return True
    # Hide only runs that never started. A missing stage means unknown.
    return run.cancellation_stage != CancellationStage.pending

The AgentOS run API returns the same value as a string, so a frontend checks run.get("cancellation_stage") == "PENDING". The human-readable reason stays on content unchanged, and an existing string match keeps working while you switch over.

See the cookbook, and learn more about cancelling a run in the documentation.

Frequently asked questions

Read cancellation_stage on the run. Agno sets it to PENDING when the run was cancelled before it started, EXECUTING when it was cancelled mid-run, and PAUSED when it was waiting for a human-in-the-loop continuation.

It means Agno doesn't know where the run stopped. Runs saved before the field existed and task-level interrupts such as an event-loop shutdown carry no stage, so show those runs and hide only the ones marked PENDING.

The three AgentOS run schemas for agents, teams and workflows include cancellation_stage. The field defaults to None and appears in stored runs only when Agno sets it.

Shipped around the same time