Python: Add GeminiChatClient#4847
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a first-class Google Gemini provider integration to the Python Agent Framework workspace via a new agent-framework-gemini package (built on google-genai), plus runnable samples and tests.
Changes:
- Introduces
agent_framework_gemini.GeminiChatClientwith Gemini-specificGeminiChatOptions/ThinkingConfigand message/tool mapping. - Adds unit + integration tests for text, streaming, tools, thinking config, grounding, code execution, and structured output.
- Adds Google Gemini sample scripts and wires the new package/dependency into the Python workspace (
uv.lock,.env.example).
Reviewed changes
Copilot reviewed 15 out of 18 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| python/uv.lock | Adds agent-framework-gemini workspace member and locks google-genai dependency. |
| python/.env.example | Documents GEMINI_API_KEY / GEMINI_CHAT_MODEL_ID env vars. |
| python/packages/gemini/pyproject.toml | Defines the new distributable package and its dependencies/tooling config. |
| python/packages/gemini/agent_framework_gemini/_chat_client.py | Implements the Gemini chat client (streaming, tools, config mapping, response parsing). |
| python/packages/gemini/agent_framework_gemini/init.py | Exposes the package public API + version. |
| python/packages/gemini/tests/test_chat_client.py | Adds unit tests for conversion/config/streaming behavior. |
| python/packages/gemini/tests/test_chat_client_integration.py | Adds integration tests gated by GEMINI_API_KEY. |
| python/samples/02-agents/providers/google/*.py | Adds runnable Gemini provider samples (basic, advanced thinking, grounding, code execution). |
| python/samples/02-agents/providers/google/README.md | Documents the new Gemini samples. |
| python/packages/gemini/README.md / LICENSE / AGENTS.md / py.typed | Packaging docs/metadata for the new provider. |
eavanvalkenburg
left a comment
There was a problem hiding this comment.
Automated Code Review
Reviewers: 4 | Confidence: 89%
✓ Correctness
This PR adds a well-structured Google Gemini integration package following the established patterns of other providers (Anthropic, Ollama, Bedrock). The implementation correctly handles message conversion, tool calling, streaming, system instructions, and finish reason mapping. The code is defensively written with proper edge-case handling (missing function call IDs, unmatched function results, consecutive tool messages). No blocking correctness issues were found. One minor suggestion relates to passing
response_formatthrough to the stream finalizer for Pydantic-model-based structured output, consistent with how Anthropic and Ollama do it, though the Gemini integration primarily usesresponse_schemaas a dict so this is low-impact.
✗ Security Reliability
This PR adds a new Google Gemini chat client integration. The implementation follows established patterns for settings, API key handling (SecretString), and message conversion. However, there is one reliability issue: the class inheritance (MRO) order for GeminiChatClient swaps ChatMiddlewareLayer and FunctionInvocationLayer compared to every other provider in the codebase, which could cause middleware to not properly wrap function invocations. No secrets are hardcoded, JSON parsing is safely wrapped, and input validation is present at key trust boundaries.
✓ Test Coverage
The new Gemini package has a solid unit test suite (879 lines) covering the main paths: text responses, streaming, tool calling, config mapping, message conversion, finish reasons, thinking config, and built-in tools. However, there are notable test coverage gaps: no test for empty/None candidates in API responses, no test for the streaming
get_final_response()finalization path, no test for_coerce_to_dictwith a JSON string that parses to a non-dict type (e.g., JSON array), and no test forresponse_schemaset withoutresponse_format. These are edge cases that the implementation appears to handle correctly, but without tests they could regress silently.
✗ Design Approach
The Gemini integration is well-structured and follows established patterns from other providers. The main design concern is that
_prepare_gemini_messagesresolves the requirednamefield for Gemini'sFunctionResponseby scanning prior conversation history to build acall_id → namemap. The root cause is thatContent.from_function_resultin the framework does not persist the function name (confirmed: thenamefield is alwaysNoneonfunction_resultContents as created by_execute_function_call). The history-scanning workaround works for the common case but silently drops tool results whenever messages are trimmed — a realistic production scenario (context-window management, memory layers). A straightforward fix exists at the framework level: add anameparameter toContent.from_function_resultand pass it from_execute_function_call, then consumecontent.namedirectly in the Gemini client. One secondary concern: settingresponse_schemaalone (withoutresponse_format) silently enablesapplication/jsonMIME type, which is undocumented behavior in the option's docstring.
Automated review by eavanvalkenburg's agents
Python Test Coverage Report •
Python Unit Test Overview
|
||||||||||||||||||||||||||||||
|
@holtvogt thanks for looking into this, I've added some comments |
Also updates constructor parameter order for environment file handling
eavanvalkenburg
left a comment
There was a problem hiding this comment.
we're getting close, some more detailed things left
|
@eavanvalkenburg The tool protocol implementation should be fixed now. The failing tests were caused by using |
Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
|
@eavanvalkenburg Sending this back like a well-traveled boomerang. Ready for another look! 🏓 |
Now reflects new options and built-in tool factory methods
eavanvalkenburg
left a comment
There was a problem hiding this comment.
Small comment on the build system, otherwise good to go! Thanks
Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
|
@eavanvalkenburg Updated the build system. Can you run the tests again? |
The Gemini chat client references several `google.genai.types` symbols (`FileSearch`, `ThinkingLevel`, `SearchTypes`, `McpServer`, `StreamableHttpTransport`, plus call-site keyword args `mcp_servers` and `search_types`) that are not present at the lower bound of `google-genai>=1.0.0`. At `lowest-direct` resolution this caused `validate-dependency-bounds-test` to fail for `packages/gemini` with eleven `reportAttributeAccessIssue` / `reportUnknownVariableType` errors. Walking the upstream `google.genai.types` API: - `GoogleMaps`, `AuthConfig`: present from 1.40.0 - `FileSearch`: introduced in 1.49.0 - `ThinkingLevel`: introduced in 1.55.0 - `SearchTypes`, `McpServer`, `StreamableHttpTransport`: introduced in 1.65.0 Bump the lower bound to 1.65.0 — the minimum version that exposes every symbol the package actually uses. Keep the `<2.0.0` upper cap unchanged. With this bump `validate-dependency-bounds-test` passes for both lower and upper resolution scenarios across all 27 workspace packages. Latent since microsoft#4847 (Gemini package introduction in 1.1.0); aggravated by subsequent feature additions that pulled in newer `types.*` symbols.
* Python: bump package versions for 1.2.1 release PATCH bump (1.2.0 -> 1.2.1) for the released cohort. The release window covers two PRs, no new public APIs: - agent-framework-core: prevent inner_exception from being lost in AgentFrameworkException (#5167) - samples: add requirements.txt and .env.example to the a2a/ hosting sample for pip-based setup (#5510) Per lockstep convention, all 21 beta packages stamp 1.0.0b260428 and all 3 alpha packages stamp 1.0.0a260428, regardless of per-package code churn. Every non-core package floor on agent-framework-core is raised to >=1.2.1 to keep cohort signaling consistent. Date stamp reflects the local (Asia) cut date 2026-04-28. * Python: silence pyright unknown-type warnings in hosted-env detection `azure.ai.agentserver.core` is probed at runtime via `importlib.util.find_spec` and is not a declared dependency. The existing `# pyright: ignore[reportMissingImports]` suppresses the missing-import warning, but at `lowest-direct` resolution pyright still reports the imported symbol (`AgentConfig`) and its members (`from_env`, `is_hosted`) as unknown, breaking `validate-dependency-bounds-test` for `packages/core`. Extend the existing ignore to cover `reportUnknownVariableType` on the import and `reportUnknownMemberType` on the call site so the bounds check returns to green. Behavior is unchanged. Latent since #5455 (shipped in 1.2.0). * Python: raise agent-framework-gemini lower bound to google-genai>=1.65.0 The Gemini chat client references several `google.genai.types` symbols (`FileSearch`, `ThinkingLevel`, `SearchTypes`, `McpServer`, `StreamableHttpTransport`, plus call-site keyword args `mcp_servers` and `search_types`) that are not present at the lower bound of `google-genai>=1.0.0`. At `lowest-direct` resolution this caused `validate-dependency-bounds-test` to fail for `packages/gemini` with eleven `reportAttributeAccessIssue` / `reportUnknownVariableType` errors. Walking the upstream `google.genai.types` API: - `GoogleMaps`, `AuthConfig`: present from 1.40.0 - `FileSearch`: introduced in 1.49.0 - `ThinkingLevel`: introduced in 1.55.0 - `SearchTypes`, `McpServer`, `StreamableHttpTransport`: introduced in 1.65.0 Bump the lower bound to 1.65.0 — the minimum version that exposes every symbol the package actually uses. Keep the `<2.0.0` upper cap unchanged. With this bump `validate-dependency-bounds-test` passes for both lower and upper resolution scenarios across all 27 workspace packages. Latent since #4847 (Gemini package introduction in 1.1.0); aggravated by subsequent feature additions that pulled in newer `types.*` symbols. * Python: add dependabot bumps to 1.2.1 CHANGELOG Catalog the 15 dependabot dependency updates that merged on `upstream/main` between python-1.2.0 and the 1.2.1 cut window under a new Changed section: - Workspace dev/runtime deps: `rich`, `prek`, `python-multipart`, `pyasn1`, `pytest` (ag-ui, devui, lab), `uv` (lab) - Frontend deps: `vite` (devui, chatkit), `postcss` (devui, chatkit, handoff), `picomatch` (devui, handoff) CHANGELOG-only — no source or pyproject.toml changes. PRs themselves merged upstream independently of this release branch and will be brought in via the PR merge.
Motivation and Context
Google Gemini is one of the leading LLM providers and is not yet supported as a first-class integration in Agent Framework. This PR adds a dedicated
agent-framework-geminipackage that gives developers a native, idiomatic way to use Google Gemini models within Agent Framework.Description
This PR introduces the
agent-framework-geminipackage. A new provider integration built on the officialgoogle-genaiSDK (>=1.0.0,<2.0.0).Google API Reference
Contribution Checklist
Reference