chore: Add more info to "Session not found" error message in ADK runners for differently named app and folder

PiperOrigin-RevId: 815795412
This commit is contained in:
George Weale
2025-10-06 10:48:28 -07:00
committed by Copybara-Service
parent e0dd06ff04
commit 46d73be41a
2 changed files with 86 additions and 0 deletions
+37
View File
@@ -205,9 +205,19 @@ class AgentLoader(BaseAgentLoader):
envs.load_dotenv_for_agent(actual_agent_name, str(agents_dir)) envs.load_dotenv_for_agent(actual_agent_name, str(agents_dir))
if root_agent := self._load_from_module_or_package(actual_agent_name): if root_agent := self._load_from_module_or_package(actual_agent_name):
self._ensure_app_name_matches(
maybe_app=root_agent,
expected_app_name=actual_agent_name,
agents_dir=agents_dir,
)
return root_agent return root_agent
if root_agent := self._load_from_submodule(actual_agent_name): if root_agent := self._load_from_submodule(actual_agent_name):
self._ensure_app_name_matches(
maybe_app=root_agent,
expected_app_name=actual_agent_name,
agents_dir=agents_dir,
)
return root_agent return root_agent
if root_agent := self._load_from_yaml_config(actual_agent_name, agents_dir): if root_agent := self._load_from_yaml_config(actual_agent_name, agents_dir):
@@ -223,6 +233,33 @@ class AgentLoader(BaseAgentLoader):
" file can be loaded if present, and a root_agent is exposed." " file can be loaded if present, and a root_agent is exposed."
) )
def _ensure_app_name_matches(
self,
*,
maybe_app: Union[BaseAgent, App],
expected_app_name: str,
agents_dir: str,
) -> None:
"""Raises a detailed error when App.name does not match its directory."""
if not isinstance(maybe_app, App):
return
# Built-in apps live under double-underscore directories.
if expected_app_name.startswith("__"):
return
if maybe_app.name == expected_app_name:
return
raise ValueError(
"App name mismatch detected. The App defined at "
f"'{agents_dir}/{expected_app_name}' declares name "
f"'{maybe_app.name}', but ADK expects it to match the directory "
f"name '{expected_app_name}'. Rename the App or the folder so they "
"match, then reload."
)
@override @override
def load_agent(self, agent_name: str) -> Union[BaseAgent, App]: def load_agent(self, agent_name: str) -> Union[BaseAgent, App]:
"""Load an agent module (with caching & .env) and return its root_agent.""" """Load an agent module (with caching & .env) and return its root_agent."""
+49
View File
@@ -15,7 +15,9 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
import inspect
import logging import logging
from pathlib import Path
import queue import queue
from typing import Any from typing import Any
from typing import AsyncGenerator from typing import AsyncGenerator
@@ -149,6 +151,11 @@ class Runner:
self.memory_service = memory_service self.memory_service = memory_service
self.credential_service = credential_service self.credential_service = credential_service
self.plugin_manager = PluginManager(plugins=plugins) self.plugin_manager = PluginManager(plugins=plugins)
(
self._agent_origin_app_name,
self._agent_origin_dir,
) = self._infer_agent_origin(self.agent)
self._enforce_app_name_alignment()
def _validate_runner_params( def _validate_runner_params(
self, self,
@@ -211,6 +218,48 @@ class Runner:
) )
return app_name, agent, context_cache_config, resumability_config, plugins return app_name, agent, context_cache_config, resumability_config, plugins
def _infer_agent_origin(
self, agent: BaseAgent
) -> tuple[Optional[str], Optional[Path]]:
module = inspect.getmodule(agent.__class__)
if not module:
return None, None
module_file = getattr(module, '__file__', None)
if not module_file:
return None, None
module_path = Path(module_file).resolve()
project_root = Path.cwd()
try:
module_path.relative_to(project_root)
except ValueError:
return None, module_path.parent
current = module_path.parent
while current != project_root and current.parent != current:
parent = current.parent
if parent.name == 'agents':
return current.name, current
current = parent
return None, module_path.parent
def _enforce_app_name_alignment(self) -> None:
origin_name = self._agent_origin_app_name
origin_dir = self._agent_origin_dir
if not origin_name or origin_name.startswith('__'):
return
if origin_name == self.app_name:
return
origin_location = str(origin_dir) if origin_dir else origin_name
message = (
'App name mismatch detected. The runner is configured with '
f'app name "{self.app_name}", but the root agent was loaded from '
f'"{origin_location}", which implies app name "{origin_name}". '
'Rename the App or its directory so the names match before running '
'the agent.'
)
raise ValueError(message)
def run( def run(
self, self,
*, *,