3.4

Task, TaskStatus, and TaskState

A Task carries one TaskStatus, whose state is one of nine TaskState values, and the specification names those values without a table of the transitions between them.

Your planner holds three tasks at once: the tests on test-runner, the review on code-reviewer, and the deploy on deployer. Each is a Task with a status, and the planner's next action turns on status.state: wait, act, or stop.

When you finish this section, you can read every field of a Task, classify every TaskState value, and say which transitions the specification defines.

Task

Task: the basic unit of work in A2A, with a unique id. The proto gives Task six fields and marks id and status REQUIRED. The server creates the id, and a client cannot supply one.

The optional fields are contextId, artifacts, history, and metadata. contextId, Artifact and chunks, and GetTask and ListTasks cover the first three in turn. Figure 3.4 lays out task 3d8f7801 from the blocking run.

Fig. 3.4the object model of one taskstructure
The object model of one task A dashed frame marks context ac3830af. Inside it, task 3d8f7801 from the blocking run is drawn as a table that fills in the order the run filled it: id and contextId, then the two history messages, the user message 21636369 and the agent message 10cc3c92 with their roles, then the artifacts test-log and summary with their names and part counts, and last status.state TASK_STATE_COMPLETED, status.message 1 failed, 11 passed, and status.timestamp 2026-10-06T09:00:00.750Z. Below, four chips show that a part holds exactly one of text, raw, url or data, with an example of each. Task EVERY MESSAGE AND ARTIFACT HOLDS PARTS text collected 12 items raw refunds.diff, base64 url screenshot.png data "passed": 11 Each part holds exactly one of these four, plus optional mediaType, filename and metadata. context ac3830af groups related tasks and messages, and this run made one task id 3d8f7801 contextId ac3830af history 2 messages messageId: 21636369 role: ROLE_USER parts: 1 text part messageId: 10cc3c92 role: ROLE_AGENT parts: 1 text part artifacts 2 artifacts artifactId: test-log name: test-log.txt parts: 5 text parts artifactId: summary name: summary.json parts: 1 data part status.state TASK_STATE_COMPLETED status.message 1 failed, 11 passed status.timestamp 2026-10-06T09:00:00.750Z
A task carries its own id, its context, one current status, its artifacts, and its history, and every message and artifact inside it is made of parts. Read the task table from the top, in the order the blocking run filled it. The boxes on the right expand its last two rows, and the chips below show the four kinds of part. Values come from the blocking-task capture, ids shortened to 8 characters. The raw and url examples come from the input-required and error captures.

TaskStatus

TaskStatus: the current status of a task, with state REQUIRED and message and timestamp optional. The message belongs to the status, and the timestamp is the ISO 8601 time when the status was recorded.

A task has one status at a time, and the previous status message can move into history, as 06-input-required.http shows.

TaskState

The enum TaskState has nine values, numbered 0 to 8. In JSON, a state travels as its name.

Terminal state: a state that ends the task for good. The proto marks four values as terminal.

Interrupted state: a state in which the task waits for something from outside the agent. The proto marks two values as interrupted.

Active state: this manual's name for TASK_STATE_SUBMITTED and TASK_STATE_WORKING, which the proto puts in neither group.

ValueNumberClassIn the kit
TASK_STATE_UNSPECIFIED0nonenever sent
TASK_STATE_SUBMITTED1activeevery new task, 04-polling.http
TASK_STATE_WORKING2activethe suite runs, 05-streaming.http
TASK_STATE_COMPLETED3terminalthe tests end, 03-blocking-task.http
TASK_STATE_FAILED4terminalcommit deadbee, 09-failed.http
TASK_STATE_CANCELED5terminalafter CancelTask, 10-cancel.http
TASK_STATE_INPUT_REQUIRED6interruptedthe base branch question, 06-input-required.http
TASK_STATE_REJECTED7terminala production deploy, 08-rejected.http
TASK_STATE_AUTH_REQUIRED8interruptedwaiting for an operator, 07-auth-required.http

TASK_STATE_UNSPECIFIED is the proto3 zero value, for a task whose state is unknown. The kit never sends it, so treat it and any unknown name as an error.

A client needs both named sets, because a blocking SendMessage returns at a terminal or an interrupted state, as SendMessage shows.

The transitions the specification allows

The specification says that tasks move through a defined lifecycle, yet neither its prose nor the proto has a transition table. What it says about transitions fits in four rules:

  • Input: an agent can ask for more input during the work by moving a task to the input-required state. That is the 0.3 name of TASK_STATE_INPUT_REQUIRED (conflict D37).
  • Authorization: an agent "MUST transition the TaskState to TASK_STATE_AUTH_REQUIRED" to ask for it, and can resume without a client message.
  • Rejection: an agent can reject a task when it creates it or later.
  • Finality: a terminal task refuses messages, cancellation, and subscription.

The migration guide says that 1.0 made the state transitions for cancellation clearer, and the specification lists none (conflict D38). The extensions guide lists extensions that add new states or transitions. It also says that extensions should use the existing enum values (conflict D29). Expect only the nine values.

With no table in the protocol, an agent's transitions are whatever its code emits. Figure 3.5 collects every transition the kit's agents make.

Fig. 3.5the nine task states and the transitions the kit makesstate
The nine task states and the transitions the kit makes Nine TaskState values without their TASK_STATE_ prefix, and the transitions the kit makes in capture order. SUBMITTED goes to WORKING in 05, and WORKING ends in COMPLETED in 03 and 05. SUBMITTED goes to INPUT_REQUIRED when the reviewer asks a question in 06, and INPUT_REQUIRED returns to WORKING when the client answers. WORKING goes to AUTH_REQUIRED and back when an operator approves in 07. SUBMITTED goes to REJECTED when the deployer refuses production in 08. WORKING ends in FAILED for a missing commit in 09, and in CANCELED after CancelTask in 10. The four terminal states have double borders and no outgoing arrows. UNSPECIFIED, value 0, stands apart and is never sent by the kit. AUTH_REQUIRED value 8 SUBMITTED value 1 WORKING value 2 INPUT_REQUIRED value 6 TERMINAL COMPLETED value 3 in 03 05 06 07 FAILED value 4 commit missing, in 09 CANCELED value 5 CancelTask, in 10 REJECTED value 7 in 08 UNSPECIFIED value 0, unused Prefix TASK_STATE_ dropped from every name. Dashed border: interrupted. Double border: terminal. starts (05) asks for a branch (06) client answers (06) needs approval (07) operator approves (07) refuses production (08)
The kit's captures show nine transitions between task states, and none of them leaves a double-bordered terminal state. Boxes are TaskState values with the TASK_STATE_ prefix dropped. Dashed arrows are the transitions the kit's agents make, in capture order, labelled with the capture that shows each one. Read them as one implementation's behavior, never as the protocol's rules. Blocking captures return only the final state, so their earlier transitions come from the history they return and from the kit's agent code.

The deployer leaves TASK_STATE_AUTH_REQUIRED with no message from the client, as the specification allows, and rejects straight from TASK_STATE_SUBMITTED. The reference SDK enforces no table either, so accept any transition out of a state that is not terminal.

A terminal task refuses a message on its taskId and SubscribeToTask with UnsupportedOperationError, and CancelTask with TaskNotCancelableError. CancelTask and terminal states covers the four endings, and the state table lists the client's next step for each value.

A2A protocol 1.0.1 · 3303592 · 2026-05-28 · Edition 2026.10