diff --git a/src/google/adk/cli/cli_tools_click.py b/src/google/adk/cli/cli_tools_click.py index 07ccc15892..1bfed725af 100644 --- a/src/google/adk/cli/cli_tools_click.py +++ b/src/google/adk/cli/cli_tools_click.py @@ -1632,8 +1632,9 @@ def cli_web( ): """Starts a FastAPI server with Web UI for agents. - AGENTS_DIR: The directory of agents, where each subdirectory is a single - agent, containing at least `__init__.py` and `agent.py` files. + AGENTS_DIR: The directory of agents, where each entry is a single agent — + either a subdirectory (containing `agent.py`, `__init__.py`, or + `root_agent.yaml`) or a flat `.py` module file. Example: @@ -1745,8 +1746,9 @@ def cli_api_server( ): """Starts a FastAPI server for agents. - AGENTS_DIR: The directory of agents, where each subdirectory is a single - agent, containing at least `__init__.py` and `agent.py` files. + AGENTS_DIR: The directory of agents, where each entry is a single agent — + either a subdirectory (containing `agent.py`, `__init__.py`, or + `root_agent.yaml`) or a flat `.py` module file. Example: diff --git a/src/google/adk/cli/utils/agent_loader.py b/src/google/adk/cli/utils/agent_loader.py index a7bbcbc2a6..0cc0d2de61 100644 --- a/src/google/adk/cli/utils/agent_loader.py +++ b/src/google/adk/cli/utils/agent_loader.py @@ -420,6 +420,8 @@ def _determine_agent_language( return "python" elif (base_path / "__init__.py").exists(): return "python" + elif (base_path.parent / f"{agent_name}.py").exists(): + return "python" raise ValueError(f"Could not determine agent type for '{agent_name}'.") diff --git a/tests/unittests/cli/utils/test_agent_loader.py b/tests/unittests/cli/utils/test_agent_loader.py index abc5718adb..93a95707ff 100644 --- a/tests/unittests/cli/utils/test_agent_loader.py +++ b/tests/unittests/cli/utils/test_agent_loader.py @@ -1006,3 +1006,56 @@ def test_validate_agent_name_rejects_nonexistent_agent(self): # 'subprocess' is a valid identifier but shouldn't be importable as an agent with pytest.raises(ValueError, match="Agent not found"): loader.load_agent("subprocess") + + +class TestDetermineAgentLanguage: + """Tests for AgentLoader._determine_agent_language covering all 4 load patterns.""" + + def test_flat_module_returns_python(self): + """Flat-module agent (agents_dir/agent_name.py) is detected as python.""" + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + (temp_path / "my_agent.py").write_text("root_agent = None\n") + loader = AgentLoader(temp_dir) + assert loader._determine_agent_language("my_agent") == "python" + + def test_agent_py_subdirectory_returns_python(self): + """Subdirectory with agent.py is detected as python.""" + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + agent_dir = temp_path / "my_agent" + agent_dir.mkdir() + (agent_dir / "agent.py").write_text("root_agent = None\n") + loader = AgentLoader(temp_dir) + assert loader._determine_agent_language("my_agent") == "python" + + def test_init_py_subdirectory_returns_python(self): + """Subdirectory with __init__.py is detected as python.""" + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + agent_dir = temp_path / "my_agent" + agent_dir.mkdir() + (agent_dir / "__init__.py").write_text("root_agent = None\n") + loader = AgentLoader(temp_dir) + assert loader._determine_agent_language("my_agent") == "python" + + def test_root_agent_yaml_returns_yaml(self): + """Subdirectory with root_agent.yaml is detected as yaml.""" + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + agent_dir = temp_path / "my_agent" + agent_dir.mkdir() + (agent_dir / "root_agent.yaml").write_text("root_agent: {}\n") + loader = AgentLoader(temp_dir) + assert loader._determine_agent_language("my_agent") == "yaml" + + def test_unrecognized_structure_raises_value_error(self): + """A directory with no recognized structure raises ValueError.""" + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + agent_dir = temp_path / "my_agent" + agent_dir.mkdir() + (agent_dir / "main.py").write_text("root_agent = None\n") + loader = AgentLoader(temp_dir) + with pytest.raises(ValueError, match="Could not determine agent type"): + loader._determine_agent_language("my_agent")