You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Discovered while reviewing PR #968 (closed). The SDK currently routes tasks/get through ProtocolClient.callTool for both MCP and A2A (src/lib/core/TaskExecutor.ts:1293). For A2A, this dispatches as message/send { skill: 'tasks/get' }.
Tension
AdCP 3.0 defines tasks/get as a buyer-callable tool with bundled request/response schemas at schemas/cache/<v>/bundled/core/tasks-get-{request,response}.json. The tool tracks AdCP work lifecycle (submitted/working/completed/failed/etc on the actual buyer task), which is what buyers need.
A2A 0.3.0 defines tasks/get as a native JSON-RPC method (alongside message/send, tasks/cancel, etc). On the wire, native A2A tasks/get polls TRANSPORT-call lifecycle — for AdCP submitted-arm sellers, Task.state is always 'completed' because the message was successfully accepted; the work lifecycle lives in the artifact.
These are different surfaces tracking different lifecycles. The names collide.
Failure modes
Seller built on @a2a-js/sdk's DefaultRequestHandler: the SDK routes JSON-RPC method names directly. A buyer sending message/send { skill: 'tasks/get' } may surface as a method-not-found from the seller's tool registry, even though the AdCP-tool implementation exists in the seller's handler chain.
(A) Sellers register the same handler under both surfaces (AdCP tool + A2A native method). The SDK could probe via tools/list on first call and prefer the AdCP-tool path when present.
(B) AdCP spec asserts that A2A sellers MUST route the native tasks/get JSON-RPC to the AdCP work-lifecycle handler (i.e., make the native method an AdCP-defined surface). Rename to disambiguate downstream.
(C) The SDK probes capability and uses native A2A tasks/get only when the seller advertises it as a polling method (e.g., capability flag), defaulting to the AdCP-tool path.
(D) Status quo: tool-only path on ProtocolClient.callTool, document that A2A sellers MUST register tasks/get as a buyer-callable tool over message/send.
Prior art
PR #968 (closed) implemented (C)-ish but only the native-A2A side, without the capability probe. The expert reviews flagged the rationale was sound but the path bypassed AdCP's work-lifecycle semantics.
Action
Discuss with adcontextprotocol/adcp maintainers — this is upstream design.
Once resolved, update getTaskStatus to match the chosen path.
Defensive fix worth applying independently of the design question: cherry-pick the typeof-guard from PR fix(protocols): use native A2A tasks/get JSON-RPC for polling (#963) #968's ca513b27 to mapTasksGetResponseToTaskInfo so non-string status values don't silently mis-compare against ADCP_STATUS.*.
Context
Discovered while reviewing PR #968 (closed). The SDK currently routes
tasks/getthroughProtocolClient.callToolfor both MCP and A2A (src/lib/core/TaskExecutor.ts:1293). For A2A, this dispatches asmessage/send { skill: 'tasks/get' }.Tension
AdCP 3.0 defines
tasks/getas a buyer-callable tool with bundled request/response schemas atschemas/cache/<v>/bundled/core/tasks-get-{request,response}.json. The tool tracks AdCP work lifecycle (submitted/working/completed/failed/etc on the actual buyer task), which is what buyers need.A2A 0.3.0 defines
tasks/getas a native JSON-RPC method (alongsidemessage/send,tasks/cancel, etc). On the wire, native A2Atasks/getpolls TRANSPORT-call lifecycle — for AdCP submitted-arm sellers,Task.stateis always'completed'because the message was successfully accepted; the work lifecycle lives in the artifact.These are different surfaces tracking different lifecycles. The names collide.
Failure modes
Seller built on
@a2a-js/sdk'sDefaultRequestHandler: the SDK routes JSON-RPC method names directly. A buyer sendingmessage/send { skill: 'tasks/get' }may surface as a method-not-found from the seller's tool registry, even though the AdCP-tool implementation exists in the seller's handler chain.Buyer using A2A native
tasks/get: gets transport-state, not AdCP work-state. Submitted arms always look "completed" — wrong polling lifecycle, breaksSubmittedContinuation.waitForCompletion().Possible resolutions
tools/liston first call and prefer the AdCP-tool path when present.tasks/getJSON-RPC to the AdCP work-lifecycle handler (i.e., make the native method an AdCP-defined surface). Rename to disambiguate downstream.tasks/getonly when the seller advertises it as a polling method (e.g., capability flag), defaulting to the AdCP-tool path.ProtocolClient.callTool, document that A2A sellers MUST registertasks/getas a buyer-callable tool overmessage/send.Prior art
PR #968 (closed) implemented (C)-ish but only the native-A2A side, without the capability probe. The expert reviews flagged the rationale was sound but the path bypassed AdCP's work-lifecycle semantics.
Action
getTaskStatusto match the chosen path.ca513b27tomapTasksGetResponseToTaskInfoso non-string status values don't silently mis-compare againstADCP_STATUS.*.