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.
Agent-to-Agent Protocol を使って AdCP を統合するためのトランスポート別ガイドです。タスク処理、ステータス管理、ワークフローパターンは Task Lifecycle を参照してください。
A2A クライアントのセットアップ
1. A2A クライアントを初期化
const a2a = new A2AClient({
endpoint: 'https://adcp.example.com/a2a',
apiKey: process.env.ADCP_API_KEY,
agent: {
name: "AdCP Media Buyer",
version: "1.0.0"
}
});
2. エージェントカードを確認
// Check available skills
const agentCard = await a2a.getAgentCard();
console.log(agentCard.skills.map(s => s.name));
// ["get_products", "create_media_buy", "sync_creatives", ...]
3. 最初のタスクを送る
const response = await a2a.send({
message: {
parts: [{
kind: "text",
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 の強みは、テキスト・データ・ファイルを組み合わせたマルチパートメッセージです:
// Text + structured data + file
const response = await a2a.send({
message: {
parts: [
{
kind: "text",
text: "Create campaign with these assets"
},
{
kind: "data",
data: {
skill: "create_media_buy",
parameters: {
packages: ["pkg_001"],
total_budget: 100000
}
}
},
{
kind: "file",
uri: "https://cdn.example.com/hero-video.mp4",
name: "hero_video_30s.mp4"
}
]
}
});
スキル呼び出し方法
自然言語(柔軟)
// Agent interprets intent
const task = await a2a.send({
message: {
parts: [{
kind: "text",
text: "Find premium CTV inventory under $50 CPM"
}]
}
});
明示的スキル(決定的)
// Explicit skill with exact parameters
const task = await a2a.send({
message: {
parts: [{
kind: "data",
data: {
skill: "get_products",
parameters: {
max_cpm: 50,
format_types: ["video"],
tier: "premium"
}
}
}]
}
});
ハイブリッド(推奨)
// Context + explicit execution for best results
const task = await a2a.send({
message: {
parts: [
{
kind: "text",
text: "Looking for inventory for spring campaign targeting millennials"
},
{
kind: "data",
data: {
skill: "get_products",
parameters: {
audience: "millennials",
season: "Q2_2024",
max_cpm: 45
}
}
}
]
}
});
ステータス処理: 完全なパターンは Task Lifecycle を参照してください。
A2A レスポンス形式
AdCP 1.6.0 の新機能: すべてのレスポンスに統一ステータスフィールドが含まれます。
標準レスポンス構造
A2A 上の AdCP レスポンスは、タスクレスポンスを含む DataPart(kind: ‘data’)を少なくとも 1 つ含める 必要があります。人間向けメッセージの TextPart(kind: ‘text’)は 推奨 ですが任意です。
{
"status": "completed", // 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": [
{
"kind": "text", // Optional but recommended
"text": "Found 12 video products perfect for pet food campaigns"
},
{
"kind": "data", // Required - contains AdCP response payload
"data": {
"products": [...],
"total": 12
}
}
]
}]
}
完全な標準仕様は A2A Response Format を参照してください。
A2A 固有フィールド
- taskId: ストリーミング更新のための A2A タスク ID
- contextId: A2A プロトコルが自動管理
- artifacts: テキスト・データを含むマルチパート成果物
- status: 一貫性のため MCP と同じ値(A2A TaskState enum)
アーティファクトの処理
DataPart が複数ある場合(ストリーミングなど)は 最後の DataPart を正とします:
// アーティファクトを抽出(現状 AdCP は 1 レスポンス 1 アーティファクト)
const artifact = response.artifacts?.[0];
if (artifact) {
const message = artifact.parts?.find(p => p.kind === 'text')?.text;
const data = artifact.parts?.find(p => p.kind === 'data')?.data;
return {
artifactId: artifact.artifactId,
message,
data,
status: response.status
};
}
return { status: response.status };
レスポンス構造の要件、エラーハンドリング、実装パターンの詳細は A2A Response Format を参照してください。
プッシュ通知(A2A 固有)
A2A では PushNotificationConfig によりプッシュ通知が標準で定義されています。Webhook URL を設定すると、ポーリング不要でサーバーがタスク更新を直接 POST します。
ベストプラクティス: URL ベースのルーティング
推奨: ルーティング情報(task_type, operation_id)はペイロードではなく Webhook URL に含めます。
理由:
- ✅ 業界標準パターン - 多くの API で採用
- ✅ 関心の分離 - ルーティングは URL、データはペイロード
- ✅ プロトコル非依存 - MCP/A2A/REST などで共通に使える
- ✅ ハンドラー簡潔化 - ペイロード解析ではなく URL でルーティング
URL Pattern Options:
// Option 1: Path parameters (recommended)
url: `https://buyer.com/webhooks/a2a/${taskType}/${operationId}`
// Example: /webhooks/a2a/create_media_buy/op_nike_q1_2025
// Option 2: Query parameters
url: `https://buyer.com/webhooks/a2a?task=${taskType}&op=${operationId}`
// Option 3: Subdomain routing
url: `https://${taskType}.webhooks.buyer.com/${operationId}`
設定例:
const operationId = "op_nike_q1_2025";
const taskType = "create_media_buy";
await a2a.send({
message: {
parts: [{
kind: "data",
data: {
skill: "create_media_buy",
parameters: { /* task params */ }
}
}]
},
pushNotificationConfig: {
url: `https://buyer.com/webhooks/a2a/${taskType}/${operationId}`,
token: "client-validation-token", // 任意: クライアントサイド検証用
authentication: {
schemes: ["bearer"],
credentials: "shared_secret_32_chars"
}
}
});
Webhook のペイロード形式、プロトコル比較、詳細な処理例は Webhooks を参照してください。
SSE ストリーミング(A2A 固有)
A2A の強みは Server-Sent Events によるリアルタイム更新です:
タスク監視
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;
}
}
}
リアルタイム更新の例
// 長時間オペレーションを開始
const response = await a2a.send({
message: {
parts: [{
kind: "data",
data: {
skill: "create_media_buy",
parameters: { packages: ["pkg_001"], total_budget: 100000 }
}
}]
}
});
// 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) => {
console.log('Created:', final.artifacts[0].parts[1].data.media_buy_id);
});
}
A2A Webhook ペイロード例
例 1: 完了時の Task ペイロード
タスク完了時、サーバーは タスク結果を .artifacts に含む 完全な Task オブジェクトを送信します:
{
"id": "task_456",
"contextId": "ctx_123",
"status": {
"state": "completed",
"timestamp": "2025-01-22T10:30:00Z"
},
"artifacts": [{
"name": "task_result",
"parts": [
{
"kind": "text",
"text": "Media buy created successfully"
},
{
"kind": "data",
"data": {
"media_buy_id": "mb_12345",
"creative_deadline": "2024-01-30T23:59:59Z",
"packages": [
{
"package_id": "pkg_001",
"context": { "line_item": "li_ctv_sports" }
}
]
}
}
]
}]
}
重要: completed または failed ステータスでは、AdCP タスク結果は status.message.parts[] ではなく .artifacts[0].parts[] に必ず入れる必要があります。
例 2: 進捗更新用 TaskStatusUpdateEvent
実行中の中間ステータス更新では、status.message.parts[] に任意データを含められます:
{
"taskId": "task_456",
"contextId": "ctx_123",
"status": {
"state": "input-required",
"message": {
"role": "agent",
"parts": [
{ "text": "Campaign budget $150K requires VP approval" },
{
"data": {
"reason": "BUDGET_EXCEEDS_LIMIT"
}
}
]
},
"timestamp": "2025-01-22T10:15:00Z"
}
}
すべてのステータスペイロードは AdCP スキーマを使用します: 最終ステータス(completed/failed)も中間ステータス(working, input-required, submitted)も async-response-data.json に参照がある対応スキーマを持ちます。中間ステータスのスキーマは策定中で将来変更される可能性があるため、実装者は緩めに扱う選択も可能です。
A2A Webhook のペイロード種別
Per the A2A specification, the server sends different payload types based on the situation:
| Payload Type | When Used | What It Contains |
|---|
Task | 最終状態(completed, failed, canceled)や完全なコンテキストが必要な場合 | 履歴とアーティファクトデータを含む完全なタスクオブジェクト |
TaskStatusUpdateEvent | 実行中のステータス遷移(working, input-required) | メッセージパートを含む軽量ステータス更新 |
TaskArtifactUpdateEvent | ストリーミングによるアーティファクト更新 | 利用可能になったアーティファクトデータ |
AdCP では主に次の 2 つが多くなります:
Task: 最終結果(completed, failed)
TaskStatusUpdateEvent: 進捗更新(working, input-required)
Webhook が送信される条件
Webhooks are sent when all of these conditions are met:
- Task type supports async (e.g.,
create_media_buy, sync_creatives, get_products)
pushNotificationConfig is provided in the request
- Task runs asynchronously — initial response is
working or submitted
初回レスポンスがすでに終端(completed, failed, rejected)なら Webhook は送信されません。結果はその場で得られます。
Webhook を送るステータス変化:
working → 進捗更新(処理中)
input-required → 人による入力が必要
completed → 最終結果
failed → エラー詳細
canceled → キャンセル確定
データスキーマのバリデーション
A2A Webhook の status.message.parts[].data フィールドはステータス別スキーマを使用します:
| Status | Schema | Contents |
|---|
completed | [task]-response.json | Full task response (success branch) |
failed | [task]-response.json | Full task response (error branch) |
working | [task]-async-response-working.json | Progress info (percentage, step) |
input-required | [task]-async-response-input-required.json | Requirements, approval data |
submitted | [task]-async-response-submitted.json | Acknowledgment (usually minimal) |
スキーマ参照: async-response-data.json
Webhook ハンドラーの例
const express = require('express');
const app = express();
app.post('/webhooks/a2a/:taskType/:operationId', async (req, res) => {
const { taskType, operationId } = req.params;
const webhook = 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' });
}
// A2A Webhook ペイロードから基本フィールドを抽出
const taskId = webhook.id || webhook.taskId;
const contextId = webhook.contextId;
const status = webhook.status?.state || webhook.status;
// ステータスに応じて AdCP データを抽出
let adcpData, textMessage;
if (status === 'completed' || status === 'failed') {
// FINAL STATES: Extract from .artifacts
const dataPart = webhook.artifacts?.[0]?.parts?.find(p => p.kind === 'data');
const textPart = webhook.artifacts?.[0]?.parts?.find(p => p.kind === 'text');
adcpData = dataPart?.data;
textMessage = textPart?.text;
} else {
// INTERIM STATES: Extract from status.message.parts (optional)
const dataPart = webhook.status?.message?.parts?.find(p => p.data);
const textPart = webhook.status?.message?.parts?.find(p => p.text);
adcpData = dataPart?.data;
textMessage = textPart?.text;
}
// ステータスに応じた処理
switch (status) {
case 'input-required':
// 人に入力が必要であることを通知
await notifyHuman({
task_id: taskId,
context_id: contextId,
message: textMessage,
data: adcpData
});
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?.errors,
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 を手動で扱う必要はありません。
自動コンテキスト
// 最初のリクエスト - A2A が自動でコンテキストを作成
const response1 = await a2a.send({
message: {
parts: [{ kind: "text", text: "Find premium video products" }]
}
});
// 後続リクエスト - A2A が自動でコンテキストを保持
const response2 = await a2a.send({
message: {
parts: [{ kind: "text", text: "Filter for sports content" }]
}
});
// システムが自動で前回のリクエストに紐づける
明示的コンテキスト(任意)
// 明示的に制御したい場合
const response2 = await a2a.send({
contextId: response1.contextId, // 任意 - A2A が追跡済み
message: {
parts: [{ kind: "text", text: "Refine those results" }]
}
});
MCP との違い: MCP の手動 context_id 管理と異なり、A2A はプロトコルレベルでセッション継続を扱います。
マルチモーダルメッセージ(A2A 固有)
A2A の特徴は、1 つのメッセージ内にテキスト・データ・ファイルを組み合わせられることです:
コンテキスト付きクリエイティブアップロード
// キャンペーンコンテキスト付きでクリエイティブを送信
const response = await a2a.send({
message: {
parts: [
{
kind: "text",
text: "Add this hero video to the premium sports campaign"
},
{
kind: "data",
data: {
skill: "sync_creatives",
parameters: {
media_buy_id: "mb_12345",
action: "upload_and_assign"
}
}
},
{
kind: "file",
uri: "https://cdn.example.com/hero-30s.mp4",
name: "sports_hero_30s.mp4"
}
]
}
});
キャンペーンブリーフ + アセット
// 完全なキャンペーンブリーフを送信
await a2a.send({
message: {
parts: [
{
kind: "text",
text: "Campaign brief and assets for Q1 launch"
},
{
kind: "file",
uri: "https://docs.google.com/campaign-brief.pdf",
name: "Q1_campaign_brief.pdf"
},
{
kind: "data",
data: {
budget: 250000,
kpis: ["reach", "awareness", "conversions"],
target_launch: "2024-01-15"
}
}
]
}
});
利用可能なスキル
すべての AdCP タスクは A2A スキルとして利用できます。確実な実行には明示的な呼び出しを使用してください:
タスク管理: 全ドメインにわたる非同期追跡、ポーリングパターン、Webhook 連携の詳細は Webhooks を参照。
スキルの構造
// Standard pattern for explicit skill invocation
await a2a.send({
message: {
parts: [{
kind: "data",
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 と Signals を参照してください。
エージェントカード
A2A エージェントは .well-known/agent.json の Agent Card で機能を公開します:
Agent Card の取得
// エージェントの機能を取得
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);
Agent Card の例
{
"name": "AdCP Media Buy Agent",
"description": "AI-powered media buying agent",
"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"]
}
}
]
}
AdCP 拡張
extensions 配列に AdCP 拡張を含めることで、プログラム的に AdCP 対応を宣言できます。
A2A プロトコルでは extensions 配列に以下を持つ拡張を列挙します:
uri: 拡張の識別子(https://adcontextprotocol.org/extensions/adcp を使用)
description: AdCP をどう使うかの説明
required: クライアントがこの拡張を必須とするか(AdCP は通常 false)
params: AdCP 固有の設定(下記スキーマ参照)
// エージェントが 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 オブジェクトは典型的な構造です。
メリット:
- テストコールなしで AdCP 対応状況を発見できます
- 実装しているプロトコルドメイン(media_buy, creative, signals)を宣言できます
- バージョンに基づく互換性チェックが可能
統合の例
// 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: { parts: [{ kind: "text", text: input }] }
});
case 'working':
// SSE ストリーミングで監視
return streamUpdates(response.taskId);
case 'completed':
return response.artifacts[0].parts[1].data;
case 'failed':
throw new Error(response.message);
}
}
// マルチモーダルメッセージによる使用例
const result = await a2a.send({
message: {
parts: [
{ kind: "text", text: "Find luxury car inventory" },
{ kind: "data", data: { skill: "get_products", parameters: { audience: "luxury car intenders" } } }
]
}
});
const finalResult = await handleA2aResponse(result);
A2A 固有の考慮点
エラーハンドリング
失敗したタスクは、アーティファクトの DataPart の adcp_error キーに構造化された AdCP エラーを格納します。完全な抽出ロジックと復旧動作は Transport Error Mapping を参照してください。
try {
const response = await a2a.send(message);
if (response.status === 'failed') {
// アーティファクト内の構造化 AdCP エラーを確認
const dataPart = response.artifacts?.[0]?.parts?.find(p => 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 for complete testable examples.
@adcp/client ライブラリは A2A アーティファクトの抽出を自動で処理するため、レスポンス構造を手動で解析する必要はありません。
ベストプラクティス
- ハイブリッドメッセージ(テキスト + データ + 必要に応じてファイル)を活用
- アーティファクト処理前に status フィールド を確認
- 長時間処理には SSE ストリーミング でリアルタイム更新
- ステータス処理パターンは Core Concepts を参照
- 利用可能なスキルと例は エージェントカード で確認
次のステップ
ステータス処理、非同期オペレーション、確認フローについては Task Lifecycle を参照してください。このガイドは A2A トランスポート固有の内容に絞っています。