Skip to content

Commit 0b73a69

Browse files
ejfncopybara-github
authored andcommitted
fix: Handle App objects in eval and graph endpoints
Merge #3060 ## Description Fixes #3059 This PR fixes two endpoints in `adk web` that fail when using App objects instead of bare agents. ## Changes - **Eval execution endpoint** (line ~969): Extract root_agent from App objects before passing to LocalEvalService - **Graph visualization endpoint** (line ~1308): Extract root_agent from App objects before graph operations Both endpoints now properly handle both BaseAgent and App objects by checking the type and extracting `.root_agent` when needed. ## Testing Plan ### Manual E2E Testing with ADK Web Tested with an App object that includes context caching: ```python from google.adk.apps import App from google.adk.agents import LlmAgent root_agent = LlmAgent(name="MyAgent", model="gemini-1.5-pro-002") app = App( name="my_agent", root_agent=root_agent, context_cache_config=ContextCacheConfig(...) ) ``` **Before fix:** - Graph visualization failed (tried to call agent methods on App object) - Eval execution failed (LocalEvalService received App instead of agent) **After fix:** - Graph visualization works correctly - Eval execution works correctly - Both endpoints properly extract root_agent from App objects ## Checklist - [x] Code follows project style (autoformat.sh passed) - [x] Changes are focused and minimal - [x] Issue #3059 created and referenced - [x] Manual E2E testing completed COPYBARA_INTEGRATE_REVIEW=#3060 from ejfn:ejfn/bugfix-app-object-endpoints 01c3019 PiperOrigin-RevId: 821746910
1 parent ee39a89 commit 0b73a69

File tree

1 file changed

+11
-11
lines changed

1 file changed

+11
-11
lines changed

src/google/adk/cli/adk_web_server.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,12 @@ async def get_runner_async(self, app_name: str) -> Runner:
486486
self.runner_dict[app_name] = runner
487487
return runner
488488

489+
def _get_root_agent(self, agent_or_app: BaseAgent | App) -> BaseAgent:
490+
"""Extract root agent from either a BaseAgent or App object."""
491+
if isinstance(agent_or_app, App):
492+
return agent_or_app.root_agent
493+
return agent_or_app
494+
489495
def _create_runner(self, agentic_app: App) -> Runner:
490496
"""Create a runner with common services."""
491497
return Runner(
@@ -933,9 +939,8 @@ async def add_session_to_eval_set(
933939

934940
# Populate the session with initial session state.
935941
agent_or_app = self.agent_loader.load_agent(app_name)
936-
if isinstance(agent_or_app, App):
937-
agent_or_app = agent_or_app.root_agent
938-
initial_session_state = create_empty_state(agent_or_app)
942+
root_agent = self._get_root_agent(agent_or_app)
943+
initial_session_state = create_empty_state(root_agent)
939944

940945
new_eval_case = EvalCase(
941946
eval_id=req.eval_id,
@@ -1096,7 +1101,8 @@ async def run_eval(
10961101
status_code=400, detail=f"Eval set `{eval_set_id}` not found."
10971102
)
10981103

1099-
root_agent = self.agent_loader.load_agent(app_name)
1104+
agent_or_app = self.agent_loader.load_agent(app_name)
1105+
root_agent = self._get_root_agent(agent_or_app)
11001106

11011107
eval_case_results = []
11021108

@@ -1437,13 +1443,7 @@ async def get_event_graph(
14371443
function_calls = event.get_function_calls()
14381444
function_responses = event.get_function_responses()
14391445
agent_or_app = self.agent_loader.load_agent(app_name)
1440-
# The loader may return an App; unwrap to its root agent so the graph builder
1441-
# receives a BaseAgent instance.
1442-
root_agent = (
1443-
agent_or_app.root_agent
1444-
if isinstance(agent_or_app, App)
1445-
else agent_or_app
1446-
)
1446+
root_agent = self._get_root_agent(agent_or_app)
14471447
dot_graph = None
14481448
if function_calls:
14491449
function_call_highlights = []

0 commit comments

Comments
 (0)