Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/google/adk/tools/_automatic_function_calling_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,15 @@ def from_function_with_options(
type='OBJECT',
properties=parameters_json_schema,
)
# Determine required fields from the function signature directly.
# _get_required_fields() relies on nullable/default metadata in Schema
# objects, which is not preserved by the json_schema fallback path.
declaration.parameters.required = [
name
for name, param in inspect.signature(func).parameters.items()
if name in parameters_json_schema
and param.default is inspect.Parameter.empty
]

if variant == GoogleLLMVariant.GEMINI_API:
return declaration
Expand Down
38 changes: 38 additions & 0 deletions tests/unittests/tools/test_from_function_with_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,41 @@ async def test_function(param: str) -> AsyncGenerator[Dict[str, str], None]:
# VERTEX_AI should extract yield type (Dict[str, str]) from AsyncGenerator
assert declaration.response is not None
assert declaration.response.type == types.Type.OBJECT


def test_from_function_with_options_required_fields_with_complex_union():
"""Test that required fields are set when complex union types trigger the json_schema fallback.

Regression test for https://github.com/google/adk-python/issues/4798

When a function has parameters with types that cause
_parse_schema_from_parameter to raise ValueError (e.g. list[str] | None),
from_function_with_options falls back to the parameters_json_schema path.
This fallback must still set the `required` field for parameters that have
no default value.
"""

def tool_with_complex_types(
query: str,
mode: str = 'default',
tags: list[str] | None = None,
) -> str:
"""A tool with a required param and a complex union type param."""
return query

declaration = _automatic_function_calling_util.from_function_with_options(
tool_with_complex_types, GoogleLLMVariant.GEMINI_API
)

assert declaration.name == 'tool_with_complex_types'
assert declaration.parameters is not None
assert declaration.parameters.type == 'OBJECT'
assert 'query' in declaration.parameters.properties
assert 'mode' in declaration.parameters.properties
assert 'tags' in declaration.parameters.properties
# The critical assertion: `query` must be in required because it has no default
assert declaration.parameters.required is not None
assert 'query' in declaration.parameters.required
# `mode` and `tags` have defaults, so they must NOT be required
assert 'mode' not in declaration.parameters.required
assert 'tags' not in declaration.parameters.required
Loading