Annotated parameters breaks `_preprocess_args` when using recursive type aliases or any unresolvable forward reference
- Dominant language
- Python
- Stars
- 21.5k
- Forks
- 4k
- Avg merge
- 1d 14h
- Merged PRs (30d)
- 37
Description
## 🔴 Required Information
**Describe the Bug:**
Annotated parameters breaks `_preprocess_args` when using recursive type aliases or any unresolvable forward reference on the fallback path when we are unable to `get_type_hints()` in `src/google/adk/tools/function_tool.py`, fixed by PR: https://github.com/google/adk-python/pull/6879
**Steps to Reproduce:**
1. Declare a tool containing parameter with a recursive type:
```python
def get_tools() -> list[FunctionTool}:
Recursive = Union[int, str, list["Recursive"]]
def fn(
user: Annotated[UserModel, Field(description="A user")],
data: Recursive = None,
) -> dict:
return {"name": user.name, "type": type(user).__name__}
```
2. Try and call the tool
**Expected Behavior:**
`user` is converted to a `UserModel` instance before the function runs (as it is on the normal path where `get_type_hints()` succeeds and strips the `Annotated` wrapper). The tool executes and returns:
```python
{"name": "Alice", "type": "UserModel"}
```
**Observed Behavior:**
`get_type_hints()` raises `NameError`, so `_preprocess_args` falls back to the raw `param.annotation`, which is still `Annotated[UserModel, ...]`wrapped. None of the conversion branches recognise the wrapper, so the dict is passed through unconverted:
```python
# tool._preprocess_args({"user": {"name": "Alice", "age": 30}})
{'user': {'name': 'Alice', 'age': 30}} # still a dict, not a UserModel
```
When the tool body then accesses `user.name`, it raises:
```
Traceback (most recent call last):
...
File "src/google/adk/tools/function_tool.py", line 353, in run_async
return await self._invoke_callable(self.func, args_to_call)
File "src/google/adk/tools/function_tool.py", line 378, in _invoke_callable
return target(**args_to_call)
File ".../your_tool.py", line 19, in fn
return {"name": user.name, "type": type(user).__name__}
^^^^^^^^^
AttributeError: 'dict' object has no attribute 'name'
```
(The line numbers in `function_tool.py` are relative to the current `main`.)
**Environment Details:**
- ADK Library Version: 2.7.1
- Desktop OS: MacOS
- Python Version: 3.13
**Model Information:**
- Are you using LiteLLM: No
- Which model is being used: gemini-3.7-flash
---
## 🟡 Optional Information
**Regression:**
Not a regression.
**How often has this issue occurred?:**
- Always (100%)
Contributor guide
Assessment
This issue has not been assessed yet.