Skip to content

fix: emit additional_properties with value type schema in dict branch - #5052

Closed
weiguangli-io wants to merge 1 commit into
google:mainfrom
weiguangli-io:fix/dict-schema-additional-properties-4868
Closed

weiguangli-io wants to merge 1 commit into
google:mainfrom
weiguangli-io:fix/dict-schema-additional-properties-4868

Conversation

@weiguangli-io

Copy link
Copy Markdown
Contributor

Summary

Fixes #4868

The dict origin branch in _parse_schema_from_parameter previously returned Schema(type=OBJECT) without any value type information for parameterized dict types like dict[str, str]. This caused Gemini to receive a bare {"type": "object"} with no field constraints, leading to:

  • Empty/blank tool arguments ([{}])
  • Infinite retry loops when combined with output_schema

Changes

  • _function_parameter_parse_util.py: When the dict type has 2 type args (key and value), parse the value type and set additional_properties on the schema. For example, dict[str, str] now emits {"type": "OBJECT", "additionalProperties": {"type": "STRING"}} instead of just {"type": "OBJECT"}.

  • test_build_function_declaration.py: Added tests for dict[str, str], dict[str, int], and list[dict[str, str]] to verify additional_properties is correctly set. Updated existing test_list to also assert on additional_properties for the dict items.

How it works

The fix follows the same pattern used by the list branch, which recursively calls _parse_schema_from_parameter on the element type to build schema.items. Similarly, the dict branch now recursively calls _parse_schema_from_parameter on the value type (args[1]) to build schema.additional_properties.

Test plan

  • Existing tests pass (40/40 in test_build_function_declaration.py)
  • New tests added for dict[str, str], dict[str, int], and list[dict[str, str]]
  • Manual verification with the reproduction script from the issue

…parameter

The dict origin branch in _parse_schema_from_parameter previously returned
Schema(type=OBJECT) without any value type information for parameterized
dict types like dict[str, str]. This caused Gemini to receive a bare
{"type": "object"} with no constraints, leading to empty tool arguments
and infinite retry loops when combined with output_schema.

Now the dict branch parses the value type argument and sets
additional_properties with the corresponding schema, so dict[str, V]
correctly emits {"type": "object", "additionalProperties": <V schema>}.

Fixes google#4868
@adk-bot adk-bot added the tools [Component] This issue is related to tools label Mar 29, 2026
@rohityan rohityan self-assigned this Mar 30, 2026
@rohityan

Copy link
Copy Markdown
Collaborator

Hi @weiguangli-io , Thank you for your contribution! We appreciate you taking the time to submit this pull request.
The _sanitize_schema_formats_for_gemini would likely delete the additional_properties added to _parse_schema_from_parameter.
Can you upload some screenshots/logs verifying the end to end testing and it won't get deleted.

@rohityan rohityan added the request clarification [Status] The maintainer need clarification or more information from the author label Mar 30, 2026
@weiguangli-io

Copy link
Copy Markdown
Contributor Author

@rohityan Thanks for the thorough review! I've investigated and here's the analysis:

_sanitize_schema_formats_for_gemini does intentionally strip additional_properties (line 167 in _gemini_schema_util.py), but this operates on a separate code path from the changes in this PR:

  1. _parse_schema_from_parameter (this PR's path) — constructs types.Schema objects directly. When build_function_declaration() is called, it returns types.Schema objects with additional_properties correctly set. This is the path used for automatic function calling.

  2. _to_gemini_schema → _sanitize_schema_formats_for_gemini — operates on JSON dict representations and strips additional_properties before sending to Gemini API, because Gemini rejects it. This is intentional and there's even an existing test (test_gemini_schema_util.py line 554) verifying this behavior.

These are independent paths. This PR adds additional_properties in path (1), which is correct — the types.Schema object carries the full schema information for automatic function calling. The Gemini sanitization in path (2) is a separate concern that only applies when converting schemas to Gemini's wire format.

Test evidence:

  • All 3 new tests in test_build_function_declaration.py verify additional_properties is correctly set on the types.Schema objects: dict[str, str] → STRING, dict[str, int] → INTEGER, list[dict[str, str]] → nested STRING.
  • The existing test_gemini_schema_util.py tests continue to pass, confirming no interference.

The behavior is consistent with how _parse_schema_from_parameter already handles other types.Schema fields that may later be filtered in the Gemini path.

copybara-service Bot pushed a commit that referenced this pull request Aug 6, 2026
@adk-bot

adk-bot commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Thank you @weiguangli-io for your contribution! 🎉

Your changes have been successfully imported and merged via Copybara in commit 93f57f4.

Closing this PR as the changes are now in the main branch.

@adk-bot adk-bot added the merged [Status] This PR is merged label Aug 6, 2026
@adk-bot adk-bot closed this Aug 6, 2026
FrigaZzz pushed a commit to FrigaZzz/adk-python that referenced this pull request Aug 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merged [Status] This PR is merged request clarification [Status] The maintainer need clarification or more information from the author tools [Component] This issue is related to tools

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Output_Schema + Tool with structured arg [List of object] causes blank tool input [{}] and infinite loop

3 participants