Skip to content

Commit 5b06baf

Browse files
google-genai-botcopybara-github
authored andcommitted
fix: retry TypeAdapter creation without config if it fails
PiperOrigin-RevId: 927430716
1 parent 1d055e3 commit 5b06baf

3 files changed

Lines changed: 44 additions & 4 deletions

File tree

src/google/adk/tools/_function_tool_declarations.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,21 @@ def _build_response_json_schema(
162162
return_annotation = type_args[0]
163163

164164
try:
165-
adapter = pydantic.TypeAdapter(
166-
return_annotation,
167-
config=pydantic.ConfigDict(arbitrary_types_allowed=True),
168-
)
165+
try:
166+
adapter = pydantic.TypeAdapter(
167+
return_annotation,
168+
config=pydantic.ConfigDict(arbitrary_types_allowed=True),
169+
)
170+
except pydantic.PydanticUserError as e:
171+
# If it failed, maybe it was because of the config argument (e.g. for dataclasses).
172+
# Retry without config.
173+
logging.debug(
174+
'Failed to build schema with config, retrying without config for'
175+
' %s: %s',
176+
func.__name__,
177+
e,
178+
)
179+
adapter = pydantic.TypeAdapter(return_annotation)
169180
return adapter.json_schema()
170181
except Exception:
171182
logging.warning(

tests/unittests/tools/BUILD

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,12 @@ pytest_test(
4444
"//third_party/py/pytest_asyncio",
4545
],
4646
)
47+
48+
pytest_test(
49+
name = "test_function_tool_declarations",
50+
srcs = ["test_function_tool_declarations.py"],
51+
deps = [
52+
"//third_party/py/absl/testing:parameterized",
53+
"//third_party/py/google/adk",
54+
],
55+
)

tests/unittests/tools/test_function_tool_declarations.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from __future__ import annotations
2222

2323
from collections.abc import Sequence
24+
import dataclasses
2425
from enum import Enum
2526
from typing import Any
2627
from typing import AsyncGenerator
@@ -76,6 +77,13 @@ class Window:
7677
height: int
7778

7879

80+
@dataclasses.dataclass
81+
class StandardReturnDataclass:
82+
"""A standard library dataclass for testing."""
83+
84+
status: str
85+
86+
7987
class TestBasicTypes(parameterized.TestCase):
8088
"""Tests for basic Python types."""
8189

@@ -618,6 +626,18 @@ def save_addresses(addresses: list[Address]) -> int:
618626
},
619627
)
620628

629+
def test_returns_standard_dataclass(self):
630+
"""Test function that returns a standard library dataclass."""
631+
632+
def get_status() -> StandardReturnDataclass:
633+
return StandardReturnDataclass(status="ok")
634+
635+
decl = build_function_declaration_with_json_schema(get_status)
636+
637+
self.assertIsNotNone(decl.response_json_schema)
638+
self.assertEqual(decl.response_json_schema["type"], "object")
639+
self.assertIn("status", decl.response_json_schema["properties"])
640+
621641

622642
class TestSpecialCases(parameterized.TestCase):
623643
"""Tests for special cases and edge cases."""

0 commit comments

Comments
 (0)