# Cancelled runs now say where they stopped

> Agno's RunOutput, TeamRunOutput and WorkflowRunOutput now carry cancellation_stage, a machine-readable PENDING, EXECUTING or PAUSED that tells clients where a cancelled run stopped.

- Published: 2026-09-23
- Author: Yash Pratap Solanky
- Categories: Changelog
- Canonical: https://www.agno.com/articles/cancelled-runs-now-say-where-they-stopped
- Markdown: https://www.agno.com/articles/cancelled-runs-now-say-where-they-stopped.md

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.](https://www.agno.com/images/v3-0-11-cancellation-stage.png)

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:

```python
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](https://github.com/agno-agi/agno/blob/main/cookbook/05_agent_os/04_run_lifecycle/cancel_run.py), and learn more about [cancelling a run](https://docs.agno.com/run-cancellation/overview) in the documentation.
