Follow-up issue after PR #261 landed the a2a-sdk 1.0 migration. Reviewing against the A2A 1.0 extraction/placement rules that just landed in the adcp spec+docs repo (see bokelley/a2a-1.0-update — docs PR pending), we found two policy conflicts and three test-coverage gaps worth addressing.
Some of these may resolve cleanly when a2a-sdk 1.0.1 ships upstream — the shim layer in tests/a2a_compat_shim.py and the MessageToDict post-processing dance are the kind of thing that gets smaller as the Python SDK matures. Suggest revisiting this list after the next upstream drop before committing to any of the fixes.
Policy conflicts (need alignment across repos)
1. Wrapper policy — docs say reject, Python unwraps silently
adcp docs (a2a-response-extraction.mdx) state the normative rule clients MUST throw or log when a DataPart's .data is a single-key { response: {...} } wrapper — it's a server-side bug.
This PR continues to silently unwrap in _extract_result_from_task and _process_task_response (src/adcp/protocols/a2a.py), and test_extract_from_a2a_with_response_wrapper / test_extract_from_a2a_with_nested_response_wrapper actively assert unwrap behavior.
Options:
- Soften the docs to "MAY unwrap with warning; MUST NOT silently consume in strict mode." Matches deployed Python behavior and preserves pressure on buggy servers without breaking consumers that already rely on forgiving extraction.
- Flip Python to reject. Aligns with current docs but risks breaking any production buyer relying on the forgiving behavior.
Leaning toward softening the docs — but wanted to surface the divergence.
2. Webhook envelope wrapping — docs say StreamResponse-wrapped, Python emits bare
adcp docs state push-notification payloads use the A2A 1.0 StreamResponse wrapper ({ task } / { statusUpdate } / { artifactUpdate } / { message }), citing A2A 1.0 §4.3.3.
This PR emits bare Task and TaskStatusUpdateEvent in create_a2a_webhook_payload (src/adcp/webhooks.py) — looks like an intentional choice for v0.3 consumer compat.
Action: direct re-read of A2A 1.0 §4.3.3. If wrapping is normative, Python needs a future fix (potentially controlled by the same enable_v0_3_compat flag so 0.3 consumers keep the bare shape). If peer-choice, adcp docs should note Python emits bare for compat and new servers SHOULD wrap.
Test coverage gaps
3. No extraction tests for rejected / auth-required
The tolerant enum maps (src/adcp/protocols/a2a.py, src/adcp/webhooks.py) include both new 1.0 states, but no test asserts adcp_error extraction from a TASK_STATE_REJECTED artifact DataPart, or auth-challenge extraction from a TASK_STATE_AUTH_REQUIRED status message.
adcp repo has vectors for both — worth mirroring in the Python test suite.
4. No integration test for 1.0 client → 0.3 server
tests/integration/test_a2a_wire_compat.py covers 0.3 client → 1.0 server (the deployment direction most likely to break). The reverse — 1.0 Python client talking to a 0.3-only peer via force_a2a_version=\"0.3\" — has unit coverage of the version-filter logic but no end-to-end regression guard.
5. CHANGELOG 4.1.0 should flag subclasser breakage
The 4.1.0 release is pragmatically a minor bump given near-zero A2A adopter population, but subclassers face breaking changes:
a2a.utils.errors.ServerError → A2AError
get_agent_info() no longer returns adcp_version / protocols_supported
a2a-sdk type import paths shifted
Worth a top-level entry in CHANGELOG 4.1.0 so downstream integrators see it.
Related
🤖 Filed with Claude Code after expert review of the 1.0 migration.
Follow-up issue after PR #261 landed the a2a-sdk 1.0 migration. Reviewing against the A2A 1.0 extraction/placement rules that just landed in the adcp spec+docs repo (see
bokelley/a2a-1.0-update— docs PR pending), we found two policy conflicts and three test-coverage gaps worth addressing.Some of these may resolve cleanly when a2a-sdk 1.0.1 ships upstream — the shim layer in
tests/a2a_compat_shim.pyand theMessageToDictpost-processing dance are the kind of thing that gets smaller as the Python SDK matures. Suggest revisiting this list after the next upstream drop before committing to any of the fixes.Policy conflicts (need alignment across repos)
1. Wrapper policy — docs say reject, Python unwraps silently
adcp docs (
a2a-response-extraction.mdx) state the normative rule clients MUST throw or log when a DataPart's.datais a single-key{ response: {...} }wrapper — it's a server-side bug.This PR continues to silently unwrap in
_extract_result_from_taskand_process_task_response(src/adcp/protocols/a2a.py), andtest_extract_from_a2a_with_response_wrapper/test_extract_from_a2a_with_nested_response_wrapperactively assert unwrap behavior.Options:
Leaning toward softening the docs — but wanted to surface the divergence.
2. Webhook envelope wrapping — docs say
StreamResponse-wrapped, Python emits bareadcp docs state push-notification payloads use the A2A 1.0
StreamResponsewrapper ({ task }/{ statusUpdate }/{ artifactUpdate }/{ message }), citing A2A 1.0 §4.3.3.This PR emits bare
TaskandTaskStatusUpdateEventincreate_a2a_webhook_payload(src/adcp/webhooks.py) — looks like an intentional choice for v0.3 consumer compat.Action: direct re-read of A2A 1.0 §4.3.3. If wrapping is normative, Python needs a future fix (potentially controlled by the same
enable_v0_3_compatflag so 0.3 consumers keep the bare shape). If peer-choice, adcp docs should note Python emits bare for compat and new servers SHOULD wrap.Test coverage gaps
3. No extraction tests for
rejected/auth-requiredThe tolerant enum maps (
src/adcp/protocols/a2a.py,src/adcp/webhooks.py) include both new 1.0 states, but no test assertsadcp_errorextraction from aTASK_STATE_REJECTEDartifact DataPart, or auth-challenge extraction from aTASK_STATE_AUTH_REQUIREDstatus message.adcp repo has vectors for both — worth mirroring in the Python test suite.
4. No integration test for 1.0 client → 0.3 server
tests/integration/test_a2a_wire_compat.pycovers 0.3 client → 1.0 server (the deployment direction most likely to break). The reverse — 1.0 Python client talking to a 0.3-only peer viaforce_a2a_version=\"0.3\"— has unit coverage of the version-filter logic but no end-to-end regression guard.5. CHANGELOG 4.1.0 should flag subclasser breakage
The 4.1.0 release is pragmatically a minor bump given near-zero A2A adopter population, but subclassers face breaking changes:
a2a.utils.errors.ServerError→A2AErrorget_agent_info()no longer returnsadcp_version/protocols_supporteda2a-sdktype import paths shiftedWorth a top-level entry in CHANGELOG 4.1.0 so downstream integrators see it.
Related
bokelley/a2a-1.0-updatebranch (PR pending)🤖 Filed with Claude Code after expert review of the 1.0 migration.