Skip to content

Commit 7fb9971

Browse files
committed
refactoring to use messageId for idempotency instead of adding a new field
1 parent 17663b8 commit 7fb9971

File tree

4 files changed

+93
-105
lines changed

4 files changed

+93
-105
lines changed

docs/specification.md

Lines changed: 30 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ Specifies optional A2A protocol features supported by the agent.
322322
--8<-- "types/src/types.ts:AgentCapabilities"
323323
```
324324

325-
- **`correlationIdRequired`**: When set to `true`, indicates that the agent requires clients to provide a `correlationId` field in `MessageSendParams` for all new task creation requests. This enables idempotent task creation to handle network failures and prevent duplicate operations. See [Section 7.1.2](#712-correlation-ids-and-idempotency) for detailed behavior.
325+
- **`idempotencySupported`**: When set to `true`, indicates that the agent supports messageId-based idempotency for new task creation. This enables the agent to detect and handle duplicate `messageId` values to prevent unintended duplicate task creation due to network failures or client retries. See [Section 7.1.2](#712-messageid-based-idempotency) for detailed behavior.
326326

327327
#### 5.5.2.1. `AgentExtension` Object
328328

@@ -699,7 +699,6 @@ Sends a message to an agent to initiate a new interaction or to continue an exis
699699
{
700700
message: Message,
701701
configuration?: MessageSendConfiguration,
702-
correlationId?: string,
703702
metadata?: { [key: string]: any }
704703
}
705704
```
@@ -724,27 +723,29 @@ The `error` response for all transports in case of failure is a [`JSONRPCError`]
724723
--8<-- "types/src/types.ts:MessageSendConfiguration"
725724
```
726725

727-
#### 7.1.2. Correlation IDs and Idempotency
726+
#### 7.1.2. MessageId-Based Idempotency
728727

729-
A2A supports optional correlation IDs to enable idempotent task creation, addressing scenarios where network failures or client crashes could result in duplicate tasks with unintended side effects.
728+
A2A supports optional messageId-based idempotency to enable idempotent task creation, addressing scenarios where network failures or client crashes could result in duplicate tasks with unintended side effects.
729+
730+
**Scope**: Idempotency **ONLY** applies to new task creation (when `message.taskId` is not provided). Messages sent to continue existing tasks follow normal message uniqueness rules without task-level deduplication.
730731

731732
**Agent Requirements:**
732-
- Agents **MAY** support correlation IDs by declaring `correlationIdRequired: true` in their `AgentCapabilities`.
733-
- When `correlationIdRequired` is `true`, agents **MUST** require a `correlationId` field in `MessageSendParams` for all new task creation requests.
734-
- When `correlationIdRequired` is `false` or absent, agents **MAY** ignore provided `correlationId` values.
733+
- Agents **MAY** support idempotency by declaring `idempotencySupported: true` in their `AgentCapabilities`.
734+
- When `idempotencySupported` is `true`, agents **MUST** track `messageId` values for new task creation within the authenticated user/session scope.
735+
- When `idempotencySupported` is `false` or absent, agents **MAY** not support idempotency and do not track `messageId` values.
735736

736737
**Server Behavior:**
737-
- **Correlation ID scope**: Correlation IDs are scoped to the authenticated user/session to prevent cross-user conflicts.
738-
- **Active task collision**: If a `correlationId` matches an existing task in a non-terminal state (`submitted`, `working`, `input-required`), the server **MUST** return a [`CorrelationIdAlreadyExistsError`](#82-a2a-specific-errors) (-32008).
739-
- **Terminal task reuse**: If a `correlationId` matches a task in a terminal state (`completed`, `failed`, `canceled`, `rejected`), the server **MAY** allow creating a new task with the same correlation ID.
740-
- **Time-based expiry**: Servers **MAY** implement time-based expiry for correlation IDs associated with terminal tasks.
738+
- **MessageId scope**: MessageId tracking is scoped to the authenticated user/session to prevent cross-user conflicts.
739+
- **Active task collision**: If a `messageId` (for new task creation) matches an existing task in a non-terminal state (`submitted`, `working`, `input-required`), the server **MUST** return a [`MessageIdAlreadyExistsError`](#82-a2a-specific-errors) (-32008).
740+
- **Terminal task reuse**: If a `messageId` matches a task in a terminal state (`completed`, `failed`, `canceled`, `rejected`), the server **MAY** allow creating a new task with the same messageId.
741+
- **Time-based expiry**: Servers **MAY** implement time-based expiry for messageId tracking associated with terminal tasks.
741742

742743
**Client Responsibilities:**
743-
- **Unique correlation IDs**: Clients **MUST** generate unique correlation IDs for each intended new task within their authenticated session.
744-
- **Error handling**: When receiving `CorrelationIdAlreadyExistsError`, clients **SHOULD**:
745-
1. Use the `existingTaskId` from the error data (if provided) to call `tasks/get`. This is the correct action when retrying a request that may have already succeeded (e.g., after a network error).
746-
2. Alternatively, if the `correlationId` was reused unintentionally and a new, distinct task is desired, generate a new `correlationId` and retry the request.
747-
- **Retry safety**: Clients can safely retry `message/send` requests with the same `correlationId` after network failures.
744+
- **Unique messageIds**: Clients **MUST** generate unique `messageId` values for each intended new task within their authenticated session (this is already required by the base A2A specification).
745+
- **Error handling**: When receiving `MessageIdAlreadyExistsError`, clients **SHOULD**:
746+
1. Use the `existingTaskId` from the error data to call `tasks/get` to retrieve the existing task. This is the correct action when retrying a request that may have already succeeded (e.g., after a network error).
747+
2. Alternatively, if the `messageId` was reused unintentionally and a new, distinct task is desired, generate a new `messageId` and retry the request.
748+
- **Retry safety**: Clients can safely retry `message/send` requests with the same `messageId` after network failures when creating new tasks.
748749

749750
### 7.2. `message/stream`
750751

@@ -788,7 +789,6 @@ Sends a message to an agent to initiate/continue a task AND subscribes the clien
788789
{
789790
message: Message,
790791
configuration?: MessageSendConfiguration,
791-
correlationId?: string,
792792
metadata?: { [key: string]: any }
793793
}
794794
```
@@ -1199,7 +1199,7 @@ These are custom error codes defined within the JSON-RPC server error range (`-3
11991199
| `-32005` | `ContentTypeNotSupportedError` | Incompatible content types | A [Media Type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types) provided in the request's `message.parts` (or implied for an artifact) is not supported by the agent or the specific skill being invoked. |
12001200
| `-32006` | `InvalidAgentResponseError` | Invalid agent response type | Agent generated an invalid response for the requested method |
12011201
| `-32007` | `AuthenticatedExtendedCardNotConfiguredError` | Authenticated Extended Card not configured | The agent does not have an Authenticated Extended Card configured.|
1202-
| `-32008` | `CorrelationIdAlreadyExistsError` | Correlation ID already exists for active task | The provided `correlationId` is already associated with an active task in a non-terminal state. The client should either retrieve the existing task using the provided `existingTaskId` or generate a new correlation ID. |
1202+
| `-32008` | `MessageIdAlreadyExistsError` | Message ID already exists for active task | The provided `messageId` is already associated with an active task in a non-terminal state. The client should either retrieve the existing task using the provided `existingTaskId` or generate a new message ID. |
12031203

12041204
Servers MAY define additional error codes within the `-32000` to `-32099` range for more specific scenarios not covered above, but they **SHOULD** document these clearly. The `data` field of the `JSONRPCError` object can be used to provide more structured details for any error.
12051205

@@ -1896,21 +1896,21 @@ _If the task were longer-running, the server might initially respond with `statu
18961896
}
18971897
```
18981898

1899-
### 9.8. Idempotent Task Creation with Correlation IDs
1899+
### 9.8. Idempotent Task Creation with MessageId
19001900

19011901
**Scenario:** Client needs to ensure idempotent task creation to avoid duplicate operations in case of network failures.
19021902

1903-
1. **Client discovers agent requires correlation IDs from Agent Card:**
1903+
1. **Client discovers agent supports idempotency from Agent Card:**
19041904

19051905
```json
19061906
{
19071907
"capabilities": {
1908-
"correlationIdRequired": true
1908+
"idempotencySupported": true
19091909
}
19101910
}
19111911
```
19121912

1913-
2. **Client sends initial message with correlation ID:**
1913+
2. **Client sends initial message (new task creation):**
19141914

19151915
```json
19161916
{
@@ -1926,9 +1926,8 @@ _If the task were longer-running, the server might initially respond with `statu
19261926
"text": "Process this critical financial transaction - charge card ending 1234 for $500"
19271927
}
19281928
],
1929-
"messageId": "a1b2c3d4-e5f6-7890-1234-567890abcdef"
1930-
},
1931-
"correlationId": "client-txn-20240315-001"
1929+
"messageId": "client-txn-20240315-001"
1930+
}
19321931
}
19331932
}
19341933
```
@@ -1947,7 +1946,7 @@ _If the task were longer-running, the server might initially respond with `statu
19471946
}
19481947
```
19491948

1950-
4. **Network failure occurs - client retries with same correlation ID:**
1949+
4. **Network failure occurs - client retries with same messageId (new task creation):**
19511950

19521951
```json
19531952
{
@@ -1963,24 +1962,23 @@ _If the task were longer-running, the server might initially respond with `statu
19631962
"text": "Process this critical financial transaction - charge card ending 1234 for $500"
19641963
}
19651964
],
1966-
"messageId": "a1b2c3d4-e5f6-7890-1234-567890abcdef"
1967-
},
1968-
"correlationId": "client-txn-20240315-001"
1965+
"messageId": "client-txn-20240315-001"
1966+
}
19691967
}
19701968
}
19711969
```
19721970

1973-
5. **Server detects duplicate correlation ID and returns error:**
1971+
5. **Server detects duplicate messageId and returns error:**
19741972

19751973
```json
19761974
{
19771975
"jsonrpc": "2.0",
19781976
"id": "req-009",
19791977
"error": {
19801978
"code": -32008,
1981-
"message": "Correlation ID already exists for active task",
1979+
"message": "Message ID already exists for active task",
19821980
"data": {
1983-
"correlationId": "client-txn-20240315-001",
1981+
"messageId": "client-txn-20240315-001",
19841982
"existingTaskId": "server-task-uuid-12345"
19851983
}
19861984
}

specification/grpc/a2a.proto

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,8 @@ message AgentCapabilities {
421421
bool push_notifications = 2;
422422
// Extensions supported by this agent.
423423
repeated AgentExtension extensions = 3;
424-
// If the agent requires correlation IDs for idempotent task creation
425-
bool correlation_id_required = 4;
424+
// If the agent supports messageId-based idempotency for task creation
425+
bool idempotency_supported = 4;
426426
}
427427

428428
// A declaration of an extension supported by an Agent.
@@ -622,9 +622,7 @@ message SendMessageRequest {
622622
Message request = 1
623623
[(google.api.field_behavior) = REQUIRED, json_name = "message"];
624624
SendMessageConfiguration configuration = 2;
625-
// Optional client-generated correlation ID for idempotent task creation
626-
string correlation_id = 3;
627-
google.protobuf.Struct metadata = 4;
625+
google.protobuf.Struct metadata = 3;
628626
}
629627

630628
message GetTaskRequest {

specification/json/a2a.json

Lines changed: 45 additions & 47 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)