Skip to content

Commit 5c88793

Browse files
matanwekssokoliva
andauthored
fix(compat): remove ListTasks from v0.3 REST adapter (#1043) (#1068)
## Summary Fixes #1043. The A2A v0.3 spec does not define a `ListTasks` method, but `REST03Adapter` advertised `GET /v1/tasks` while `REST03Handler.list_tasks` raised `NotImplementedError` — exposing a route guaranteed to fail at runtime. This PR aligns the v0.3 REST adapter with the rest of the v0.3 compat surface: - **Removes** `('/v1/tasks', 'GET')` from `REST03Adapter.routes()`. - **Removes** the dead `REST03Handler.list_tasks` stub. - **Replaces** the stale `pytest.raises(NotImplementedError)` test with a regression test asserting the route is no longer registered in `REST03Adapter.routes()`. This matches the design already present in the three sibling v0.3 transports — `jsonrpc_transport.py`, `grpc_transport.py`, and `rest_transport.py` — all of which explicitly raise `NotImplementedError('ListTasks is not supported in A2A v0.3 ...')`. (Confirmed with @ishymko in the issue thread to go with Option 2 from the report.) ## Known follow-up (out of scope) With the route gone, `GET /v1/tasks` now falls through to the tenant catch-all (`Mount('/{tenant}', ...)` in `rest_routes.py`). A request with `A2A-Version: 0.3` will get a 400 version-mismatch error instead of a clean 404/405. This is a pre-existing routing quirk that affects any `/v1/<unknown>` path, not just `/v1/tasks` — worth a separate issue to tighten the tenant path converter or register an explicit 405 for reserved prefixes when v0.3 compat is enabled. Happy to follow up. ## Test plan - [x] `uv run pytest tests/compat/v0_3/` — 249 passed - [x] `./scripts/lint.sh` — ruff clean; `ty` reports only pre-existing errors in untouched lines (generated protobuf stubs) - [x] Manual trace: `GET /v1/tasks` no longer routes to `REST03Handler.list_tasks`; the route is absent from `REST03Adapter.routes()` Co-authored-by: Iva Sokolaj <102302011+sokoliva@users.noreply.github.com>
1 parent 1122d4e commit 5c88793

4 files changed

Lines changed: 13 additions & 18 deletions

File tree

src/a2a/compat/v0_3/rest_adapter.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,10 @@ def routes(self) -> dict[tuple[str, str], Callable[[Request], Any]]:
142142
): functools.partial(
143143
self._handle_request, self.handler.list_push_notifications
144144
),
145-
('/v1/tasks', 'GET'): functools.partial(
146-
self._handle_request, self.handler.list_tasks
147-
),
145+
# ListTasks is intentionally absent: not in the A2A v0.3 spec (see
146+
# issue #1043). Sibling v0.3 transports (jsonrpc_transport,
147+
# grpc_transport, rest_transport) also reject list_tasks with
148+
# NotImplementedError — do not add a route here.
148149
('/v1/card', 'GET'): functools.partial(
149150
self._handle_request, self.handler.on_get_extended_agent_card
150151
),

src/a2a/compat/v0_3/rest_handler.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -290,15 +290,6 @@ async def list_push_notifications(
290290

291291
return MessageToDict(pb2_v03_resp)
292292

293-
@validate_version(constants.PROTOCOL_VERSION_0_3)
294-
async def list_tasks(
295-
self,
296-
request: Request,
297-
context: ServerCallContext,
298-
) -> dict[str, Any]:
299-
"""Handles the 'tasks/list' REST method."""
300-
raise NotImplementedError('list tasks not implemented')
301-
302293
@validate_version(constants.PROTOCOL_VERSION_0_3)
303294
async def on_get_extended_agent_card(
304295
self,

tests/compat/v0_3/test_rest_handler.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -357,12 +357,6 @@ async def test_list_push_notifications(
357357
assert called_req.params.id == 'task-1'
358358

359359

360-
@pytest.mark.anyio
361-
async def test_list_tasks(rest_handler, mock_request, mock_context):
362-
with pytest.raises(NotImplementedError):
363-
await rest_handler.list_tasks(mock_request, mock_context)
364-
365-
366360
# Add our new translation method test
367361
@pytest.mark.anyio
368362
async def test_on_get_extended_agent_card_success(

tests/compat/v0_3/test_rest_routes_compat.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import pytest
66

77
from a2a.compat.v0_3 import a2a_v0_3_pb2
8+
from a2a.compat.v0_3.rest_adapter import REST03Adapter
89
from a2a.server.request_handlers.request_handler import RequestHandler
910
from a2a.server.routes import create_agent_card_routes
1011
from a2a.server.routes.rest_routes import create_rest_routes
@@ -166,6 +167,14 @@ async def test_get_task_v03(
166167
assert expected_response == actual_response
167168

168169

170+
@pytest.mark.anyio
171+
async def test_list_tasks_not_in_v03_adapter_routes(
172+
request_handler: RequestHandler,
173+
) -> None:
174+
adapter = REST03Adapter(http_handler=request_handler)
175+
assert ('/v1/tasks', 'GET') not in adapter.routes()
176+
177+
169178
@pytest.mark.anyio
170179
async def test_cancel_task_v03(
171180
client: AsyncClient, request_handler: MagicMock

0 commit comments

Comments
 (0)