Skip to content

Field note

Agent Cancellation: Track Outstanding Work

A stop button needs to report what stopped, what completed and what remains uncertain.

Pressing Stop should prevent an agent from starting more work. It should also tell the user which work had already crossed the point of cancellation. A single green “cancelled” label is misleading if a background export is still running or a message has already been sent.

Design cancellation as a lifecycle for the whole task. Include the model request, local workers, remote tools and external operations. The agentic AI security checklist asks for a stop route; this is what that route needs underneath the interface.

Give the parent task a view of its children

Every scheduled unit of work should have an ID linked to the parent task. Record whether it is queued, running, completed, failed or awaiting reconciliation, and which service can cancel or inspect it.

Keep this record outside the model's conversation. A restarted worker must be able to find outstanding jobs without asking the assistant what it remembers. The same applies when a browser tab closes: losing the interface should not lose the operational record.

When a user cancels, record a cancellation request on the parent before dispatching stop messages. Workers should check that state before starting queued work and before submitting a new external action. This closes the common gap where the current model response stops but the next queue item still starts.

Know what each cancellation mechanism promises

OpenAI background responses have a cancellation endpoint, and repeating that cancellation is documented as idempotent. Cancelling the response is useful, but the application must still inspect external work it launched while the response was active.

The MCP cancellation specification dated 18 June 2025 allows a receiver to ignore cancellation when a request has completed or cannot be cancelled. It explicitly recognises races between cancellation and completion. Confirm the version and behaviour implemented by your client and server.

Inside a Python service, asyncio cancellation raises CancelledError at a cancellation opportunity. Cleanup belongs in finally blocks, with cancellation generally propagated afterwards. Stopping a local coroutine does not establish what a remote service has committed.

These mechanisms are related, but they are not interchangeable. The orchestration layer must connect them and record each outcome.

Decide the result at each stage

Use a small matrix when reviewing a tool:

Queued and not submittedRemove from dispatch and mark cancelled
Running computation with cancellation supportRequest cancellation and inspect final status
External action acceptedReconcile the action's actual result
Action completedReport completion; assess a separate reversal if needed
Result unknown after timeoutKeep an uncertain state and investigate

The table is a design pattern, not a promise about any provider. Add provider-specific timeouts and status lookups to make it executable.

For example, cancelling an invoice analysis can discard an unfinished draft. Cancelling a task after it created a CRM record might allow that record to be archived through a separate authorised operation. Cancelling after an external email was sent cannot make the recipient unread it. Show these outcomes plainly.

Separate compensation from cancellation

A compensating action is new work intended to address an earlier effect. It may need fresh permission and can fail independently. Do not automatically delete a created record if other staff may already have updated it.

Preserve the external record ID and, where available, its version. Before compensation, check that the state still matches the action you intend to reverse. Escalate changes made by someone else rather than overwriting them in the name of cleanup.

The interface can remain simple: “Stopped new work. Two drafts discarded. One record created; review required.” That is more useful than exposing every protocol event, and more accurate than claiming everything was cancelled.

Exercise the races before release

Test cancellation before dispatch, during a tool call and immediately after external acceptance. Add a slow child job, a disconnected client, an unavailable cancellation endpoint and a duplicate stop request.

Inspect the queue and the external systems after each test. No new action should start after the application's cancellation boundary, and every action already submitted should reach a known or explicitly uncertain state. Set a deadline for investigating the latter.

For an initial rollout, use reversible test actions and retain the existing manual workflow. If the stop path cannot account for all submitted work, narrow the agent's tool set until it can. Completion tracking is part of the feature, because users need to know what the assistant actually changed when they asked it to stop.

References

Keep reading

Related notes