Bug Description
When passing a raw dict schema as output_schema to an LlmAgent, the SetModelResponseTool crashes with TypeError: unhashable type: 'dict' during function declaration generation.
Steps to Reproduce
from google.adk.agents import Agent
agent = Agent(
name="test",
model="gemini-2.5-flash",
instruction="You are a helpful agent.",
output_schema={"type": "object", "properties": {"result": {"type": "string"}}},
)
Running a query with this agent produces:
TypeError: unhashable type: 'dict'
Root Cause
In src/google/adk/tools/set_model_response_tool.py, the else branch (lines 90-99) handles non-BaseModel, non-list schemas by setting annotation=output_schema — i.e., the dict instance itself:
else:
params = [
inspect.Parameter(
'response',
inspect.Parameter.KEYWORD_ONLY,
annotation=output_schema, # <-- dict INSTANCE, e.g. {"type": "object", ...}
)
]
Later, in _function_parameter_parse_util.py line 140, _is_builtin_primitive_or_compound does:
return annotation in _py_builtin_type_to_schema_type.keys()
This calls __hash__ on the annotation, but dict instances aren't hashable, so it raises TypeError.
Expected Behavior
Raw dict schemas should work — SchemaType = types.SchemaUnion explicitly includes dict[Any, Any], and _schema_utils.py documents support for "Raw dict schemas".
Suggested Fix
Add an isinstance(output_schema, dict) branch in SetModelResponseTool.__init__ before the else fallthrough:
elif isinstance(output_schema, dict):
params = [
inspect.Parameter(
'response',
inspect.Parameter.KEYWORD_ONLY,
annotation=dict, # the TYPE, not the instance
)
]
This way _is_builtin_primitive_or_compound sees dict (the type, which is hashable and already mapped to types.Type.OBJECT in _py_builtin_type_to_schema_type).
Full Stack Trace
File "google/adk/flows/llm_flows/_output_schema_processor.py", line 54, in run_async
llm_request.append_tools([set_response_tool])
File "google/adk/models/llm_request.py", line 256, in append_tools
declaration = tool._get_declaration()
File "google/adk/tools/set_model_response_tool.py", line 116, in _get_declaration
build_function_declaration(
File "google/adk/tools/_automatic_function_calling_util.py", line 259, in build_function_declaration
from_function_with_options(func, variant)
File "google/adk/tools/_automatic_function_calling_util.py", line 340, in from_function_with_options
schema = _function_parameter_parse_util._parse_schema_from_parameter(
File "google/adk/tools/_function_parameter_parse_util.py", line 227, in _parse_schema_from_parameter
if _is_builtin_primitive_or_compound(param.annotation):
File "google/adk/tools/_function_parameter_parse_util.py", line 140, in _is_builtin_primitive_or_compound
return annotation in _py_builtin_type_to_schema_type.keys()
TypeError: unhashable type: 'dict'
Environment
- google-adk version: 1.31.1
- Python: 3.12
Bug Description
When passing a raw
dictschema asoutput_schemato anLlmAgent, theSetModelResponseToolcrashes withTypeError: unhashable type: 'dict'during function declaration generation.Steps to Reproduce
Running a query with this agent produces:
Root Cause
In
src/google/adk/tools/set_model_response_tool.py, theelsebranch (lines 90-99) handles non-BaseModel, non-list schemas by settingannotation=output_schema— i.e., the dict instance itself:Later, in
_function_parameter_parse_util.pyline 140,_is_builtin_primitive_or_compounddoes:This calls
__hash__on the annotation, but dict instances aren't hashable, so it raisesTypeError.Expected Behavior
Raw dict schemas should work —
SchemaType = types.SchemaUnionexplicitly includesdict[Any, Any], and_schema_utils.pydocuments support for "Raw dict schemas".Suggested Fix
Add an
isinstance(output_schema, dict)branch inSetModelResponseTool.__init__before theelsefallthrough:This way
_is_builtin_primitive_or_compoundseesdict(the type, which is hashable and already mapped totypes.Type.OBJECTin_py_builtin_type_to_schema_type).Full Stack Trace
Environment