Skip to content

ci(python): update a2a-sdk requirement from <0.4.0,>=0.3.0 to >=0.3.0,<1.2.0 in /strands-py - #3313

Open
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/pip/strands-py/a2a-sdk-gte-0.3.0-and-lt-1.2.0
Open

dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/pip/strands-py/a2a-sdk-gte-0.3.0-and-lt-1.2.0

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Jul 17, 2026

Copy link
Copy Markdown
Contributor

Updates the requirements on a2a-sdk to permit the latest version.

Release notes

Sourced from a2a-sdk's releases.

v1.1.1

1.1.1 (2026-07-15)

Bug Fixes

  • server: improve Swagger /docs example annotations for A2A routes (#1092) (46b292b)

Miscellaneous Chores

  • grpc: eliminate third-party grpcio-status dependency (#1130) (723880e)
  • http: eliminate httpx-sse dependency (#1132) (0d82ab9)
Changelog

Sourced from a2a-sdk's changelog.

1.1.1 (2026-07-15)

Bug Fixes

  • server: improve Swagger /docs example annotations for A2A routes (#1092) (46b292b)

Miscellaneous Chores

  • grpc: eliminate third-party grpcio-status dependency (#1130) (723880e)
  • http: eliminate httpx-sse dependency (#1132) (0d82ab9)

1.1.0 (2026-05-29)

Features

  • server: restore FastAPI /docs visibility for A2A routes (#1024) (1122d4e)

Bug Fixes

  • compat: remove ListTasks from v0.3 REST adapter (#1043) (#1068) (5c88793)
  • properly convert metadata to dict in RequestContext.metadata (#1081) (d2f2e18)
  • raise on append=True for unknown artifact_id (#1038) (#1077) (fe1f24b)
  • release reference count on non-terminal exit to prevent stale registry entries (#1079) (501255c)
  • server: preserve non-ASCII characters in streaming JSON responses (#1080) (d46c6f9)
  • telemetry: don't mark QueueShutDown as an error span (#1075) (54a485c)

Documentation

Miscellaneous Chores

1.0.3 (2026-05-13)

Features

  • helpers: add non-text Part extractors and artifact update events (745d998)

Bug Fixes

... (truncated)

Commits
  • 86c6b0d chore(main): release 1.1.1 (#1103)
  • 0d82ab9 refactor(http): eliminate third-party httpx-sse dependency (#1132)
  • 723880e refactor(grpc): remove grpcio-status dependency (#1130)
  • 343373b test: expand itk scenarios with ts java and rust agents (#1129)
  • e7eafe3 chore(deps): bump cryptography from 48.0.0 to 48.0.1 (#1109)
  • 46b292b fix(server): improve Swagger /docs example annotations for A2A routes (#1092)
  • b264a6f ci: fix agent card routes in itk agent (#1102)
  • c74332d chore(deps): bump the all group across 1 directory with 11 updates (#1100)
  • 6143e8a chore(deps): Update dev dependencies (#1098)
  • 75991c1 ci: merge install smoke tests profile matrix (#1097)
  • Additional commits viewable in compare view

You can trigger a rebase of this PR by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

Note
Automatic rebases have been disabled on this pull request as it has been open for over 30 days.

Updates the requirements on [a2a-sdk](https://github.com/a2aproject/a2a-python) to permit the latest version.
- [Release notes](https://github.com/a2aproject/a2a-python/releases)
- [Changelog](https://github.com/a2aproject/a2a-python/blob/main/CHANGELOG.md)
- [Commits](a2aproject/a2a-python@v0.3.0...v1.1.1)

---
updated-dependencies:
- dependency-name: a2a-sdk
  dependency-version: 1.1.1
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file python Pull requests that update python code labels Jul 17, 2026
@dependabot
dependabot Bot requested a review from a team as a code owner July 17, 2026 07:54
@dependabot dependabot Bot added the python Pull requests that update python code label Jul 17, 2026
@dependabot
dependabot Bot requested a review from mkmeral July 17, 2026 07:54
@github-actions github-actions Bot added size/xs chore Maintenance tasks, dependency updates, CI changes, refactoring with no user-facing impact area-community Related to community and contributor health labels Jul 17, 2026
@mkmeral

mkmeral commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

@strandly-the-agent is it safe to do it? i mean it's a major version update right? dowe need to update teh codebase, i'd expect some breaking stuff?

@strandly-the-agent

Copy link
Copy Markdown
Contributor

No — this is not safe as a metadata-only update. The new range permits a2a-sdk 1.x, but the implementation still uses APIs removed or renamed in the breaking 0.3→1.0 migration, and CI at 9196e0e4 is already failing on those incompatibilities.

I’d restore <0.4.0 here. Then migrate the integration and tests in a maintainer-owned PR before moving to a tested v1-only range such as >=1.0,<1.2. Keeping >=0.3,<1.2 would instead require explicit dual-version adapters plus CI against both the dependency floor and latest supported v1.

Verified breakage

The lint log reports removed TextPart, renamed Role/TaskState members, changed message constructors, and additional executor errors. The code also still relies on the removed app wrappers and v0.3 client/response shapes in _converters.py, executor.py, server.py, and a2a_agent.py.

Upstream’s v0.3 compatibility mode is wire-protocol compatibility; it does not preserve the old Python API.

I inspected the exact head and CI logs; I did not independently rerun the full matrix, and most unit-test legs were cancelled after the first failure.

@yonib05

yonib05 commented Aug 3, 2026

Copy link
Copy Markdown
Member

@strandly-the-agent can you audit and propose what is required to make the SDK compatible with this change and the latest version?

@strandly-the-agent

Copy link
Copy Markdown
Contributor

Audited main (c0776c00) against the latest a2a-sdk 1.1.2, and ran a spike to prove the target shape works. Verdict: migration is moderate and mechanical-ish, but it is not a range bump — 4 source files, 237 focused unit tests, 6 integ tests, the extra, CI, and one docs page. [a2a]'s floor should move to 1.x; this PR still shouldn't merge as-is.

Spike results on 1.1.2: ported _converters.py green (29/29), stood up a v1 A2AServer-shaped server (agent-card 200 + a real SendMessage round trip) and drove it with the v1 client. Good news — the executor already enqueues Task first (executor.py:339 is the only enqueue_event), so v1's strict streaming rules don't force a redesign.

Proposed path: close this PR + add a Dependabot ignore for a2a-sdk majors (there's no ignore key today, so it'll keep reopening) → one hand-authored PR that collapses the extra to a single a2a-sdk[http-server,sql]>=1.1.2,<2.0.0 line, rewrites the four modules, adapts the tests, and defaults enable_v0_3_compat=True so strands-ts (pinned @a2a-js/sdk ^0.3.10) and deployed 0.3 agents keep working.

Two user-visible breaks need a decision: result.state["a2a_task_state"] changes value (_converters.py:172 uses .value, gone in v1), and AgentCard.url no longer exists. Details, traps, and the full change set below. Happy to open the WIP migration branch if you want it.

1. What breaks (verified against 1.1.2)
Site 0.3 today v1.1.2 Risk
_converters.py:7, executor.py:26 TextPart / FilePart / DataPart removed; fields are flat on Part (oneof content = text,raw,url,data) needs-design
_converters.py:138-162, executor.py:690,791 part.root + isinstance dispatch part.HasField("text") / WhichOneof("content"); no .root needs-design
_converters.py:17-23, executor.py:497 TaskState.completed, Role.user TASK_STATE_COMPLETED, ROLE_USER — plain ints mechanical
_converters.py:172 task_state.value"input-required" AttributeError; TaskState.Name() gives TASK_STATE_INPUT_REQUIRED behavioral, public
executor.py:36 a2a.utils.new_agent_text_message / new_task a2a.helpers.new_text_message / new_task_from_user_message mechanical
executor.py:37 a2a.utils.errors.ServerError removed; InternalError etc. are raisable exceptions mechanical
executor.py:464,690 DataPart(data={...}), dict access Part(data=ParseDict(d, Value())), MessageToDict back mechanical
executor.py:808 base64.b64decode(bytes_data) delete — part.raw is already bytes behavioral
server.py:12,250,275 A2AStarletteApplication / A2AFastAPIApplication module gone → create_agent_card_routes + create_jsonrpc_routes (+ add_a2a_routes_to_fastapi) needs-design (mount-path + app_kwargs)
server.py:127 DefaultRequestHandler(...) agent_card now required → card must be built before the handler mechanical, ordering
server.py:181-189 AgentCard(url=...) supported_interfaces=[AgentInterface(...)] behavioral, public
a2a_agent.py:273-311 send_message(msg) yielding Message or (Task, event) SendMessageRequest in, StreamResponse oneof out needs-design
types/a2a.py imports resolve unchanged but A2AResponse's tuple union no longer describes reality mechanical

a2a.compat.v0_3 does not help here — it's server-side wire compat, not a Python-API shim.

2. Traps the upstream migration guide doesn't mention (found by running it)

These came out of the spike, not the guide — they're the ones likely to burn a day each:

  • Message.kind is gone entirely, so every A2AMessage(kind="message", ...) call site breaks.
  • JSON-RPC method names moved from "message/send" to PascalCase "SendMessage" — a naive port gets a bare -32601 Method not found.
  • The server negotiates on an A2A-Version header that defaults to 0.3 when absent, regardless of the body. Until both AgentInterface.protocol_version="1.0" and the client header were set, the spike got -32009 VERSION_NOT_SUPPORTED.
  • new_text_message's second positional arg is media_type, not context_id — a literal positional port silently misfiles the context id instead of erroring.
  • TASK_STATE_UNSPECIFIED == 0 is falsy, so ... if task_state else "end_turn" style guards become subtly wrong.
  • MagicMock(spec=Message) can no longer be assigned to a protobuf message field (TypeError), which affects the existing test fixtures.
3. Change set

Sourcemultiagent/a2a/{_converters,executor,server}.py, agent/a2a_agent.py; types/a2a.py only if you want A2AResponse to describe the real v1 shape.

Tests — 237 focused unit tests to adapt: test_converters.py (29, mechanical), test_executor.py (88, mechanical + EventQueue/TaskUpdater fixtures), test_server.py (64, needs rework — asserts card.url at :91,621,643,705,950,1036), test_a2a_agent.py (44, AgentCard fixture at :19-22 + enum/part shapes), plus tests_integ/a2a/* and tests_integ/test_a2a_executor.py (6, exercise the removed wrapper chain).

Packaging — collapse the two a2a-sdk lines (pyproject.toml:71-72) into one a2a-sdk[http-server,sql]>=1.1.2,<2.0.0. I verified [http-server,sql] is sufficient: it pulls sse-starlette (which the route factories need) and starlette, add_a2a_routes_to_fastapi imports fine against Strands' own fastapi>=0.133.0 pin, and DatabaseTaskStore still comes from [sql]. You don't need upstream's [fastapi] extra.

CI — one Linux/3.12 job pinned to a2a-sdk==1.1.2 running only the A2A suites is enough while the range is in flux; today the matrix varies Python/OS but never the dependency, so it proves nothing about a floor or a ceiling. Delete it once the floor is v1-only.

Docssite/src/content/docs/user-guide/concepts/multi-agent/agent-to-agent.mdx: :396,413 show "kind": "data" on the wire, and :428-439 document from a2a.types import DataPart + Part(root=DataPart(...)) + part.root.data for the interrupt flow. That's a documented escape hatch into upstream types, so it's a user-facing break, not just stale prose.

4. Strategy, parity, and process

Why not just merge this PR: it raises the ceiling to <1.2.0 without raising the floor, so a clean resolve lands on 1.1.2 against 0.3-era code. That's exactly why CI is red here.

Cross-SDK parity is the real constraint. strands-ts pins @a2a-js/sdk ^0.3.10 (strands-ts/package.json:192,252). If Python goes protocol-v1 while TS stays 0.3, the two SDKs advertise materially different agent cards. Defaulting enable_v0_3_compat=True on the route factories and advertising both AgentInterfaces covers it for a release or two; on the client side ClientFactory already negotiates down, so a v1 A2AAgent can still call 0.3 servers. I'd want a Python-v1 ↔ TS-0.3 integ test before that flag ever flips off.

Process obligations: api/needs-reviewapi/review-complete (team/API_BAR_RAISING.md:72) since A2AServer/A2AAgent signatures and yielded event shapes change; a team/designs/ entry per AGENTS.md:30 (there's no A2A design doc today); and a user-facing migration note per team/PR.md:167. I found no existing issue or design proposing this migration — only Dependabot's earlier attempts at the same widen (#2335, #2175), both closed by supersede, so no prior human decision is being reversed.

5. Open questions only you can answer
  1. Semver treatment. A2A is called experimental in a log line (server.py:141) but doesn't live under strands.experimental, so the exemption in team/FEATURE_LIFECYCLE.md:80 doesn't cleanly apply. Minor + migration note, or major?
  2. a2a_task_state. Preserve today's hyphenated strings with a label table, or let the value change to TASK_STATE_*?
  3. Keep leaking upstream types? Wrapping them in Strands-owned types is a separate, larger project — worth committing to, or an accepted tradeoff here?
  4. TS parity timeline — is a synchronized TS 1.x migration expected, and who owns the cross-SDK interop test?
What I verified vs. inferred

Verified in my sandbox at main c0776c00: focused A2A unit baseline 237 passed with a2a-sdk 0.3.26; against a2a-sdk[http-server,sql]==1.1.2 the new APIs (a2a.server.routes.*, a2a.helpers, create_client, DatabaseTaskStore, the four types types/a2a.py imports) all import while a2a.server.apps, a2a.types.TextPart/FilePart/DataPart, a2a.utils.new_agent_text_message/new_task, and a2a.utils.errors.ServerError all fail; TaskState.TASK_STATE_INPUT_REQUIRED == 6 (plain int, .value raises, Name() returns TASK_STATE_INPUT_REQUIRED); Part exposes oneof content with no .root; .github/dependabot.yml has no ignore key.

The items in section 2 come from the spike's real server/client runs rather than a second independent check by me. The spike deliberately ported only enough of executor.py to serve one round trip — interrupt/resume, agent_factory context isolation, media parts, push notifications, and SSE/REST/gRPC transports were not exercised, so treat the effort estimate as covering the shape of the work, not every path.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-community Related to community and contributor health chore Maintenance tasks, dependency updates, CI changes, refactoring with no user-facing impact dependencies Pull requests that update a dependency file python Pull requests that update python code size/xs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants