diff --git a/src/google/adk/cli/fast_api.py b/src/google/adk/cli/fast_api.py index 7ff10c5414..d2cf83e366 100644 --- a/src/google/adk/cli/fast_api.py +++ b/src/google/adk/cli/fast_api.py @@ -317,7 +317,7 @@ async def get_agent_builder( 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 @@ -375,18 +375,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 f0b6c89e7e..4b5381b466 100755 --- a/tests/unittests/cli/test_fast_api.py +++ b/tests/unittests/cli/test_fast_api.py @@ -26,6 +26,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 @@ -422,11 +424,22 @@ 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: @@ -496,20 +509,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) @@ -959,9 +964,21 @@ def list_agents(self): ) 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")