Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 4 additions & 10 deletions src/google/adk/cli/fast_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)

Expand Down
37 changes: 27 additions & 10 deletions tests/unittests/cli/test_fast_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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")


Expand Down
Loading