You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
11.[Summary of Key Changes](#11-summary-of-key-changes-in-v10)
29
+
12.[Get Started](#12-get-started)
29
30
30
31
---
31
32
@@ -96,7 +97,7 @@ Constructing messages is simplified in v1.0. The old API required wrapping conte
96
97
| Structured data |`Part(DataPart(data=..., ...))`|`Part(data=..., ...)`|
97
98
98
99
**Note**:
99
-
* When using `File (bytes)` in v1.0, the data serialisatinon (via base64 encoding) is not required as A2A now uses Protobuf that automatically does it for you.
100
+
* When using `File (bytes)` in v1.0, data serialization (via base64 encoding) is not required because A2A now uses Protobuf, which handles it automatically.
100
101
* In v1.0, `Part.DataPart.data` is renamed to `Part.data` and is of type `google.protobuf.Value`. Use `ParseDict` to convert a Python dict into a suitable value. See the examples below for more details.
101
102
102
103
**Before (v0.3):**
@@ -175,7 +176,7 @@ message = Message(
175
176
)
176
177
```
177
178
178
-
For text-only messages, use the [A2A helper utilities](#9-helper-utilities) to reduce boilerplate:
179
+
For text-only messages, use the [A2A helper utilities](#10-helper-utilities) to reduce boilerplate:
179
180
180
181
```python
181
182
from a2a.helpers import new_text_message
@@ -191,7 +192,7 @@ message = new_text_message(text="What's the weather in Warsaw?", role=Role.ROLE_
191
192
Key changes:
192
193
- Added an `AgentInterface` class to support multiple transport bindings via the newly added `supported_interfaces` field in AgentCard.
193
194
- The `url` parameter in `AgentCard` is removed and is now part of `AgentInterface`.
194
-
- Accepted values for `AgentInterface.protocol_binding`: `'JSONRPC'`, `'HTTP+JSON'`, `'GRPC'`
195
+
- Accepted values for `AgentInterface.protocol_binding`: `'JSONRPC'`, `'HTTP+JSON'`, `'GRPC'`.
195
196
- The `AgentCard.supports_authenticated_extended_card` field is renamed to `AgentCapabilities.extended_agent_card`.
196
197
- The `AgentCapabilities.input_modes` and `AgentCapabilities.output_modes` fields are removed; use `AgentCard.default_input_modes` and `AgentCard.default_output_modes` for card-level defaults, or `AgentSkill.input_modes` and `AgentSkill.output_modes` for per-skill overrides.
197
198
- The `examples` parameter in `AgentCard` is removed and is now part of `AgentSkill`.
The application wrapper classes (`A2AStarletteApplication`, `A2AFastApiApplication` and `A2ARESTFastApiApplication`) have been removed. The server setup now uses Starlette route factory functions directly, giving you better control over the routing, middleware, authentication, logging, and other aspects of the server.
305
+
The server now strictly enforces the [A2A spec rules for `message/stream`](https://a2a-protocol.org/v1.0.0/specification/#312-send-streaming-message). Existing executors that mix message and task events, or emit task updates before the initial `Task`, will fail at runtime with `InvalidAgentResponseError`. See [PR #979](https://github.com/a2aproject/a2a-python/pull/979).
306
+
307
+
In v1.0, your `AgentExecutor` MUST follow exactly one of these two streaming patterns:
308
+
309
+
1.**Message-only stream** — enqueue exactly **one**`Message` and stop.
310
+
2.**Task lifecycle stream** — enqueue a `Task`**first**, then zero or more `TaskStatusUpdateEvent` / `TaskArtifactUpdateEvent` objects until a terminal state is reached.
311
+
312
+
The following are now hard errors (each raises `InvalidAgentResponseError`):
313
+
314
+
| Violation | Error message |
315
+
|---|---|
316
+
| Enqueue a `Message` after a `Task` (mixing modes) |*Received Message object in task mode...*|
317
+
| Enqueue more than one `Message`|*Multiple Message objects received.*|
318
+
| Enqueue a `Task`/update event after a `Message`|*Received `<Type>` in message mode...*|
319
+
| Enqueue a `TaskStatusUpdateEvent` before the initial `Task`|*Agent should enqueue Task before `<Type>` event*|
320
+
321
+
### Migration
322
+
323
+
**Before (v0.3 — silently tolerated):**
324
+
```python
325
+
from a2a.helpers import new_text_message
326
+
from a2a.server.agent_execution import AgentExecutor
327
+
from a2a.types import TaskStatusUpdateEvent
328
+
329
+
classMyExecutor(AgentExecutor):
330
+
asyncdefexecute(self, context, event_queue):
331
+
# Mixing Message and Task events — no longer allowed.
332
+
await event_queue.enqueue_event(new_text_message('Working on it...'))
self._agent = agent # Your underlying agent (LLM, tool, etc.)
361
+
362
+
asyncdefexecute(self, context, event_queue):
363
+
task = context.current_task or new_task_from_user_message(context.message)
364
+
await event_queue.enqueue_event(task) # ✅ Task MUST be first
365
+
366
+
await event_queue.enqueue_event(
367
+
new_text_status_update_event(
368
+
task_id=task.id,
369
+
context_id=task.context_id,
370
+
state=TaskState.TASK_STATE_WORKING,
371
+
text='Processing...',
372
+
)
373
+
)
374
+
375
+
result =awaitself._agent.invoke(context.message)
376
+
await event_queue.enqueue_event(
377
+
new_text_artifact_update_event(
378
+
task_id=task.id,
379
+
context_id=task.context_id,
380
+
name='result',
381
+
text=result,
382
+
)
383
+
)
384
+
385
+
await event_queue.enqueue_event(
386
+
new_text_status_update_event(
387
+
task_id=task.id,
388
+
context_id=task.context_id,
389
+
state=TaskState.TASK_STATE_COMPLETED,
390
+
text='Done!',
391
+
)
392
+
)
393
+
```
394
+
395
+
**Quick checklist when migrating an executor:**
396
+
- Decide upfront: is this a one-shot message reply, or a tracked task?
397
+
- If task-based, always enqueue the `Task` object as the very first event.
398
+
- Never mix `Message` events with `TaskStatusUpdateEvent` / `TaskArtifactUpdateEvent` in the same stream.
399
+
- Send only one `Message` per stream when using the message-only pattern.
400
+
401
+
> **Example**: [`helloworld/agent_executor.py` in PR #474](https://github.com/a2aproject/a2a-samples/pull/474/files#diff-950e8baafcf17d50db5c10b525949407e129995df5295161fbf688e6374ad284)
402
+
403
+
---
404
+
405
+
## 5. Server: Application Setup
406
+
407
+
The application wrapper classes (`A2AStarletteApplication`, `A2AFastApiApplication`, and `A2ARESTFastApiApplication`) have been removed. The server setup now uses Starlette route factory functions directly, giving you better control over routing, middleware, authentication, logging, and other aspects of the server.
The `BaseClient.send_message()` return type is standardized from `AsyncIterator[ClientEvent | Message]` to `AsyncIterator[StreamResponse]`.
429
532
@@ -457,7 +560,7 @@ async for chunk in client.send_message(request):
457
560
458
561
---
459
562
460
-
## 8. Client: Push Notifications Config
563
+
## 9. Client: Push Notifications Config
461
564
462
565
`ClientConfig.push_notification_config` is now **singular** (a single `TaskPushNotificationConfig` or `None`), not a list.
463
566
@@ -478,7 +581,7 @@ config = ClientConfig(
478
581
479
582
---
480
583
481
-
## 9. Helper Utilities
584
+
## 10. Helper Utilities
482
585
483
586
To improve the developer experience, we have consolidated helper functions into a single import. In v0.3, these helper functions were scattered across different modules. In v1.0, they are all available under `a2a.helpers`.
484
587
@@ -525,19 +628,20 @@ print(text)
525
628
526
629
---
527
630
528
-
## 10. Summary of Key Changes in v1.0
631
+
## 11. Summary of Key Changes in v1.0
529
632
530
633
-**Migration to Protobuf** — Core types have migrated from Pydantic models to Protobuf-based classes. Protobuf objects do not support arbitrary attribute assignment. Use `MessageToDict` from `google.protobuf.json_format` to convert objects to dictionaries, and `HasField('field_name')` to check for optional fields.
531
634
-**Standardization to `SCREAMING_SNAKE_CASE`** — All enum values have been renamed from `snake_case` strings to `SCREAMING_SNAKE_CASE` for compliance with the ProtoJSON specification.
532
635
-**`AgentCard`** — Significantly restructured to support multiple transport interfaces.
533
636
-**`AgentInterface`** — The top-level `url` field is replaced by `supported_interfaces`, a list of `AgentInterface` objects. Each entry describes a single transport endpoint with fields for `protocol_binding`, `protocol_version`, and `url`.
534
637
-**Input and output modes** — `AgentCapabilities.input_modes` and `AgentCapabilities.output_modes` are removed and now live directly on `AgentCard` as `default_input_modes` and `default_output_modes`. Individual skills can override these with their own `input_modes` and `output_modes`.
535
-
-**Application setup** — The wrapper classes (`A2AStarletteApplication`, `A2AFastApiApplication` and `A2ARESTFastApiApplication`) have been removed. Server setup now uses route factory functions — `create_jsonrpc_routes()`, `create_rest_routes()`, and `create_agent_card_routes()` — composed directly into a Starlette or FastAPI app.
638
+
-**AgentExecutor streaming rules** — The server now strictly enforces the A2A spec: an executor must enqueue either a single `Message` or a `Task` followed by update events (with the `Task` first). Mixing modes, emitting multiple `Message`s, or sending updates before the initial `Task` raises `InvalidAgentResponseError`.
639
+
-**Application setup** — The wrapper classes (`A2AStarletteApplication`, `A2AFastApiApplication`, and `A2ARESTFastApiApplication`) have been removed. Server setup now uses route factory functions — `create_jsonrpc_routes()`, `create_rest_routes()`, and `create_agent_card_routes()` — composed directly into a Starlette or FastAPI app.
536
640
-**Helper utilities** — A new `a2a.helpers` module consolidates all helper functions under a single import, replacing the scattered `a2a.utils.*` modules and adding new helpers for constructing and reading v1.0 proto types.
537
641
538
642
---
539
643
540
-
## 11. Get Started
644
+
## 12. Get Started
541
645
542
646
The fastest way to see v1.0 in action is to run the samples:
0 commit comments