Repository navigation
Description
🔴 Required Information
Describe the Bug:
When an LlmAgent has output_schema and its model is Gemini(use_interactions_api=True), the schema never reaches the request. ADK puts it in llm_request.config.response_schema, but the Interactions request builder doesn't read that field. The model's output is unconstrained, and nothing raises an error or logs a warning.
This applies to:
- Agents with
output_schemaand no tools, on Vertex AI and on the Gemini Developer API. - Agents with
output_schemaand tools, on Vertex AI.Gemini.capabilities.output_schema_and_toolsisTrueon Vertex (_capabilities.py#L48-L51). That makesbasic.pycallset_output_schema()(basic.py#L138-L143), and theset_model_responsefallback is skipped (_schema.py#L67-L72). The schema goes intoconfig.response_schema, and the Interactions path drops it there too.
Only one combination keeps its schema: tools on the Gemini Developer API. There the capability is False, so set_model_response is added as a function tool.
Where the schema is dropped (src/google/adk/models/interactions_utils.py on main):
generate_content_via_interactionsbuildscreate_kwargsfrom onlymodel,input,system_instruction,tools,generation_configandprevious_interaction_id, plusservice_tier/background(L1932-L1947).build_generation_configcopies onlymax_output_tokens,stop_sequences,seedand the sampling params (L1373-L1403).config.response_schema,config.response_json_schemaandconfig.response_mime_typeare never read, and noresponse_formatis sent. The schema also doesn't appear in the system instruction.
The Interactions API does support this. In google-genai 2.31.0, interactions.create() declares response_format (a ResponseFormatParam or a list of them) and response_mime_type. TextResponseFormatParam has the fields type: "text", mime_type and schema_ (schema on the wire). For example:
"response_format": {"type": "text", "mime_type": "application/json", "schema": {...}}Steps to Reproduce:
The repro below runs offline. It swaps in a fake client that records the kwargs passed to aio.interactions.create() and then raises.
- Install:
pip install google-adk==2.13.0 google-genai==2.31.0 - Save the script below as
repro.py. - Run
GOOGLE_GENAI_USE_VERTEXAI=1 GOOGLE_CLOUD_PROJECT=p GOOGLE_CLOUD_LOCATION=global python repro.py(no tool), then the same command with atoolargument (adds a function tool). - Run
GOOGLE_GENAI_USE_VERTEXAI=0 GOOGLE_API_KEY=x python repro.py toolto compare with the Developer API.
Expected Behavior:
The Interactions API enforces an LlmAgent's output_schema the same way generateContent does. config.response_schema / response_json_schema (with response_mime_type="application/json") should be sent as response_format.
Observed Behavior:
create() receives no response_format, and the schema's field names appear nowhere in the request:
# Vertex, output_schema, no tools
keys sent to interactions.create(): ['extra_headers', 'input', 'model', 'stream', 'system_instruction']
generation_config: None
response_format sent: False
schema field 'reason' anywhere in request: False
# Vertex, output_schema + one function tool
keys sent to interactions.create(): ['extra_headers', 'input', 'model', 'stream', 'system_instruction', 'tools']
tools sent: ['lookup']
response_format sent: False
schema field 'reason' anywhere in request: False
# Developer API, output_schema + one function tool (for comparison: the fallback applies)
tools sent: ['set_model_response', 'lookup']
response_format sent: False
schema field 'reason' anywhere in request: True
We found this after turning on the Interactions API in production on Vertex. As a workaround, we moved every agent with output_schema or tools back to generateContent (use_interactions_api=False).
Environment Details:
- ADK Library Version: google-adk 2.13.0 (latest on PyPI as of 2026-10-30). Code paths above are unchanged on
main@ 73b6790. - google-genai: 2.31.0 (also checked 2.34.0: no change)
- Desktop OS: macOS (repro); production on Cloud Run (Linux)
- Python Version: 3.13
Model Information:
- Are you using LiteLLM: No
- Which model is being used: Gemini 3.x on Vertex AI / Gemini Enterprise Agent Platform,
globalendpoint, non-streaming. The repro usesgemini-3.6-flash, but the request builder doesn't depend on the model.
🟡 Optional Information
Regression:
No. As far as we can tell, the Interactions path has never forwarded the schema.
Additional Context:
- We checked
main. The latest commit tointeractions_utils.py, a9cabe7 (2026-10-30), is about thought signatures. Insrc/,response_formatappears only in the OpenAI, OCI, LiteLLM and Apigee connectors. tests/unittests/models/test_interactions_utils.pyhas no coverage foroutput_schemaorresponse_schema.contributing/samples/models/interactions_apiuses tools and nooutput_schema.- We found no existing issue (searched "use_interactions_api", "interactions output_schema", "interactions response_format", "interactions response_schema").
Suggested fix:
In generate_content_via_interactions, when config.response_schema or config.response_json_schema is set, send:
response_format={"type": "text", "mime_type": "application/json", "schema": <JSON schema>}response_mime_type="application/json", which the google-genai docstring says is required whenresponse_formatis set
Things to watch for:
- The API silently ignores some JSON Schema keywords (e.g.
minLength,maxLength,uniqueItems) and returns 400 for overly complex schemas. Logging a warning, or documenting this, would help. - A unit test in
test_interactions_utils.pyshould assert thatresponse_formatis present for an agent withoutput_schema. - Until this is fixed, either log a warning when
response_schemais set on the Interactions path, or fall back toset_model_response, so the schema isn't dropped silently.
Related (separate from this bug, for docs):
- On the Interactions API, a thinking model's reply can start with a thought part that carries only a signature and no text, so
content.parts[0].textisNone. That's expected behavior, but callers that readparts[0].textbreak when they switch to the Interactions API. A docs note would help. - The Interactions API returns 400 when a function result contains an empty list. Separately, Gemini(use_interactions_api=True) streaming does not coalesce consecutive text/thought delta Parts #7468 reported a streaming issue (closed as stale).
Minimal Reproduction Code:
import asyncio, json, sys
from types import SimpleNamespace
from pydantic import BaseModel
from google.adk.agents import LlmAgent
from google.adk.models import Gemini
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types
class Verdict(BaseModel):
ok: bool
reason: str
captured = {}
class _FakeInteractions:
async def create(self, **kwargs):
captured.update(kwargs)
raise RuntimeError("captured; stop before network")
class _FakeClient:
aio = SimpleNamespace(interactions=_FakeInteractions())
vertexai = True
class RecordingGemini(Gemini):
@property
def api_client(self):
return _FakeClient()
def lookup(q: str) -> str:
"""Looks something up."""
return "x"
async def main(with_tool: bool):
agent = LlmAgent(
name="schema_probe",
model=RecordingGemini(model="gemini-3.6-flash", use_interactions_api=True),
instruction="Judge it.",
output_schema=Verdict,
tools=[lookup] if with_tool else [],
)
sessions = InMemorySessionService()
runner = Runner(app_name="t", agent=agent, session_service=sessions)
s = await sessions.create_session(app_name="t", user_id="u")
msg = types.Content(role="user", parts=[types.Part.from_text(text="hi")])
try:
async for _ in runner.run_async(user_id="u", session_id=s.id, new_message=msg):
pass
except Exception:
pass
print("keys sent to interactions.create():", sorted(k for k, v in captured.items() if v is not None))
print("tools sent:", [t.get("name") for t in (captured.get("tools") or [])])
print("generation_config:", captured.get("generation_config"))
print("response_format sent:", "response_format" in captured)
print("schema field 'reason' anywhere in request:", "reason" in json.dumps(captured, default=str))
asyncio.run(main(with_tool=len(sys.argv) > 1))How often has this issue occurred?:
- Always (100%)
Activity
himanshu096 commentedon Oct 30, 2026
I've sent a fix with unit tests and a live check on Vertex AI: #7871
fix: send output_schema to the Interactions API as response_format
fix: send output_schema to the Interactions API as response_format
llalitkumarrr commentedon Nov 4, 2026
Hello @himanshu096,
Thank you for reporting this and for your contribution. Your PR is currently under review and will be merged once it is approved by the reviewer, in the meantime we appreciate your patience. We will reach out if we require any further information.