Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7b51ae9

Browse files
seanzhougooglecopybara-github
authored andcommitted
fix: enhance agent loader exception handler and expose precise error information
PiperOrigin-RevId: 766876662
1 parentbf12a4a commit7b51ae9

File tree

2 files changed

+142
-18
lines changed

2 files changed

+142
-18
lines changed

‎src/google/adk/cli/utils/agent_loader.py‎

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,23 @@ def _load_from_module_or_package(
6161
"Root agent found is not an instance of BaseAgent. But a type %s",
6262
type(module_candidate.root_agent),
6363
)
64-
65-
exceptModuleNotFoundError:
66-
logger.debug("Module %s itself not found.",agent_name)
67-
# Re-raise as ValueError to be caught by the final error message construction
68-
raiseValueError(
69-
f"Module{agent_name} not found during import attempts."
70-
)fromNone
71-
exceptImportErrorase:
72-
logger.warning("Error importing %s: %s",agent_name,e)
64+
else:
65+
logger.debug(
66+
"Module %s has no root_agent. Trying next pattern.",
67+
agent_name,
68+
)
69+
70+
exceptModuleNotFoundErrorase:
71+
ife.name==agent_name:
72+
logger.debug("Module %s itself not found.",agent_name)
73+
else:
74+
# it's the case the module imported by {agent_name}.agent module is not
75+
# found
76+
e.msg=f"Fail to load '{agent_name}' module. "+e.msg
77+
raisee
78+
exceptExceptionase:
79+
e.msg=f"Fail to load '{agent_name}' module. "+e.msg
80+
raisee
7381

7482
returnNone
7583

@@ -87,12 +95,23 @@ def _load_from_submodule(self, agent_name: str) -> Optional[BaseAgent]:
8795
"Root agent found is not an instance of BaseAgent. But a type %s",
8896
type(module_candidate.root_agent),
8997
)
90-
exceptModuleNotFoundError:
91-
logger.debug(
92-
"Module %s.agent not found, trying next pattern.",agent_name
93-
)
94-
exceptImportErrorase:
95-
logger.warning("Error importing %s.agent: %s",agent_name,e)
98+
else:
99+
logger.debug(
100+
"Module %s.agent has no root_agent.",
101+
agent_name,
102+
)
103+
exceptModuleNotFoundErrorase:
104+
# if it's agent module not found, it's fine, search for next pattern
105+
ife.name==f"{agent_name}.agent"ore.name==agent_name:
106+
logger.debug("Module %s.agent not found.",agent_name)
107+
else:
108+
# it's the case the module imported by {agent_name}.agent module is not
109+
# found
110+
e.msg=f"Fail to load '{agent_name}.agent' module. "+e.msg
111+
raisee
112+
exceptExceptionase:
113+
e.msg=f"Fail to load '{agent_name}.agent' module. "+e.msg
114+
raisee
96115

97116
returnNone
98117

@@ -107,10 +126,10 @@ def _perform_load(self, agent_name: str) -> BaseAgent:
107126
)
108127
envs.load_dotenv_for_agent(agent_name,str(self.agents_dir))
109128

110-
ifroot_agent:=self._load_from_submodule(agent_name):
129+
ifroot_agent:=self._load_from_module_or_package(agent_name):
111130
returnroot_agent
112131

113-
ifroot_agent:=self._load_from_module_or_package(agent_name):
132+
ifroot_agent:=self._load_from_submodule(agent_name):
114133
returnroot_agent
115134

116135
# If no root_agent was found by any pattern

‎tests/unittests/cli/utils/test_agent_loader.py‎

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,40 @@ def test_env_loading_for_agent(self):
219219
assertagent.config=="production"
220220
assertos.environ.get("AGENT_SECRET")=="test_secret_123"
221221

222+
deftest_loading_order_preference(self):
223+
"""Test that module/package is preferred over agent.py in a sub-package."""
224+
withtempfile.TemporaryDirectory()astemp_dir:
225+
temp_path=Path(temp_dir)
226+
agent_name="order_test_agent"
227+
228+
# Create structure 1: agents_dir/agent_name.py (expected to be loaded)
229+
agent_module_file=temp_path/f"{agent_name}.py"
230+
agent_module_file.write_text(dedent(f"""
231+
from google.adk.agents.base_agent import BaseAgent
232+
class ModuleAgent(BaseAgent):
233+
def __init__(self):
234+
super().__init__(name="{agent_name}_module_version")
235+
root_agent = ModuleAgent()
236+
"""))
237+
238+
# Create structure 2: agents_dir/agent_name/agent.py (should be ignored)
239+
agent_package_dir=temp_path/agent_name
240+
agent_package_dir.mkdir()
241+
agent_submodule_file=agent_package_dir/"agent.py"
242+
agent_submodule_file.write_text(dedent(f"""
243+
from google.adk.agents.base_agent import BaseAgent
244+
class SubmoduleAgent(BaseAgent):
245+
def __init__(self):
246+
super().__init__(name="{agent_name}_submodule_version")
247+
root_agent = SubmoduleAgent()
248+
"""))
249+
250+
loader=AgentLoader(str(temp_path))
251+
agent=loader.load_agent(agent_name)
252+
253+
# Assert that the module version was loaded due to the new loading order
254+
assertagent.name==f"{agent_name}_module_version"
255+
222256
deftest_load_multiple_different_agents(self):
223257
"""Test loading multiple different agents."""
224258
withtempfile.TemporaryDirectory()astemp_dir:
@@ -249,12 +283,24 @@ def test_agent_not_found_error(self):
249283
"""Test that appropriate error is raised when agent is not found."""
250284
withtempfile.TemporaryDirectory()astemp_dir:
251285
loader=AgentLoader(temp_dir)
286+
agents_dir=temp_dir# For use in the expected message string
252287

253288
# Try to load non-existent agent
254289
withpytest.raises(ValueError)asexc_info:
255290
loader.load_agent("nonexistent_agent")
256291

257-
assert"Module nonexistent_agent not found"instr(exc_info.value)
292+
expected_msg_part_1="No root_agent found for 'nonexistent_agent'."
293+
expected_msg_part_2= (
294+
"Searched in 'nonexistent_agent.agent.root_agent',"
295+
" 'nonexistent_agent.root_agent'."
296+
)
297+
expected_msg_part_3= (
298+
f"Ensure '{agents_dir}/nonexistent_agent' is structured correctly"
299+
)
300+
301+
assertexpected_msg_part_1instr(exc_info.value)
302+
assertexpected_msg_part_2instr(exc_info.value)
303+
assertexpected_msg_part_3instr(exc_info.value)
258304

259305
deftest_agent_without_root_agent_error(self):
260306
"""Test that appropriate error is raised when agent has no root_agent."""
@@ -279,6 +325,65 @@ def __init__(self):
279325

280326
assert"No root_agent found for 'broken_agent'"instr(exc_info.value)
281327

328+
deftest_agent_internal_module_not_found_error(self):
329+
"""Test error when an agent tries to import a non-existent module."""
330+
withtempfile.TemporaryDirectory()astemp_dir:
331+
temp_path=Path(temp_dir)
332+
agent_name="importer_agent"
333+
334+
# Create agent that imports a non-existent module
335+
agent_file=temp_path/f"{agent_name}.py"
336+
agent_file.write_text(dedent(f"""
337+
from google.adk.agents.base_agent import BaseAgent
338+
import non_existent_module # This will fail
339+
340+
class{agent_name.title()}Agent(BaseAgent):
341+
def __init__(self):
342+
super().__init__(name="{agent_name}")
343+
344+
root_agent ={agent_name.title()}Agent()
345+
"""))
346+
347+
loader=AgentLoader(str(temp_path))
348+
withpytest.raises(ModuleNotFoundError)asexc_info:
349+
loader.load_agent(agent_name)
350+
351+
assertf"Fail to load '{agent_name}' module."instr(exc_info.value)
352+
assert"No module named 'non_existent_module'"instr(exc_info.value)
353+
354+
deftest_agent_internal_import_error(self):
355+
"""Test other import errors within an agent's code (e.g., SyntaxError)."""
356+
withtempfile.TemporaryDirectory()astemp_dir:
357+
temp_path=Path(temp_dir)
358+
agent_name="syntax_error_agent"
359+
360+
# Create agent with a syntax error (which leads to ImportError)
361+
agent_file=temp_path/f"{agent_name}.py"
362+
agent_file.write_text(dedent(f"""
363+
from google.adk.agents.base_agent import BaseAgent
364+
365+
# Invalid syntax
366+
this is not valid python code
367+
368+
class{agent_name.title()}Agent(BaseAgent):
369+
def __init__(self):
370+
super().__init__(name="{agent_name}")
371+
372+
root_agent ={agent_name.title()}Agent()
373+
"""))
374+
375+
loader=AgentLoader(str(temp_path))
376+
# SyntaxError is a subclass of Exception, and importlib might wrap it
377+
# The loader is expected to prepend its message and re-raise.
378+
withpytest.raises(
379+
SyntaxError
380+
)asexc_info:# Or potentially ImportError depending on Python version specifics with importlib
381+
loader.load_agent(agent_name)
382+
383+
assertf"Fail to load '{agent_name}' module."instr(exc_info.value)
384+
# Check for part of the original SyntaxError message
385+
assert"invalid syntax"instr(exc_info.value).lower()
386+
282387
deftest_sys_path_modification(self):
283388
"""Test that agents_dir is added to sys.path correctly."""
284389
withtempfile.TemporaryDirectory()astemp_dir:

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp