Skip to content

fix(tools): handle optional and union pydantic models with string annotations in FunctionTool#6471

Open
hsusul wants to merge 1 commit into
google:mainfrom
hsusul:fix/function-tool-optional-pydantic-annotations
Open

fix(tools): handle optional and union pydantic models with string annotations in FunctionTool#6471
hsusul wants to merge 1 commit into
google:mainfrom
hsusul:fix/function-tool-optional-pydantic-annotations

Conversation

@hsusul

@hsusul hsusul commented Jul 24, 2026

Copy link
Copy Markdown

Problem

In FunctionTool._preprocess_args, parameter type inspection checked param.annotation (from inspect.signature) directly rather than target_type (resolved via get_type_hints). When from __future__ import annotations (or string annotations) is used, param.annotation is a str, causing get_origin(param.annotation) to evaluate to None. Consequently, FunctionTool failed to convert dictionary arguments into pydantic.BaseModel instances for functions with Optional[BaseModel], BaseModel | None, or Optional[list[BaseModel]] parameter annotations, leaving parameters as raw dict objects and causing runtime AttributeErrors inside the tool functions.

Solution

  • Updated FunctionTool._preprocess_args to inspect target_type (from get_type_hints) for typing.Union and types.UnionType origins.
  • Unwrapped single non-None types from union types so that both BaseModel and list[BaseModel] parameters are properly identified and converted into Pydantic model instances regardless of string annotations or PEP 604 union syntax (|).

Testing Plan

Added unit tests in tests/unittests/tools/test_function_tool_with_import_annotations.py:

  • test_preprocess_args_with_optional_pydantic_model_and_annotations
  • test_preprocess_args_with_pipe_union_pydantic_model_and_annotations
  • test_preprocess_args_with_optional_list_of_pydantic_models_and_annotations

All tests pass cleanly:

uv run pytest tests/unittests/tools/test_function_tool*.py
uv run pre-commit run --files src/google/adk/tools/function_tool.py tests/unittests/tools/test_function_tool_with_import_annotations.py

…otations in FunctionTool

In FunctionTool._preprocess_args, parameter type resolution was inspecting param.annotation directly instead of the target_type hint resolved by get_type_hints. When from __future__ import annotations (or string annotations) is used, param.annotation is a string, causing get_origin(param.annotation) to return None and skip converting dict arguments to Pydantic BaseModel instances for Optional[BaseModel] or BaseModel | None parameters.

This fixes the issue by:
- Inspecting target_type (from get_type_hints) for Union and UnionType origins
- Correctly unwrapping single non-None types so Pydantic BaseModel and list[BaseModel] parameters are preprocessed into model instances regardless of string annotations or PEP 604 union syntax.
@adk-bot adk-bot added the tools [Component] This issue is related to tools label Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tools [Component] This issue is related to tools

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants