Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 3, 2025

Motivation and Context

Adds IChatClient implementation for Google AI using the Google.GenAI library, enabling M.E.AI abstractions support. Since Google.GenAI only supports NET 8+, this is gated behind #if NET conditionals.

Description

  • New GoogleGenAIChatClient - Internal polyfill implementing IChatClient based on stephentoub/dotnet-genai reference

    • Wraps Google.GenAI.Client/Models for chat completions
    • Supports streaming, function calling, multimodal content
    • Extracts usage metadata
    • Added thought signature handling for agentic scenarios
    • Added TextReasoningContent support for reasoning/thought content
    • Added hosted tools support (CodeInterpreter, FileSearch, WebSearch)
    • Added RawRepresentation handling for Part objects
    • Enhanced FunctionResultContent handling (AIContent, IEnumerable, TextContent)
    • Added CodeInterpreterToolCallContent and CodeInterpreterToolResultContent support
    • Added citation metadata handling with CitationAnnotation
    • Added DisplayName support for DataContent
  • Extension methods for DI registration with distinct prefixes:

    • AddGoogleAIChatClient(modelId, googleClient, ...) - accepts Google.GenAI.Client directly
    • AddGoogleGenAIChatClient(modelId, apiKey, ...) - for Google GenAI with API key authentication
    • AddGoogleVertexAIChatClient(modelId, project?, location?, credential?, ...) - for Vertex AI with optional Google.Apis.Auth.OAuth2.ICredential (uses environment discovery if null)
    • Corresponding IKernelBuilder extensions for all methods
  • Package changes:

    • Added Google.GenAI v0.6.0 to Directory.Packages.props
    • Added Google.Apis.Auth for ICredential type support in VertexAI extension
    • Conditional reference in Connectors.Google.csproj for NET 8/9/10
  • Unit tests:

    • GoogleGeminiChatClientTests.cs - Tests for ChatClient creation with API key, Google client, service ID, and exception handling
    • GoogleAIServiceCollectionExtensionsTests.cs - Tests for GenAI and VertexAI extension method registration
  • Integration tests (separate classes for each API):

    • GeminiGenAIChatClientTests.cs - Chat tests for Google GenAI
    • GeminiVertexAIChatClientTests.cs - Chat tests for Vertex AI
    • GeminiGenAIFunctionCallingChatClientTests.cs - Function calling tests for Google GenAI
    • GeminiVertexAIFunctionCallingChatClientTests.cs - Function calling tests for Vertex AI
// Google GenAI with API key
builder.AddGoogleGenAIChatClient("gemini-2.0-flash", apiKey);

// Google Vertex AI with project/location (uses environment credentials)
builder.AddGoogleVertexAIChatClient("gemini-2.0-flash", project: "my-project", location: "us-central1");

// Google Vertex AI with explicit credentials
builder.AddGoogleVertexAIChatClient("gemini-2.0-flash", project: "my-project", location: "us-central1", credential: myCredential);

// With existing client
var client = new Google.GenAI.Client(apiKey: apiKey);
builder.AddGoogleAIChatClient("gemini-2.0-flash", client);

Contribution Checklist

Original prompt

I need to add a new ChatClient service into the Google connector using a reference to the Google.GenAI library.

this implementation should use internal a polyfill of the IChatClient implementation, similar how was done in the sample from Microsoft Agent Framework here:

https://github.com/microsoft/agent-framework/blob/main/dotnet/samples/GettingStarted/AgentProviders/Agent_With_GoogleGemini/GeminiChatClient.cs

and here:

https://github.com/microsoft/agent-framework/blob/main/dotnet/samples/GettingStarted/AgentProviders/Agent_With_GoogleGemini/GoogleGenAIExtensions.cs

Also take note that I need to add some extra Extension methods similiar to the AddGoogleChatCompletion, which in this case will be AddGoogleChatClient extensions to both the IServiceCollection and IKernelBuilder.

Ensure this new extension methods are unit test covered.

One extra observation, Google.GenAI currently is only available to NET 8 and there's not support for NetStandard, so this new extensions should only be available for the NET 8+ targets with proper csproj conditionals and #if NET checks.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI changed the title [WIP] Add ChatClient service to Google connector Add Google.GenAI ChatClient support with IChatClient polyfill Dec 3, 2025
Copilot AI requested a review from rogerbarreto December 3, 2025 12:45
@rogerbarreto
Copy link
Member

@copilot the Google.GenAI.Client type accepts bool vertexAI, I think we should also expose this argument in the extension methods that don't take the client directly.

Directory.Packages.Props should also consider the $(TargetFramework) == net9.0, as we also build for this.

Google.GenAI is already in the version 0.6.0, please update to the latest.

Copy link
Contributor Author

Copilot AI commented Dec 3, 2025

@copilot the Google.GenAI.Client type accepts bool vertexAI, I think we should also expose this argument in the extension methods that don't take the client directly.

Directory.Packages.Props sho...

Addressed in 1586f0e:

  • Added vertexAI parameter (default false) to AddGoogleAIChatClient extension methods that take apiKey directly
  • Updated Google.GenAI package to version 0.6.0 in Directory.Packages.props
  • Added net9.0 to the conditional package reference in Connectors.Google.csproj

@rogerbarreto
Copy link
Member

@copilot Remove any added [Experimental("SKEXP0070")] flag as this package is an alpha pre-release package and experimental API's are not needed to be flagged.

Copy link
Contributor Author

Copilot AI commented Dec 3, 2025

@copilot Remove any added [Experimental("SKEXP0070")] flag as this package is an alpha pre-release package and experimental API's are not needed to be flagged.

Removed all [Experimental("SKEXP0070")] attributes from the extension methods and tests in 238fcde.

@rogerbarreto
Copy link
Member

