Skip to content

fix: populate required fields in FunctionDeclaration json_schema fallback#4812

Closed
giulio-leone wants to merge 2 commits intogoogle:mainfrom
giulio-leone:fix/required-fields-json-schema-fallback
Closed

fix: populate required fields in FunctionDeclaration json_schema fallback#4812
giulio-leone wants to merge 2 commits intogoogle:mainfrom
giulio-leone:fix/required-fields-json-schema-fallback

Conversation

@giulio-leone
Copy link
Copy Markdown

Summary

Fixes #4798required fields lost in FunctionDeclaration when the parameters_json_schema fallback path is used.

Root Cause

from_function_with_options() has two code paths for building function declarations:

  1. Primary path (parameters_properties): calls _get_required_fields()
  2. Fallback path (parameters_json_schema): triggered when _parse_schema_from_parameter raises ValueError for complex union types (e.g. list[str] | None) — never called _get_required_fields()

Additionally, the fallback path didn't propagate default values from inspect.Parameter to the generated Schema, so _get_required_fields() (which checks schema.default is None) would treat defaulted parameters as required.

Impact

The LLM sees all parameters as optional and may omit required ones. Observed in production: Gemini Flash omitted the mandatory query parameter when calling a tool, because the schema had no required field.

Fix

Three changes to the elif parameters_json_schema branch in from_function_with_options():

Change Purpose
Added _get_required_fields() call Populates required field (mirrors primary path)
Propagate non-None defaults to schema.default Ensures _get_required_fields() correctly excludes defaulted params
Set schema.nullable=True for None-default params Ensures _get_required_fields() correctly excludes nullable params

Test

Added regression test test_required_fields_set_in_json_schema_fallback that verifies:

  • query (no default) → required ✅
  • mode (default='default') → not required ✅
  • tags: list[str] | None = None → not required ✅

Full test suite: 4726 passed, 0 failures

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@google-cla
Copy link
Copy Markdown

google-cla bot commented Mar 13, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@adk-bot
Copy link
Copy Markdown
Collaborator

adk-bot commented Mar 13, 2026

Response from ADK Triaging Agent

Hello @giulio-leone, thank you for creating this PR!

Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). You can find more information at https://cla.developers.google.com/.

Thanks!

@adk-bot adk-bot added the tools [Component] This issue is related to tools label Mar 13, 2026
@rohityan rohityan self-assigned this Mar 13, 2026
@rohityan
Copy link
Copy Markdown
Collaborator

Hi @giulio-leone , Thank you for your contribution! It appears you haven't yet signed the Contributor License Agreement (CLA). Please visit https://cla.developers.google.com/ to complete the signing process. Once the CLA is signed, we'll be able to proceed with the review of your PR. Thank you!

@rohityan rohityan added the request clarification [Status] The maintainer need clarification or more information from the author label Mar 13, 2026
@giulio-leone giulio-leone force-pushed the fix/required-fields-json-schema-fallback branch from cd48cd4 to ed192a1 Compare March 14, 2026 20:08
@giulio-leone
Copy link
Copy Markdown
Author

@rohityan Thanks for the heads-up! I'll get the Google CLA signed. Will follow up once it's done.

@giulio-leone
Copy link
Copy Markdown
Author

I have signed the Google CLA. Could you please re-run the CLA check? Thank you!

@giulio-leone giulio-leone force-pushed the fix/required-fields-json-schema-fallback branch 2 times, most recently from 16dd249 to 9002a03 Compare March 15, 2026 16:03
@giulio-leone
Copy link
Copy Markdown
Author

Hi @rohityan — the CLA is now signed and passing ✅ (it was a Co-authored-by trailer issue that has been resolved). Ready for review!

@giulio-leone giulio-leone force-pushed the fix/required-fields-json-schema-fallback branch from 9d5c8cc to 8643f46 Compare March 17, 2026 21:52
@rohityan
Copy link
Copy Markdown
Collaborator

Hi @giulio-leone , our PR has been received by the team and is currently under review. We will provide feedback as soon as we have an update to share.

@rohityan rohityan added needs review [Status] The PR/issue is awaiting review from the maintainer and removed request clarification [Status] The maintainer need clarification or more information from the author labels Mar 17, 2026
@rohityan
Copy link
Copy Markdown
Collaborator

Hi @Jacksunwei , can you please review this. LGTM

@giulio-leone
Copy link
Copy Markdown
Author

