Skip to main content
このページは、A2A Task オブジェクトと TaskStatusUpdateEvents から AdCP レスポンスデータを抽出する規範的アルゴリズムを定義します。セラーが生成しなければならない正準レスポンス構造については A2A Response Format を参照。エラー固有の抽出については Transport Error Mapping を参照。

A2A の上の AdCP 慣例

このページのルールは AdCP 固有のセマンティクスを A2A に重ねます。非 AdCP の A2A エージェントはそれらを強制せず、準拠する出力を生成することを期待されるべきではありません。
  • 単一アーティファクト不変条件。 AdCP タスクはすべての出力パーツを含む 1 つのアーティファクトを生成する。クライアントは artifacts[0] から読む。セラーが複数の distinct な成果物を必要とする場合、複数のアーティファクトではなく別々のタスクとしてモデル化すべき。
  • Last-DataPart 権威。 1 つのアーティファクトに複数の DataPart が現れるとき(ストリーミング中に典型的)、最後のものが権威的。以前の DataPart は置き換えられた進捗スナップショット。
  • First-DataPart は interim 用。 status.message.parts に複数の DataPart が現れるとき、最初のものが使われる — interim 更新は累積ではなく単一イベントのスナップショット。
  • ラッパー拒否。 .data{ response: {...} }response という単一キー)の DataPart は、有効なペイロードではなくフレームワークラッパーのバグとして扱われる。

ワイヤー形式の互換性

このアルゴリズムは A2A 1.0v0.3 の両レスポンスを扱います。抽出は 1 つのワイヤー形式を仮定してはなりません — 同じ AdCP クライアントが v0.3 互換性期間中に両方と話す可能性があります。 State 値。 status.state フィールドは、1.0 では ProtoJSON 形式("TASK_STATE_COMPLETED""TASK_STATE_WORKING" …)、v0.3 では小文字形式("completed""working" …)で到着します。クライアントは比較前に正規化します。 Part 形状。 1.0 の DataPart は非 null の data フィールドを持ち kind を持ちません。v0.3 の DataPart は kind: "data"data フィールドを持ちます。両方が「data フィールドが非 null オブジェクト」を満たします。同じことが TextParts(text フィールド存在)と FileParts(1.0 の url/raw、または v0.3 の kind: "file")にも当てはまります。A2A 1.0 §4.1.6 に従い、Part は厳格な oneof です — textrawurldata の正確に 1 つが設定されます。複数のコンテンツフィールドを持つ Part を受け取るクライアントは、それを不正な形式として扱うべきです(SHOULD)。 ストリーミングエンベロープ。 A2A 1.0 は、ストリーミングレスポンスとプッシュ通知ペイロードを、taskmessagestatusUpdateartifactUpdate の正確に 1 つのキーを持つ StreamResponse oneof でラップします(A2A 1.0 §3.2.3、§4.3.3)。非ストリーミングレスポンス(例: tasks/get、または HTTP 上の v0.3)は素のオブジェクトを配信します。抽出は下のアルゴリズムを適用する前に単一キーエンベロープをアンラップします。

ステータスベースの抽出

抽出場所はタスクのステータスに依存します。この表の State 名は正規化された小文字形式で示されます — 生のワイヤー値ではなく正規化された state に対してマッチしてください。 Final 状態は、.artifacts が欠如または空のとき status.message.parts[] にフォールバックします — これは、別のアーティファクトではなくステータスメッセージに最終ペイロードを置くサーバーをカバーします。 Canceled タスクはめったにデータを運びません — DataPart が存在しないとき抽出は null を返し、それが期待されるケースです。Rejected タスクは、リクエストがなぜ拒否されたか(tier/policy/validation)を記述する adcp_error DataPart を運ぶことが期待されます。

抽出アルゴリズム