@copilot Now I need you to add similar set of unit tests in here GoogleAIGeminiChatCompletionServiceTests targeting the new GoogleChatClient, with name like GoogleGeminiChatClientTests

as well as integration tests similar targeting the new ChatClientService.
So basically for the IT, we need new GeminiChatClientTests.cs and a new GeminiFunctionCAllingChatClientTests.cs targeting the new client.

Keep in mind for the integration tests, Facts should be Theories accepting the IsVertexAI argument which will use the VertexAI API, otherwise would use the GenAI API.

Copy link
Contributor Author

Copilot AI commented Dec 3, 2025

@copilot Now I need you to add similar set of unit tests in here GoogleAIGeminiChatCompletionServiceTests targeting the new GoogleChatClient, with name like GoogleGeminiChatClientTests

as well as...

Added in 4f6c91c:

  • Unit tests: GoogleGeminiChatClientTests.cs in Connectors.Google.UnitTests/Services/
  • Integration tests: GeminiChatClientTests.cs and GeminiFunctionCallingChatClientTests.cs in IntegrationTests/Connectors/Google/Gemini/

All integration tests use [RetryTheory] with [InlineData(false)] and [InlineData(true)] for the isVertexAI parameter. Updated TestsBase.cs with GetChatClient(bool isVertexAI) method that uses the vertexAI parameter.

@rogerbarreto
Copy link
Member

@copilot I need to change a bit the strategy, actually the VertexAI and GenAI should be distinct extensions where the GenAI requires the ApiKey, VertexAI endpoint will expect instead of an apiKey an optional Google.Auth.ICredential? that if not provided, it passes as null to the Google.GenAI.Client that will use it's internal discovery impl to get from the environment.

Extension methods that accepts directly the Google.GenAI.Client don't need to change.

Suggested prefixes.
AddGoogleAIChatClient - extension methods that accepts the client as argument.
AddGoogleGenAIChatClient - extension methods that accepts the apiKey be prefixed as
AddGoogleVertexAIChatClient - extension methods that accepts (ICredential)

Update the unit tests accordingly, the integration tests can now be specific separate classes for each.

Copy link
Contributor Author

Copilot AI commented Dec 3, 2025

@copilot I need to change a bit the strategy, actually the VertexAI and GenAI should be distinct extensions where the GenAI requires the ApiKey, VertexAI endpoint will expect instead of an apiKey an...

Addressed in c8be251:

Extension methods split:

  • AddGoogleGenAIChatClient - accepts apiKey for Google GenAI
  • AddGoogleVertexAIChatClient - accepts project, location, and optional Google.Apis.Auth.OAuth2.ICredential? for Vertex AI
  • AddGoogleAIChatClient - accepts Google.GenAI.Client directly (unchanged)

Unit tests updated with separate tests for each extension type.

Integration tests split into separate classes:

  • GeminiGenAIChatClientTests.cs / GeminiGenAIFunctionCallingChatClientTests.cs for GenAI
  • GeminiVertexAIChatClientTests.cs / GeminiVertexAIFunctionCallingChatClientTests.cs for VertexAI

@moonbox3 moonbox3 added .NET Issue or Pull requests regarding .NET code kernel Issues or pull requests impacting the core kernel labels Dec 8, 2025
@github-actions github-actions bot changed the title Add Google.GenAI ChatClient support with IChatClient polyfill .Net: Add Google.GenAI ChatClient support with IChatClient polyfill Dec 8, 2025
@rogerbarreto
Copy link
Member

@copilot Please update the current polyfill Google.GenAI ChatClient implementation using the latest updates made to the ChatClient in here:

https://raw.githubusercontent.com/stephentoub/dotnet-genai/41d6cc2d3938e43b72faae5f5be6f99287486783/Google.GenAI/GoogleGenAIChatClient.cs

Copy link
Contributor Author

Copilot AI commented Dec 8, 2025

@copilot Please update the current polyfill Google.GenAI ChatClient implementation using the latest updates made to the ChatClient in here:

https://raw.githubusercontent.com/stephentoub/dotnet-gena...

Updated the GoogleGenAIChatClient polyfill with the latest implementation in 4f24c7a.

Key enhancements:

  • Added thought signature handling (s_skipThoughtValidation) for agentic scenarios
  • Added TextReasoningContent support for reasoning/thought content
  • Added hosted tools: HostedCodeInterpreterTool, HostedFileSearchTool, HostedWebSearchTool
  • Enhanced FunctionResultContent handling (AIContent, IEnumerable, TextContent)
  • Added CodeInterpreterToolCallContent and CodeInterpreterToolResultContent support
  • Added citation metadata handling with CitationAnnotation and TextSpanAnnotatedRegion
  • Added RawRepresentation handling for Part objects
  • Added DisplayName support for DataContent

@rogerbarreto rogerbarreto marked this pull request as ready for review December 10, 2025 18:29
@rogerbarreto rogerbarreto requested a review from a team as a code owner December 10, 2025 18:29
}

// Transfer messages to request, handling system messages specially
Dictionary<string, string>? callIdToFunctionNames = null;
Copy link
Member

Choose a reason for hiding this comment

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

This variable is declared passed as ref to AddPartsForAIContents and not used anywhere after taht.

Copy link
Member

Choose a reason for hiding this comment

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

My understand is that this variable is being used during the iteration in the foreach where each iteration mutates it, just wonder why the ref is enforced in the parameter as Dictionary AFAIK works by ref as an object.

cc @stephentoub

Copy link
Member

Choose a reason for hiding this comment

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

Because it's being lazily initialized by the callee. It starts out as null, and if the callee needs to store a found call in it, it ensures the collection is instantiated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kernel Issues or pull requests impacting the core kernel .NET Issue or Pull requests regarding .NET code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants