Skip to content

Commit bda3df2

Browse files
Poggeccicopybara-github
authored andcommitted
feat: Refactor AgentLoader into base class and add InMemory impl alongside existing filesystem impl
PiperOrigin-RevId: 786008518
1 parent 4ae4c69 commit bda3df2

File tree

5 files changed

+58
-24
lines changed

5 files changed

+58
-24
lines changed

src/google/adk/cli/cli_eval.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
from typing_extensions import deprecated
2929

30-
from ..agents import Agent
30+
from ..agents.llm_agent import Agent
3131
from ..artifacts.base_artifact_service import BaseArtifactService
3232
from ..evaluation.base_eval_service import BaseEvalService
3333
from ..evaluation.base_eval_service import EvaluateConfig

src/google/adk/cli/fast_api.py

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
from typing import Any
2828
from typing import List
2929
from typing import Literal
30-
from typing import Mapping
3130
from typing import Optional
3231

3332
import click
@@ -407,20 +406,7 @@ def _parse_agent_engine_resource_name(agent_engine_id_or_resource_name):
407406

408407
@app.get("/list-apps")
409408
def list_apps() -> list[str]:
410-
base_path = Path.cwd() / agents_dir
411-
if not base_path.exists():
412-
raise HTTPException(status_code=404, detail="Path not found")
413-
if not base_path.is_dir():
414-
raise HTTPException(status_code=400, detail="Not a directory")
415-
agent_names = [
416-
x
417-
for x in os.listdir(base_path)
418-
if os.path.isdir(os.path.join(base_path, x))
419-
and not x.startswith(".")
420-
and x != "__pycache__"
421-
]
422-
agent_names.sort()
423-
return agent_names
409+
return agent_loader.list_agents()
424410

425411
@app.get("/debug/trace/{event_id}")
426412
def get_trace_dict(event_id: str) -> Any:
@@ -525,13 +511,6 @@ async def create_session(
525511

526512
return session
527513

528-
def _get_eval_set_file_path(app_name, agents_dir, eval_set_id) -> str:
529-
return os.path.join(
530-
agents_dir,
531-
app_name,
532-
eval_set_id + _EVAL_SET_FILE_EXTENSION,
533-
)
534-
535514
@app.post(
536515
"/apps/{app_name}/eval_sets/{eval_set_id}",
537516
response_model_exclude_none=True,

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

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,23 @@
1717
import importlib
1818
import logging
1919
import os
20+
from pathlib import Path
2021
import sys
2122
from typing import Optional
2223

2324
from pydantic import ValidationError
25+
from typing_extensions import override
2426

2527
from . import envs
2628
from ...agents import config_agent_utils
2729
from ...agents.base_agent import BaseAgent
2830
from ...utils.feature_decorator import working_in_progress
31+
from .base_agent_loader import BaseAgentLoader
2932

3033
logger = logging.getLogger("google_adk." + __name__)
3134

3235

33-
class AgentLoader:
36+
class AgentLoader(BaseAgentLoader):
3437
"""Centralized agent loading with proper isolation, caching, and .env loading.
3538
Support loading agents from below folder/file structures:
3639
a) {agent_name}.agent as a module name:
@@ -188,6 +191,7 @@ def _perform_load(self, agent_name: str) -> BaseAgent:
188191
" exposed."
189192
)
190193

194+
@override
191195
def load_agent(self, agent_name: str) -> BaseAgent:
192196
"""Load an agent module (with caching & .env) and return its root_agent."""
193197
if agent_name in self._agent_cache:
@@ -199,6 +203,20 @@ def load_agent(self, agent_name: str) -> BaseAgent:
199203
self._agent_cache[agent_name] = agent
200204
return agent
201205

206+
@override
207+
def list_agents(self) -> list[str]:
208+
"""Lists all agents available in the agent loader (sorted alphabetically)."""
209+
base_path = Path.cwd() / self.agents_dir
210+
agent_names = [
211+
x
212+
for x in os.listdir(base_path)
213+
if os.path.isdir(os.path.join(base_path, x))
214+
and not x.startswith(".")
215+
and x != "__pycache__"
216+
]
217+
agent_names.sort()
218+
return agent_names
219+
202220
def remove_agent_from_cache(self, agent_name: str):
203221
# Clear module cache for the agent and its submodules
204222
keys_to_delete = [
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Base class for agent loaders."""
16+
17+
from __future__ import annotations
18+
19+
from abc import ABC
20+
from abc import abstractmethod
21+
22+
from ...agents.base_agent import BaseAgent
23+
24+
25+
class BaseAgentLoader(ABC):
26+
"""Abstract base class for agent loaders."""
27+
28+
@abstractmethod
29+
def load_agent(self, agent_name: str) -> BaseAgent:
30+
"""Loads an instance of an agent with the given name."""
31+
32+
@abstractmethod
33+
def list_agents(self) -> list[str]:
34+
"""Lists all agents available in the agent loader in alphabetical order."""

tests/unittests/cli/test_fast_api.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ def __init__(self, agents_dir: str):
189189
def load_agent(self, app_name):
190190
return root_agent
191191

192+
def list_agents(self):
193+
return ["test_app"]
194+
192195
return MockAgentLoader(".")
193196

194197

0 commit comments

Comments
 (0)