> ## Documentation Index
> Fetch the complete documentation index at: https://adcp-docs-ja.pier1.co.jp/llms.txt
> Use this file to discover all available pages before exploring further.

# A2A ガイド

> AdCP A2A 連携ガイド: クライアントセットアップ、エージェントカード確認、非同期タスク向け SSE ストリーミング、アーティファクト処理、Agent-to-Agent Protocol のレスポンス形式。

Agent-to-Agent Protocol を使って AdCP を統合するためのトランスポート別ガイドです。タスク処理、ステータス管理、ワークフローパターンは [Task Lifecycle](/docs/building/by-layer/L3/task-lifecycle) を参照してください。

## A2A プロトコルバージョン

AdCP は Linux Foundation ガバナンス下の [A2A 仕様](https://a2a-protocol.org/latest/)を追跡します。**1.0** ワイヤーフォーマットがターゲットです。**v0.3** は依然広くデプロイされており、互換期間中サポートされます。

### 1.0 で変わったこと

| 領域                | v0.3                               | 1.0                                                                                   |
| ----------------- | ---------------------------------- | ------------------------------------------------------------------------------------- |
| エージェントカードのトランスポート | ルートの `url` + `protocolVersion`     | 各インターフェースごとの `url`、`protocolBinding`、`protocolVersion` を持つ `supportedInterfaces[]` 配列 |
| `Part` 判別子        | `kind: "text" \| "data" \| "file"` | `kind` なし — コンテンツはどのフィールドが設定されているか（`text`、`data`、`url`、`raw`）で決まる                     |
| File フィールド        | `uri`、`name`、`mimeType`            | `url`（参照）または `raw`（base64 バイト）、`filename`、`mediaType`                                 |
| メッセージロール          | `"user"` / `"agent"`               | `"ROLE_USER"` / `"ROLE_AGENT"`（ProtoJSON 正準形）                                         |
| タスク状態             | `"completed"`、`"working"`、…        | `"TASK_STATE_COMPLETED"`、`"TASK_STATE_WORKING"`、…                                     |
| タイムスタンプ           | ISO-8601                           | ミリ秒精度の ISO-8601 UTC（`YYYY-MM-DDTHH:mm:ss.sssZ`）                                       |

AdCP 自身の統合トップレベル `status` フィールド（`@adcp/sdk` が返す）は、引き続き小文字の短縮形（`"completed"`、`"working"`、…）を使用します — これは生の A2A `status.state` に対する AdCP の抽象化であり、A2A ワイヤー値ではありません。

### デュアルバージョン互換性

v0.3 と 1.0 の両方のクライアントに提供する必要のあるサーバーは、エージェントカードで両方のインターフェースを宣伝し、トランスポート層で明示的な互換性を有効にします（例: Python SDK の `enable_v0_3_compat=True`）。後方互換性はデフォルトでは有効に**なりません**。

1.0 を話すクライアントは、SDK が下位変換を提供する場合に v0.3 サーバーと通信できます。逆（v0.3 クライアント → 1.0 専用サーバー）はサーバーが互換を有効にする必要があります。

### 本ガイドの例

以下の例は **1.0 ワイヤーフォーマット**（`kind` フィールドなし、ProtoJSON enum）を使用します。v0.3 サーバーの場合、同じ Part は `{ kind: "text", text: "…" }` になり、状態は小文字になります。AdCP 抽出クライアント（[A2A レスポンス抽出](/docs/building/by-layer/L0/a2a-response-extraction)を参照）は互換期間中に両方の形状を受け入れます。

## A2A クライアントのセットアップ

### 1. A2A クライアントを初期化

```javascript theme={null}
const a2a = new A2AClient({
  endpoint: 'https://adcp.example.com/a2a',
  auth: {
    type: 'bearer',
    token: process.env.ADCP_API_KEY
  },
  agent: {
    name: "AdCP Media Buyer",
    version: "1.0.0"
  }
});
```

### 2. エージェントカードを確認

```javascript theme={null}
// Check available skills
const agentCard = await a2a.getAgentCard();
console.log(agentCard.skills.map(s => s.name));
// ["get_products", "create_media_buy", "sync_creatives", ...]
```

### 3. 最初のタスクを送る

```javascript theme={null}
const response = await a2a.send({
  message: {
    role: "ROLE_USER",
    parts: [{
      text: "Find video products for pet food campaign"
    }]
  }
});

// すべてのレスポンスに統一ステータスフィールドが含まれる（AdCP 1.6.0+）  
console.log(response.status);   // "completed" | "input-required" | "working" | etc.
console.log(response.message);  // Human-readable summary
```

## メッセージ構造（A2A 固有）

### マルチパートメッセージ

A2A の強みは、テキスト・データ・ファイルを組み合わせたマルチパートメッセージです:

```javascript theme={null}
// Text + structured data + file
const response = await a2a.send({
  message: {
    role: "ROLE_USER",
    parts: [
      {
        text: "Create campaign with these assets"
      },
      {
        data: {
          skill: "create_media_buy",
          parameters: {
            packages: ["pkg_001"],
            total_budget: 100000
          }
        }
      },
      {
        url: "https://cdn.example.com/hero-video.mp4",
        filename: "hero_video_30s.mp4",
        mediaType: "video/mp4"
      }
    ]
  }
});
```

### スキル呼び出し方法

#### 自然言語（柔軟）

```javascript theme={null}
// Agent interprets intent
const task = await a2a.send({
  message: {
    role: "ROLE_USER",
    parts: [{
      text: "Find premium CTV inventory under $50 CPM"
    }]
  }
});
```

#### 明示的スキル（決定的）

```javascript theme={null}
// Explicit skill with exact parameters
const task = await a2a.send({
  message: {
    role: "ROLE_USER",
    parts: [{
      data: {
        skill: "get_products",
        parameters: {
          max_cpm: 50,
          channels: ["ctv"],
          tier: "premium"
        }
      }
    }]
  }
});
```

#### ハイブリッド（推奨）

```javascript theme={null}
// Context + explicit execution for best results
const task = await a2a.send({
  message: {
    role: "ROLE_USER",
    parts: [
      {
        text: "Looking for inventory for spring campaign targeting millennials"
      },
      {
        data: {
          skill: "get_products",
          parameters: {
            audience: "millennials",
            season: "Q2_2024",
            max_cpm: 45
          }
        }
      }
    ]
  }
});
```

**ステータス処理**: 完全なパターンは [Task Lifecycle](/docs/building/by-layer/L3/task-lifecycle) を参照してください。

## A2A レスポンス形式

**AdCP 1.6.0 の新機能**: すべてのレスポンスに統一ステータスフィールドが含まれます。

### 標準レスポンス構造

A2A 上の AdCP レスポンスは、タスクレスポンスを含む DataPart（`data` フィールドを運ぶ Part）を少なくとも 1 つ含める **必要があります**。人間向けメッセージの TextPart（`text` フィールドを運ぶ Part）は **推奨** ですが任意です。

```json theme={null}
{
  "status": "completed",        // AdCP unified status (see Core Concepts)
  "taskId": "task-123",         // A2A task identifier
  "contextId": "ctx-456",       // Automatic context management
  "artifacts": [{               // A2A-specific artifact structure
    "artifactId": "artifact-product-catalog-abc",
    "name": "product_catalog",
    "parts": [
      {
        "text": "Found 12 video products perfect for pet food campaigns"
      },
      {
        "data": {
          "products": [...],
          "total": 12
        }
      }
    ]
  }]
}
```

A2A 1.0 ワイヤーフォーマットは `kind` 判別子を運びません — Part のコンテンツタイプはどのフィールドが設定されているか（`text`、`data`、`url`、`raw`）で暗黙的に決まります。v0.3 のサーバー/クライアントでは、同等の Part に `"kind": "text"` / `"kind": "data"` / `"kind": "file"` が含まれます。

**完全な標準仕様は [A2A Response Format](/docs/building/by-layer/L0/a2a-response-format) を参照してください。**

### A2A 固有フィールド

* **taskId**: ストリーミング更新のための A2A タスク ID
* **contextId**: A2A プロトコルが自動管理
* **artifacts**: テキスト・データを含むマルチパート成果物
* **status**: A2A の `status.state` からマップされる AdCP の統合小文字短縮形（[A2A レスポンス抽出](/docs/building/by-layer/L0/a2a-response-extraction#wire-format-compatibility)を参照）

### アーティファクトの処理

`DataPart` が複数ある場合（ストリーミングなど）は **最後の `DataPart` を正とします**:

```javascript theme={null}
// アーティファクトを抽出（現状 AdCP は 1 レスポンス 1 アーティファクト）
const artifact = response.artifacts?.[0];

if (artifact) {
  // Detect Part type by presence of field (1.0) with kind fallback (v0.3)
  const isText = (p) => typeof p.text === 'string' || p.kind === 'text';
  const isData = (p) => p.data != null || p.kind === 'data';

  const message = artifact.parts?.find(isText)?.text;
  const data = artifact.parts?.find(isData)?.data;

  return {
    artifactId: artifact.artifactId,
    message,
    data,
    status: response.status
  };
}

return { status: response.status };
```

**レスポンス構造の要件、エラーハンドリング、実装パターンの詳細は [A2A Response Format](/docs/building/by-layer/L0/a2a-response-format) を参照してください。**

## プッシュ通知（A2A 固有）

A2A では `PushNotificationConfig` によりプッシュ通知が標準で定義されています。Webhook URL を設定すると、ポーリング不要でサーバーがタスク更新を直接 POST します。

### 相関: URL ではなくペイロードフィールド

受信する通知は、ペイロードボディの `operation_id`（および `task_type`）を使って相関します — `pushNotificationConfig.url` を解析することは**決して**しません。URL はサーバーにとって不透明で、相関のワイヤーレベルの真実の源はペイロードフィールドです。完全な規範的ワイヤー契約は [Webhooks — Operation IDs and URL templates](/docs/building/by-layer/L3/webhooks#operation-ids-and-url-templates) を参照してください（MCP と A2A の両方に適用されます — アドテックのすべての比較可能な非同期通知プロトコルは URL を発火エンティティにとって不透明にします）。

バイヤーは自身の HTTP サーバーのルーティング補助として `operation_id` を URL パスやクエリにエンコードしてもよい（MAY）— 多くの Web フレームワークはボディを解析する前にパスセグメントでディスパッチします — が、それはバイヤー側のサーバー設計の選択であり、ワイヤー契約の一部ではありません。バイヤーのサーバールーティングテンプレートはセラーには見えません。セラーはバイヤーが供給した `pushNotificationConfig.operation_id` フィールドからのみ `operation_id` を読み、ペイロードでそのままエコーします。

**URL テンプレート（バイヤー側のサーバールーティングのみ）:**

```javascript theme={null}
// Path parameters
url: `https://buyer.com/webhooks/a2a/${taskType}/${operationId}`

// Query parameters
url: `https://buyer.com/webhooks/a2a?task=${taskType}&op=${operationId}`

// Or fully opaque — the seller doesn't care about URL shape
url: `https://buyer.com/webhooks/${randomToken}`
```

**設定例:**

```javascript theme={null}
const operationId = "op_nike_q1_2025";
const taskType = "create_media_buy";

await a2a.send({
  message: {
    role: "ROLE_USER",
    parts: [{
      data: {
        skill: "create_media_buy",
        parameters: { /* task params */ }
      }
    }]
  },
  pushNotificationConfig: {
    url: `https://buyer.com/webhooks/a2a/${taskType}/${operationId}`,
    operation_id: operationId,  // canonical correlation channel — seller echoes verbatim
    token: "client-validation-token",  // Optional: for client-side validation
    authentication: {
      schemes: ["bearer"],
      credentials: "shared_secret_32_chars"
    }
  }
});
```

Webhook のペイロード形式、プロトコル比較、詳細な処理例は [Webhooks](/docs/building/by-layer/L3/webhooks) を参照してください。

## SSE ストリーミング（A2A 固有）

A2A の強みは Server-Sent Events によるリアルタイム更新です:

A2A 上でもアプリケーション層のタスクライフサイクルは依然として AdCP が所有します。A2A `Task`、`taskId`、SSE、プッシュ通知フレームはトランスポート配信の仕組みです。耐久性のあるビジネスオペレーションは AdCP `task_id` でキーされる AdCP ペイロードのままです。完了した A2A タスクでも、ペイロードが `status: 'submitted'` と言う AdCP レスポンスを運ぶことがあります。

### タスク監視

```javascript theme={null}
class A2aTaskMonitor {
  constructor(taskId) {
    this.taskId = taskId;
    this.events = new EventSource(`/a2a/tasks/${taskId}/events`);
    
    this.events.addEventListener('status', (e) => {
      const update = JSON.parse(e.data);
      this.handleStatusUpdate(update);
    });
    
    this.events.addEventListener('progress', (e) => {
      const data = JSON.parse(e.data);
      console.log(`${data.percentage}% - ${data.message}`);
    });
  }
  
  handleStatusUpdate(update) {
    switch (update.status) {
      case 'input-required':
        // 追加情報・承認が必要
        this.emit('input-required', update);
        break;
      case 'completed':
        this.events.close();
        this.emit('completed', update);
        break;
      case 'failed':
        this.events.close();
        this.emit('failed', update);
        break;
    }
  }
}
```

### リアルタイム更新の例

```javascript theme={null}
// 長時間オペレーションを開始
const response = await a2a.send({
  message: {
    role: "ROLE_USER",
    parts: [{
      data: {
        skill: "create_media_buy",
        parameters: { packages: ["pkg_001"], total_budget: 100000 }
      }
    }]
  }
});

// Monitor A2A transport progress in real time via SSE
if (response.status === 'working' || response.status === 'submitted') {
  const monitor = new A2aTaskMonitor(response.taskId);
  
  monitor.on('progress', (data) => {
    updateUI(`${data.percentage}%: ${data.message}`);
  });
  
  monitor.on('completed', (final) => {
    // Extract last DataPart from the artifact — don't assume a positional index.
    const parts = final.artifacts[0].parts;
    const dataParts = parts.filter(p => p.data != null || p.kind === 'data');
    const payload = dataParts[dataParts.length - 1]?.data;
    if (payload?.status === 'submitted') {
      // A2A delivery completed, but the AdCP operation is still queued.
      return pollAdcpTask(payload.task_id);
    }
    console.log('Created:', payload?.media_buy_id);
  });
}
```

### A2A Webhook ペイロード例

**例 1: 完了オペレーションの `Task` ペイロード**

タスク完了時、サーバーは A2A 1.0 の `StreamResponse` エンベロープでラップされた完全な `Task` オブジェクトを送信します。タスク結果は `.artifacts` に存在します:

```json theme={null}
{
  "task": {
    "id": "task_456",
    "contextId": "ctx_123",
    "status": {
      "state": "TASK_STATE_COMPLETED",
      "timestamp": "2026-01-22T10:30:00.000Z"
    },
    "artifacts": [{
      "name": "task_result",
      "parts": [
        {
          "text": "Media buy created successfully"
        },
        {
          "data": {
            "media_buy_id": "mb_12345",
            "creative_deadline": "2026-01-30T23:59:59.000Z",
            "packages": [
              {
                "package_id": "pkg_001",
                "context": { "line_item": "li_ctv_sports" }
              }
            ]
          }
        }
      ]
    }]
  }
}
```

**重要**: **`completed`、`failed`、`rejected`** ステータスでは、AdCP タスク結果は **`.artifacts[0].parts[]` に必ず入れる必要があります**。サーバーがフリーテキストの致命的メッセージのみ（構造化ペイロードなし）を持つ場合、`status.message.parts[]` にフォールバックしてもよい（MAY）— クライアントは両方を扱います。

A2A 1.0 の `StreamResponse` oneof は、すべての SSE フレームとプッシュ通知ペイロードを、`{ task }`、`{ statusUpdate }`、`{ artifactUpdate }`、`{ message }` のちょうど 1 つでラップします（A2A 1.0 §3.2.3、§4.3.3）。`tasks/get` と v0.3 サーバーからの非ストリーミングレスポンスは素のオブジェクトを配信します。クライアントはフィールドを読む前にアンラップします。

**例 2: 進捗更新用 `TaskStatusUpdateEvent`**

実行中の中間ステータス更新では、`status.message.parts[]` に任意データを含められます。SSE/プッシュフレームはイベントを `{ "statusUpdate": { … } }` としてラップします:

```json theme={null}
{
  "statusUpdate": {
    "taskId": "task_456",
    "contextId": "ctx_123",
    "status": {
      "state": "TASK_STATE_INPUT_REQUIRED",
      "message": {
        "role": "ROLE_AGENT",
        "parts": [
          { "text": "Campaign budget $150K requires VP approval" },
          {
            "data": {
              "reason": "BUDGET_EXCEEDS_LIMIT"
            }
          }
        ]
      },
      "timestamp": "2026-01-22T10:15:00.000Z"
    }
  }
}
```

**すべてのステータスペイロードは AdCP スキーマを使用します**: 最終ステータス（completed/failed）も中間ステータス（working, input-required, submitted）も [`async-response-data.json`](https://adcontextprotocol.org/schemas/v3/core/async-response-data.json) に参照がある対応スキーマを持ちます。中間ステータスのスキーマは策定中で将来変更される可能性があるため、実装者は緩めに扱う選択も可能です。

### A2A Webhook のペイロード種別

[A2A 1.0 仕様](https://a2a-protocol.org/latest/specification/#433-push-notification-payload)に従い、サーバーは `StreamResponse` oneof でラップした異なるペイロードタイプを送信します:

| エンベロープキー         | 内側ペイロード                   | いつ使うか                                                                  | 何を含むか                                     |
| ---------------- | ------------------------- | ---------------------------------------------------------------------- | ----------------------------------------- |
| `task`           | `Task`                    | 最終状態（`completed`, `failed`, `canceled`, `rejected`）や完全なコンテキストが必要な場合    | 履歴とアーティファクトデータを含む完全なタスクオブジェクト             |
| `statusUpdate`   | `TaskStatusUpdateEvent`   | 実行中のステータス遷移（`working`, `input-required`, `auth-required`, `submitted`） | メッセージパートを含む軽量ステータス更新                      |
| `artifactUpdate` | `TaskArtifactUpdateEvent` | ストリーミングによるアーティファクト更新                                                   | `append` / `lastChunk` フラグ付きのアーティファクトチャンク |
| `message`        | `Message`                 | 帯域外のエージェントメッセージ                                                        | タスクステータス遷移に紐づかないメッセージ                     |

AdCP では主に次の 2 つが多くなります:

* `{ task }`: 最終結果（`completed`, `failed`, `rejected`）
* `{ statusUpdate }`: 進捗更新（`working`, `input-required`, `auth-required`）

クライアントはフィールドを読む前に単一キーのエンベロープをアンラップします。非ストリーミングレスポンス（例: `tasks/get`）は素のペイロードを配信します — そこでは単一キーエンベロープのアンラップは no-op です。

**エンベロープのセマンティクス:**

* **`{ artifactUpdate }`** フレームは、ブール値フラグ `append`（名前付きアーティファクトにパートを連結）と `lastChunk`（最終チャンクを示す）付きの増分アーティファクトチャンクを運びます。ストリームを消費する AdCP クライアントは、これらをターゲットアーティファクトに蓄積し、終端状態の `{ task }` フレームが到着したときに抽出アルゴリズムを適用すべきです（SHOULD）。プッシュ通知を消費するクライアントは通常、すでにマージされた `Task` オブジェクトを受け取り、個々の `artifactUpdate` フレームを無視できます。A2A 1.0 §7.3 を参照。
* **`{ message }`** フレームは、タスクステータス遷移に紐づかない帯域外のエージェントメッセージです。AdCP はタスク指向です — タスク向けクライアントは素の `message` エンベロープをログして無視すべきです（SHOULD）。

### Webhook が送信される条件

Webhooks are sent when **all** of these conditions are met:

1. **Task type supports async** (e.g., `create_media_buy`, `sync_creatives`, `get_products`)
2. **`pushNotificationConfig` is provided** in the request
3. **Task runs asynchronously** — initial response is `working` or `submitted`

初回レスポンスがすでに終端（`completed`, `failed`, `rejected`）なら Webhook は送信されません。結果はその場で得られます。

**Webhook を送るステータス変化:**

* `working` → 進捗更新（処理中）
* `input-required` → 人による入力が必要
* `auth-required`（1.0） → 実行中の再認証チャレンジ
* `completed` → 最終結果
* `failed` → エラー詳細
* `rejected`（1.0） → `adcp_error` 付きのポリシー/検証拒否
* `canceled` → キャンセル確定

### データスキーマのバリデーション

A2A Webhook の DataPart `data` フィールドはステータス別スキーマを使用します:

| Status               | Schema                                      | Contents                             |
| -------------------- | ------------------------------------------- | ------------------------------------ |
| `completed`          | `[task]-response.json`                      | Full task response (success branch)  |
| `failed`             | `[task]-response.json`                      | Full task response (error branch)    |
| `rejected`（1.0）      | `[task]-response.json`（error branch）        | `adcp_error` 付きのポリシー/検証拒否            |
| `working`            | `[task]-async-response-working.json`        | Progress info (`percentage`, `step`) |
| `input-required`     | `[task]-async-response-input-required.json` | Requirements, approval data          |
| `auth-required`（1.0） | `[task]-async-response-auth-required.json`  | Auth challenge (scheme, URL, scopes) |
| `submitted`          | `[task]-async-response-submitted.json`      | Acknowledgment (usually minimal)     |

スキーマ参照: [`async-response-data.json`](https://adcontextprotocol.org/schemas/v3/core/async-response-data.json)

### Webhook ハンドラーの例

```javascript theme={null}
const express = require('express');
const app = express();

app.post('/webhooks/a2a/:taskType/:operationId', async (req, res) => {
  const { taskType, operationId } = req.params;
  const rawBody = req.body;

  // Webhook の正当性検証（Bearer トークン例）
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'Missing Authorization header' });
  }
  const token = authHeader.substring(7);
  if (token !== process.env.A2A_WEBHOOK_TOKEN) {
    return res.status(401).json({ error: 'Invalid token' });
  }

  // Unwrap A2A 1.0 StreamResponse envelope: { task } | { statusUpdate } | { artifactUpdate } | { message }
  const envelopeKeys = ['task', 'message', 'statusUpdate', 'artifactUpdate'];
  const bodyKeys = Object.keys(rawBody || {});
  const webhook = (bodyKeys.length === 1 && envelopeKeys.includes(bodyKeys[0]))
    ? rawBody[bodyKeys[0]]
    : rawBody;

  // Extract basic fields from A2A webhook payload
  const taskId = webhook.id || webhook.taskId;
  const contextId = webhook.contextId;
  const status = webhook.status?.state || webhook.status;

  // Normalize 1.0 / v0.3 state values
  const normalizeState = (s) => s?.replace(/^TASK_STATE_/, '').toLowerCase().replace(/_/g, '-');
  const normalizedStatus = normalizeState(status);

  // Detect Part type by field presence (1.0) with kind fallback (v0.3)
  const isDataPart = (p) => p.data != null || p.kind === 'data';
  const isTextPart = (p) => typeof p.text === 'string' || p.kind === 'text';

  // Extract AdCP data based on status
  let adcpData, textMessage;

  const FINAL = ['completed', 'failed', 'canceled', 'rejected'];

  if (FINAL.includes(normalizedStatus)) {
    // FINAL STATES: Extract from .artifacts (fallback to status.message.parts)
    const artifactParts = webhook.artifacts?.[0]?.parts;
    const dataPart = artifactParts?.find(isDataPart)
      ?? webhook.status?.message?.parts?.find(isDataPart);
    const textPart = artifactParts?.find(isTextPart)
      ?? webhook.status?.message?.parts?.find(isTextPart);
    adcpData = dataPart?.data;
    textMessage = textPart?.text;
  } else {
    // INTERIM STATES: Extract from status.message.parts (optional)
    const dataPart = webhook.status?.message?.parts?.find(isDataPart);
    const textPart = webhook.status?.message?.parts?.find(isTextPart);
    adcpData = dataPart?.data;
    textMessage = textPart?.text;
  }

  // Handle status changes (normalized works for both 1.0 and v0.3 wire values)
  switch (normalizedStatus) {
    case 'input-required':
      // 人に入力が必要であることを通知
      await notifyHuman({
        task_id: taskId,
        context_id: contextId,
        message: textMessage,
        data: adcpData
      });
      break;

    case 'auth-required':
      // A2A 1.0: re-authenticate and resume the task
      // SECURITY: validate challenge_url against the agent's registered origin
      // before opening/fetching. See A2A Response Extraction §Auth Challenge URL Validation.
      if (!isValidChallengeUrl(adcpData?.challenge_url, agentAuthOrigin(taskId))) {
        return res.status(400).json({ error: 'Invalid challenge_url for agent' });
      }
      await startAuthChallenge({
        task_id: taskId,
        auth_scheme: adcpData?.auth_scheme,
        challenge_url: adcpData.challenge_url,
        scopes: adcpData?.scopes  // show to user for fresh consent, do not auto-grant
      });
      break;

    case 'completed':
      // 完了したオペレーションを処理
      if (adcpData?.media_buy_id) {
        await handleMediaBuyCreated({
          media_buy_id: adcpData.media_buy_id,
          packages: adcpData.packages
        });
      }
      break;

    case 'failed':
      // 失敗を処理
      await handleOperationFailed({
        task_id: taskId,
        error: adcpData?.adcp_error ?? adcpData?.errors,
        message: textMessage
      });
      break;

    case 'rejected':
      // A2A 1.0: policy/validation rejection with structured adcp_error
      await handleOperationRejected({
        task_id: taskId,
        error: adcpData?.adcp_error,
        message: textMessage
      });
      break;

    case 'working':
      // 進捗 UI を更新
      await updateProgress({
        task_id: taskId,
        percentage: adcpData?.percentage,
        message: textMessage
      });
      break;

    case 'canceled':
      await handleOperationCanceled(taskId);
      break;
  }

  // 正常処理時は必ず 200 を返す
  res.status(200).json({ status: 'processed' });
});
```

## コンテキスト管理（A2A 固有）

**主要な利点**: A2A はコンテキストを自動管理するため、`context_id` を手動で扱う必要はありません。

### 自動コンテキスト

```javascript theme={null}
// 最初のリクエスト - A2A が自動でコンテキストを作成
const response1 = await a2a.send({
  message: {
    role: "ROLE_USER",
    parts: [{ text: "Find premium video products" }]
  }
});

