Universal.Operative.Sdk.Discrete.Google.Gemini
3.0.0
dotnet add package Universal.Operative.Sdk.Discrete.Google.Gemini --version 3.0.0
NuGet\Install-Package Universal.Operative.Sdk.Discrete.Google.Gemini -Version 3.0.0
<PackageReference Include="Universal.Operative.Sdk.Discrete.Google.Gemini" Version="3.0.0" />
<PackageVersion Include="Universal.Operative.Sdk.Discrete.Google.Gemini" Version="3.0.0" />
<PackageReference Include="Universal.Operative.Sdk.Discrete.Google.Gemini" />
paket add Universal.Operative.Sdk.Discrete.Google.Gemini --version 3.0.0
#r "nuget: Universal.Operative.Sdk.Discrete.Google.Gemini, 3.0.0"
#:package Universal.Operative.Sdk.Discrete.Google.Gemini@3.0.0
#addin nuget:?package=Universal.Operative.Sdk.Discrete.Google.Gemini&version=3.0.0
#tool nuget:?package=Universal.Operative.Sdk.Discrete.Google.Gemini&version=3.0.0
About
Universal.Operative.Sdk.Discrete.Google.Gemini plugs Google's Gemini models into Universal.Operative.Sdk via an IModel adapter (Model) backed by the Universal.Google.Gemini.Client transport (Gemini's v1beta REST/SSE API).
How to Use
Installation
dotnet add package Universal.Operative.Sdk.Discrete.Google.Gemini
Configuration
using Universal.Operative.Sdk;
using Universal.Operative.Sdk.Discrete.Google.Gemini;
IModel model = new Model(apiKey, new Model.Options
{
ModelId = Models.Gemini35Flash,
MaxOutputTokens = 4096,
});
The constructor also accepts an existing Universal.Google.Gemini.Client.V1Beta.GeminiClient in place of an API key, so you can reuse a pre-built client (custom headers, handlers, ...) across models:
using Universal.Google.Gemini.Client.V1Beta;
GeminiClient client = new GeminiClient(apiKey);
IModel model = new Model(client, new Model.Options { ModelId = Models.Gemini35Flash });
Usage
Drop the model into EngineBuilder like any other IModel:
IEngine engine = EngineBuilder.FromDefaults(model)
.AddBaselineToolSet()
.Build();
await foreach (EngineEvent e in engine.ExecuteAsync(conversation))
{
// handle events as usual — see Universal.Operative.Sdk's Package.md
}
Extended thinking
Model.Options.ThinkingConfig forwards directly to Gemini's thinkingConfig (thinking budget, whether to surface thought summaries). Thinking text round-trips through the universal ReasoningBlock.Text, the same slot Anthropic's extended thinking uses.
Gemini's thoughtSignature, however, does not live on the thought itself — verified against live responses, it's attached to whichever block concludes the thinking segment (the final answer TextBlock, or the ToolCallBlock for the function call that followed). Since neither has a native signature slot, it round-trips via the Gemini extension property added onto Block:
using Universal.Operative.Sdk.Discrete.Google.Gemini;
string? signature = someBlock.Gemini.ThoughtSignature;
You only need to read this if you're inspecting history yourself — the adapter re-attaches it to the right outbound part automatically when you replay a conversation, so tool calls and answers produced under ThinkingConfig continue to validate correctly on the next turn.
Usage accounting
Gemini reports thinking tokens (thoughtsTokenCount) and tool-use prompt tokens (toolUsePromptTokenCount) as additive counters alongside promptTokenCount/candidatesTokenCount — unlike Usage.InputTokens/OutputTokens, which mirror Gemini's own headline counters as-is. Use Usage.Gemini to read the breakdown, and GeminiUsageExtensions.ProjectCompactionTokens as a CompactionTransformer.Options.ProjectedTokensCalculator so auto-compaction accounts for thinking-token cost correctly.
Prompt caching
Gemini 2.5+ already caches long context automatically — no configuration needed; savings show up in Usage.Gemini's cachedContentTokenCount. For a guaranteed cache hit instead, create a CachedContent via GeminiClient.CreateCachedContentAsync and reference it:
IModel model = new Model(client, new Model.Options
{
ModelId = Models.Gemini35Flash,
CachedContentName = cachedContent.Name,
});
A referenced cache carries its own system instruction/tools, so the request omits Message.Tools/Conversation.System while it's set.
License
Free for noncommercial use under the Universal.Operative Noncommercial License. Source is closed; commercial use requires a separate license from Andrew Ong.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Universal.Google.Gemini.Client (>= 1.1.0)
- Universal.Operative.Sdk (>= 6.1.2)
- Universal.Operative.Sdk.Discrete (>= 3.0.0)
-
net8.0
- Universal.Google.Gemini.Client (>= 1.1.0)
- Universal.Operative.Sdk (>= 6.1.2)
- Universal.Operative.Sdk.Discrete (>= 3.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Supports conversation managers and durable chronologies.