クライアントは、これらのステップを使って A2A レスポンスから AdCP データを抽出しなければなりません(MUST):
  1. ストリームエンベロープをアンラップ。 入力が taskmessagestatusUpdateartifactUpdate という正確に 1 つのトップレベルキーを持つオブジェクトで、そのキーの値が非 null・非配列オブジェクトなら、入力をその値で置き換える(A2A 1.0 StreamResponse oneof)。素の Task / TaskStatusUpdateEvent オブジェクト — 非ストリーミングレスポンスまたは v0.3 — は変更なく通過。artifactUpdate はタスクステータスを運ばない。アンラップされると status.state は欠如しステップ 1 は null を返す。 正確に一度 アンラップする。クライアントは再帰してはならない(MUST NOT)。アンラップされた内部オブジェクト自体が単一キーエンベロープ形状({ task: { task: {...} } } または任意の組み合わせ)を持つ場合、不正な形式として扱い null を返す — これはネストされたエンベロープの密輸試行。内部値のトップレベルキーが task / message / statusUpdate / artifactUpdate のいずれかを含むエンベロープは拒否されなければならない(MUST)。 素の { message } エンベロープ(帯域外エージェントメッセージ)はタスク指向の抽出器によって無視されなければならない(MUST) — アンラップされたオブジェクトが status.state を持たないときステップ 1 は null を返す。Webhook/SSE ハンドラーは、認識されない { message } エンベロープに 200 OK 承認を返してはならない(MUST NOT)。エンドポイントをプローブする攻撃者への存在オラクルとして動作するのを避けるため、400 Bad Request を返すかトランスポート層で黙って破棄する。
  2. status.state を読む。 欠如なら null を返す。比較前に小文字形式に正規化(TASK_STATE_COMPLETEDcompleted)。正規化後、state は 正確な ASCII 文字列等価 で既知の final/interim トークンの 1 つに一致しなければならない(MUST)。クライアントは、繰り返しのセパレーターを折り畳んだり、空白をトリムしたり、ASCII 小文字を超えた Unicode case-folding を適用したりしてはならない(MUST NOT)。他の任意の値 — クライアントが認識しない新しい TASK_STATE_* 入力を含む — は「unknown」で、抽出は null を返す(ステップ 4)。
  3. Final 状態completedfailedcanceledrejected): a. artifacts[0].parts[] で DataPart(data フィールドが非 null オブジェクトの Part — kind の存在にかかわらず)を探す。 b. 最後の DataPart を権威的として使う(Last-DataPart Authority を参照)。 c. ラッパーを拒否: DataPart の .data がオブジェクトを含む単一キー response を持つ場合、これはフレームワークラッパーのバグ。throw またはエラーをログ。 d. .data を返す。 e. フォールバック: アーティファクトがない、またはアーティファクトに DataPart がない場合、ステップ 3 を使って status.message.parts[] を確認。
  4. Interim 状態workingsubmittedinput-requiredauth-required): a. status.message.parts[] で DataPart を探す。 b. 最初の DataPart を使う。 c. .data を返す、または DataPart が見つからなければ null。
  5. Unknown 状態: null を返す。前方互換のクライアントは認識されないステータス値で throw すべきではない(SHOULD NOT)。
State 正規化: TASK_STATE_ プレフィックスを除去、小文字化、アンダースコアをハイフンに置換。これは A2A 1.0("TASK_STATE_INPUT_REQUIRED")と v0.3("input-required")の両方を同じ値にマップします。 DataPart 検出はフィールド存在を使います — 1.0 Part { "data": {...} } と v0.3 Part { "kind": "data", "data": {...} } は両方とも「非 null オブジェクト data フィールド」テストを満たします。

Last-DataPart Authority

Final 状態については、artifacts[0].parts[]最後の DataPart が権威的です。ストリーミング中、中間の DataPart は最終結果に置き換えられる古い進捗データを含みうる:
抽出されるデータは {"progress": 25} ではなく {"products": [...], "total": 12} です。 Interim 状態については、interim 更新が累積ではなく単一イベントのスナップショットなので、最初の DataPart が使われます。

ラッパー拒否

クライアントは、.data がフレームワーク固有のオブジェクトでラップされた DataPart を拒否しなければなりません(MUST):
検出ルール: .data が値がオブジェクトの response という正確に 1 つのキーを持つ場合、それはラッパーです。これはサーバー側のバグです — クライアントは黙ってアンラップするのではなく throw またはエラーをログすべきです。 ラッパー検出は Final 状態のみ(アーティファクト)に適用されます。Interim ステータスメッセージは軽量な進捗スナップショットです — status.message.parts にラッパー検出は不要です。 例外: 他のキーと並んで response を持つ .data オブジェクトはラッパーでは ありません:

エラー抽出との関係

このアルゴリズムは、エラーペイロード(adcp_error)を含む A2A レスポンスから 任意の AdCP データを抽出します。エラー固有の抽出(Transport Error Mapping)は、抽出されたデータで adcp_error キーを確認する特殊化です。 transport-errors 仕様は、すべてのアーティファクトを adcp_error についてスキャンする独自の extractAdcpErrorFromA2A 関数を提供します。その関数はエラー検出(すべてのパーツをエラーキーについてスキャン)に最適化されています。この関数は汎用の抽出器(最初のアーティファクトからの最後の DataPart)です。単一の adcp_error DataPart を持つ failed タスクについては、両方が等価な結果を生成します。 典型的なクライアントフロー:

セキュリティ考慮事項

セラー制御データ

.artifacts[].parts[].datastatus.message.parts[].data のすべてのデータはセラー制御です。Transport Error Mapping のプロンプトインジェクション、データ境界、サイズ制限の要件が適用されます。

プロトタイプ汚染

クライアントは、キーをフィルターせずに抽出された DataPart ペイロードを Object.assign やスプレッド経由でアプリケーション状態にマージしてはなりません(MUST NOT)。マージ前に期待されるタスクレスポンススキーマに対して検証してください。

FilePart URI 検証

