Skip to content

fix(agent_tool): wrap input_schema payload in ReAct prompt and propagate tool_choice to LiteLLM#5924

Open
ecanlar wants to merge 7 commits into
google:mainfrom
ecanlar:fix/agent-tool-input-schema-tool-choice-litellm
Open

fix(agent_tool): wrap input_schema payload in ReAct prompt and propagate tool_choice to LiteLLM#5924
ecanlar wants to merge 7 commits into
google:mainfrom
ecanlar:fix/agent-tool-input-schema-tool-choice-litellm

Conversation

@ecanlar
Copy link
Copy Markdown

@ecanlar ecanlar commented Jun 1, 2026

Summary

Fixes two issues that prevent Claude-family models from entering the ReAct tool-calling loop when used via LiteLLM inside a nested AgentTool:

  1. AgentTool with input_schema — the serialized JSON payload sent as the first message causes Claude to interpret the request as already complete and respond directly without calling any tools.
  2. tool_choice not propagatedllm_request.config.tool_config.function_calling_config.mode was not forwarded to LiteLLM's completion_args, so callers could not enforce tool use at the request level.

Changes

src/google/adk/tools/agent_tool.py

Wrap the serialized input_schema JSON in a natural-language instruction that explicitly asks the inner agent to use its available tools before producing a response. This keeps Claude in ReAct mode regardless of the message content format.

src/google/adk/models/lite_llm.py

Read llm_request.config.tool_config.function_calling_config.mode and map it to LiteLLM's tool_choice parameter:

  • ANY"required"
  • NONE"none"
  • AUTO → provider default (unchanged, key omitted from completion_args)

_get_completion_inputs now returns a 5-tuple (messages, tools, response_format, generation_params, tool_choice).

Unit Tests Added