Rebased this branch onto the latest main and force-pushed it.

Local validation I ran:

  • actual repo test file under Python 3.13 using a lightweight bootstrap that bypasses the heavyweight package init but still executes the real source modules: tests/unittests/tools/test_from_function_with_options.py -k 'required_fields_set_in_json_schema_fallback or collections_type_parameter or no_params' -q -> 3 passed\n\nReal branch-vs-main proof for the exact regression path (query: str, mode: str = "default", tags: list[str] | None = None):\n- main imported adk-python-main/src/google/adk/tools/_automatic_function_calling_util.py\n - required=[]\n - mode_default=null\n - tags_nullable=null\n- this branch imported adk-python/src/google/adk/tools/_automatic_function_calling_util.py\n - required=["query"]\n - mode_default="default"\n - tags_nullable=true\n\nSo on main the json-schema fallback path still loses the required/default/nullable metadata that the LLM needs, while this rebased branch restores the correct contract for the same runtime scenario.

@giulio-leone giulio-leone force-pushed the fix/required-fields-json-schema-fallback branch from 54906af to 2c8f536 Compare March 19, 2026 11:16
…back

When _parse_schema_from_parameter raises ValueError for complex union
types (e.g. list[str] | None), from_function_with_options falls back to
the parameters_json_schema branch. This branch was missing two things:

1. The _get_required_fields() call to populate declaration.parameters.required
2. Default value propagation from inspect.Parameter to Schema.default/nullable

Without these, the LLM sees all parameters as optional and may omit
required ones.

This fix:
- Adds _get_required_fields() to the elif branch (mirrors primary path)
- Propagates non-None defaults to schema.default
- Sets schema.nullable=True for parameters defaulting to None

Includes regression test with list[str] | None parameter type.

Fixes #4798
Clear the pyink failure on PR #4812 after validating the json_schema fallback behavior with targeted pytest and a runtime reproduction script.
@giulio-leone giulio-leone force-pushed the fix/required-fields-json-schema-fallback branch from 2c8f536 to 71720a0 Compare March 21, 2026 01:44
@giulio-leone
Copy link
Copy Markdown
Author

Refreshed this branch onto current origin/main and re-ran the gate from rebased head 71720a02.

Validation (two consecutive clean passes, no code changes between passes):

  • uv run --project /Users/giulioleone/Sviluppo/pr/work/adk-python-4812 --extra dev --extra test pyink --check src/google/adk/tools/_automatic_function_calling_util.py tests/unittests/tools/test_from_function_with_options.py
  • uv run --project /Users/giulioleone/Sviluppo/pr/work/adk-python-4812 --extra dev --extra test isort --check-only src/google/adk/tools/_automatic_function_calling_util.py tests/unittests/tools/test_from_function_with_options.py
  • uv run --project /Users/giulioleone/Sviluppo/pr/work/adk-python-4812 --extra dev --extra test pytest tests/unittests/tools/test_from_function_with_options.py -q
  • result: 16 passed on both passes
  • mypy diff check against current origin/main: branch errors 1342, main errors 1342, new errors introduced 0

Direct runtime proof for the actual fallback case from #4798 using:

complex_tool(query: str, mode: str = "default", tags: list[str] | None = None)
  • rebased branch: required == ["query"], mode_default == "default", tags_nullable == true
  • current origin/main: required == null, mode_default == null, tags_nullable == null

Worktree stayed clean after pass 2.

@giulio-leone
Copy link
Copy Markdown
Author

✅ Autonomous Validation — Pass 2/2 Clean

Branch: fix/required-fields-json-schema-fallback
HEAD: 71720a02
Rebased onto: current origin/main (0 commits behind)

Test Results (double-pass, no code changes between passes)

Pass Tests Result
1 16/16
2 16/16

Runner: python -m pytest <test_file> -v (Python venv)

Validated autonomously — double-pass strict protocol

@giulio-leone giulio-leone closed this by deleting the head repository Mar 25, 2026
giulio-leone added a commit to giulio-leone/adk-python that referenced this pull request Mar 30, 2026
Clear the pyink failure on PR google#4812 after validating the json_schema fallback behavior with targeted pytest and a runtime reproduction script.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs review [Status] The PR/issue is awaiting review from the maintainer tools [Component] This issue is related to tools

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: required fields lost in FunctionDeclaration when parameters_json_schema fallback is used

3 participants