This sample demonstrates user-initiated A2A task cancellation. The agent runs a
multi-step (5×1s) task and checks for cancellation before each step. The
companion client kicks off the task and, after a short delay, calls
cancelTask on the same client instance.
For details, see the A2A Specification §3.1.7 cancelTask.
agent_executor.ts— implementscancelTask(taskId, eventBus)by recording the taskId in an in-memorySet. Theexecuteloop checks this set before each step and, if cancelled, publishes a finalTaskState.TASK_STATE_CANCELEDstatus update.index.ts— Express A2A server using JSON-RPC.client.ts— sends a streaming message, captures the taskId from the firsttaskevent, then triggers cancellation afterCANCEL_AFTER_MS.
Open two terminals.
Terminal 1 — start the agent:
npm run agents:cancellable-agentTerminal 2 — run the cancelling client:
npm run agents:cancellable-clientExpected output (timing-dependent):
[Client] Sending streaming message to http://localhost:41241
[Client] Task created id=<task-id> state=TASK_STATE_SUBMITTED
[Client] statusUpdate task=<task-id> state=TASK_STATE_WORKING
[Client] Sending cancelTask for <task-id> after 2500ms
[Client] statusUpdate task=<task-id> state=TASK_STATE_CANCELED
[Client] Confirmed task <task-id> was cancelled.
[Client] cancelTask returned state=TASK_STATE_CANCELED
[Client] Stream complete.
On the agent side you should see:
[CancellableAgentExecutor] Task <task-id>: step 1/5
[CancellableAgentExecutor] Task <task-id>: step 2/5
[CancellableAgentExecutor] Cancellation requested for task <task-id>
[CancellableAgentExecutor] Aborting task <task-id> at step 3.
| Variable | Default | Used by |
|---|---|---|
PORT |
41241 |
server |
AGENT_URL |
http://localhost:41241 |
client |
CANCEL_AFTER_MS |
2500 |
client |