Skip to content

Commit cd48cd4

Browse files
giulio-leoneCopilot
andcommitted
fix: populate required fields in FunctionDeclaration json_schema fallback
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 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 31b005c commit cd48cd4

File tree

2 files changed

+43
-0
lines changed

2 files changed

+43
-0
lines changed

src/google/adk/tools/_automatic_function_calling_util.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,11 @@ def from_function_with_options(
368368
parameters_json_schema[name] = types.Schema.model_validate(
369369
json_schema_dict
370370
)
371+
if param.default is not inspect.Parameter.empty:
372+
if param.default is not None:
373+
parameters_json_schema[name].default = param.default
374+
else:
375+
parameters_json_schema[name].nullable = True
371376
except Exception as e:
372377
_function_parameter_parse_util._raise_for_unsupported_param(
373378
param, func.__name__, e
@@ -392,6 +397,11 @@ def from_function_with_options(
392397
type='OBJECT',
393398
properties=parameters_json_schema,
394399
)
400+
declaration.parameters.required = (
401+
_function_parameter_parse_util._get_required_fields(
402+
declaration.parameters
403+
)
404+
)
395405

396406
if variant == GoogleLLMVariant.GEMINI_API:
397407
return declaration

tests/unittests/tools/test_from_function_with_options.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,36 @@ async def test_function(param: str) -> AsyncGenerator[Dict[str, str], None]:
319319
# VERTEX_AI should extract yield type (Dict[str, str]) from AsyncGenerator
320320
assert declaration.response is not None
321321
assert declaration.response.type == types.Type.OBJECT
322+
323+
324+
def test_required_fields_set_in_json_schema_fallback():
325+
"""Test that required fields are populated when the json_schema fallback path is used.
326+
327+
When a parameter has a complex union type (e.g. list[str] | None) that
328+
_parse_schema_from_parameter can't handle, from_function_with_options falls
329+
back to the parameters_json_schema branch. This test verifies that the
330+
required fields are correctly populated in that fallback branch.
331+
332+
Regression test for https://github.com/google/adk-python/issues/4798
333+
"""
334+
335+
def complex_tool(
336+
query: str,
337+
mode: str = "default",
338+
tags: list[str] | None = None,
339+
) -> str:
340+
"""A tool where one param has a complex union type."""
341+
return query
342+
343+
declaration = _automatic_function_calling_util.from_function_with_options(
344+
complex_tool, GoogleLLMVariant.GEMINI_API
345+
)
346+
347+
assert declaration.name == 'complex_tool'
348+
assert declaration.parameters.type == 'OBJECT'
349+
# 'query' has no default → must be required
350+
assert declaration.parameters.required is not None
351+
assert 'query' in declaration.parameters.required
352+
# 'mode' and 'tags' have defaults → must NOT be required
353+
assert 'mode' not in declaration.parameters.required
354+
assert 'tags' not in declaration.parameters.required

0 commit comments

Comments
 (0)