You've already forked adk-python
mirror of
https://github.com/encounter/adk-python.git
synced 2026-07-09 18:19:28 -07:00
fix: filter non-agent directoris from list_agents()
Merge https://github.com/google/adk-python/pull/4648 **Please ensure you have read the [contribution guide](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) before creating a pull request.** ### Link to Issue or Description of Change **1. Link to an existing issue (if applicable):** - Closes: #4647 - Related: #3429, #3430 **2. Or, if no issue exists, describe the change:** **Problem:** `AgentLoader.list_agents()` returns every non-hidden subdirectory in the agents directory, regardless of whether it contains a valid agent definition. This causes non-agent directories (e.g. `tmp/`, `data/`, `utils/`) to appear in the `/list-apps` API response. This affects both the ADK web UI agent selector and any production deployment depending on this API. **Solution:** Reuse the existing `_determine_agent_language()` method inside `list_agents()` to verify each candidate directory contains at least one recognized agent file (`root_agent.yaml`, `agent.py`, or `__init__.py`). Directories that fail this check are excluded from the result. This avoids introducing any new methods or abstractions and keeps the check lightweight (filesystem only, no agent imports). ### Testing Plan **Unit Tests:** - [x] I have added or updated unit tests for my change. - [x] All unit tests pass locally. 27 passed in 2.85s: pytest tests/unittests/cli/utils/test_agent_loader.py -v ======================= 27 passed, 14 warnings in 2.85s ======================== Added `test_list_agents_excludes_non_agent_directories` which creates a temp directory with three valid agent types (package with `__init__.py`, module with `agent.py`, YAML with `root_agent.yaml`) and three non-agent directories, and asserts only the valid agents are listed. **Screenshots / Video:** | Before (non-agent directories listed) | After (only valid agents listed) | |----------------------------------------|----------------------------------| |<img width="566" height="553" alt="Image" src="https://github.com/user-attachments/assets/0f50084b-319f-480e-8d8a-051c28d4a7e7" />|<img width="567" height="532" alt="Image" src="https://github.com/user-attachments/assets/52d3543f-4c4c-4ff3-a6dd-7d5ce3f19bb2" />| **Manual End-to-End (E2E) Tests:** 1. Create a project directory containing both valid agent subdirectories and non-agent subdirectories 2. Run `adk web .` 3. Open the web UI and verify only valid agents appear in the agent selector 4. See screenshots below for before/after comparison ### Checklist - [x] I have read the [CONTRIBUTING.md](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) document. - [x] I have performed a self-review of my own code. - [x] I have commented my code, particularly in hard-to-understand areas. - [x] I have added tests that prove my fix is effective or that my feature works. - [x] New and existing unit tests pass locally with my changes. - [x] I have manually tested my changes end-to-end. - [ ] Any dependent changes have been merged and published in downstream modules. ### Additional context COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/4648 from markadelnawar:fix/list-agents-filter-non-agents-dirs 041895610fa0c52f2bf3cf7ba0d072a5c580c1b6 PiperOrigin-RevId: 878674609
This commit is contained in:
committed by
Copybara-Service
parent
94684874e4
commit
3b5937f022
@@ -335,13 +335,18 @@ class AgentLoader(BaseAgentLoader):
|
||||
def list_agents(self) -> list[str]:
|
||||
"""Lists all agents available in the agent loader (sorted alphabetically)."""
|
||||
base_path = Path.cwd() / self.agents_dir
|
||||
agent_names = [
|
||||
x
|
||||
for x in os.listdir(base_path)
|
||||
if os.path.isdir(os.path.join(base_path, x))
|
||||
and not x.startswith(".")
|
||||
and x != "__pycache__"
|
||||
]
|
||||
agent_names = []
|
||||
for x in os.listdir(base_path):
|
||||
if (
|
||||
os.path.isdir(os.path.join(base_path, x))
|
||||
and not x.startswith(".")
|
||||
and x != "__pycache__"
|
||||
):
|
||||
try:
|
||||
self._determine_agent_language(x)
|
||||
agent_names.append(x)
|
||||
except ValueError:
|
||||
continue
|
||||
agent_names.sort()
|
||||
return agent_names
|
||||
|
||||
|
||||
@@ -993,3 +993,48 @@ class TestAgentLoader:
|
||||
assert len(detailed_list) == 1
|
||||
assert detailed_list[0]["name"] == agent_name
|
||||
assert not detailed_list[0]["is_computer_use"]
|
||||
|
||||
def test_list_agents_excludes_non_agent_directories(self):
|
||||
"""Test that list_agents filters out directories without agent definitions."""
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
temp_path = Path(temp_dir)
|
||||
|
||||
valid_package = temp_path / "valid_agent"
|
||||
valid_package.mkdir()
|
||||
(valid_package / "__init__.py").write_text(dedent("""
|
||||
from google.adk.agents.base_agent import BaseAgent
|
||||
|
||||
class ValidAgent(BaseAgent):
|
||||
def __init__(self):
|
||||
super().__init__(name="valid_agent")
|
||||
|
||||
root_agent = ValidAgent()
|
||||
"""))
|
||||
|
||||
valid_module = temp_path / "module_agent"
|
||||
valid_module.mkdir()
|
||||
(valid_module / "agent.py").write_text(dedent("""
|
||||
from google.adk.agents.base_agent import BaseAgent
|
||||
|
||||
class ModuleAgent(BaseAgent):
|
||||
def __init__(self):
|
||||
super().__init__(name="module_agent")
|
||||
|
||||
root_agent = ModuleAgent()
|
||||
"""))
|
||||
|
||||
valid_yaml = temp_path / "yaml_agent"
|
||||
valid_yaml.mkdir()
|
||||
(valid_yaml / "root_agent.yaml").write_text("name: yaml_agent\n")
|
||||
|
||||
(temp_path / "random_folder").mkdir()
|
||||
(temp_path / "data").mkdir()
|
||||
(temp_path / "tmp").mkdir()
|
||||
|
||||
loader = AgentLoader(str(temp_path))
|
||||
agents = loader.list_agents()
|
||||
|
||||
assert agents == ["module_agent", "valid_agent", "yaml_agent"]
|
||||
assert "random_folder" not in agents
|
||||
assert "data" not in agents
|
||||
assert "tmp" not in agents
|
||||
|
||||
Reference in New Issue
Block a user