fix(agents): report which toolset an agent lost when one fails to load

Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 964417035
This commit is contained in:
George Weale
2026-08-13 19:01:15 -07:00
committed by Copybara-Service
parent c93fcc0930
commit 66930e6526
2 changed files with 46 additions and 2 deletions
+15 -2
View File
@@ -210,10 +210,23 @@ async def _convert_tool_union_to_tools(
try:
return await tool_union.get_tools_with_prefix(ctx)
except Exception as e:
logger.warning(
'Failed to get tools from toolset %s: %s',
# The agent still runs, just without this toolset's tools, and the model
# will answer as though it never had them. That is a lost capability
# rather than a degraded one, so report it at error level, name which
# toolset was lost, and keep the traceback: str(e) is empty for several
# of the exceptions raised by transport clients.
logger.error(
'Agent %s will run without the tools from toolset %s%s, which failed'
' to load: %s',
ctx.agent_name if ctx else '<unknown>',
type(tool_union).__name__,
(
f' (prefix {tool_union.tool_name_prefix!r})'
if tool_union.tool_name_prefix
else ''
),
e,
exc_info=True,
)
return []
@@ -612,6 +612,37 @@ class TestCanonicalTools:
assert tools[0].name == '_regular_tool'
assert tools[1].name == 'working_tool'
async def test_canonical_tools_reports_the_toolset_it_dropped(self, caplog):
"""A toolset that fails to load is reported at error level, with context."""
from google.adk.tools.base_toolset import BaseToolset
class FailingToolset(BaseToolset):
async def get_tools(self, readonly_context=None):
raise ConnectionError('MCP server unavailable')
agent = LlmAgent(
name='test_agent',
model='gemini-pro',
tools=[FailingToolset(tool_name_prefix='books')],
)
ctx = await _create_readonly_context(agent)
with caplog.at_level(logging.ERROR, logger='google_adk'):
tools = await agent.canonical_tools(ctx)
assert tools == []
record = next(
r for r in caplog.records if 'failed to load' in r.getMessage()
)
message = record.getMessage()
assert 'test_agent' in message
assert 'FailingToolset' in message
assert 'books' in message
assert 'MCP server unavailable' in message
# The traceback is what identifies where inside the toolset it broke.
assert record.exc_info is not None
# Tests for multi-provider model support via string model names
@pytest.mark.parametrize(