Skip to content

feat: add generation field to Task for ordering, long-polling, and optimistic concurrency#1810

Open
Tehsmash wants to merge 8 commits into
a2aproject:mainfrom
Tehsmash:feat/task-generation-field
Open

feat: add generation field to Task for ordering, long-polling, and optimistic concurrency#1810
Tehsmash wants to merge 8 commits into
a2aproject:mainfrom
Tehsmash:feat/task-generation-field

Conversation

@Tehsmash

@Tehsmash Tehsmash commented May 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a monotonically increasing generation field to Task (and related messages) that supports three new capabilities:

1. Event ordering / missed-event detection

TaskStatusUpdateEvent and TaskArtifactUpdateEvent now carry the task's generation value after the mutation that produced them. A gap in generation values (e.g. jumping from 3 to 5) tells a client it missed at least one event and should re-fetch the full task state.

2. Long-polling via GetTaskRequest.current_generation

If currentGeneration is supplied on a GetTask call the server SHOULD hold the request open until the task's generation advances beyond that value, returning immediately if it already has. This replaces tight polling loops with a single blocking call.

3. Optimistic concurrency via SendMessageConfiguration.if_generation_match

If ifGenerationMatch is set the server MUST reject the request with HTTP 412 Precondition Failed / gRPC ABORTED (TaskGenerationMismatchError) if the task's generation has changed since the client last read it, preventing lost-update races in multi-client scenarios.

Proto changes

Message New field
Task int64 generation = 7
TaskStatusUpdateEvent int64 generation = 5
TaskArtifactUpdateEvent int64 generation = 7
GetTaskRequest optional int64 current_generation = 4
SendMessageConfiguration optional int64 if_generation_match = 5

Spec documentation changes

  • New §3.2.7 Task Generation Semantics — comprehensive description of the generation field, event ordering, long-polling behaviour, optimistic concurrency, and backwards compatibility.
  • §3.1.3 Get Task — cross-reference to §3.2.7 for currentGeneration long-polling.
  • §3.2.2 SendMessageConfiguration — document ifGenerationMatch optimistic concurrency behaviour and the new error.
  • §3.3.2 Error Handling — add TaskGenerationMismatchError to the A2A-Specific Errors table.
  • §3.5.1 Overview of Update Mechanisms — add Long-Polling as a delivery mechanism.
  • §3.5.2 Streaming Event Delivery — note generation-based event ordering and missed-event detection.
  • §5.4 Error Code Mappings — add TaskGenerationMismatchError (JSON-RPC -32010 / gRPC ABORTED / HTTP 412).
  • §11.5 Query Parameter Naming — add currentGeneration to the mapping table and example.
  • §11.6 Error Handling — add HTTP 412 generation mismatch error response example including ifGenerationMatch body mapping.

Backwards compatibility

generation defaults to 0 in proto3. Existing clients that do not read or send generation continue to interoperate without change. Clients SHOULD treat a server-returned generation of 0 as "generation unknown" and MUST NOT use it for ordering, long-polling, or precondition checks against a server that does not implement this feature.

Fixes #1794

…and optimistic concurrency

Adds a monotonically increasing `generation` field to `Task` that the
server increments on every state-changing mutation (TaskState transition
or Artifact addition/update).

Proto changes:
- `Task.generation`: the current generation of the task snapshot.
- `TaskStatusUpdateEvent.generation` / `TaskArtifactUpdateEvent.generation`:
  the post-mutation generation, allowing clients to detect missed events
  by observing gaps in the sequence.
- `GetTaskRequest.current_generation`: enables efficient long-polling;
  the server SHOULD hold the request until the task's generation exceeds
  the supplied value.
- `SendMessageConfiguration.if_generation_match`: optimistic concurrency
  guard; the server MUST reject the request (HTTP 412 / gRPC ABORTED) if
  the task's generation does not match, preventing lost-update races.

Spec documentation changes:
- New Section 3.2.7 Task Generation Semantics covering the generation
  field, event ordering/missed-event detection, long-polling behaviour,
  optimistic concurrency, and backwards compatibility.
- Section 3.1.3 Get Task: cross-reference to new generation semantics
  section for currentGeneration long-polling.
- Section 3.2.2 SendMessageConfiguration: document ifGenerationMatch
  optimistic concurrency behaviour.
- Section 3.3.2 Error Handling: add TaskGenerationMismatchError.
- Section 3.5.1: add long-polling as an update delivery mechanism.
- Section 3.5.2: note generation-based event ordering.
- Section 5.4: add TaskGenerationMismatchError error code mappings
  (JSON-RPC -32010 / gRPC ABORTED / HTTP 412).
