Skip to content

Python: Add GeminiChatClient#4847

Open
holtvogt wants to merge 57 commits intomicrosoft:mainfrom
holtvogt:feat/add-gemini-client
Open

Python: Add GeminiChatClient#4847
holtvogt wants to merge 57 commits intomicrosoft:mainfrom
holtvogt:feat/add-gemini-client

Conversation

@holtvogt
Copy link
Copy Markdown

@holtvogt holtvogt commented Mar 23, 2026

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-gemini package that gives developers a native, idiomatic way to use Google Gemini models within Agent Framework.

Description

This PR introduces the agent-framework-gemini package. A new provider integration built on the official google-genai SDK (>=1.0.0,<2.0.0).

Google API Reference

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? If yes, add "[BREAKING]" prefix to the title of the PR.

Reference

Copilot AI review requested due to automatic review settings March 23, 2026 07:34
@markwallace-microsoft markwallace-microsoft added documentation Improvements or additions to documentation python labels Mar 23, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.GeminiChatClient with Gemini-specific GeminiChatOptions/ThinkingConfig and 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.

Copy link
Copy Markdown
Member

@eavanvalkenburg eavanvalkenburg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_format through to the stream finalizer for Pydantic-model-based structured output, consistent with how Anthropic and Ollama do it, though the Gemini integration primarily uses response_schema as 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_dict with a JSON string that parses to a non-dict type (e.g., JSON array), and no test for response_schema set without response_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_messages resolves the required name field for Gemini's FunctionResponse by scanning prior conversation history to build a call_id → name map. The root cause is that Content.from_function_result in the framework does not persist the function name (confirmed: the name field is always None on function_result Contents 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 a name parameter to Content.from_function_result and pass it from _execute_function_call, then consume content.name directly in the Gemini client. One secondary concern: setting response_schema alone (without response_format) silently enables application/json MIME type, which is undocumented behavior in the option's docstring.


Automated review by eavanvalkenburg's agents

@markwallace-microsoft
Copy link
Copy Markdown
Contributor

markwallace-microsoft commented Mar 23, 2026

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/gemini/agent_framework_gemini
   _chat_client.py2790100% 
TOTAL27574321488% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
5421 20 💤 0 ❌ 0 🔥 1m 30s ⏱️

@eavanvalkenburg
Copy link
Copy Markdown
Member

@holtvogt thanks for looking into this, I've added some comments

@eavanvalkenburg
Copy link
Copy Markdown
Member

@holtvogt thanks for your patience with this, I've left some comments and the checks fail, let me know when you have a change to update, then I'll run the checks and review again

Replaces boolean tool options (code_execution, google_search_grounding,
google_maps_grounding) with static factory methods that return types.Tool
objects: get_code_interpreter_tool, get_web_search_tool, get_mcp_tool,
get_file_search_tool, and get_maps_grounding_tool.

Simplifies _prepare_tools to a single translation boundary between
FunctionTool (framework) and FunctionDeclaration (Gemini API), with
types.Tool objects passed through unchanged.
_parse_parts now maps executable_code and code_execution_result
parts to text Content objects so callers can see the code run
and its output. Unknown part types log at debug level rather than
being silently dropped.
Copy link
Copy Markdown
Member

@eavanvalkenburg eavanvalkenburg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're getting close, some more detailed things left

@holtvogt
Copy link
Copy Markdown
Author

@eavanvalkenburg The tool protocol implementation should be fixed now. The failing tests were caused by using model_id in ChatResponse. I updated it, and the tests are running 💚 Returning it back to you for another look 👀

holtvogt and others added 2 commits April 10, 2026 17:25
Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
Co-authored-by: Eduard van Valkenburg <eavanvalkenburg@users.noreply.github.com>
@holtvogt
Copy link
Copy Markdown
Author

@eavanvalkenburg Sending this back like a well-traveled boomerang. Ready for another look! 🏓

Now reflects new options and built-in tool factory methods
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation python

Projects

Status: Community PR

Development

Successfully merging this pull request may close these issues.

4 participants