From 803c874e6bd90458051d489cd4ee44d391373a38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Ra=C4=8Dinsk=C3=BD?= Date: Wed, 20 Aug 2025 12:26:28 +0200 Subject: [PATCH 1/2] fix: old a2a url works --- src/google/adk/cli/fast_api.py | 13 +++----- tests/unittests/cli/test_fast_api.py | 48 ++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/google/adk/cli/fast_api.py b/src/google/adk/cli/fast_api.py index 7d93b54360..849ae7fcbe 100644 --- a/src/google/adk/cli/fast_api.py +++ b/src/google/adk/cli/fast_api.py @@ -23,6 +23,7 @@ from typing import Mapping from typing import Optional +from a2a.server.apps import A2AFastAPIApplication import click from fastapi import FastAPI from fastapi import UploadFile @@ -364,18 +365,12 @@ async def _get_a2a_runner_async() -> Runner: data = json.load(f) agent_card = AgentCard(**data) - a2a_app = A2AStarletteApplication( + a2a_app = A2AFastAPIApplication( agent_card=agent_card, http_handler=request_handler, - ) - - routes = a2a_app.routes( - rpc_url=f"/a2a/{app_name}", - agent_card_url=f"/a2a/{app_name}{AGENT_CARD_WELL_KNOWN_PATH}", - ) + ).build() - for new_route in routes: - app.router.routes.append(new_route) + app.mount(f"/a2a/{app_name}", a2a_app) logger.info("Successfully configured A2A agent: %s", app_name) diff --git a/tests/unittests/cli/test_fast_api.py b/tests/unittests/cli/test_fast_api.py index f1c9e9d6ef..ae657d420d 100755 --- a/tests/unittests/cli/test_fast_api.py +++ b/tests/unittests/cli/test_fast_api.py @@ -24,6 +24,8 @@ from unittest.mock import MagicMock from unittest.mock import patch +from a2a.utils import AGENT_CARD_WELL_KNOWN_PATH +from a2a.utils import PREV_AGENT_CARD_WELL_KNOWN_PATH from fastapi.testclient import TestClient from google.adk.agents.base_agent import BaseAgent from google.adk.agents.run_config import RunConfig @@ -502,11 +504,37 @@ def temp_agents_dir_with_a2a(): # Create agent.json file agent_card = { + "capabilities": { + "pushNotifications": True, + "streaming": True + }, + "defaultInputModes": [ + "text", + "text/plain" + ], + "defaultOutputModes": [ + "text", + "text/plain" + ], "name": "test_a2a_agent", "description": "Test A2A agent", "version": "1.0.0", "author": "test", - "capabilities": ["text"], + "protocolVersion": "0.2.6", + "skills": [ + { + "description": "Makes the tests pass", + "examples": [ + "Fix the tests." + ], + "id": "test_a2a_agent", + "name": "Test A2A agent", + "tags": [ + "testing" + ] + } + ], + "url": "", } with open(agent_dir / "agent.json", "w") as f: @@ -580,20 +608,12 @@ def test_app_with_a2a( patch( "a2a.server.request_handlers.DefaultRequestHandler" ) as mock_handler, - patch("a2a.server.apps.A2AStarletteApplication") as mock_a2a_app, ): # Configure mocks mock_task_store.return_value = MagicMock() mock_executor.return_value = MagicMock() mock_handler.return_value = MagicMock() - # Mock A2AStarletteApplication - mock_app_instance = MagicMock() - mock_app_instance.routes.return_value = ( - [] - ) # Return empty routes for testing - mock_a2a_app.return_value = mock_app_instance - # Change to temp directory original_cwd = os.getcwd() os.chdir(temp_agents_dir_with_a2a) @@ -879,9 +899,17 @@ def test_debug_trace(test_app): ) def test_a2a_agent_discovery(test_app_with_a2a): """Test that A2A agents are properly discovered and configured.""" - # This test mainly verifies that the A2A setup doesn't break the app + # This test verifies that the A2A setup doesn't break the app + # and that the well known card works response = test_app_with_a2a.get("/list-apps") assert response.status_code == 200 + response2 = test_app_with_a2a.get(f"/a2a/test_a2a_agent{AGENT_CARD_WELL_KNOWN_PATH}") + assert response2.status_code == 200 + # testing backward compatibility + response3 = test_app_with_a2a.get(f"/a2a/test_a2a_agent{PREV_AGENT_CARD_WELL_KNOWN_PATH}") + assert response3.status_code == 200 + response4 = test_app_with_a2a.get(f"/a2a/test_a2a_agent/openapi.json") + assert response4.status_code == 200 logger.info("A2A agent discovery test passed") From 6626adfea40e15e24ca74daa229392f45c0a8f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C4=9Bj=20Ra=C4=8Dinsk=C3=BD?= Date: Fri, 29 Aug 2025 20:51:42 +0200 Subject: [PATCH 2/2] fix: correct import and format --- src/google/adk/cli/fast_api.py | 3 +- tests/unittests/cli/test_fast_api.py | 43 +++++++++++----------------- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/google/adk/cli/fast_api.py b/src/google/adk/cli/fast_api.py index 849ae7fcbe..4d0277a04d 100644 --- a/src/google/adk/cli/fast_api.py +++ b/src/google/adk/cli/fast_api.py @@ -23,7 +23,6 @@ from typing import Mapping from typing import Optional -from a2a.server.apps import A2AFastAPIApplication import click from fastapi import FastAPI from fastapi import UploadFile @@ -307,7 +306,7 @@ async def get_agent_builder(app_name: str, file_path: Optional[str] = None): if a2a: try: - from a2a.server.apps import A2AStarletteApplication + from a2a.server.apps import A2AFastAPIApplication from a2a.server.request_handlers import DefaultRequestHandler from a2a.server.tasks import InMemoryTaskStore from a2a.types import AgentCard diff --git a/tests/unittests/cli/test_fast_api.py b/tests/unittests/cli/test_fast_api.py index 90555720af..19f77a36ac 100755 --- a/tests/unittests/cli/test_fast_api.py +++ b/tests/unittests/cli/test_fast_api.py @@ -504,36 +504,21 @@ def temp_agents_dir_with_a2a(): # Create agent.json file agent_card = { - "capabilities": { - "pushNotifications": True, - "streaming": True - }, - "defaultInputModes": [ - "text", - "text/plain" - ], - "defaultOutputModes": [ - "text", - "text/plain" - ], + "capabilities": {"pushNotifications": True, "streaming": True}, + "defaultInputModes": ["text", "text/plain"], + "defaultOutputModes": ["text", "text/plain"], "name": "test_a2a_agent", "description": "Test A2A agent", "version": "1.0.0", "author": "test", "protocolVersion": "0.2.6", - "skills": [ - { - "description": "Makes the tests pass", - "examples": [ - "Fix the tests." - ], - "id": "test_a2a_agent", - "name": "Test A2A agent", - "tags": [ - "testing" - ] - } - ], + "skills": [{ + "description": "Makes the tests pass", + "examples": ["Fix the tests."], + "id": "test_a2a_agent", + "name": "Test A2A agent", + "tags": ["testing"], + }], "url": "", } @@ -905,10 +890,14 @@ def test_a2a_agent_discovery(test_app_with_a2a): # and that the well known card works response = test_app_with_a2a.get("/list-apps") assert response.status_code == 200 - response2 = test_app_with_a2a.get(f"/a2a/test_a2a_agent{AGENT_CARD_WELL_KNOWN_PATH}") + response2 = test_app_with_a2a.get( + f"/a2a/test_a2a_agent{AGENT_CARD_WELL_KNOWN_PATH}" + ) assert response2.status_code == 200 # testing backward compatibility - response3 = test_app_with_a2a.get(f"/a2a/test_a2a_agent{PREV_AGENT_CARD_WELL_KNOWN_PATH}") + response3 = test_app_with_a2a.get( + f"/a2a/test_a2a_agent{PREV_AGENT_CARD_WELL_KNOWN_PATH}" + ) assert response3.status_code == 200 response4 = test_app_with_a2a.get(f"/a2a/test_a2a_agent/openapi.json") assert response4.status_code == 200