Skip to main content
Do this when you want to render or follow a run as it happens. Do not build a polling loop against GET /v1/agents/{agent_id}/tasks/{task_id} for this — the stream already replays everything from the beginning, so attaching late loses nothing.

Prerequisites

  • A task id and its agent id. See Start a task.
  • An API key.
  • A client that can hold an open HTTP response. curl -N works; curl without -N buffers and looks hung.

Choose an endpoint

Steps

1

Stream live

Each frame is a standard SSE event. The SSE event name and the payload’s event_type are the same dotted string, so a consumer can key on either:
The feed replays the task’s full durable history first, then tails live events, de-duplicating by event_id across the hand-off. It closes after task.completed, task.failed, or task.cancelled.
2

Drop token-level chunks

llm.call.chunk events are high volume — one per token. They are included by default. Turn them off when you only need structural progress:
3

Read history instead

Filter with ?event_type=tool.call. Chunks never appear here — they are stream-only and are not persisted.
4

Write the consumer correctly

Two rules keep a consumer from breaking when the vocabulary grows:
  1. Do not switch on every event name. Pass unknown types through. New event types are added without a version bump.
  2. Only three types are terminal: task.completed, task.failed, task.cancelled. Stop on those and nothing else.
To collapse a model call or a tool call into one UI element rather than four lines, group by part id: tool_call_id for tool events, {execution_id}:{iteration} for LLM events. A later event with the same part id replaces the earlier one.

Verify

Confirm the stream terminates on its own with a terminal event rather than hanging:
The command exits as soon as the terminal frame arrives. If it exits with no output, the task produced no terminal event within the feed’s limits — see below.

Troubleshooting

Without -N , curl buffers the response. Add -N . If frames still do not arrive, confirm the task actually dispatched: a task with execution_id: null never started a workflow and will never emit events.
The feed has a 30-minute wall-clock limit so a stuck task does not tail forever. This is the feed giving up, not the task ending. Re-attach, or check GET .../tasks/{task_id} for the current status.
Expected. The reader replays from the database, then attaches to the live tail and waits for a terminal event it may have already replayed. It closes on the replayed terminal event.
The event was published to the live stream but its database write failed; that failure is recorded and does not retry. The live tail is also best-effort in the other direction — a failed publish leaves the event in history only. History is the durable copy; prefer GET .../events when completeness matters.
There is no such event type. A blocked task emits task.failed on the feed while its row reads blocked . Read failure_reason from the task to tell them apart.

Events

The one dotted event vocabulary AgentArea emits, the two delivery paths behind it

Debug a failed task

Read the failure code, narrow it with the task rollup

Start a task

Launch an agent run over REST, the CLI, or A2A
Last modified on September 17, 2026