Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
13 changes: 10 additions & 3 deletions src/google/adk/tools/_function_tool_declarations.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,12 @@ def _get_function_fields(
# Get type hints with forward reference resolution
try:
type_hints = get_type_hints(func)
except TypeError:
# Can happen with mock objects or complex annotations
except (TypeError, NameError, AttributeError):
# TypeError can happen with mock objects or complex annotations. NameError
# / AttributeError happen when an annotation is an unresolvable forward
# reference at runtime, e.g. a type imported only under `if TYPE_CHECKING:`
# (common for the context parameter, which is excluded from the schema
# anyway). Fall back to the raw per-parameter annotations below.
type_hints = {}

for name, param in sig.parameters.items():
Expand Down Expand Up @@ -145,7 +149,10 @@ def _build_response_json_schema(
try:
type_hints = get_type_hints(func)
return_annotation = type_hints.get('return', return_annotation)
except TypeError:
except (TypeError, NameError, AttributeError):
# An unresolvable parameter annotation (e.g. a `TYPE_CHECKING`-only
# import) must not block resolving the return type; fall back to the
# raw return annotation, which pydantic resolves below.
pass

# Handle AsyncGenerator and Generator return types (streaming tools)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@

from typing import Any
from typing import Dict
from typing import TYPE_CHECKING

from google.adk.tools import _automatic_function_calling_util
from google.adk.tools.function_tool import FunctionTool
from google.adk.utils.variant_utils import GoogleLLMVariant
from google.genai import types
import pydantic

if TYPE_CHECKING:
from google.adk.tools.tool_context import ToolContext


def test_string_annotation_none_return_vertex():
"""Test function with string annotation 'None' return for VERTEX_AI."""
Expand Down Expand Up @@ -229,3 +233,25 @@ def function_with_list(items: list[ItemModel]) -> int:
assert processed_args['items'][0].name == 'Burger'
assert processed_args['items'][0].quantity == 10
assert processed_args['items'][1].quantity == 5


def test_type_checking_only_context_annotation_builds_declaration():
"""A context parameter annotated with a TYPE_CHECKING-only import must not
break declaration building for the remaining parameters."""

def test_function(x: int, tool_context: ToolContext) -> str:
"""A tool with a context parameter.

Args:
x: a number.
"""
return str(x)

declaration = FunctionTool(test_function)._get_declaration()

assert declaration.name == 'test_function'
schema = declaration.parameters_json_schema
# The real parameter is described, the context parameter is excluded.
assert 'x' in schema['properties']
assert 'tool_context' not in schema['properties']
assert schema['required'] == ['x']
Loading