Skip to content
Closed
Show file tree
Hide file tree
Changes from 9 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
1 change: 0 additions & 1 deletion contributing/samples/gepa/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
from tau_bench.types import EnvRunResult
from tau_bench.types import RunConfig
import tau_bench_agent as tau_bench_agent_lib

import utils


Expand Down
1 change: 0 additions & 1 deletion contributing/samples/gepa/run_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from absl import flags
import experiment
from google.genai import types

import utils

_OUTPUT_DIR = flags.DEFINE_string(
Expand Down
20 changes: 19 additions & 1 deletion src/google/adk/cli/adk_web_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,17 @@ class ListMetricsInfoResponse(common.BaseModel):
metrics_info: list[MetricInfo]


class AppInfo(common.BaseModel):
simple_name: str
agent_name: str
description: str
agent_type: Literal["yaml", "package"]


class ListAppsResponse(common.BaseModel):
apps: list[AppInfo]


def _setup_telemetry(
otel_to_cloud: bool = False,
internal_exporters: Optional[list[SpanProcessor]] = None,
Expand Down Expand Up @@ -699,7 +710,14 @@ async def internal_lifespan(app: FastAPI):
)

@app.get("/list-apps")
async def list_apps() -> list[str]:
async def list_apps(
detailed: bool = Query(
default=False, description="Return detailed app information"
)
) -> list[str] | ListAppsResponse:
if detailed:
apps_info = self.agent_loader.list_agents_detailed()
return ListAppsResponse(apps=[AppInfo(**app) for app in apps_info])
return self.agent_loader.list_agents()

@app.get("/debug/trace/{event_id}", tags=[TAG_DEBUG])
Expand Down
46 changes: 46 additions & 0 deletions src/google/adk/cli/utils/agent_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import os
from pathlib import Path
import sys
from typing import Any
from typing import Literal
from typing import Optional
from typing import Union

Expand Down Expand Up @@ -321,6 +323,50 @@ def list_agents(self) -> list[str]:
agent_names.sort()
return agent_names

def list_agents_detailed(self) -> list[dict[str, Any]]:
"""Lists all agents with detailed metadata (name, description, type)."""
agent_names = self.list_agents()
apps_info = []

for agent_name in agent_names:
try:
loaded = self.load_agent(agent_name)
if isinstance(loaded, App):
agent = loaded.root_agent
else:
agent = loaded

agent_type = self._determine_agent_type(agent_name)

app_info = {
"simple_name": agent_name,
"agent_name": agent.name,
"description": agent.description,
"agent_type": agent_type,
}
apps_info.append(app_info)

except Exception as e:
logger.error("Failed to load agent '%s': %s", agent_name, e)
continue

return apps_info

def _determine_agent_type(
self, agent_name: str
) -> Literal["yaml", "package"]:
"""Determine the type of agent based on file structure."""
base_path = Path.cwd() / self.agents_dir / agent_name

if (base_path / "root_agent.yaml").exists():
return "yaml"
elif (base_path / "agent.py").exists():
return "package"
elif (base_path / "__init__.py").exists():
return "package"

raise ValueError(f"Could not determine agent type for '{agent_name}'.")

def remove_agent_from_cache(self, agent_name: str):
# Clear module cache for the agent and its submodules
keys_to_delete = [
Expand Down
5 changes: 5 additions & 0 deletions src/google/adk/cli/utils/base_agent_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

from abc import ABC
from abc import abstractmethod
from typing import Any
from typing import Union

from ...agents.base_agent import BaseAgent
Expand All @@ -34,3 +35,7 @@ def load_agent(self, agent_name: str) -> Union[BaseAgent, App]:
@abstractmethod
def list_agents(self) -> list[str]:
"""Lists all agents available in the agent loader in alphabetical order."""

@abstractmethod
def list_agents_detailed(self) -> list[dict[str, Any]]:
"""Lists all agents with detailed metadata (name, display name, description, type)."""
28 changes: 28 additions & 0 deletions tests/unittests/cli/test_fast_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,14 @@ def load_agent(self, app_name):
def list_agents(self):
return ["test_app"]

def list_agents_detailed(self):
return [{
"simple_name": "test_app",
"agent_name": "test_agent",
"description": "A test agent for unit testing",
"agent_type": "package",
}]

return MockAgentLoader(".")


Expand Down Expand Up @@ -550,6 +558,26 @@ def test_list_apps(test_app):
logger.info(f"Listed apps: {data}")


def test_list_apps_detailed(test_app):
"""Test listing available applications with detailed metadata."""
response = test_app.get("/list-apps?detailed=true")

assert response.status_code == 200
data = response.json()
assert isinstance(data, dict)
assert "apps" in data
assert isinstance(data["apps"], list)

for app in data["apps"]:
assert "simpleName" in app
assert "agentName" in app
assert "description" in app
assert "agentType" in app
assert app["agentType"] in ["yaml", "package"]

logger.info(f"Listed apps: {data}")


def test_create_session_with_id(test_app, test_session_info):
"""Test creating a session with a specific ID."""
new_session_id = "new_session_id"
Expand Down