Python (fix:gemini): make Gemini honor declarative outputSchema, not just JSON mode#5893
Merged
Merged
Conversation
Contributor
Author
|
@microsoft-github-policy-service agree |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes Gemini structured output handling so declarative outputSchema (propagated as response_format) is forwarded to Gemini as an actual response_schema, not just enabling JSON mode via response_mime_type="application/json". This keeps declarative agents’ schema contracts intact across the provider adapter boundary.
Changes:
- Add schema extraction for mapping-shaped
response_formatvalues (raw JSON Schema mappings and supported envelope shapes) and forward them as Geminiresponse_schema. - Preserve precedence for explicit Gemini
response_schemaover any schema inferred fromresponse_format. - Expand Gemini client tests and provider README documentation to cover these structured-output behaviors (including streaming/tools and negative cases).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| python/packages/gemini/agent_framework_gemini/_chat_client.py | Extracts/forwards JSON schemas from mapping response_format and correctly applies precedence/JSON mode behavior. |
| python/packages/gemini/tests/test_gemini_client.py | Adds coverage ensuring schemas are forwarded and final parsed value works for mapping formats across non-streaming/streaming/tools. |
| python/packages/gemini/README.md | Documents supported structured-output configuration options for Gemini (response_format and response_schema). |
Contributor
Python Test Coverage Report •
Python Unit Test Overview
|
||||||||||||||||||||||||||||||
peibekwe
reviewed
May 26, 2026
Contributor
|
@cooleryu please run Pyright and address the few issues as well. |
moonbox3
approved these changes
May 27, 2026
eavanvalkenburg
approved these changes
May 27, 2026
4 tasks
Cast Any-narrowed mappings to Mapping[str, Any] in the structured-output schema helpers so pyright strict no longer reports partially-unknown member, argument, and variable types. Pass response_format["format"] straight into the recursive extractor, which already guards non-mapping inputs. No behavior change.
The Sequence[Any] cast pyright strict needs to know the loop element type is reported as a redundant-cast by mypy, which already narrows the isinstance branch to Sequence[Any]. Cast to Sequence[object] instead: pyright gets a fully known element type and mypy no longer sees an identical-type cast. No behavior change.
peibekwe
approved these changes
Jun 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the Gemini structured-output path so declarative
outputSchemais forwarded as an actual Geminiresponse_schema, not only asresponse_mime_type="application/json".Motivation
Issue #5888 shows a subtle but important failure mode:
outputSchemaintoresponse_formatresponse_formatand switches the request into JSON moderesponse_schemaThat means Gemini is asked for JSON, but not constrained by the schema the agent author wrote. In practice, the model can return arbitrary JSON that satisfies neither the requested task nor the declarative schema.
Changes
response_formatvalues:json_schemaenvelopesformatenvelopesschemamappingsresponse_schemaas the highest-priority Gemini-specific option.{"type": "json_object"}as schemas.response_format, JSON schemaresponse_format, and Gemini-specificresponse_schema.Test Plan
Ran:
uv run --frozen --package agent-framework-gemini pytest packages/gemini/tests/test_gemini_client.py -q uv run --frozen --package agent-framework-declarative pytest packages/declarative/tests/test_declarative_loader.py -k "outputSchema or response_format" -q uv run --frozen --package agent-framework-gemini ruff check packages/gemini/agent_framework_gemini/_chat_client.py packages/gemini/tests/test_gemini_client.py uv run --frozen --package agent-framework-gemini ruff format --check packages/gemini/agent_framework_gemini/_chat_client.py packages/gemini/tests/test_gemini_client.py uv run --frozen --package agent-framework-gemini mypy --config-file packages/gemini/pyproject.toml packages/gemini/agent_framework_gemini git diff --checkThe new tests cover:
Agent(default_options={"response_format": ...})path used by declarative agentsadditionalPropertiesjson_schema,format, and directschemaenvelopesanyOf, union type arrays, and empty schemasresponse.valueparsing for mapping response formatsRisk
The change is intentionally scoped to request config preparation for Gemini structured output.
Existing behavior is preserved for:
response_formatresponse_schemaThe main behavioral change is that mapping-shaped schemas already accepted by the framework are now actually forwarded to Gemini.
Related Issue
Fixes #5888
Maintainer Context
This keeps the declarative-agent contract intact across the provider boundary:
outputSchema->response_format-> Geminiresponse_schemaWithout this, declarative schemas silently degrade into plain JSON mode for Gemini. The patch keeps the adapter behavior narrow, adds negative tests to avoid over-eager schema detection, and covers the tool/streaming paths where this kind of regression can be easy to miss.