tests/unittests/tools/test_agent_tool.py

  • test_run_async_no_input_schema_passes_request_unchanged: without input_schema, the content passed to the inner runner is args['request'] verbatim.
  • test_run_async_with_input_schema_wraps_in_natural_language: with input_schema, the text begins with "Process the following structured request", contains "Request:\n" followed by the JSON payload, and is not a bare JSON blob.
  • test_run_async_with_input_schema_text_not_raw_json: asserts the text does not start with {.

tests/unittests/models/test_litellm.py

  • test_get_completion_inputs_tool_choice_none_without_tool_config: tool_choice is None with no tool_config.
  • test_get_completion_inputs_tool_choice_required_for_any_mode: returns "required" for ANY mode.
  • test_get_completion_inputs_tool_choice_none_for_none_mode: returns "none" for NONE mode.
  • test_get_completion_inputs_tool_choice_none_for_auto_mode: returns None for AUTO mode.
  • test_generate_content_async_propagates_tool_choice_required: acompletion receives tool_choice="required" for ANY.
  • test_generate_content_async_propagates_tool_choice_none_mode: acompletion receives tool_choice="none" for NONE.
  • test_generate_content_async_omits_tool_choice_for_auto_mode: tool_choice key absent from completion_args for AUTO.
  • test_generate_content_async_omits_tool_choice_without_tool_config: tool_choice key absent when no tool_config.

Also updated all existing _get_completion_inputs call sites (10 occurrences) to unpack the new 5-tuple.

Pytest Results

tests/unittests/tools/test_agent_tool.py + tests/unittests/models/test_litellm.py
1 failed (pre-existing: test_custom_schema[GOOGLE_AI] — unrelated to this PR),
302 passed, 1 skipped in 2.98s

New tests: 11 passed (3 agent_tool + 8 litellm)

The 1 pre-existing failure (test_custom_schema[GOOGLE_AI]) is a pydantic.ValidationError that reproduces on the base branch before any of these changes and is unrelated to this fix.

Related

…ol_choice to LiteLLM

When AgentTool uses input_schema, the inner agent receives a raw JSON blob
that causes Claude models to skip the tool-calling loop (ReAct). Fix by
wrapping the payload in a natural-language instruction.

Also propagate tool_config.function_calling_config.mode to LiteLLM's
tool_choice parameter so callers can enforce tool_choice='required'.
Addresses google#773.

Fixes: google#5926
@ecanlar ecanlar force-pushed the fix/agent-tool-input-schema-tool-choice-litellm branch from ded18ca to 6168c49 Compare June 1, 2026 09:51
@adk-bot adk-bot added models [Component] Issues related to model support tools [Component] This issue is related to tools labels Jun 1, 2026
@adk-bot
Copy link
Copy Markdown
Collaborator

adk-bot commented Jun 1, 2026

Response from ADK Triaging Agent

Hello @ecanlar, thank you for creating this PR!

We appreciate your contribution to fixing the LiteLLM/Claude AgentTool issue. To help our reviewers process this pull request more efficiently, please ensure it complies with our contribution guidelines.

Currently, the following items are missing:

  1. Unit Tests: The PR modifies behavior in lite_llm.py and agent_tool.py, but does not add or update any unit tests (e.g., under tests/unittests/). Please add unit tests covering the new tool wrapping and tool_choice behavior.
  2. Pytest Results Summary: Please run the tests and include a summary of the passed pytest or tox results in the PR description.
  3. Logs/Screenshots: Please provide console logs or screenshots demonstrating that the inner agent successfully enters the ReAct loop and calls tools after applying the fix.

Providing this information helps ensure high code quality, prevents future regressions, and makes the review process smoother. Thank you!

…tool_choice propagation

- Update existing _get_completion_inputs call sites to handle new 5-tuple
  return value (adds tool_choice as 5th element)
- Add 3 tests for AgentTool.run_async: verifies message is passed verbatim
  without input_schema, and is wrapped in a natural-language instruction
  with input_schema (PR google#5924 fix)
- Add 8 tests for LiteLLM tool_choice propagation: covers _get_completion_inputs
  returning correct tool_choice for ANY/NONE/AUTO modes and None when no
  tool_config; covers generate_content_async correctly including/omitting
  tool_choice in completion_args
rohityan and others added 2 commits June 1, 2026 19:11
- Fix: only apply the ReAct wrapper in agent_tool.py when output_schema is not set on the inner agent, preventing breaking of single-shot structured output mode
- Add regression test test_run_async_with_input_and_output_schema_passes_raw_json documenting that raw JSON is passed when both input_schema and output_schema are set
- Apply pre-commit formatting fixes (isort + pyink)
@ecanlar ecanlar force-pushed the fix/agent-tool-input-schema-tool-choice-litellm branch from 23d582a to 67d087a Compare June 2, 2026 09:44
ecanlar and others added 2 commits June 3, 2026 08:26
…st HTTP call

Move the ValueError from module import time to the lazy _get_session()
factory so that importing the package (e.g. pytest collection) does not
fail in environments where GITHUB_TOKEN is not set.
@ecanlar ecanlar force-pushed the fix/agent-tool-input-schema-tool-choice-litellm branch from f8c61e3 to 7c23d83 Compare June 5, 2026 11:05
@ecanlar
Copy link
Copy Markdown
Author

ecanlar commented Jun 5, 2026

Good catch — confirmed the guard was not in place. tool_choice and tools were derived from two independent config fields (config.tool_config and config.tools) with no cross-check, so a caller setting mode=ANY with no function_declarations would reach acompletion() with tools=None, tool_choice="required" — exactly the combination LiteLLM rejects.

Fixed in the latest commit:

  • _get_completion_inputs: coerce tool_choice to None when tools is falsy before returning.
  • generate_content_async: null tool_choice alongside tools inside the "functions" additional-arg branch.

Two new tests cover both paths; 10 tool_choice tests passing.

@rohityan
Copy link
Copy Markdown
Collaborator

rohityan commented Jun 5, 2026

Hi @ecanlar , Thank you for your contribution! We appreciate you taking the time to submit this pull request.

@rohityan
Copy link
Copy Markdown
Collaborator

rohityan commented Jun 5, 2026

/adk-pr-analyze

@rohityan rohityan added request clarification [Status] The maintainer need clarification or more information from the author and removed request clarification [Status] The maintainer need clarification or more information from the author labels Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

models [Component] Issues related to model support tools [Component] This issue is related to tools

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: AgentTool with input_schema + LiteLLM/Claude skips inner agent tool calls

3 participants