diff --git a/src/google/adk/agents/base_agent.py b/src/google/adk/agents/base_agent.py index ed721ffa3c..916bfdc9dd 100644 --- a/src/google/adk/agents/base_agent.py +++ b/src/google/adk/agents/base_agent.py @@ -737,20 +737,26 @@ def validate_sub_agents_unique_names( seen_names: set[str] = set() duplicates: set[str] = set() - for sub_agent in value: - name = sub_agent.name + def visit(agent: BaseAgent) -> None: + name = agent.name if name in seen_names: duplicates.add(name) else: seen_names.add(name) + for child in agent.sub_agents: + visit(child) + + for sub_agent in value: + visit(sub_agent) if duplicates: duplicate_names_str = ', '.join( f'`{name}`' for name in sorted(duplicates) ) logger.warning( - 'Found duplicate sub-agent names: %s. ' - 'All sub-agents must have unique names.', + 'Found duplicate agent names: %s. ' + 'All agents in the tree must have unique names. ' + 'find_agent() returns the first match in a depth-first walk.', duplicate_names_str, ) diff --git a/tests/unittests/agents/test_base_agent.py b/tests/unittests/agents/test_base_agent.py index 1dbe7e4bae..9995e90c7d 100644 --- a/tests/unittests/agents/test_base_agent.py +++ b/tests/unittests/agents/test_base_agent.py @@ -1248,7 +1248,7 @@ def test_validate_sub_agents_unique_names_single_duplicate( name=f'{request.function.__name__}_parent', sub_agents=[sub_agent_1, sub_agent_2], ) - assert f'Found duplicate sub-agent names: `{duplicate_name}`' in caplog.text + assert f'Found duplicate agent names: `{duplicate_name}`' in caplog.text def test_validate_sub_agents_unique_names_multiple_duplicates( @@ -1328,6 +1328,35 @@ def test_validate_sub_agents_unique_names_no_duplicates( assert parent.sub_agents[2].name == f'{request.function.__name__}_sub_agent_3' +def test_validate_sub_agents_unique_names_across_parents( + request: pytest.FixtureRequest, + caplog: pytest.LogCaptureFixture, +): + """Cousins under different parents that share a name must warn.""" + shared = f'{request.function.__name__}_shared' + left = _TestingAgent( + name=f'{request.function.__name__}_left', + sub_agents=[_TestingAgent(name=shared)], + ) + right = _TestingAgent( + name=f'{request.function.__name__}_right', + sub_agents=[_TestingAgent(name=shared)], + ) + + with caplog.at_level(logging.WARNING): + root = _TestingAgent( + name=f'{request.function.__name__}_root', + sub_agents=[left, right], + ) + + assert f'Found duplicate agent names: `{shared}`' in caplog.text + assert 'unique names' in caplog.text + # First DFS match wins; the other cousin is unreachable by name. + found = root.find_agent(shared) + assert found is not None + assert found is left.sub_agents[0] + + def test_validate_sub_agents_unique_names_empty_list( request: pytest.FixtureRequest, ):