Skip to content

A2A 1.0 follow-ups: wrapper policy, webhook envelope, test coverage #263

@bokelley

Description

@bokelley

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.ServerErrorA2AError
  • 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingclaude-triageddocumentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions