Skip to content

fix(tools): handle missing 'request' key in AgentTool.run_async fallb…#5678

Open
phinglaspure123 wants to merge 3 commits into
google:mainfrom
phinglaspure123:fix/agent-tool-keyerror-request
Open

fix(tools): handle missing 'request' key in AgentTool.run_async fallb…#5678
phinglaspure123 wants to merge 3 commits into
google:mainfrom
phinglaspure123:fix/agent-tool-keyerror-request

Conversation

@phinglaspure123
Copy link
Copy Markdown

Problem

When AgentTool wraps an agent with no input_schema, run_async falls back to:

parts=[types.Part.from_text(text=args['request'])]

If the orchestrating LLM passes arguments under any key other than request (which is commonLLMs infer argument names from agent descriptions), 
this crashes:

ERROR - Error in event_generator: 'request'
Traceback (most recent call last):
  File "google/adk/tools/agent_tool.py", line 218, in run_async
    parts=[types.Part.from_text(text=args['request'])],
KeyError: 'request'

Full crash path:
runners.pybase_agent.pyllm_agent.pybase_llm_flow.pyfunctions.py: handle_function_calls_asyncfunctions.py: __call_tool_asyncagent_tool.py: run_asyncCRASH HERE

This is the second bug reported in #1084. The AttributeError: 'AgentTool' object has no attribute 'func' half was fixed in November 2025, but     
args['request'] on line 218 was never addressed. Issue #1084 was closed after the first fix but this crash path remains in main.

Solution

# Before (broken)
else:
    content = types.Content(
        role='user',
        parts=[types.Part.from_text(text=args['request'])],
    )

# After (fixed)
else:
    request_text = args.get('request') or json.dumps(args, ensure_ascii=False)
    content = types.Content(
        role='user',
        parts=[types.Part.from_text(text=request_text)],
    )

- If LLM passed {"request": "do the task"} → use value as-is (backward compatible)
- If LLM passed {"brand": "Nike", "product": "shoes"} → serialize all args as JSON stringsub-agent receives '{"brand": "Nike", "product":      
"shoes"}'

Also adds import json to the stdlib imports at the top of the file.

Testing Plan

Unit Tests:
- Added test_no_schema_non_request_args_serialized_as_jsonverifies non-request args are JSON-serialized and passed to sub-agent without        
crashing
- Added test_no_schema_request_key_backward_compatverifies existing request key behavior is unchanged
- All 30 existing tests pass

============================= test session starts =============================
platform win32 -- Python 3.12.12, pytest-9.0.3, pluggy-1.6.0 -- D:\coding\adk-python\.venv\Scripts\python.exe
cachedir: .pytest_cache
rootdir: D:\coding\adk-python
configfile: pyproject.toml
plugins: anyio-4.13.0, langsmith-0.8.3, asyncio-1.3.0, mock-3.15.1, xdist-3.8.0
asyncio: mode=Mode.AUTO, debug=False, asyncio_default_fixture_loop_scope=function, asyncio_default_test_loop_scope=function
collecting ... collected 30 items

