Skip to content

Commit b4b7e12

Browse files
committed
Merge branch 'main' of https://github.com/NasserAAA/a2a-python into 1.0-dev
2 parents 044408f + 86c6759 commit b4b7e12

33 files changed

+1804
-70
lines changed

.github/actions/spelling/allow.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,14 @@ initdb
4747
inmemory
4848
INR
4949
isready
50+
jku
5051
JPY
5152
JSONRPCt
53+
jwk
54+
jwks
5255
JWS
56+
jws
57+
kid
5358
kwarg
5459
langgraph
5560
lifecycles

.github/workflows/stale.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ name: Mark stale issues and pull requests
77

88
on:
99
schedule:
10-
# Scheduled to run at 10.30PM UTC everyday (1530PDT/1430PST)
10+
# Scheduled to run at 10.30PM UTC every day (1530PDT/1430PST)
1111
- cron: "30 22 * * *"
1212
workflow_dispatch:
1313

CHANGELOG.md

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,45 @@
11
# Changelog
22

3+
## [0.3.22](https://github.com/a2aproject/a2a-python/compare/v0.3.21...v0.3.22) (2025-12-16)
4+
5+
6+
### Features
7+
8+
* Add custom ID generators to SimpleRequestContextBuilder ([#594](https://github.com/a2aproject/a2a-python/issues/594)) ([04bcafc](https://github.com/a2aproject/a2a-python/commit/04bcafc737cf426d9975c76e346335ff992363e2))
9+
10+
11+
### Code Refactoring
12+
13+
* Move agent card signature verification into `A2ACardResolver` ([6fa6a6c](https://github.com/a2aproject/a2a-python/commit/6fa6a6cf3875bdf7bfc51fb1a541a3f3e8381dc0))
14+
15+
## [0.3.21](https://github.com/a2aproject/a2a-python/compare/v0.3.20...v0.3.21) (2025-12-12)
16+
17+
18+
### Documentation
19+
20+
* Fixing typos ([#586](https://github.com/a2aproject/a2a-python/issues/586)) ([5fea21f](https://github.com/a2aproject/a2a-python/commit/5fea21fb34ecea55e588eb10139b5d47020a76cb))
21+
22+
## [0.3.20](https://github.com/a2aproject/a2a-python/compare/v0.3.19...v0.3.20) (2025-12-03)
23+
24+
25+
### Bug Fixes
26+
27+
* Improve streaming errors handling ([#576](https://github.com/a2aproject/a2a-python/issues/576)) ([7ea7475](https://github.com/a2aproject/a2a-python/commit/7ea7475091df2ee40d3035ef1bc34ee2f86524ee))
28+
29+
## [0.3.19](https://github.com/a2aproject/a2a-python/compare/v0.3.18...v0.3.19) (2025-11-25)
30+
31+
32+
### Bug Fixes
33+
34+
* **jsonrpc, rest:** `extensions` support in `get_card` methods in `json-rpc` and `rest` transports ([#564](https://github.com/a2aproject/a2a-python/issues/564)) ([847f18e](https://github.com/a2aproject/a2a-python/commit/847f18eff59985f447c39a8e5efde87818b68d15))
35+
36+
## [0.3.18](https://github.com/a2aproject/a2a-python/compare/v0.3.17...v0.3.18) (2025-11-24)
37+
38+
39+
### Bug Fixes
40+
41+
* return updated `agent_card` in `JsonRpcTransport.get_card()` ([#552](https://github.com/a2aproject/a2a-python/issues/552)) ([0ce239e](https://github.com/a2aproject/a2a-python/commit/0ce239e98f67ccbf154f2edcdbcee43f3b080ead))
42+
343
## [0.3.17](https://github.com/a2aproject/a2a-python/compare/v0.3.16...v0.3.17) (2025-11-24)
444

545

@@ -94,7 +134,7 @@
94134
### Bug Fixes
95135

96136
* apply `history_length` for `message/send` requests ([#498](https://github.com/a2aproject/a2a-python/issues/498)) ([a49f94e](https://github.com/a2aproject/a2a-python/commit/a49f94ef23d81b8375e409b1c1e51afaf1da1956))
97-
* **client:** `A2ACardResolver.get_agent_card` will auto-populate with `agent_card_path` when `relative_card_path` is empty ([#508](https://github.com/a2aproject/a2a-python/issues/508)) ([ba24ead](https://github.com/a2aproject/a2a-python/commit/ba24eadb5b6fcd056a008e4cbcef03b3f72a37c3))
137+
* **client:** `A2ACardResolver.get_agent_card` will autopopulate with `agent_card_path` when `relative_card_path` is empty ([#508](https://github.com/a2aproject/a2a-python/issues/508)) ([ba24ead](https://github.com/a2aproject/a2a-python/commit/ba24eadb5b6fcd056a008e4cbcef03b3f72a37c3))
98138

99139

100140
### Documentation
@@ -431,8 +471,8 @@
431471
* Event consumer should stop on input_required ([#167](https://github.com/a2aproject/a2a-python/issues/167)) ([51c2d8a](https://github.com/a2aproject/a2a-python/commit/51c2d8addf9e89a86a6834e16deb9f4ac0e05cc3))
432472
* Fix Release Version ([#161](https://github.com/a2aproject/a2a-python/issues/161)) ([011d632](https://github.com/a2aproject/a2a-python/commit/011d632b27b201193813ce24cf25e28d1335d18e))
433473
* generate StrEnum types for enums ([#134](https://github.com/a2aproject/a2a-python/issues/134)) ([0c49dab](https://github.com/a2aproject/a2a-python/commit/0c49dabcdb9d62de49fda53d7ce5c691b8c1591c))
434-
* library should released as 0.2.6 ([d8187e8](https://github.com/a2aproject/a2a-python/commit/d8187e812d6ac01caedf61d4edaca522e583d7da))
435-
* remove error types from enqueable events ([#138](https://github.com/a2aproject/a2a-python/issues/138)) ([511992f](https://github.com/a2aproject/a2a-python/commit/511992fe585bd15e956921daeab4046dc4a50a0a))
474+
* library should be released as 0.2.6 ([d8187e8](https://github.com/a2aproject/a2a-python/commit/d8187e812d6ac01caedf61d4edaca522e583d7da))
475+
* remove error types from enqueueable events ([#138](https://github.com/a2aproject/a2a-python/issues/138)) ([511992f](https://github.com/a2aproject/a2a-python/commit/511992fe585bd15e956921daeab4046dc4a50a0a))
436476
* **stream:** don't block event loop in EventQueue ([#151](https://github.com/a2aproject/a2a-python/issues/151)) ([efd9080](https://github.com/a2aproject/a2a-python/commit/efd9080b917c51d6e945572fd123b07f20974a64))
437477
* **task_updater:** fix potential duplicate artifact_id from default v… ([#156](https://github.com/a2aproject/a2a-python/issues/156)) ([1f0a769](https://github.com/a2aproject/a2a-python/commit/1f0a769c1027797b2f252e4c894352f9f78257ca))
438478

Gemini.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
- uv as package manager
55

66
## How to run all tests
7-
1. If dependencies are not installed install them using following command
7+
1. If dependencies are not installed, install them using the following command
88
```
99
uv sync --all-extras
1010
```

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ grpc = ["grpcio>=1.60", "grpcio-tools>=1.60", "grpcio_reflection>=1.7.0"]
3535
telemetry = ["opentelemetry-api>=1.33.0", "opentelemetry-sdk>=1.33.0"]
3636
postgresql = ["sqlalchemy[asyncio,postgresql-asyncpg]>=2.0.0"]
3737
mysql = ["sqlalchemy[asyncio,aiomysql]>=2.0.0"]
38+
signing = ["PyJWT>=2.0.0"]
3839
sqlite = ["sqlalchemy[asyncio,aiosqlite]>=2.0.0"]
3940

4041
sql = ["a2a-sdk[postgresql,mysql,sqlite]"]
@@ -45,6 +46,7 @@ all = [
4546
"a2a-sdk[encryption]",
4647
"a2a-sdk[grpc]",
4748
"a2a-sdk[telemetry]",
49+
"a2a-sdk[signing]",
4850
]
4951

5052
[project.urls]
@@ -86,6 +88,7 @@ style = "pep440"
8688
dev = [
8789
"datamodel-code-generator>=0.30.0",
8890
"mypy>=1.15.0",
91+
"PyJWT>=2.0.0",
8992
"pytest>=8.3.5",
9093
"pytest-asyncio>=0.26.0",
9194
"pytest-cov>=6.1.1",

src/a2a/client/base_client.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from collections.abc import AsyncIterator
1+
from collections.abc import AsyncIterator, Callable
22
from typing import Any
33

44
from a2a.client.client import (
@@ -272,6 +272,7 @@ async def get_card(
272272
*,
273273
context: ClientCallContext | None = None,
274274
extensions: list[str] | None = None,
275+
signature_verifier: Callable[[AgentCard], None] | None = None,
275276
) -> AgentCard:
276277
"""Retrieves the agent's card.
277278
@@ -281,12 +282,15 @@ async def get_card(
281282
Args:
282283
context: The client call context.
283284
extensions: List of extensions to be activated.
285+
signature_verifier: A callable used to verify the agent card's signatures.
284286
285287
Returns:
286288
The `AgentCard` for the agent.
287289
"""
288290
card = await self._transport.get_card(
289-
context=context, extensions=extensions
291+
context=context,
292+
extensions=extensions,
293+
signature_verifier=signature_verifier,
290294
)
291295
self._card = card
292296
return card

src/a2a/client/card_resolver.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
22
import logging
33

4+
from collections.abc import Callable
45
from typing import Any
56

67
import httpx
@@ -44,6 +45,7 @@ async def get_agent_card(
4445
self,
4546
relative_card_path: str | None = None,
4647
http_kwargs: dict[str, Any] | None = None,
48+
signature_verifier: Callable[[AgentCard], None] | None = None,
4749
) -> AgentCard:
4850
"""Fetches an agent card from a specified path relative to the base_url.
4951
@@ -56,6 +58,7 @@ async def get_agent_card(
5658
agent card path. Use `'/'` for an empty path.
5759
http_kwargs: Optional dictionary of keyword arguments to pass to the
5860
underlying httpx.get request.
61+
signature_verifier: A callable used to verify the agent card's signatures.
5962
6063
Returns:
6164
An `AgentCard` object representing the agent's capabilities.
@@ -86,6 +89,8 @@ async def get_agent_card(
8689
agent_card_data,
8790
)
8891
agent_card = AgentCard.model_validate(agent_card_data)
92+
if signature_verifier:
93+
signature_verifier(agent_card)
8994
except httpx.HTTPStatusError as e:
9095
raise A2AClientHTTPError(
9196
e.response.status_code,

src/a2a/client/client.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ async def get_card(
196196
*,
197197
context: ClientCallContext | None = None,
198198
extensions: list[str] | None = None,
199+
signature_verifier: Callable[[AgentCard], None] | None = None,
199200
) -> AgentCard:
200201
"""Retrieves the agent's card."""
201202

src/a2a/client/client_factory.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ async def connect( # noqa: PLR0913
116116
resolver_http_kwargs: dict[str, Any] | None = None,
117117
extra_transports: dict[str, TransportProducer] | None = None,
118118
extensions: list[str] | None = None,
119+
signature_verifier: Callable[[AgentCard], None] | None = None,
119120
) -> Client:
120121
"""Convenience method for constructing a client.
121122
@@ -146,6 +147,7 @@ async def connect( # noqa: PLR0913
146147
extra_transports: Additional transport protocols to enable when
147148
constructing the client.
148149
extensions: List of extensions to be activated.
150+
signature_verifier: A callable used to verify the agent card's signatures.
149151
150152
Returns:
151153
A `Client` object.
@@ -158,12 +160,14 @@ async def connect( # noqa: PLR0913
158160
card = await resolver.get_agent_card(
159161
relative_card_path=relative_card_path,
160162
http_kwargs=resolver_http_kwargs,
163+
signature_verifier=signature_verifier,
161164
)
162165
else:
163166
resolver = A2ACardResolver(client_config.httpx_client, agent)
164167
card = await resolver.get_agent_card(
165168
relative_card_path=relative_card_path,
166169
http_kwargs=resolver_http_kwargs,
170+
signature_verifier=signature_verifier,
167171
)
168172
else:
169173
card = agent
@@ -256,7 +260,7 @@ def minimal_agent_card(
256260
"""Generates a minimal card to simplify bootstrapping client creation.
257261
258262
This minimal card is not viable itself to interact with the remote agent.
259-
Instead this is a short hand way to take a known url and transport option
263+
Instead this is a shorthand way to take a known url and transport option
260264
and interact with the get card endpoint of the agent server to get the
261265
correct agent card. This pattern is necessary for gRPC based card access
262266
as typically these servers won't expose a well known path card.

src/a2a/client/transports/base.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from abc import ABC, abstractmethod
2-
from collections.abc import AsyncGenerator
2+
from collections.abc import AsyncGenerator, Callable
33

44
from a2a.client.middleware import ClientCallContext
55
from a2a.types import (
@@ -114,6 +114,7 @@ async def get_card(
114114
*,
115115
context: ClientCallContext | None = None,
116116
extensions: list[str] | None = None,
117+
signature_verifier: Callable[[AgentCard], None] | None = None,
117118
) -> AgentCard:
118119
"""Retrieves the AgentCard."""
119120

0 commit comments

Comments
 (0)