You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Legacy function declaration path raises NameError for a context param typed with a TYPE_CHECKING-only import #7436
With JSON_SCHEMA_FOR_FUNC_DECL disabled, a FunctionTool whose context parameter is typed with a TYPE_CHECKING-only import fails to build its declaration:
NameError: name 'ToolContext' is not defined
This is the same pattern #6488 reported, and 2ecb3fb fixed it on the JSON-schema path. The legacy path still fails, for a different reason. build_function_declaration removes the ignored params (tool_context) from the signature, then copies all of the original __annotations__ onto the new function:
from_function_with_options then calls typing.get_type_hints(new_func), which resolves every annotation, including the one for the param that was just removed.
Run ADK_DISABLE_JSON_SCHEMA_FOR_FUNC_DECL=1 python repro.py.
weather_tools.py
from __future__ importannotationsfromtypingimportTYPE_CHECKINGifTYPE_CHECKING:
fromgoogle.adk.tools.tool_contextimportToolContextdefget_weather(city: str, tool_context: ToolContext) ->str:
"""Returns the weather for a city."""tool_context.state['last_city'] =cityreturnf'Sunny in {city}'
The declaration builds with a single city parameter, as it does on the default JSON-schema path. tool_context is excluded from the schema, so its annotation never needs to resolve.
Observed Behavior:
File ".../google/adk/tools/_automatic_function_calling_util.py", line 350, in from_function_with_options
annotation_under_future = typing.get_type_hints(func)
...
NameError: name 'ToolContext' is not defined
An agent using this tool fails on its first model request.
Environment Details:
ADK Library Version (pip show google-adk): 2.11.0 (main @ 77d4dcd)
Desktop OS: macOS 26.5
Python Version (python -V): 3.12.13
Model Information:
Are you using LiteLLM: No
Which model is being used: N/A (the failure happens while building the tool declaration, before any model call)
🟡 Optional Information
Additional Context:
The fix doesn't need to catch NameError. The comment above that get_type_hints call says leaving it uncaught is deliberate, and an unresolvable annotation on a param that is declared should still raise. It's enough to copy only the kept params' annotations (and return) onto the stripped function. I have a PR ready that does that, with tests for both declaration paths. The JSON-schema-path test also pins 2ecb3fb, which has no test today (noted in #6488 (comment)).
How often has this issue occurred?:
Always (100%) with JSON_SCHEMA_FOR_FUNC_DECL disabled.
Reproduced this on 2.11.0 with ADK_DISABLE_JSON_SCHEMA_FOR_FUNC_DECL=1 @Akshaay1 and your read on the root cause matches what I'm seeing.
Filtering the annotations down to the kept params (plus return) before get_type_hints worked in my local test so that looks like the right direction. Until it lands importing ToolContext at runtime or leaving the JSON-schema path enabled should get you unblocked.
Since #7437 is already up could you give it one more pass against a real agent run on both paths and confirm everything holds? Once you're happy with it we'll get it in front of the maintainers for review.
Thanks for reproducing it @surajksharma07. I did another pass on #7437 merged onto current main (ea656b0), which merges cleanly.
Agent run: an LlmAgent with the get_weather tool from the issue, through InMemoryRunner. A scripted BaseLlm calls the tool once and then answers. Everything except the model call is the real code path: declaration building, function call, tool execution with tool_context injected, the follow-up request, and the session write. I don't have model credentials on this machine, so it didn't call live Gemini.
In all four runs the tool is declared with only city on both model requests, it returns {'result': 'Sunny in Paris'}, the agent finishes, and session.state['last_city'] == 'Paris', so tool_context still reaches the tool. On main without the fix, the legacy path still fails with NameError: name 'ToolContext' is not defined, and the JSON-schema path is unchanged.
tests/unittests/tools and tests/unittests/flows on the merged tree: 3872 passed, 1 skipped.
Checked #7437 on current main (ea656b0) @Akshaay1. It merges cleanly, your 16 tests pass and an InMemoryRunner run with a scripted model gives only city in the declaration on both paths with last_city written to state. Main without the fix still hits the NameError on the legacy path.
Also like that the declared-param test keeps the NameError deliberate rather than swallowing it.
#7447 has the same one-line fix but also includes an unrelated a2a commit so #7437 looks like the cleaner one to move forward with. @xuanyang15 could you take a look when you get a chance?
Activity
surajksharma07 commentedon Oct 8, 2026
Reproduced this on 2.11.0 with ADK_DISABLE_JSON_SCHEMA_FOR_FUNC_DECL=1 @Akshaay1 and your read on the root cause matches what I'm seeing.
Filtering the annotations down to the kept params (plus return) before get_type_hints worked in my local test so that looks like the right direction. Until it lands importing ToolContext at runtime or leaving the JSON-schema path enabled should get you unblocked.
Since #7437 is already up could you give it one more pass against a real agent run on both paths and confirm everything holds? Once you're happy with it we'll get it in front of the maintainers for review.
Akshaay1 commentedon Oct 8, 2026
Thanks for reproducing it @surajksharma07. I did another pass on #7437 merged onto current
main(ea656b0), which merges cleanly.Agent run: an
LlmAgentwith theget_weathertool from the issue, throughInMemoryRunner. A scriptedBaseLlmcalls the tool once and then answers. Everything except the model call is the real code path: declaration building, function call, tool execution withtool_contextinjected, the follow-up request, and the session write. I don't have model credentials on this machine, so it didn't call live Gemini.ADK_DISABLE_JSON_SCHEMA_FOR_FUNC_DECL=1)In all four runs the tool is declared with only
cityon both model requests, it returns{'result': 'Sunny in Paris'}, the agent finishes, andsession.state['last_city'] == 'Paris', sotool_contextstill reaches the tool. Onmainwithout the fix, the legacy path still fails withNameError: name 'ToolContext' is not defined, and the JSON-schema path is unchanged.tests/unittests/toolsandtests/unittests/flowson the merged tree: 3872 passed, 1 skipped.Ready for maintainer review from my side.
surajksharma07 commentedon Oct 8, 2026
Checked #7437 on current main (ea656b0) @Akshaay1. It merges cleanly, your 16 tests pass and an InMemoryRunner run with a scripted model gives only city in the declaration on both paths with last_city written to state. Main without the fix still hits the NameError on the legacy path.
Also like that the declared-param test keeps the NameError deliberate rather than swallowing it.
#7447 has the same one-line fix but also includes an unrelated a2a commit so #7437 looks like the cleaner one to move forward with. @xuanyang15 could you take a look when you get a chance?
fix: skip ignored params' annotations on the legacy declaration path