Skip to content

Cancel a running flow: flow_cancel and POST /flows/runs/:id/cancel stop the step a run is on (1.9.0) - #65

Merged
pallaoro merged 1 commit into
mainfrom
flow-cancel
Nov 4, 2026
Merged

pallaoro merged 1 commit into
mainfrom
flow-cancel

Conversation

@pallaoro

@pallaoro pallaoro commented Nov 4, 2026

Copy link
Copy Markdown
Member

What changes

A run could not be stopped. The runner had a per-run AbortController that nothing aborted, and only custom steps received its signal. This adds cancelling, and makes each step's timeout stop the step's work.

  • FlowRunner.cancel(instanceId, reason?), the flow_cancel tool, and POST /:basePath/runs/:instanceId/cancel on the flow server. The route answers 200 { ok, instanceId, status }, 404 run_not_found, or 409 run_finished.
  • A run executing in the process stops on the step it is on, and the run ends cancelled, the interrupted step's trace entry too. Nothing after it runs or retries. What the step gets:
    • agent: its openclaw agent process gets SIGTERM, which the CLI answers by aborting its turn in the gateway;
    • exec: its shell is killed;
    • http and ai: the request is aborted;
    • sleep and wait-for-event: they stop;
    • custom steps: they get ctx.abortSignal, and are abandoned if they ignore it.
  • Live runs are found through one registry per process on globalThis, like the step registry. A host may call register() more than once, and the flow server keeps the runner of the first call, so a cancel has to cross runners.
  • A run not executing in this process (paused at an approval gate, or left running by a restart) is marked cancelled and its approval dropped. A runner in another process that still holds the run stops before its next step and keeps the cancel.
  • Each attempt is stopped when it times out, before a retry starts, instead of running on in the background. An agent step with no timeout now gets 120 s per attempt, the timeout its openclaw agent process always had. With 30 s, the step failed while its turn ran on to 120 s.
  • The flow_run guard now resolves a step that names only an agent. Such a step runs in agent:<agent>:<session.mainKey>, "main" by default; the plugin reads the main key from the host config. The guard also covers agent steps inside loops, branches and conditions.

Version 1.9.0, and the manifest version is brought level with the package.

Tests

271 pass, 19 of them new (tests/cancel.test.ts, tests/plugin-cancel.test.ts). They cover:

  • a real exec process killed;
  • a stand-in openclaw CLI receiving SIGTERM;
  • sleep and loop steps stopped at once, no retry after a cancel, and a cancel from a second runner;
  • a paused run and an orphaned run marked cancelled, and a finished run left alone;
  • a run held by another process stopping before its next step;
  • the flow-server route;
  • a timed-out attempt's process stopped before the retry;
  • the agent step's 120 s default;
  • the agent-only guard, also inside a loop;
  • flow_cancel registered and declared in contracts.tools.

…op the step a run is on (1.9.0)

A run could not be stopped. The runner had a per-run AbortController that nothing aborted, and only custom steps received its signal.

- Runs executing in a process are kept in one registry per process (on globalThis, like the step registry), so a cancel finds a run whichever FlowRunner started it: the flow server keeps the runner it started with, while flow_run and the scheduler use the newest one.
- FlowRunner.cancel(instanceId, reason) aborts a live run. Every step gets the signal of its attempt: an agent step's openclaw process gets SIGTERM, on which the CLI aborts its turn in the gateway; exec kills its shell; http and ai abort their request; sleep and wait-for-event stop; a custom step gets ctx.abortSignal and is abandoned if it ignores it. The run ends "cancelled", the interrupted step's trace entry too, and nothing after it runs or retries.
- A run not executing in this process (paused at an approval gate, or left "running" by a restart) is marked cancelled and its approval dropped. A runner in another process that still holds a run stops before its next step and keeps the cancel.
- flow_cancel tool, and POST /:basePath/runs/:instanceId/cancel on the flow server (404 run_not_found, 409 run_finished).
- Each attempt is also stopped when it times out, before a retry starts, instead of running on in the background. An agent step with no timeout now gets 120 s per attempt, the timeout its openclaw process always had; with 30 s the step failed while its turn ran on to 120 s.
- The flow_run guard now catches a step that names only an agent (it runs in agent:<agent>:<session.mainKey>, "main" by default, read from the host config), and agent steps inside loops, branches and conditions.
@pallaoro
pallaoro merged commit 1f271a3 into main Nov 4, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant