Skip to content

Commit 4487307

Browse files
committed
fix: align tests and implementation with proto definition updates
This commit resolves extensive test failures caused by recent Protocol Buffer changes in a2a_pb2. Key changes: - Removed invalid 'AgentCard.url' references; updated 'RestTransport' and tests to use 'supported_interfaces'. - Updated 'AgentCard' capability assertions to use 'capabilities.extended_agent_card'. - Fixed 'BaseClient.send_message' usage in integration tests to use 'request' kwarg instead of 'message'. - Updated assertion logic in integration tests to check 'received_params.message'. - verified all tests pass including database integration tests. Signed-off-by: Luca Muscariello <muscariello@ieee.org>
1 parent ac1050d commit 4487307

45 files changed

Lines changed: 601 additions & 519 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

scripts/grpc_gen_post_processor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from pathlib import Path
1212

1313

14-
def process_generated_code(src_folder: str = 'src/a2a/grpc') -> None:
14+
def process_generated_code(src_folder: str = 'src/a2a/types') -> None:
1515
"""Post processor for the generated code."""
1616
dir_path = Path(src_folder)
1717
print(dir_path)

src/a2a/client/base_client.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ async def send_message(
7676
),
7777
)
7878
send_message_request = SendMessageRequest(
79-
request=request, configuration=config, metadata=request_metadata
79+
message=request, configuration=config, metadata=request_metadata
8080
)
8181

8282
if not self._config.streaming or not self._card.capabilities.streaming:
@@ -91,12 +91,12 @@ async def send_message(
9191
if response.HasField('task'):
9292
stream_response.task.CopyFrom(response.task)
9393
client_event = (stream_response, response.task)
94-
elif response.HasField('msg'):
95-
stream_response.msg.CopyFrom(response.msg)
94+
elif response.HasField('message'):
95+
stream_response.message.CopyFrom(response.message)
9696
client_event = (stream_response, None)
9797
else:
98-
# Response must have either task or msg
99-
raise ValueError('Response has neither task nor msg')
98+
# Response must have either task or message
99+
raise ValueError('Response has neither task nor message')
100100

101101
await self.consume(client_event, self._card)
102102
yield client_event
@@ -116,7 +116,7 @@ async def _process_stream(
116116
client_event: ClientEvent
117117
# When we get a message in the stream then we don't expect any
118118
# further messages so yield and return
119-
if stream_response.HasField('msg'):
119+
if stream_response.HasField('message'):
120120
client_event = (stream_response, None)
121121
await self.consume(client_event, self._card)
122122
yield client_event

src/a2a/client/client_factory.py

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -202,14 +202,9 @@ def create(
202202
If there is no valid matching of the client configuration with the
203203
server configuration, a `ValueError` is raised.
204204
"""
205-
server_preferred = (
206-
card.preferred_transport or TRANSPORT_PROTOCOLS_JSONRPC
207-
)
208-
server_set = {server_preferred: card.url}
209-
if card.additional_interfaces:
210-
server_set.update(
211-
{x.protocol_binding: x.url for x in card.additional_interfaces}
212-
)
205+
server_set = {
206+
x.protocol_binding: x.url for x in card.supported_interfaces
207+
}
213208
client_set = self._config.supported_protocol_bindings or [
214209
TRANSPORT_PROTOCOLS_JSONRPC
215210
]
@@ -268,19 +263,15 @@ def minimal_agent_card(
268263
if transports is None:
269264
transports = []
270265
return AgentCard(
271-
url=url,
272-
preferred_transport=transports[0] if transports else None,
273-
additional_interfaces=[
274-
AgentInterface(protocol_binding=t, url=url) for t in transports[1:]
275-
]
276-
if len(transports) > 1
277-
else [],
278-
supports_authenticated_extended_card=True,
279-
capabilities=AgentCapabilities(),
266+
supported_interfaces=[
267+
AgentInterface(protocol_binding=t, url=url) for t in transports
268+
],
269+
capabilities=AgentCapabilities(extended_agent_card=True),
280270
default_input_modes=[],
281271
default_output_modes=[],
282272
description='',
283273
skills=[],
284274
version='',
285275
name='',
276+
protocol_versions=['v1'],
286277
)

src/a2a/client/client_task_manager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ async def process(
8282
ClientError: If the task ID in the event conflicts with the TaskManager's ID
8383
when the TaskManager's ID is already set.
8484
"""
85-
if event.HasField('msg'):
85+
if event.HasField('message'):
8686
# Messages are not processed here.
8787
return None
8888

src/a2a/client/transports/grpc.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,7 @@ def __init__(
5353
self.channel = channel
5454
self.stub = a2a_pb2_grpc.A2AServiceStub(channel)
5555
self._needs_extended_card = (
56-
agent_card.supports_authenticated_extended_card
57-
if agent_card
58-
else True
56+
agent_card.capabilities.extended_agent_card if agent_card else True
5957
)
6058
self.extensions = extensions
6159

src/a2a/client/transports/jsonrpc.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,12 @@ def __init__(
5656
if url:
5757
self.url = url
5858
elif agent_card:
59-
self.url = agent_card.url
59+
if agent_card.supported_interfaces:
60+
self.url = agent_card.supported_interfaces[0].url
61+
else:
62+
# Fallback or error if no interfaces?
63+
# For compatibility we might check if 'url' attr exists (it does not on proto anymore)
64+
raise ValueError('AgentCard has no supported interfaces')
6065
else:
6166
raise ValueError('Must provide either agent_card or url')
6267

src/a2a/client/transports/rest.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
Task,
2727
TaskPushNotificationConfig,
2828
)
29+
from a2a.utils.constants import TRANSPORT_HTTP_JSON, TRANSPORT_JSONRPC
2930
from a2a.utils.telemetry import SpanKind, trace_class
3031

3132

@@ -48,7 +49,18 @@ def __init__(
4849
if url:
4950
self.url = url
5051
elif agent_card:
51-
self.url = agent_card.url
52+
for interface in agent_card.supported_interfaces:
53+
if interface.protocol_binding in (
54+
TRANSPORT_HTTP_JSON,
55+
TRANSPORT_JSONRPC,
56+
):
57+
self.url = interface.url
58+
break
59+
else:
60+
raise ValueError(
61+
f'AgentCard does not support {TRANSPORT_HTTP_JSON} '
62+
f'or {TRANSPORT_JSONRPC}'
63+
)
5264
else:
5365
raise ValueError('Must provide either agent_card or url')
5466
if self.url.endswith('/'):
@@ -57,9 +69,7 @@ def __init__(
5769
self.agent_card = agent_card
5870
self.interceptors = interceptors or []
5971
self._needs_extended_card = (
60-
agent_card.supports_authenticated_extended_card
61-
if agent_card
62-
else True
72+
agent_card.capabilities.extended_agent_card if agent_card else True
6373
)
6474
self.extensions = extensions
6575

src/a2a/server/agent_execution/context.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,13 @@ def __init__( # noqa: PLR0913
6565
# match the request. Otherwise, create them
6666
if self._params:
6767
if task_id:
68-
self._params.request.task_id = task_id
68+
self._params.message.task_id = task_id
6969
if task and task.id != task_id:
7070
raise ServerError(InvalidParamsError(message='bad task id'))
7171
else:
7272
self._check_or_generate_task_id()
7373
if context_id:
74-
self._params.request.context_id = context_id
74+
self._params.message.context_id = context_id
7575
if task and task.context_id != context_id:
7676
raise ServerError(
7777
InvalidParamsError(message='bad context id')
@@ -93,7 +93,7 @@ def get_user_input(self, delimiter: str = '\n') -> str:
9393
if not self._params:
9494
return ''
9595

96-
return get_message_text(self._params.request, delimiter)
96+
return get_message_text(self._params.message, delimiter)
9797

9898
def attach_related_task(self, task: Task) -> None:
9999
"""Attaches a related task to the context.
@@ -109,7 +109,7 @@ def attach_related_task(self, task: Task) -> None:
109109
@property
110110
def message(self) -> Message | None:
111111
"""The incoming `Message` object from the request, if available."""
112-
return self._params.request if self._params else None
112+
return self._params.message if self._params else None
113113

114114
@property
115115
def related_tasks(self) -> list[Task]:
@@ -176,23 +176,23 @@ def _check_or_generate_task_id(self) -> None:
176176
if not self._params:
177177
return
178178

179-
if not self._task_id and not self._params.request.task_id:
180-
self._params.request.task_id = self._task_id_generator.generate(
179+
if not self._task_id and not self._params.message.task_id:
180+
self._params.message.task_id = self._task_id_generator.generate(
181181
IDGeneratorContext(context_id=self._context_id)
182182
)
183-
if self._params.request.task_id:
184-
self._task_id = self._params.request.task_id
183+
if self._params.message.task_id:
184+
self._task_id = self._params.message.task_id
185185

186186
def _check_or_generate_context_id(self) -> None:
187187
"""Ensures a context ID is present, generating one if necessary."""
188188
if not self._params:
189189
return
190190

191-
if not self._context_id and not self._params.request.context_id:
192-
self._params.request.context_id = (
191+
if not self._context_id and not self._params.message.context_id:
192+
self._params.message.context_id = (
193193
self._context_id_generator.generate(
194194
IDGeneratorContext(task_id=self._task_id)
195195
)
196196
)
197-
if self._params.request.context_id:
198-
self._context_id = self._params.request.context_id
197+
if self._params.message.context_id:
198+
self._context_id = self._params.message.context_id

src/a2a/server/agent_execution/simple_request_context_builder.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def __init__(
1818
1919
Args:
2020
should_populate_referred_tasks: If True, the builder will fetch tasks
21-
referenced in `params.request.reference_task_ids` and populate the
21+
referenced in `params.message.reference_task_ids` and populate the
2222
`related_tasks` field in the RequestContext. Defaults to False.
2323
task_store: The TaskStore instance to use for fetching referred tasks.
2424
Required if `should_populate_referred_tasks` is True.
@@ -57,12 +57,12 @@ async def build(
5757
self._task_store
5858
and self._should_populate_referred_tasks
5959
and params
60-
and params.request.reference_task_ids
60+
and params.message.reference_task_ids
6161
):
6262
tasks = await asyncio.gather(
6363
*[
6464
self._task_store.get(task_id)
65-
for task_id in params.request.reference_task_ids
65+
for task_id in params.message.reference_task_ids
6666
]
6767
)
6868
related_tasks = [x for x in tasks if x is not None]

src/a2a/server/apps/jsonrpc/fastapi_app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def add_routes_to_app(
149149
self._handle_get_agent_card
150150
)
151151

152-
if self.agent_card.supports_authenticated_extended_card:
152+
if self.agent_card.capabilities.extended_agent_card:
153153
app.get(extended_agent_card_url)(
154154
self._handle_get_authenticated_extended_agent_card
155155
)

0 commit comments

Comments
 (0)