A2A レスポンスは FilePart を含みうる。1.0 ではこれらは url フィールド(参照によるファイル)または raw フィールド(base64 バイト)を運ぶ Part。v0.3 では uri フィールドを伴う kind: "file" を運ぶ。クライアントは、URL が https スキームを使い、userinfo コンポーネントを含まず、期待されるドメイン許可リストに一致することを検証しなければならない(MUST)。javascript:data:file:http: URI を拒否。raw パーツについては、受け入れる前に最大デコードサイズを強制する。

Auth チャレンジ URL 検証

auth-required を扱うとき、セラーは status.message.parts に auth チャレンジ — 通常 auth_schemechallenge_urlscopes のようなフィールドを持つ DataPart — を送る。クライアントが開くまたはフェッチするセラー制御の URL は OAuth フィッシングと SSRF ベクター。任意のユーザー向けまたはプログラム的な auth フローを開始する前に、クライアントは challenge_url を検証しなければならない(MUST):
  • スキームは https でなければならない(MUST)。http:javascript:data:file: を拒否。
  • URL は userinfo コンポーネント(user:pass@host 形式)を含んではならない(MUST NOT)。
  • ホストは、このエージェントカードの認証されたセラーの登録された auth オリジンに一致しなければならない(MUST)。クライアントは、タスクペイロードから導出されるのではなく、Agent Card の supportedInterfaces[].url オリジンまたは宣言された authOrigin 拡張フィールドからシードされたエージェントごとの許可リストを維持すべき(SHOULD)。
  • 任意の redirect_urireturn_url、または類似のクエリパラメーターは、ナビゲーション前にクライアントによって落とされるか上書きされなければならない(MUST)。セラー供給のリダイレクトを決して転送しない。
  • scopes は付与ではなくリクエストとして扱われなければならない(MUST)。scopes をユーザーに示し、各チャレンジで新鮮な同意を得る。
クライアントがチャレンジ URL をサーバー側でフェッチする場合、レスポンスサイズとタイムアウトの境界が適用される(例: 256 KB レスポンス上限、10 秒タイムアウト、リダイレクト制限 3)。

セラー制御文字列の衛生

すべての adcp_error.messageadcp_error.details.*、ステータス TextPart コンテンツはセラー制御です。これらを UI にレンダリングするクライアントは、ターゲットコンテキスト(HTML、Slack、CLI)用にエスケープしなければならない(MUST)。それらをログするクライアントは、ログ注入を防ぐため CRLF を除去しなければならない(MUST)。これは adcp_error を運ぶすべての状態(failedrejected、システム開始の canceled)と自由テキストの status.message に適用されます。

サイズ制限

クライアントはスキーマ検証前に最大 DataPart サイズ(例: 1MB)を強制すべきです(SHOULD)。エラーペイロード(4096 バイトに上限)とは異なり、成功ペイロードはより大きくなりうるが依然として境界が必要です。

仲介者注入

last-DataPart 慣例は、アーティファクトが単一の信頼された送信者から無傷で受け取られることを仮定します。マルチホップシナリオ(buyer → orchestrator → seller)では、仲介者が追加のパーツを注入できます。仲介者を通じて動作するクライアントは、アーティファクトのパーツ数が期待に一致することを検証すべきです(SHOULD)。

クライアントライブラリ要件

この仕様を実装するクライアントライブラリは次をしなければなりません(MUST):
  1. A2A 1.0 ストリームエンベロープをアンラップ。 taskmessagestatusUpdateartifactUpdate のキーを持つ単一キーオブジェクトは StreamResponse ラッパー — アルゴリズムの残りを適用する前に内部オブジェクトにアンラップ。素のオブジェクトは変更なく通過。
  2. A2A 1.0 と v0.3 の両ワイヤー形状を受け入れる。 比較前に status.state を正規化(TASK_STATE_ プレフィックス除去、小文字化、アンダースコアをハイフンに)。kind ではなくフィールド存在(data が非 null オブジェクト)で DataPart を検出。
  3. 正規化された state で分岐。 Final 状態(completedfailedcanceledrejected)はアーティファクトを使い、interim 状態(workingsubmittedinput-requiredauth-required)は status.message.parts を使う。
  4. Final 状態には最後の DataPart を使う。 null、非オブジェクト、配列 .data の DataPart をスキップ。
  5. Interim 状態には最初の DataPart を使う。
  6. ラッパーを検出し拒否。 単一キー {response: {...}} ペイロードはバグ。
  7. 優雅にフォールバック。 Final 状態でアーティファクトが空なら、status.message.parts を確認。
  8. Unknown 状態を扱う。 null を返し、throw しない。

テストベクター

機械可読なテストベクターは /static/test-vectors/a2a-response-extraction.json で利用可能です。各ベクターは次を含みます:
  • status: A2A タスクステータス
  • path: 抽出パス(artifactstatus_message、または none
  • response: A2A Task または TaskStatusUpdateEvent
  • expected_data: 抽出されるべき AdCP データ(または null
  • expected_error_type: 存在する場合、抽出は throw すべき(例: wrapper_detected
クライアントライブラリはこれらのベクターに対して抽出ロジックを検証すべきです(SHOULD)。

関連項目