From 77a9984c54cdf8b32969ce3d0efaef2ba909f0d0 Mon Sep 17 00:00:00 2001 From: Emma Mulitz Date: Fri, 21 Nov 2025 16:30:43 -0500 Subject: [PATCH 1/3] Fix A2A payload structure in documentation examples Fixed inconsistent A2A (Agent-to-Agent Protocol) examples that were confusing developers: **Issues Fixed:** 1. Changed "input" to "parameters" in skill invocation data (3 instances in create_media_buy.mdx) 2. Added proper A2A message wrapper structure with message.parts[] (2 instances) 3. Moved pushNotificationConfig from skill data to configuration object (2 instances across 2 files) **Files Modified:** - docs/media-buy/task-reference/create_media_buy.mdx - docs/media-buy/advanced-topics/orchestrator-design.mdx **Canonical A2A Structure (now consistent everywhere):** ```json { "message": { "parts": [{ "kind": "data", "data": { "skill": "task_name", "parameters": { ... } // Always "parameters", never "input" } }] }, "configuration": { // pushNotificationConfig goes here "pushNotificationConfig": { ... } } } ``` All A2A examples now match the A2A guide specification. Verified all 26 documentation files - only these 2 had issues. --- .../advanced-topics/orchestrator-design.mdx | 4 +- .../task-reference/create_media_buy.mdx | 70 ++++++++++++------- 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/docs/media-buy/advanced-topics/orchestrator-design.mdx b/docs/media-buy/advanced-topics/orchestrator-design.mdx index 116990f8d3..0e2ac06952 100644 --- a/docs/media-buy/advanced-topics/orchestrator-design.mdx +++ b/docs/media-buy/advanced-topics/orchestrator-design.mdx @@ -558,7 +558,9 @@ class AdCPOrchestrator: } }] }, - "push_notification_config": webhook_config + "configuration": { + "pushNotificationConfig": webhook_config + } }) # 4. Handle response with unified status handling diff --git a/docs/media-buy/task-reference/create_media_buy.mdx b/docs/media-buy/task-reference/create_media_buy.mdx index 901b33f619..dc2c1fb5b6 100644 --- a/docs/media-buy/task-reference/create_media_buy.mdx +++ b/docs/media-buy/task-reference/create_media_buy.mdx @@ -390,7 +390,7 @@ data: {"status": {"state": "completed"}, "artifacts": [{ - **A2A**: Always returns task with updates via: - Server-Sent Events (SSE) for real-time streaming - Webhooks (push notifications) for long-running tasks -- **Payload**: The `input` field in A2A contains the exact same structure as MCP's `arguments` +- **Payload**: The `parameters` field in A2A contains the exact same structure as MCP's `arguments` ## Human-in-the-Loop Examples @@ -466,17 +466,24 @@ A2A can use Server-Sent Events for real-time streaming or webhooks for push noti **Initial Request with SSE:** ```json { - "skill": "create_media_buy", - "input": { - "buyer_ref": "large_campaign_2024", - "packages": [...], - "brand_manifest": { - "name": "ACME Corporation", - "url": "https://acmecorp.com" - }, - "po_number": "PO-2024-LARGE-001", - "start_time": "2024-02-01T00:00:00Z", - "end_time": "2024-06-30T23:59:59Z" + "message": { + "parts": [{ + "kind": "data", + "data": { + "skill": "create_media_buy", + "parameters": { + "buyer_ref": "large_campaign_2024", + "packages": [...], + "brand_manifest": { + "name": "ACME Corporation", + "url": "https://acmecorp.com" + }, + "po_number": "PO-2024-LARGE-001", + "start_time": "2024-02-01T00:00:00Z", + "end_time": "2024-06-30T23:59:59Z" + } + } + }] } } ``` @@ -520,22 +527,31 @@ data: {"status": {"state": "completed"}, "artifacts": [{ **Initial Request with Webhook Configuration:** ```json { - "skill": "create_media_buy", - "input": { - "buyer_ref": "large_campaign_2024", - "packages": [...], - "brand_manifest": { - "name": "ACME Corporation", - "url": "https://acmecorp.com" - }, - "po_number": "PO-2024-LARGE-001", - "start_time": "2024-02-01T00:00:00Z", - "end_time": "2024-06-30T23:59:59Z" + "message": { + "parts": [{ + "kind": "data", + "data": { + "skill": "create_media_buy", + "parameters": { + "buyer_ref": "large_campaign_2024", + "packages": [...], + "brand_manifest": { + "name": "ACME Corporation", + "url": "https://acmecorp.com" + }, + "po_number": "PO-2024-LARGE-001", + "start_time": "2024-02-01T00:00:00Z", + "end_time": "2024-06-30T23:59:59Z" + } + } + }] }, - "pushNotificationConfig": { - "url": "https://buyer.example.com/webhooks/adcp", - "authType": "bearer", - "authToken": "secret-token-xyz" + "configuration": { + "pushNotificationConfig": { + "url": "https://buyer.example.com/webhooks/adcp", + "authType": "bearer", + "authToken": "secret-token-xyz" + } } } ``` From b71abac344d5ba30cb6b2e6da255dc2be510daa2 Mon Sep 17 00:00:00 2001 From: Emma Mulitz Date: Fri, 21 Nov 2025 17:22:25 -0500 Subject: [PATCH 2/3] Add artifactId to all A2A response examples Fixed missing artifactId field in A2A artifact examples to align with A2A protocol specification. **Changes:** - Added `artifactId` field to all 11 A2A response examples across 8 documentation files - Updated processing code example in a2a-guide.mdx to show artifactId usage - Made `name` field optional (kept where present, but artifactId is required) - Used descriptive naming pattern: `artifact-{type}-{identifier}` **Why:** - A2A protocol requires artifactId for artifact identification - Critical for multi-artifact responses (to be added in future PR) - Enables proper artifact tracking and versioning - All A2A responses now align with protocol specification **Files Modified:** - docs/protocols/a2a-guide.mdx - Updated response structure and processing example - docs/media-buy/task-reference/create_media_buy.mdx - Added to 3 examples - docs/signals/tasks/activate_signal.mdx - docs/signals/tasks/get_signals.mdx - docs/protocols/protocol-comparison.mdx - docs/protocols/envelope-examples.mdx - Added to 2 examples - docs/protocols/getting-started.mdx - docs/media-buy/task-reference/provide_performance_feedback.mdx **Next:** Multi-artifact examples will be added in separate PR to show when/how multiple artifacts are used. --- .../task-reference/create_media_buy.mdx | 5 ++-- .../provide_performance_feedback.mdx | 3 +- docs/protocols/a2a-guide.mdx | 29 ++++++++++++------- docs/protocols/envelope-examples.mdx | 2 ++ docs/protocols/getting-started.mdx | 1 + docs/protocols/protocol-comparison.mdx | 3 +- docs/signals/tasks/activate_signal.mdx | 1 + docs/signals/tasks/get_signals.mdx | 1 + 8 files changed, 31 insertions(+), 14 deletions(-) diff --git a/docs/media-buy/task-reference/create_media_buy.mdx b/docs/media-buy/task-reference/create_media_buy.mdx index dc2c1fb5b6..f4dab6b058 100644 --- a/docs/media-buy/task-reference/create_media_buy.mdx +++ b/docs/media-buy/task-reference/create_media_buy.mdx @@ -366,6 +366,7 @@ data: {"message": "Validating packages..."} data: {"message": "Checking inventory availability..."} data: {"message": "Creating campaign in ad server..."} data: {"status": {"state": "completed"}, "artifacts": [{ + "artifactId": "artifact-mb-conf-abc123", "name": "media_buy_confirmation", "parts": [ {"kind": "text", "text": "Successfully created $100,000 media buy. Upload creatives by Jan 30."}, @@ -508,7 +509,7 @@ data: {"message": "Sales team notified. Expected review time: 2-4 hours"} data: {"message": "First approval received from regional manager"} data: {"message": "Second approval received from finance team"} data: {"status": {"state": "completed"}, "artifacts": [{ - "artifactId": "artifact-mb-large-xyz", + "artifactId": "artifact-mb-approval-xyz789", "name": "media_buy_confirmation", "parts": [ {"kind": "text", "text": "Media buy approved and created successfully. $500,000 campaign scheduled Feb 1 - Jun 30. Upload creatives by Jan 30."}, @@ -584,7 +585,7 @@ data: {"status": {"state": "completed"}, "artifacts": [{ "contextId": "ctx-conversation-xyz", "status": {"state": "completed"}, "artifacts": [{ - "artifactId": "artifact-mb-webhook-xyz", + "artifactId": "artifact-mb-webhook-def456", "name": "media_buy_confirmation", "parts": [ {"kind": "data", "data": { diff --git a/docs/media-buy/task-reference/provide_performance_feedback.mdx b/docs/media-buy/task-reference/provide_performance_feedback.mdx index ca408911d6..a37d21720a 100644 --- a/docs/media-buy/task-reference/provide_performance_feedback.mdx +++ b/docs/media-buy/task-reference/provide_performance_feedback.mdx @@ -120,6 +120,7 @@ A2A returns results as artifacts: ```json { "artifacts": [{ + "artifactId": "artifact-perf-feedback-abc789", "name": "performance_feedback_confirmation", "parts": [ { @@ -127,7 +128,7 @@ A2A returns results as artifacts: "text": "Performance feedback received for campaign gam_1234567890. The 35% above-expected conversion rate will be used to optimize future delivery. Next optimization cycle runs tonight at midnight UTC." }, { - "kind": "data", + "kind": "data", "data": { "success": true } diff --git a/docs/protocols/a2a-guide.mdx b/docs/protocols/a2a-guide.mdx index 1779de20e6..6adbc755ec 100644 --- a/docs/protocols/a2a-guide.mdx +++ b/docs/protocols/a2a-guide.mdx @@ -159,6 +159,7 @@ const task = await a2a.send({ "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": [ { @@ -166,7 +167,7 @@ const task = await a2a.send({ "text": "Found 12 video products perfect for pet food campaigns" }, { - "kind": "data", + "kind": "data", "data": { "products": [...], "total": 12 @@ -186,15 +187,23 @@ const task = await a2a.send({ ### Processing Artifacts ```javascript function processA2aResponse(response) { - // Extract human message - const message = response.artifacts?.[0]?.parts - ?.find(p => p.kind === 'text')?.text; - - // Extract structured data - const data = response.artifacts?.[0]?.parts - ?.find(p => p.kind === 'data')?.data; - - return { message, data, status: response.status }; + // A2A responses may contain multiple artifacts - iterate through them + const artifacts = response.artifacts || []; + + // For simple single-artifact responses, access first artifact + const artifact = 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 }; } ``` diff --git a/docs/protocols/envelope-examples.mdx b/docs/protocols/envelope-examples.mdx index dc7794da3d..39499b486f 100644 --- a/docs/protocols/envelope-examples.mdx +++ b/docs/protocols/envelope-examples.mdx @@ -105,6 +105,7 @@ MCP sends progress notifications separately: "state": "completed", "artifacts": [ { + "artifactId": "artifact-get-products-abc123", "name": "get_products_result", "content_type": "application/json", "content": "{\"products\": [...]}" @@ -155,6 +156,7 @@ Later, webhook notification: "state": "completed", "artifacts": [ { + "artifactId": "artifact-media-buy-webhook-def456", "name": "create_media_buy_result", "content_type": "application/json", "content": "{\"media_buy_id\": \"mb_789\", ...}" diff --git a/docs/protocols/getting-started.mdx b/docs/protocols/getting-started.mdx index 98c0aa31d1..305d34758d 100644 --- a/docs/protocols/getting-started.mdx +++ b/docs/protocols/getting-started.mdx @@ -109,6 +109,7 @@ Both protocols support all features - they just express them differently: { "contextId": "ctx-123", "artifacts": [{ + "artifactId": "artifact-product-catalog-xyz123", "name": "product_catalog", "parts": [ {"kind": "text", "text": "Found 5 CTV products"}, diff --git a/docs/protocols/protocol-comparison.mdx b/docs/protocols/protocol-comparison.mdx index 21c15ceb23..6889f223c0 100644 --- a/docs/protocols/protocol-comparison.mdx +++ b/docs/protocols/protocol-comparison.mdx @@ -72,10 +72,11 @@ Same status and data, different packaging: "status": "input-required", "contextId": "ctx-123", "artifacts": [{ + "artifactId": "artifact-product-discovery-xyz", "name": "product_discovery", "parts": [ { - "kind": "text", + "kind": "text", "text": "I need your budget and target audience" }, { diff --git a/docs/signals/tasks/activate_signal.mdx b/docs/signals/tasks/activate_signal.mdx index 74cb196e9e..0b69247ca3 100644 --- a/docs/signals/tasks/activate_signal.mdx +++ b/docs/signals/tasks/activate_signal.mdx @@ -264,6 +264,7 @@ data: {"message": "Validating signal access permissions..."} data: {"message": "Configuring deployment on The Trade Desk..."} data: {"message": "Finalizing activation..."} data: {"status": {"state": "completed"}, "artifacts": [{ + "artifactId": "artifact-signal-activation-abc123", "name": "signal_activation_result", "parts": [ {"kind": "text", "text": "Signal successfully activated on The Trade Desk"}, diff --git a/docs/signals/tasks/get_signals.mdx b/docs/signals/tasks/get_signals.mdx index d60d3a7788..02baf27080 100644 --- a/docs/signals/tasks/get_signals.mdx +++ b/docs/signals/tasks/get_signals.mdx @@ -342,6 +342,7 @@ A2A returns results as artifacts with the same data structure: ```json { "artifacts": [{ + "artifactId": "artifact-signal-discovery-def456", "name": "signal_discovery_result", "parts": [ { From d3668f87d3224ed6c9fcef0e35ef9ecc06f42b2b Mon Sep 17 00:00:00 2001 From: Emma Mulitz Date: Fri, 21 Nov 2025 17:32:44 -0500 Subject: [PATCH 3/3] Fix misleading comment in artifact processing example The comment said 'iterate through them' but code just accessed [0]. Changed to accurately reflect current single-artifact implementation. When multi-artifact support is added in future PR, we'll update this to show proper iteration pattern. --- docs/protocols/a2a-guide.mdx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/protocols/a2a-guide.mdx b/docs/protocols/a2a-guide.mdx index 6adbc755ec..0bde1be5b8 100644 --- a/docs/protocols/a2a-guide.mdx +++ b/docs/protocols/a2a-guide.mdx @@ -187,14 +187,13 @@ const task = await a2a.send({ ### Processing Artifacts ```javascript function processA2aResponse(response) { - // A2A responses may contain multiple artifacts - iterate through them - const artifacts = response.artifacts || []; + // Extract the artifact (currently AdCP returns single artifact per response) + const artifact = response.artifacts?.[0]; - // For simple single-artifact responses, access first artifact - const artifact = 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,