tests/unittests/tools/test_agent_tool.py::test_agent_tool_inherits_parent_app_name PASSED [  3%]
tests/unittests/tools/test_agent_tool.py::test_no_schema PASSED          [  6%]
tests/unittests/tools/test_agent_tool.py::test_use_plugins PASSED        [ 10%]
tests/unittests/tools/test_agent_tool.py::test_update_state PASSED       [ 13%]
tests/unittests/tools/test_agent_tool.py::test_update_artifacts PASSED   [ 16%]
tests/unittests/tools/test_agent_tool.py::test_custom_schema[GOOGLE_AI] PASSED [ 20%]
tests/unittests/tools/test_agent_tool.py::test_agent_tool_response_schema_no_output_schema_vertex_ai[VERTEX] PASSED [ 23%]
tests/unittests/tools/test_agent_tool.py::test_agent_tool_response_schema_with_output_schema_vertex_ai[VERTEX] PASSED [ 26%]
tests/unittests/tools/test_agent_tool.py::test_agent_tool_response_schema_gemini_api[GOOGLE_AI] PASSED [ 30%]
tests/unittests/tools/test_agent_tool.py::test_agent_tool_response_schema_with_input_schema_vertex_ai[VERTEX] PASSED [ 33%]
tests/unittests/tools/test_agent_tool.py::test_agent_tool_response_schema_with_input_schema_no_output_vertex_ai[VERTEX] PASSED [ 36%]
tests/unittests/tools/test_agent_tool.py::test_include_plugins_default_true PASSED [ 40%]
tests/unittests/tools/test_agent_tool.py::test_include_plugins_explicit_true PASSED [ 43%]
tests/unittests/tools/test_agent_tool.py::test_include_plugins_false PASSED [ 46%]
tests/unittests/tools/test_agent_tool.py::test_agent_tool_description_with_input_schema PASSED [ 50%]
tests/unittests/tools/test_agent_tool.py::test_agent_tool_no_schema_with_json_schema_feature PASSED [ 53%]
tests/unittests/tools/test_agent_tool.py::test_agent_tool_response_json_schema_no_output_schema_vertex_ai[VERTEX] PASSED [ 56%]
tests/unittests/tools/test_agent_tool.py::test_agent_tool_response_json_schema_with_output_schema_vertex_ai[VERTEX] PASSED [ 60%]
tests/unittests/tools/test_agent_tool.py::test_agent_tool_no_response_json_schema_gemini_api[GOOGLE_AI] PASSED [ 63%]
tests/unittests/tools/test_agent_tool.py::test_agent_tool_with_input_schema_uses_json_schema_feature[VERTEX] PASSED [ 66%]
tests/unittests/tools/test_agent_tool.py::test_run_async_handles_none_parts_in_response PASSED [ 70%]
tests/unittests/tools/test_agent_tool.py::TestAgentToolWithCompositeAgents::test_sequential_agent_with_first_sub_agent_input_schema PASSED [ 73%]
tests/unittests/tools/test_agent_tool.py::TestAgentToolWithCompositeAgents::test_sequential_agent_without_input_schema_falls_back_to_request PASSED [ 76%]
tests/unittests/tools/test_agent_tool.py::TestAgentToolWithCompositeAgents::test_sequential_agent_with_last_sub_agent_output_schema[VERTEX] PASSED [ 80%]
tests/unittests/tools/test_agent_tool.py::TestAgentToolWithCompositeAgents::test_nested_sequential_agent_input_schema PASSED [ 83%]
tests/unittests/tools/test_agent_tool.py::TestAgentToolWithCompositeAgents::test_sequential_agent_custom_schema_end_to_end[GOOGLE_AI] PASSED [ 86%]
tests/unittests/tools/test_agent_tool.py::TestAgentToolWithCompositeAgents::test_sequential_agent_custom_schema_end_to_end[VERTEX] PASSED [ 90%]
tests/unittests/tools/test_agent_tool.py::TestAgentToolWithCompositeAgents::test_empty_sequential_agent_falls_back_to_request PASSED [ 93%]
tests/unittests/tools/test_agent_tool.py::test_no_schema_non_request_args_serialized_as_json PASSED [ 96%]
tests/unittests/tools/test_agent_tool.py::test_no_schema_request_key_backward_compat PASSED [100%]

============================== warnings summary ===============================
tests/unittests/tools/test_agent_tool.py: 20 warnings
D:\coding\adk-python\src\google\adk\runners.py:250: DeprecationWarning: The `plugins` argument is deprecated. Please use the `app` argument to provide plugins instead.
  warnings.warn(

tests/unittests/tools/test_agent_tool.py::test_agent_tool_no_schema_with_json_schema_feature
D:\coding\adk-python\tests\unittests\tools\test_agent_tool.py:769: UserWarning: [WIP] feature FeatureName.JSON_SCHEMA_FOR_FUNC_DECL is enabled.
  declaration = agent_tool._get_declaration()

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
======================= 30 passed, 21 warnings in 5.44s =======================


Manual E2E Test:

Orchestrator agent (LiteLLM) called sub-agent via AgentTool with {"brand": "Nike", "product": "running shoes"}. After fix, pipeline completed     
successfully:

[orchestrator]: Here's a concise synthesis of Nike running shoes based on
the latest brand/product research...

No KeyError. Before fix, same call crashed at agent_tool.py:218.

Checklist

- I have read the CONTRIBUTING.md document.
- I have performed a self-review of my own code.
- I have added tests that prove my fix is effective or that my feature works.
- New and existing unit tests pass locally with my changes.
- I have manually tested my changes end-to-end.

Closes #1084 (KeyError half — the AttributeError half was fixed Nov 2025)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant