# Миграция с 0.3 на 1.0

Что изменилось и в каком порядке обновлять

> Страница сайта A2A Docs — неофициального перевода документации протокола Agent2Agent (https://a2adocs.ru/migration/). Тип: Перевод. Основа: What's New in v1.0 (https://a2a-protocol.org/latest/whats-new-v1/). Версия спецификации 1.0.0, сверено 05.10.2026.

Версия 1.0 — первая стабильная версия A2A. Она делает протокол строже и понятнее, но содержит ломающие изменения во взаимодействии, поэтому код, написанный для 0.3, придётся обновить. Страница систематизирует и переводит документ «What's New in v1.0» из официальной документации.

> **Заметка переводчика.** В анонсе релиза сказано, что Agent Card изменён так, что агент может объявлять поддержку и 0.3, и 1.0 одновременно. Но структура полей карточки при этом изменилась (см. [ниже](#agent-card)), так что код разбора карточки обновлять всё равно нужно.

## С чего начать

Официальная документация расставляет приоритеты так.

| Приоритет | Что сделать |
| --- | --- |
| Критично, сразу | Обновить разбор частей (`Part`) и событий потока (способ различения типов). Обновить разбор Agent Card (структура). Добавить заголовок `A2A-Version` во все запросы. |
| Высокий, в течение месяца | Перейти на курсорную пагинацию. Обновить обработку значений состояния и ролей. Добавить поддержку параметра `returnImmediately`. |
| Средний, в течение трёх месяцев | Реализовать проверку подписи Agent Card. Проверять требуемые расширения. Привести временные метки к ISO 8601. Реализовать новые типы ошибок. |
| Низкий, по возможности | Использовать расширенные метаданные. Реализовать аутентификацию mTLS. |

## Переименование операций

| Версия 0.3.0 | Версия 1.0 |
| --- | --- |
| `message/send` | `SendMessage` |
| `message/stream` | `SendStreamingMessage` |
| `tasks/get` | `GetTask` |
| (не было) | `ListTasks` — новая операция |
| `tasks/cancel` | `CancelTask` |
| `tasks/resubscribe` | `SubscribeToTask` |
| `agent/getAuthenticatedExtendedCard` | `GetExtendedAgentCard` |
| `tasks/pushNotificationConfig/set` | `CreateTaskPushNotificationConfig` |
| `tasks/pushNotificationConfig/get` | `GetTaskPushNotificationConfig` |
| `tasks/pushNotificationConfig/list` | `ListTaskPushNotificationConfigs` |
| `tasks/pushNotificationConfig/delete` | `DeleteTaskPushNotificationConfig` |

Модель запросов всех операций push-уведомлений изменилась, а `TaskPushNotificationConfig` стала плоской. Оригинал отмечает, что на время перехода предусмотрены псевдонимы имён операций.

## Значения перечислений

Все значения перечислений теперь записываются в стиле `SCREAMING_SNAKE_CASE` с префиксом типа. Так требует спецификация ProtoJSON. Это один из самых заметных ломающих изменений.

| Версия 0.3.0 | Версия 1.0 |
| --- | --- |
| `"submitted"` | `"TASK_STATE_SUBMITTED"` |
| `"working"` | `"TASK_STATE_WORKING"` |
| `"completed"` | `"TASK_STATE_COMPLETED"` |
| `"failed"` | `"TASK_STATE_FAILED"` |
| `"canceled"` | `"TASK_STATE_CANCELED"` |
| `"rejected"` | `"TASK_STATE_REJECTED"` |
| `"input-required"` | `"TASK_STATE_INPUT_REQUIRED"` |
| `"auth-required"` | `"TASK_STATE_AUTH_REQUIRED"` |
| `"user"` | `"ROLE_USER"` |
| `"agent"` | `"ROLE_AGENT"` |

```json
// 0.3.0
{ "status": { "state": "completed", "timestamp": "2024-03-15T10:15:00Z" } }

// 1.0
{ "status": { "state": "TASK_STATE_COMPLETED", "timestamp": "2024-03-15T10:15:00.000Z" } }
```

Время теперь указывается строго по ISO 8601 в UTC с миллисекундами: `YYYY-MM-DDTHH:mm:ss.sssZ`.

## Part

Структура частей полностью переработана. Вместо отдельных `TextPart`, `FilePart` и `DataPart` теперь одно сообщение `Part`.

**Что изменилось:**

- удалены отдельные типы `TextPart`, `FilePart`, `DataPart`;
- удалено поле-различитель `kind`;
- удалён вложенный объект `file`;
- появилось единое сообщение `Part` с полем `oneof content`: тип определяется тем, какое поле есть: `text`, `raw`, `url` или `data`;
- `mediaType` заменяет `mimeType` и доступно для всех видов частей;
- `filename` доступно для всех видов частей, а не только для файлов;
- `raw` — встроенное двоичное содержимое (в JSON — base64);
- `url` — ссылка на файл, заменяет `file.fileWithUri`.

```json
// 0.3.0
{ "kind": "text", "text": "Hello world" }
{ "kind": "file", "file": { "fileWithUri": "https://example.com/doc.pdf", "mimeType": "application/pdf" } }
{ "kind": "data", "data": { "key": "value" } }

// 1.0
{ "text": "Hello world", "mediaType": "text/plain" }
{ "url": "https://example.com/doc.pdf", "filename": "doc.pdf", "mediaType": "application/pdf" }
{ "data": { "key": "value" }, "mediaType": "application/json" }
```

Код, который определял тип по `kind`, нужно заменить проверкой наличия поля:

```javascript
// 0.3.0
if (part.kind === "text") { return part.text; }
else if (part.kind === "file") { /* part.file.fileWithUri или fileWithBytes */ }
else if (part.kind === "data") { return part.data; }

// 1.0
if ("text" in part) { return part.text; }
else if ("url" in part) { return fetchFile(part.url); }
else if ("raw" in part) { return decodeBase64(part.raw); }
else if ("data" in part) { return part.data; }
```

В `Message` и `Artifact` появилось поле `extensions[]` с URI расширений.

## События потока

Тип события больше не определяется полем `kind`: его определяет имя JSON-поля-обёртки.

- удалено поле `kind`;
- удалено логическое поле `final` у `TaskStatusUpdateEvent`: завершение потока определяется механизмом закрытия потока конкретной привязки;
- новый шаблон: тип события определяется именем члена JSON, `statusUpdate` или `artifactUpdate`.

```json
// 0.3.0
{ "kind": "status-update", "taskId": "...", "contextId": "...", "status": {}, "final": true }

// 1.0
{ "statusUpdate": { "taskId": "...", "contextId": "...", "status": {} } }
```

```javascript
// 0.3.0
if (event.kind === "status-update") { handleStatusUpdate(event); }
else if (event.kind === "artifact-update") { handleArtifactUpdate(event); }

// 1.0
if ("statusUpdate" in event) { handleStatusUpdate(event.statusUpdate); }
else if ("artifactUpdate" in event) { handleArtifactUpdate(event.artifactUpdate); }
```

Дополнительно уточнено, что допускается несколько одновременных потоков одной задачи, и все они получают одни и те же события в одном порядке. Подробнее: [«Обновления задач»](https://a2adocs.ru/protocol/updates/).

## Agent Card

Структура карточки переработана: сведения об интерфейсах собраны в один список.

| Что | Как было в 0.3.0 | Как стало в 1.0 |
| --- | --- | --- |
| Версия протокола | `protocolVersion` в карточке | В каждом интерфейсе: `supportedInterfaces[].protocolVersion` |
| Основной адрес | `url` | `supportedInterfaces[0].url` |
| Предпочтительный транспорт и дополнительные интерфейсы | `preferredTransport`, `additionalInterfaces` | Единый список `supportedInterfaces[]` (у каждого `url`, `protocolBinding`, `protocolVersion`) |
| Расширенная карточка | `supportsAuthenticatedExtendedCard` в корне | `capabilities.extendedAgentCard` |
| Подписи | Не было | Необязательное поле `signatures` |

```json
// 0.3.0
{
  "protocolVersion": "0.3",
  "url": "https://agent.example.com/a2a",
  "preferredTransport": "JSONRPC",
  "supportsAuthenticatedExtendedCard": true,
  "additionalInterfaces": [...]
}

// 1.0
{
  "supportedInterfaces": [
    { "url": "https://agent.example.com/a2a", "protocolBinding": "JSONRPC", "protocolVersion": "1.0" }
  ],
  "capabilities": { "extendedAgentCard": true },
  "signatures": [...]
}
```

```javascript
// 0.3.0
const endpoint = agentCard.url;
const transport = agentCard.preferredTransport;
const supportsExtended = agentCard.supportsAuthenticatedExtendedCard;

// 1.0
const primaryInterface = agentCard.supportedInterfaces[0];
const endpoint = primaryInterface.url;
const transport = primaryInterface.protocolBinding;
const supportsExtended = agentCard.capabilities.extendedAgentCard;
```

Адрес публикации остался прежним: `/.well-known/agent-card.json`. Подробнее: [«Agent Card»](https://a2adocs.ru/concepts/agent-card/).

## Пагинация

Операция `ListTasks` появилась только в 1.0, и она сразу курсорная. Если вы реализовывали постраничный список по-своему, перейдите на `pageToken` и `nextPageToken`:

```javascript
let pageToken = undefined;
do {
  const response = await listTasks({ pageToken, pageSize: 50 });
  // обработать response.tasks
  pageToken = response.nextPageToken;
} while (pageToken);
```

Подробнее: [«Методы»](https://a2adocs.ru/protocol/methods/#listtasks).

## Ошибки

HTTP+JSON-ответы с ошибкой теперь используют ProtoJSON-представление `google.rpc.Status` вместо RFC 9457. Тип содержимого изменился с `application/problem+json` на `application/json`. Для ошибок A2A в `details` (JSON-RPC: `data`) ДОЛЖЕН быть объект `google.rpc.ErrorInfo` с полями `reason` и `domain: "a2a-protocol.org"`. Примеры и список ошибок: [«Ошибки»](https://a2adocs.ru/protocol/errors/#model-oshibok-v-versii-1-0).

## HTTP-адреса и идентификаторы

- **Без префикса `/v1`.** В HTTP+JSON-привязке убран префикс `/v1`. Было `POST /v1/message:send`, стало `POST /message:send` и `GET /tasks/{id}`. Версию при необходимости владелец агента может включить в базовый адрес.
- **Простые идентификаторы.** Все идентификаторы теперь простые значения. Составные идентификаторы вида `tasks/{taskId}` ушли: операции, где раньше использовались составные идентификаторы, теперь принимают родителя и ресурс отдельными полями. Например, `tasks/{taskId}/pushNotificationConfigs/{configId}` превратилось в отдельные `task_id` и `id`. Идентификаторы прямо соответствуют ключам в базе данных.

## OAuth 2.0

Поддержка OAuth 2.0 приведена в соответствие с актуальными рекомендациями по безопасности (BCP).

- **Удалены потоки:** `ImplicitOAuthFlow` (риск утечки токена через историю и журналы браузера) и `PasswordOAuthFlow` (риск раскрытия учётных данных).
- **Добавлен поток:** `DeviceCodeOAuthFlow` (RFC 8628) для консольных инструментов, IoT-устройств и сред без удобного ввода.
- **Усилена безопасность:** в `AuthorizationCodeOAuthFlow` добавлено поле `pkceRequired` (RFC 7636): оно показывает, обязателен ли PKCE. PKCE рекомендуется всем OAuth-клиентам и обязателен для публичных клиентов.

```json
// 0.3.0: поток implicit (теперь удалён)
{ "implicitFlow": { "authorizationUrl": "https://auth.example.com/authorize", "scopes": { "read": "Read access" } } }

// 1.0: вместо него код авторизации + PKCE
{
  "authorizationCodeFlow": {
    "authorizationUrl": "https://auth.example.com/authorize",
    "tokenUrl": "https://auth.example.com/token",
    "pkceRequired": true,
    "scopes": { "read": "Read access" }
  }
}
```

## Что нового в 1.0

- **Новая операция `ListTasks`** с фильтрацией и курсорной пагинацией.
- **Мультитенантность.** Поле `tenant` во всех запросах и в `AgentInterface`: так можно обслуживать несколько агентов с одной точки входа.
- **Режим выполнения.** Параметр `returnImmediately` в `SendMessageConfiguration`: ждать завершения задачи (по умолчанию) или вернуться сразу.
- **Подпись Agent Card.** JWS и каноническая форма JSON (RFC 8785).
- **Требуемые расширения.** Расширение в Agent Card можно пометить как обязательное (`required`).
- **Согласование версий.** Заголовок `A2A-Version` и версия протокола в каждом интерфейсе.
- **Взаимная аутентификация TLS.** Объявление схемы mTLS среди схем безопасности.
- **Новые зависимости.** `google.rpc.Status` и `ErrorInfo`, RFC 8785, RFC 7515, руководства по проектированию API Google и ISO 8601.

## Порядок миграции

Оригинал советует мигрировать поэтапно.

1. **Слой совместимости.** Научитесь разбирать оба шаблона различения типов (старый и новый), определять версию протокола и поддерживать обе структуры Agent Card на время перехода.
2. **Двойная поддержка.** Переведите все API на выдачу формата 1.0, оставив читателей для 0.3.0. Добавьте обработку заголовка `A2A-Version` и курсорную пагинацию рядом со старой постраничной.
3. **Только 1.0.** Уберите код совместимости с 0.3.0: старый разбор различителей, постраничную выдачу и поддержку двух форматов.

### Стратегия обратной совместимости

Каждый интерфейс (`AgentInterface`) объявляет собственную версию протокола. Агент может поддерживать несколько версий одновременно, открыв несколько интерфейсов. Клиент выбирает подходящий интерфейс из Agent Card, а SDK могут поддерживать несколько версий протокола и постепенно отказываться от старых.

### Что проверить тестами

- работу с данными и формата 0.3.0, и формата 1.0;
- проверку подписи Agent Card;
- курсорную пагинацию в крайних случаях: пустой результат, единственная страница;
- обработку новых типов ошибок;
- проверку требуемых расширений.

> **Заметка переводчика.** Заголовок `A2A-Version` клиент обязан отправлять с каждым запросом, кроме клиентов версии 0.3: если заголовок пуст, агент считает, что запрос версии 0.3. Это основа безопасной поэтапной миграции. Подробнее: [«Протокол»](https://a2adocs.ru/protocol/#versionirovanie).

## Расхождения внутри оригинала

Пока мы сверяли источники, нашлись места, где документы описывают одно и то же по-разному. Это не ошибки перевода; сверяйтесь с a2a.proto.

- У события `TaskArtifactUpdateEvent` на странице «What's New» есть поле `index`, а в таблице спецификации (раздел 4.2.2) его нет.
- Примеры заголовка `A2A-Version` в разных местах спецификации показывают разные значения.
- Для требований безопасности Agent Card встречаются два названия: `security` и `security_requirements`.
