Skip to content

Commit 50cc24e

Browse files
committed
Fixed errors
1 parent c2fb02d commit 50cc24e

3 files changed

Lines changed: 89 additions & 79 deletions

File tree

src/google/adk/cli/fast_api.py

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
from starlette.types import Lifespan
4545
from watchdog.observers import Observer
4646

47+
4748
from ..auth.credential_service.in_memory_credential_service import InMemoryCredentialService
4849
from ..runners import Runner
4950
from ..telemetry._agent_engine import get_propagated_context
@@ -61,30 +62,34 @@
6162
from .utils.service_factory import create_memory_service_from_options
6263
from .utils.service_factory import create_session_service_from_options
6364
from ..apps.app import App
64-
from collections.abc import Mapping
65+
66+
6567
_ALLOWED_AGENT_ENGINE_CLASS_METHODS = frozenset(
6668
method["name"] for method in _AGENT_ENGINE_CLASS_METHODS
6769
)
6870

69-
class DynamicAppMap(Mapping):
70-
def __init__(self, agent_loader):
71-
self.agent_loader = agent_loader
72-
73-
def __getitem__(self, app_name):
74-
for folder_name in self.agent_loader.list_agents():
75-
try:
76-
loaded = self.agent_loader.load_agent(folder_name)
77-
if isinstance(loaded, App) and loaded.name == app_name:
78-
return folder_name
79-
except Exception:
80-
pass
81-
return app_name
82-
83-
def __iter__(self):
84-
return iter([])
85-
86-
def __len__(self):
87-
return 1
71+
72+
class AgentAppMapping(Mapping[str, str]):
73+
74+
def __init__(self, agent_loader):
75+
self.agent_loader = agent_loader
76+
77+
def __getitem__(self, app_name):
78+
for folder_name in self.agent_loader.list_agents():
79+
try:
80+
loaded = self.agent_loader.load_agent(folder_name)
81+
if isinstance(loaded, App) and loaded.name == app_name:
82+
return folder_name
83+
except Exception:
84+
pass
85+
return app_name
86+
87+
def __iter__(self):
88+
return iter([])
89+
90+
def __len__(self):
91+
return 1
92+
8893

8994
class _QueryRequest(BaseModel):
9095
input: dict[str, Any] | None = None
@@ -254,15 +259,15 @@ def get_fast_api_app(
254259
)
255260
except ValueError as exc:
256261
raise click.ClickException(str(exc)) from exc
257-
258-
app_name_to_dir = DynamicAppMap(agent_loader)
262+
263+
app_name_to_dir = AgentAppMapping(agent_loader)
259264
# Build the Session service
260265
session_service = create_session_service_from_options(
261266
base_dir=agents_dir,
262267
session_service_uri=session_service_uri,
263268
session_db_kwargs=session_db_kwargs,
264269
use_local_storage=use_local_storage,
265-
app_name_to_dir=app_name_to_dir
270+
app_name_to_dir=app_name_to_dir,
266271
)
267272

268273
# Build the Artifact service

src/google/adk/cli/utils/service_factory.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from urllib.parse import parse_qsl
2222
from urllib.parse import urlsplit
2323
from urllib.parse import urlunsplit
24+
from typing import Mapping, Optional
2425

2526
from ...artifacts.base_artifact_service import BaseArtifactService
2627
from ...memory.base_memory_service import BaseMemoryService
@@ -172,7 +173,7 @@ def create_session_service_from_options(
172173
base_dir: Path | str,
173174
session_service_uri: str | None = None,
174175
session_db_kwargs: dict[str, Any] | None = None,
175-
app_name_to_dir: dict[str, str] | None = None,
176+
app_name_to_dir: Optional[Mapping[str, str]] = None,
176177
use_local_storage: bool = True,
177178
) -> BaseSessionService:
178179
"""Creates a session service based on CLI/web options."""

tests/unittests/cli/test_fast_api.py

Lines changed: 59 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
from google.adk.artifacts.base_artifact_service import ArtifactVersion
3535
from google.adk.cli import fast_api as fast_api_module
3636
from google.adk.cli.fast_api import get_fast_api_app
37+
from google.adk.cli.fast_api import AgentAppMapping
38+
from google.adk.apps.app import App
3739
from google.adk.errors.input_validation_error import InputValidationError
3840
from google.adk.errors.session_not_found_error import SessionNotFoundError
3941
from google.adk.evaluation.eval_case import EvalCase
@@ -50,8 +52,6 @@
5052
from google.genai import types
5153
from pydantic import BaseModel
5254
import pytest
53-
from google.adk.cli.fast_api import DynamicAppMap
54-
from google.adk.apps.app import App
5555

5656
# Configure logging to help diagnose server startup issues
5757
logging.basicConfig(
@@ -4430,63 +4430,67 @@ def test_create_eval_set_legacy_route_creates_eval_set(
44304430
if __name__ == "__main__":
44314431
pytest.main(["-xvs", __file__])
44324432

4433+
44334434
def test_dynamic_app_map_finds_matching_app():
4434-
mock_agent_loader = MagicMock()
4435-
mock_agent_loader.list_agents.return_value = ["folder_a", "folder_b"]
4436-
4437-
def mock_load_agent(folder):
4438-
mock_app = MagicMock(spec=App)
4439-
if folder == "folder_b":
4440-
mock_app.name = "target_app"
4441-
else:
4442-
mock_app.name = "other_app"
4443-
return mock_app
4444-
4445-
mock_agent_loader.load_agent.side_effect = mock_load_agent
4446-
4447-
app_map = DynamicAppMap(mock_agent_loader)
4448-
4449-
# Should correctly map the internal app name to its physical folder
4450-
assert app_map["target_app"] == "folder_b"
4435+
mock_agent_loader = MagicMock()
4436+
mock_agent_loader.list_agents.return_value = ["folder_a", "folder_b"]
4437+
4438+
def mock_load_agent(folder):
4439+
mock_app = MagicMock(spec=App)
4440+
if folder == "folder_b":
4441+
mock_app.name = "target_app"
4442+
else:
4443+
mock_app.name = "other_app"
4444+
return mock_app
4445+
4446+
mock_agent_loader.load_agent.side_effect = mock_load_agent
4447+
4448+
app_map = AgentAppMapping(mock_agent_loader)
4449+
4450+
# Should correctly map the internal app name to its physical folder
4451+
assert app_map["target_app"] == "folder_b"
4452+
44514453

44524454
def test_dynamic_app_map_fallback_when_not_found():
4453-
mock_agent_loader = MagicMock()
4454-
mock_agent_loader.list_agents.return_value = ["folder_a"]
4455-
4456-
def mock_load_agent(folder):
4457-
mock_app = MagicMock(spec=App)
4458-
mock_app.name = "other_app"
4459-
return mock_app
4460-
4461-
mock_agent_loader.load_agent.side_effect = mock_load_agent
4462-
4463-
app_map = DynamicAppMap(mock_agent_loader)
4464-
4465-
# If the app isn't found, it should return the exact string it was given
4466-
assert app_map["missing_app"] == "missing_app"
4455+
mock_agent_loader = MagicMock()
4456+
mock_agent_loader.list_agents.return_value = ["folder_a"]
4457+
4458+
def mock_load_agent(folder):
4459+
mock_app = MagicMock(spec=App)
4460+
mock_app.name = "other_app"
4461+
return mock_app
4462+
4463+
mock_agent_loader.load_agent.side_effect = mock_load_agent
4464+
4465+
app_map = AgentAppMapping(mock_agent_loader)
4466+
4467+
# If the app isn't found, it should return the exact string it was given
4468+
assert app_map["missing_app"] == "missing_app"
4469+
44674470

44684471
def test_dynamic_app_map_ignores_load_errors():
4469-
mock_agent_loader = MagicMock()
4470-
mock_agent_loader.list_agents.return_value = ["broken_folder", "good_folder"]
4471-
4472-
def mock_load_agent(folder):
4473-
if folder == "broken_folder":
4474-
raise ValueError("Agent is completely broken")
4475-
mock_app = MagicMock(spec=App)
4476-
mock_app.name = "good_app"
4477-
return mock_app
4478-
4479-
mock_agent_loader.load_agent.side_effect = mock_load_agent
4480-
4481-
app_map = DynamicAppMap(mock_agent_loader)
4482-
4483-
# Should ignore the ValueError from broken_folder and still find good_app
4484-
assert app_map["good_app"] == "good_folder"
4472+
mock_agent_loader = MagicMock()
4473+
mock_agent_loader.list_agents.return_value = ["broken_folder", "good_folder"]
4474+
4475+
def mock_load_agent(folder):
4476+
if folder == "broken_folder":
4477+
raise ValueError("Agent is completely broken")
4478+
mock_app = MagicMock(spec=App)
4479+
mock_app.name = "good_app"
4480+
return mock_app
4481+
4482+
mock_agent_loader.load_agent.side_effect = mock_load_agent
4483+
4484+
app_map = AgentAppMapping(mock_agent_loader)
4485+
4486+
# Should ignore the ValueError from broken_folder and still find good_app
4487+
assert app_map["good_app"] == "good_folder"
4488+
44854489

44864490
def test_dynamic_app_map_is_truthy():
4487-
mock_agent_loader = MagicMock()
4488-
app_map = DynamicAppMap(mock_agent_loader)
4489-
4490-
# Must evaluate to True so that `app_map or {}` evaluates to app_map
4491-
assert bool(app_map) is True
4492-
assert (app_map or {}) is app_map
4491+
mock_agent_loader = MagicMock()
4492+
app_map = AgentAppMapping(mock_agent_loader)
4493+
4494+
# Must evaluate to True so that `app_map or {}` evaluates to app_map
4495+
assert bool(app_map) is True
4496+
assert (app_map or {}) is app_map

0 commit comments

Comments
 (0)