// 後続リクエスト - A2A が自動でコンテキストを保持  
const response2 = await a2a.send({
  message: {
    role: "ROLE_USER",
    parts: [{ text: "Filter for sports content" }]
  }
});
// システムが自動で前回のリクエストに紐づける
```

### 明示的コンテキスト（任意）

```javascript theme={null}
// 明示的に制御したい場合
const response2 = await a2a.send({
  contextId: response1.contextId,  // 任意 - A2A が追跡済み
  message: {
    role: "ROLE_USER",
    parts: [{ text: "Refine those results" }]
  }
});
```

**MCP との違い**: MCP の手動 context\_id 管理と異なり、A2A はプロトコルレベルでセッション継続を扱います。

## マルチモーダルメッセージ（A2A 固有）

A2A の特徴は、1 つのメッセージ内にテキスト・データ・ファイルを組み合わせられることです:

### コンテキスト付きクリエイティブアップロード

```javascript theme={null}
// キャンペーンコンテキスト付きでクリエイティブを送信
const response = await a2a.send({
  message: {
    role: "ROLE_USER",
    parts: [
      {
        text: "Add this hero video to the premium sports campaign"
      },
      {
        data: {
          skill: "sync_creatives",
          parameters: {
            media_buy_id: "mb_12345",
            action: "upload_and_assign"
          }
        }
      },
      {
        url: "https://cdn.example.com/hero-30s.mp4",
        filename: "sports_hero_30s.mp4",
        mediaType: "video/mp4"
      }
    ]
  }
});
```

### キャンペーンブリーフ + アセット

```javascript theme={null}
// 完全なキャンペーンブリーフを送信
await a2a.send({
  message: {
    role: "ROLE_USER",
    parts: [
      {
        text: "Campaign brief and assets for Q1 launch"
      },
      {
        url: "https://docs.google.com/campaign-brief.pdf",
        filename: "Q1_campaign_brief.pdf",
        mediaType: "application/pdf"
      },
      {
        data: {
          budget: 250000,
          kpis: ["reach", "awareness", "conversions"],
          target_launch: "2024-01-15"
        }
      }
    ]
  }
});
```

## 利用可能なスキル

すべての AdCP タスクは A2A スキルとして利用できます。確実な実行には明示的な呼び出しを使用してください:

**タスク管理**: 全ドメインにわたる非同期追跡、ポーリングパターン、Webhook 連携の詳細は [Webhooks](/docs/building/by-layer/L3/webhooks) を参照。

### スキルの構造

```javascript theme={null}
// Standard pattern for explicit skill invocation
await a2a.send({
  message: {
    role: "ROLE_USER",
    parts: [{
      data: {
        skill: "skill_name",        // Exact name from Agent Card
        parameters: {              // Task-specific parameters
          // See task documentation for parameters
        }
      }
    }]
  }
});
```

### 利用可能なスキル

* **Protocol**: `get_adcp_capabilities` (start here to discover agent capabilities)
* **Media Buy**: `get_products`, `list_creative_formats`, `create_media_buy`, `update_media_buy`, `sync_creatives`, `get_media_buy_delivery`, `provide_performance_feedback`
* **Signals**: `get_signals`, `activate_signal`

**タスクパラメータ**: 詳細なパラメータ仕様は [Media Buy](/docs/media-buy) と [Signals](/docs/signals/overview) を参照してください。

## エージェントカード

A2A エージェントは `.well-known/agent.json` の Agent Card で機能を公開します。

### Agent Card の取得

```javascript theme={null}
// エージェントの機能を取得
const agentCard = await a2a.getAgentCard();

// 利用可能なスキルを列挙
const skillNames = agentCard.skills.map(skill => skill.name);
console.log('Available skills:', skillNames);

// スキル詳細を取得
const getProductsSkill = agentCard.skills.find(s => s.name === 'get_products');
console.log('Examples:', getProductsSkill.examples);

// Pick a transport interface (1.0)
const jsonrpc = agentCard.supportedInterfaces?.find(
  i => i.protocolBinding === 'JSONRPC' && i.protocolVersion === '1.0'
);
console.log('Endpoint:', jsonrpc?.url);
```

### Agent Card 構造の例（A2A 1.0）

1.0 では、v0.3 のトップレベル `url` と `protocolVersion` フィールドが `supportedInterfaces` 配列に置き換えられます。各エントリは 1 つのトランスポートバインディングとプロトコルバージョンを宣伝します。`supportsAuthenticatedExtendedCard` は `capabilities.extendedAgentCard` に移動しました。

```json theme={null}
{
  "name": "AdCP Media Buy Agent",
  "description": "AI-powered media buying agent",
  "version": "1.0.0",
  "securitySchemes": {
    "bearerAuth": {
      "type": "http",
      "scheme": "bearer"
    }
  },
  "security": [{"bearerAuth": []}],
  "supportedInterfaces": [
    {
      "url": "https://sales.example.com/a2a/jsonrpc",
      "protocolBinding": "JSONRPC",
      "protocolVersion": "1.0"
    }
  ],
  "defaultInputModes": ["text/plain", "application/json"],
  "defaultOutputModes": ["application/json"],
  "capabilities": {
    "streaming": true,
    "pushNotifications": true,
    "extendedAgentCard": false
  },
  "skills": [
    {
      "name": "get_products",
      "description": "Discover available advertising products",
      "examples": [
        "Find premium CTV inventory for sports fans",
        "Show me video products under $50 CPM"
      ]
    }
  ],
  "extensions": [
    {
      "uri": "https://adcontextprotocol.org/extensions/adcp",
      "description": "AdCP media buying protocol support",
      "required": false,
      "params": {
        "adcp_version": "2.6.0",
        "protocols_supported": ["media_buy"],
        "extensions_supported": ["sustainability"]
      }
    }
  ]
}
```

### v0.3 互換のためのデュアル宣伝

v0.3 から移行するサーバーは両方のインターフェースを宣伝します。クライアントは理解できるバージョンを選びます:

```json theme={null}
{
  "supportedInterfaces": [
    {
      "url": "https://sales.example.com/a2a/jsonrpc",
      "protocolBinding": "JSONRPC",
      "protocolVersion": "1.0"
    },
    {
      "url": "https://sales.example.com/",
      "protocolBinding": "JSONRPC",
      "protocolVersion": "0.3"
    }
  ]
}
```

Python SDK サーバーはルート構築時に `enable_v0_3_compat=True` も渡す必要があります — 後方互換性はデフォルトでは有効になりません。[A2A Python SDK 1.0 migration guide](https://github.com/a2aproject/a2a-python/blob/v1.0.0/docs/migrations/v1_0/README.md) を参照してください。

### AdCP 拡張

<Note>
  **推奨**: 実行時の機能発見には [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities) を使用してください。エージェントカードの拡張は、レジストリやディスカバリーサービス向けの静的メタデータを提供します。
</Note>

`extensions` 配列に AdCP 拡張を含めることで、プログラム的に AdCP 対応を宣言できます。

A2A プロトコルでは `extensions` 配列に以下を持つ拡張を列挙します:

* **`uri`**: 拡張の識別子（`https://adcontextprotocol.org/extensions/adcp` を使用）
* **`description`**: AdCP をどう使うかの説明
* **`required`**: クライアントがこの拡張を必須とするか（AdCP は通常 `false`）
* **`params`**: AdCP 固有の設定（下記スキーマ参照）

```javascript theme={null}
// エージェントが AdCP に対応しているか確認
const agentCard = await fetch('https://sales.example.com/.well-known/agent.json')
  .then(r => r.json());

// extensions 配列から AdCP 拡張を取得
const adcpExt = agentCard.extensions?.find(
  ext => ext.uri === 'https://adcontextprotocol.org/extensions/adcp'
);

if (adcpExt) {
  console.log('AdCP Version:', adcpExt.params.adcp_version);
  console.log('Supported domains:', adcpExt.params.protocols_supported);
  // ["media_buy", "creative", "signals"]
  console.log('Typed extensions:', adcpExt.params.extensions_supported);
  // ["sustainability"]
}
```

**Extension Params**: v2 では `adcp-extension.json` スキーマが使われていましたが、v3 で廃止されました。v3 以降のエージェントでは `get_adcp_capabilities` タスクで実行時に機能を発見してください。上記の `params` オブジェクトは典型的な構造です。

:::note
エージェントカードメタデータの `adcp_version` フィールドは v2 の慣習であり、v3 スペックの一部ではありません。v3 のバージョンネゴシエーションでは、バイヤーがすべてのリクエストでリリース精度の `adcp_version`（例: `"3.1"`）を送り、セラーが [`get_adcp_capabilities`](/docs/protocol/get_adcp_capabilities) の `adcp.supported_versions` でサポートするリリースを宣伝し、すべてのレスポンスでエンベロープルートに `adcp_version` をエコーします。レガシーの整数のみの `adcp_major_version` フィールドも後方互換性のため依然受け入れられます。完全な契約は [versioning.mdx § Version negotiation](/docs/reference/versioning#version-negotiation) を参照してください。
:::

**メリット**:

* テストコールなしで AdCP 対応状況を発見できます
* 実装しているプロトコルドメイン（media\_buy, creative, signals）を宣言できます
* バージョンに基づく互換性チェックが可能

## 統合の例

```javascript theme={null}
// A2A クライアントを初期化  
const a2a = new A2AClient({ /* config */ });

// 統一ステータスで処理（Core Concepts を参照）
async function handleA2aResponse(response) {
  switch (response.status) {
    case 'input-required':
      // 追加情報要求を処理（パターンは Core Concepts 参照）
      const input = await promptUser(response.message);
      return a2a.send({
        contextId: response.contextId,
        message: { role: "ROLE_USER", parts: [{ text: input }] }
      });
      
    case 'working':
      // SSE ストリーミングで監視
      return streamUpdates(response.taskId);
      
    case 'completed':
      // Extract last DataPart — presence of .data field identifies it in 1.0
      const parts = response.artifacts[0].parts;
      const dataParts = parts.filter(p => p.data != null || p.kind === 'data');
      return dataParts[dataParts.length - 1].data;

    case 'failed':
      throw new Error(response.message);
  }
}

// マルチモーダルメッセージによる使用例
const result = await a2a.send({
  message: {
    role: "ROLE_USER",
    parts: [
      { text: "Find luxury car inventory" },
      { data: { skill: "get_products", parameters: { audience: "luxury car intenders" } } }
    ]
  }
});

const finalResult = await handleA2aResponse(result);
```

## A2A 固有の考慮点

### エラーハンドリング

失敗したタスクは、アーティファクトの `DataPart` の `adcp_error` キーに構造化された AdCP エラーを格納します。完全な抽出ロジックと復旧動作は [Transport Error Mapping](/docs/building/operating/transport-errors) を参照してください。

```javascript theme={null}
try {
  const response = await a2a.send(message);

  if (response.status === 'failed') {
    // Check for structured AdCP error in artifacts
    // Detect DataPart by field presence (1.0) or kind (v0.3)
    const dataPart = response.artifacts?.[0]?.parts?.find(
      p => p.data != null || p.kind === 'data'
    );
    const adcpError = dataPart?.data?.adcp_error;

    if (adcpError) {
      // code, recovery, retry_after などを含む構造化エラー
      console.log('AdCP error:', adcpError.code, adcpError.recovery);
      if (adcpError.recovery === 'transient') {
        // 遅延後にリトライ
        await sleep((adcpError.retry_after || 5) * 1000);
        return retry();
      }
    }
    throw new Error(response.message);
  }
} catch (a2aError) {
  // A2A トランスポートエラー（接続、認証など）
  console.error('A2A Error:', a2aError);
}
```

### クリエイティブアップロードのエラーハンドリング

For uploading creative assets and handling validation errors, use the `sync_creatives` task. See [sync\_creatives Task Reference](/docs/creative/task-reference/sync_creatives) for complete testable examples.

`@adcp/sdk` ライブラリは A2A アーティファクトの抽出を自動で処理するため、レスポンス構造を手動で解析する必要はありません。

## ベストプラクティス

1. **ハイブリッドメッセージ**（テキスト + データ + 必要に応じてファイル）を活用
2. アーティファクト処理前に **status フィールド** を確認
3. 長時間処理には **SSE ストリーミング** でリアルタイム更新
4. ステータス処理パターンは **Core Concepts** を参照
5. 利用可能なスキルと例は **エージェントカード** で確認

## 次のステップ

* **Core Concepts**: ステータス処理とワークフローは [Task Lifecycle](/docs/building/by-layer/L3/task-lifecycle) を参照
* **Task Reference**: [Media Buy Tasks](/docs/media-buy) と [Signals](/docs/signals/overview)
* **Protocol Comparison**: [MCP integration](/docs/building/by-layer/L0/mcp-guide) と比較
* **Examples**: 完全なワークフロー例は Core Concepts に掲載

**ステータス処理、非同期オペレーション、確認フローについては [Task Lifecycle](/docs/building/by-layer/L3/task-lifecycle) を参照してください。このガイドは A2A トランスポート固有の内容に絞っています。**