- Section 11.5: add currentGeneration query parameter example.
- Section 11.6: add 412 Precondition Failed error response example.

Closes a2aproject#1794

Signed-off-by: Sam Betts <1769706+Tehsmash@users.noreply.github.com>
@Tehsmash Tehsmash requested a review from a team as a code owner May 1, 2026 13:07

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces task generation semantics to the A2A protocol, adding a monotonically increasing generation field to tasks and events. This enables reliable event ordering, missed-event detection, optimistic concurrency control via a new ifGenerationMatch field, and efficient long-polling through the currentGeneration parameter. The review feedback suggests initializing the generation counter at 1 instead of 0 to distinguish between a new task and a server that does not support generations. Additionally, it is recommended to map the TaskGenerationMismatchError to HTTP 409 Conflict to maintain consistency with canonical gRPC-to-HTTP status mappings.

Comment thread docs/specification.md Outdated
Comment thread docs/specification.md Outdated
| `ExtendedAgentCardNotConfiguredError` | `-32007` | `FAILED_PRECONDITION` | `400 Bad Request` |
| `ExtensionSupportRequiredError` | `-32008` | `FAILED_PRECONDITION` | `400 Bad Request` |
| `VersionNotSupportedError` | `-32009` | `FAILED_PRECONDITION` | `400 Bad Request` |
| `TaskGenerationMismatchError` | `-32010` | `ABORTED` | `412 Precondition Failed` |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The mapping of gRPC ABORTED to HTTP 412 Precondition Failed deviates from the canonical gRPC mapping (where ABORTED maps to 409 Conflict). Per the general rules of this repository, compatibility with gRPC transcoding systems should be prioritized by using canonical mappings. While 412 is semantically appropriate for If-Match failures in REST, using ABORTED will likely result in 409 being generated by standard transcoders.

Suggested change
| `TaskGenerationMismatchError` | `-32010` | `ABORTED` | `412 Precondition Failed` |
| TaskGenerationMismatchError | -32010 | ABORTED | 409 Conflict |
References
  1. When mapping gRPC statuses to HTTP statuses, prioritize compatibility with gRPC transcoding systems by using the canonical mapping, even if a more specific HTTP status code is available.

Comment thread specification/a2a.proto Outdated
- Document that clients receiving two consecutive events with identical
  generation values (including two 0s) MUST conclude the server does not
  implement generation and fall back to stream ordering / timestamps.
  This replaces the earlier sentinel-value approach with a robust
  detection rule and covers the backward-compat case cleanly.

- Change TaskGenerationMismatchError HTTP mapping from 412 Precondition
  Failed to 409 Conflict to align with the canonical gRPC ABORTED to
  HTTP 409 transcoding mapping used by standard gRPC-HTTP proxies.
  Updates all four references in the spec and the proto comment.

Signed-off-by: Sam Betts <1769706+Tehsmash@users.noreply.github.com>
Comment thread docs/specification.md Outdated

<span id="327-task-generation-semantics"></span>

The `generation` field on [`Task`](#411-task) is a monotonically increasing integer maintained by the server. It is initialised to `0` when a task is created and **MUST** be incremented by the server on every state-changing mutation:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

monotonically -> sequentially. increasing is always monotonic but not always sequential which is important here. in line 511 we mention that this is assumed on the client, but we never outright say that the server should act in that way, i would make is as explicit as possible, something like:

Events produced by the server MUST have sequential numbering, meaning each change in the generation of a Task MUST by an increase by one and must map 1:1 to a produced Event.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A what-if question. Along with generation, can we have generationIDs ? It would be a list of integers.

Comment thread docs/specification.md Outdated

**Backwards Compatibility:**

The `generation` field was introduced in version **1.1** of this specification. The field defaults to `0` in the Protocol Buffer encoding (proto3 default for `int64`). Clients that do not read or send `generation` continue to interoperate correctly with servers that support it. Servers that have not yet implemented `generation` will return `0` on all events and responses; clients will detect this via the duplicate-generation rule above and gracefully fall back.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we have 1.1 but may be we should have :)

Latest Released Version 1.0.0

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current release is 1.0.0 and we're not going back to change that, this change would only be included if we cut a 1.1 because it involves a proto change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should start planning for that.

Tehsmash and others added 3 commits May 5, 2026 09:42
Replace "monotonically increasing" with "sequentially increasing" and
make the server obligation explicit: generation MUST be incremented by
exactly 1 per mutation, with each mutation mapping 1:1 to one emitted
event. Update both the spec prose and the proto comment accordingly.

Signed-off-by: Sam Betts <1769706+Tehsmash@users.noreply.github.com>
Starting at 1 means generation=0 is an unambiguous sentinel detectable
from a single event, rather than requiring two consecutive events with
the same value. Update the detection rule accordingly: any event
carrying generation=0 signals a non-implementing server. Also update
the backwards-compatibility note and the proto comment.

Signed-off-by: Sam Betts <1769706+Tehsmash@users.noreply.github.com>
@msampathkumar

Copy link
Copy Markdown
Member

Added a git commit to fix the merge conflict.

For TaskNotCancelableError error state, the terminal states are updated.

@msampathkumar

msampathkumar commented Jun 2, 2026

Copy link
Copy Markdown
Member

Should this be part of 1.1 or 2.0 ? (vote yes for 1.1)

/vote

@git-vote

git-vote Bot commented Jun 2, 2026

Copy link
Copy Markdown

Vote created

@msampathkumar has called for a vote on feat(spec): add generation field to Task for ordering, long-polling, and optimistic concurrency (#1810).

The members of the following teams have binding votes:

Team
@a2aproject/a2a-tsc

Non-binding votes are also appreciated as a sign of support!

How to vote

You can cast your vote by reacting to this comment. The following reactions are supported:

In favor Against Abstain
👍 👎 👀

Please note that voting for multiple options is not allowed and those votes won't be counted.

The vote will be open for 11months 29days 3h 50m 24s. It will pass if at least 51% of the users with binding votes vote In favor 👍. Once it's closed, results will be published here as a new comment.

@git-vote

git-vote Bot commented Jun 3, 2026

Copy link
Copy Markdown

Vote status

So far 25.00% of the users with binding vote are in favor and 0.00% are against (passing threshold: 51%).

Summary

In favor Against Abstain Not voted
2 0 0 6

Binding votes (2)

User Vote Timestamp
muscariello In favor 2026-06-02 16:48:05.0 +00:00:00
spetschulatSFDC In favor 2026-06-02 16:46:17.0 +00:00:00
@darrelmiller Pending
@geneknit Pending
@hughesthe1st Pending
@ToddSegal Pending
@siwachabhi Pending
@SivaNSAP Pending

Non-binding votes (1)

User Vote Timestamp
msampathkumar In favor 2026-06-02 16:45:35.0 +00:00:00

3 similar comments
@git-vote

git-vote Bot commented Jun 3, 2026

Copy link
Copy Markdown

Vote status

So far 25.00% of the users with binding vote are in favor and 0.00% are against (passing threshold: 51%).

Summary

In favor Against Abstain Not voted
2 0 0 6

Binding votes (2)

User Vote Timestamp
muscariello In favor 2026-06-02 16:48:05.0 +00:00:00
spetschulatSFDC In favor 2026-06-02 16:46:17.0 +00:00:00
@darrelmiller Pending
@geneknit Pending
@hughesthe1st Pending
@ToddSegal Pending
@siwachabhi Pending
@SivaNSAP Pending

Non-binding votes (1)

User Vote Timestamp
msampathkumar In favor 2026-06-02 16:45:35.0 +00:00:00

@git-vote

git-vote Bot commented Jun 4, 2026

Copy link
Copy Markdown

Vote status

So far 25.00% of the users with binding vote are in favor and 0.00% are against (passing threshold: 51%).

Summary

In favor Against Abstain Not voted
2 0 0 6

Binding votes (2)

User Vote Timestamp
muscariello In favor 2026-06-02 16:48:05.0 +00:00:00
spetschulatSFDC In favor 2026-06-02 16:46:17.0 +00:00:00
@darrelmiller Pending
@geneknit Pending
@hughesthe1st Pending
@ToddSegal Pending
@siwachabhi Pending
@SivaNSAP Pending

Non-binding votes (1)

User Vote Timestamp
msampathkumar In favor 2026-06-02 16:45:35.0 +00:00:00

@git-vote

git-vote Bot commented Jun 5, 2026

Copy link
Copy Markdown

Vote status

So far 25.00% of the users with binding vote are in favor and 0.00% are against (passing threshold: 51%).

Summary

In favor Against Abstain Not voted
2 0 0 6

Binding votes (2)

User Vote Timestamp
muscariello In favor 2026-06-02 16:48:05.0 +00:00:00
spetschulatSFDC In favor 2026-06-02 16:46:17.0 +00:00:00
@darrelmiller Pending
@geneknit Pending
@hughesthe1st Pending
@ToddSegal Pending
@siwachabhi Pending
@SivaNSAP Pending

Non-binding votes (1)

User Vote Timestamp
msampathkumar In favor 2026-06-02 16:45:35.0 +00:00:00

@git-vote

git-vote Bot commented Jun 6, 2026

Copy link
Copy Markdown

Vote status

So far 37.50% of the users with binding vote are in favor and 0.00% are against (passing threshold: 51%).

Summary

In favor Against Abstain Not voted
3 0 0 5

Binding votes (3)

User Vote Timestamp
muscariello In favor 2026-06-02 16:48:05.0 +00:00:00
siwachabhi In favor 2026-06-05 18:09:03.0 +00:00:00
spetschulatSFDC In favor 2026-06-02 16:46:17.0 +00:00:00
@darrelmiller Pending
@geneknit Pending
@hughesthe1st Pending
@ToddSegal Pending
@SivaNSAP Pending

Non-binding votes (1)

User Vote Timestamp
msampathkumar In favor 2026-06-02 16:45:35.0 +00:00:00

2 similar comments
@git-vote

git-vote Bot commented Jun 7, 2026

Copy link
Copy Markdown

Vote status

So far 37.50% of the users with binding vote are in favor and 0.00% are against (passing threshold: 51%).

Summary

In favor Against Abstain Not voted
3 0 0 5

Binding votes (3)

User Vote Timestamp
muscariello In favor 2026-06-02 16:48:05.0 +00:00:00
siwachabhi In favor 2026-06-05 18:09:03.0 +00:00:00
spetschulatSFDC In favor 2026-06-02 16:46:17.0 +00:00:00
@darrelmiller Pending
@geneknit Pending
@hughesthe1st Pending
@ToddSegal Pending
@SivaNSAP Pending

Non-binding votes (1)

User Vote Timestamp
msampathkumar In favor 2026-06-02 16:45:35.0 +00:00:00

@git-vote

git-vote Bot commented Jun 8, 2026

Copy link
Copy Markdown

Vote status

So far 37.50% of the users with binding vote are in favor and 0.00% are against (passing threshold: 51%).

Summary

In favor Against Abstain Not voted
3 0 0 5

Binding votes (3)

User Vote Timestamp
muscariello In favor 2026-06-02 16:48:05.0 +00:00:00
siwachabhi In favor 2026-06-05 18:09:03.0 +00:00:00
spetschulatSFDC In favor 2026-06-02 16:46:17.0 +00:00:00
@darrelmiller Pending
@geneknit Pending
@hughesthe1st Pending
@ToddSegal Pending
@SivaNSAP Pending

Non-binding votes (1)

User Vote Timestamp
msampathkumar In favor 2026-06-02 16:45:35.0 +00:00:00

@git-vote

git-vote Bot commented Jun 9, 2026

Copy link
Copy Markdown

Vote status

So far 62.50% of the users with binding vote are in favor and 0.00% are against (passing threshold: 51%).

Summary

In favor Against Abstain Not voted
5 0 0 3

Binding votes (5)

User Vote Timestamp
darrelmiller In favor 2026-06-09 15:37:13.0 +00:00:00
geneknit In favor 2026-06-09 16:10:56.0 +00:00:00
muscariello In favor 2026-06-02 16:48:05.0 +00:00:00
siwachabhi In favor 2026-06-05 18:09:03.0 +00:00:00
spetschulatSFDC In favor 2026-06-02 16:46:17.0 +00:00:00
@hughesthe1st Pending
@ToddSegal Pending
@SivaNSAP Pending

Non-binding votes (1)

User Vote Timestamp
msampathkumar In favor 2026-06-02 16:45:35.0 +00:00:00

@git-vote

git-vote Bot commented Jun 10, 2026

Copy link
Copy Markdown

Vote closed

The vote passed! 🎉

62.50% of the users with binding vote were in favor and 0.00% were against (passing threshold: 51%).

Summary

In favor Against Abstain Not voted
5 0 0 3

Binding votes (5)

User Vote Timestamp
@darrelmiller In favor 2026-06-09 15:37:13.0 +00:00:00
@geneknit In favor 2026-06-09 16:10:56.0 +00:00:00
@muscariello In favor 2026-06-02 16:48:05.0 +00:00:00
@siwachabhi In favor 2026-06-05 18:09:03.0 +00:00:00
@spetschulatSFDC In favor 2026-06-02 16:46:17.0 +00:00:00

Non-binding votes (1)

User Vote Timestamp
@msampathkumar In favor 2026-06-02 16:45:35.0 +00:00:00

@Tehsmash Tehsmash changed the title feat(spec): add generation field to Task for ordering, long-polling, and optimistic concurrency feat: add generation field to Task for ordering, long-polling, and optimistic concurrency Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat]: Add generation/version number field to Task for event ordering, long-polling, and optimistic concurrency

6 participants