Visitar URL original
Legacy function declaration path raises NameError for a context param typed with a TYPE_CHECKING-only import · Issue #7436 · google/adk-python · GitHub
Skip to content

Legacy function declaration path raises NameError for a context param typed with a TYPE_CHECKING-only import #7436

Description

@Akshaay1

🔴 Required Information

Describe the Bug:

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:

https://github.com/google/adk-python/blob/77d4dcd0/src/google/adk/tools/_automatic_function_calling_util.py#L275

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.

Steps to Reproduce:

  1. Install google-adk 2.11.0 (or main @ 77d4dcd).
  2. Save the two files below.
  3. Run ADK_DISABLE_JSON_SCHEMA_FOR_FUNC_DECL=1 python repro.py.

weather_tools.py

from __future__ import annotations

from typing import TYPE_CHECKING

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


def get_weather(city: str, tool_context: ToolContext) -> str:
  """Returns the weather for a city."""
  tool_context.state['last_city'] = city
  return f'Sunny in {city}'

repro.py

from google.adk.tools.function_tool import FunctionTool

from weather_tools import get_weather

print(FunctionTool(get_weather)._get_declaration())

Expected Behavior:

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.

Activity

  1. surajksharma07 commented on Oct 8, 2026

    @surajksharma07
    Collaborator

    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.

  2. Akshaay1 commented on Oct 8, 2026

    @Akshaay1
    Author

    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.

    Gemini API Vertex AI
    JSON-schema path (default) ✅ ✅
    Legacy path (ADK_DISABLE_JSON_SCHEMA_FOR_FUNC_DECL=1) ✅ ✅

    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.

    Ready for maintainer review from my side.

  3. surajksharma07 commented on Oct 8, 2026

    @surajksharma07
    Collaborator

    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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

tools[Component] This issue is related to tools

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions