Universal.Google.Gemini.Client 1.0.2

dotnet add package Universal.Google.Gemini.Client --version 1.0.2
                    
NuGet\Install-Package Universal.Google.Gemini.Client -Version 1.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Universal.Google.Gemini.Client" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Universal.Google.Gemini.Client" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="Universal.Google.Gemini.Client" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Universal.Google.Gemini.Client --version 1.0.2
                    
#r "nuget: Universal.Google.Gemini.Client, 1.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Universal.Google.Gemini.Client@1.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Universal.Google.Gemini.Client&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=Universal.Google.Gemini.Client&version=1.0.2
                    
Install as a Cake Tool

Universal.Google.Gemini.Client

Universal.Google.Gemini.Client is a C# library for interacting with the Google Gemini API (generativelanguage.googleapis.com/v1beta). It provides a simple and efficient way to generate content and handle streaming responses from Google's Gemini models.

Features

  • Easy-to-use client for the Gemini API
  • Support for generating content (text, images, audio, video, documents)
  • Streaming support for real-time responses
  • Function calling (tools) with JSON Schema parameters
  • Extended thinking support, including thought signatures
  • Structured JSON output
  • Built-in Google Search grounding
  • Token counting before generation
  • Text embeddings (single and batch)
  • Explicit context caching (cachedContents)
  • File uploads via the resumable Files API
  • List available models
  • Built-in error handling and deserialization

Usage

Initializing the Client

var client = new GeminiClient("YOUR_API_KEY");

Generating Content

var request = new GenerateContentRequest
{
    Contents = new[]
    {
        new Content
        {
            Role = Roles.User,
            Parts = new[] { new Part { Text = "Hello, how are you?" } }
        }
    }
};

var response = await client.GenerateContentAsync(Models.Gemini35Flash, request);
Console.WriteLine(response.Candidates[0].Content.Parts[0].Text);

Streaming a Response

var streamingRequest = new GenerateContentRequest
{
    Contents = new[]
    {
        new Content
        {
            Role = Roles.User,
            Parts = new[] { new Part { Text = "Tell me a story about a brave knight." } }
        }
    }
};

await foreach (var chunk in client.GenerateContentStreamingAsync(Models.Gemini35Flash, streamingRequest))
{
    var text = chunk.Candidates?.FirstOrDefault()?.Content?.Parts?.FirstOrDefault()?.Text;
    if (text is not null) Console.Write(text);
}

Counting Tokens

The countTokens endpoint lets you count the tokens a request would consume without generating a response — useful for estimating costs or validating size limits before calling GenerateContentAsync:

var countRequest = new CountTokensRequest
{
    Contents = new[]
    {
        new Content { Role = Roles.User, Parts = new[] { new Part { Text = "What is the square root of 841?" } } }
    }
};

var tokenCountResponse = await client.CountTokensAsync(Models.Gemini35Flash, countRequest);
Console.WriteLine($"Total tokens: {tokenCountResponse.TotalTokens}");

Listing Available Models

var modelsResponse = await client.ListModelsAsync();

foreach (var model in modelsResponse.Models)
{
    Console.WriteLine($"Name: {model.Name}");
    Console.WriteLine($"Display name: {model.DisplayName}");
    Console.WriteLine($"Input token limit: {model.InputTokenLimit}");
}

Using Tools (Function Calling)

var weatherTool = new Tool
{
    FunctionDeclarations = new[]
    {
        new FunctionDeclaration
        {
            Name = "get_weather",
            Description = "Get the current weather in a given location",
            Parameters = new Schema
            {
                Type = SchemaTypes.Object,
                Properties = new Dictionary<string, Schema>
                {
                    ["location"] = new Schema { Type = SchemaTypes.String, Description = "The city and state, e.g. San Francisco, CA" }
                },
                Required = new[] { "location" }
            }
        }
    }
};

var request = new GenerateContentRequest
{
    Contents = new[]
    {
        new Content { Role = Roles.User, Parts = new[] { new Part { Text = "What's the weather like in San Francisco?" } } }
    },
    Tools = new[] { weatherTool },
    ToolConfig = new ToolConfig { FunctionCallingConfig = new FunctionCallingConfig { Mode = FunctionCallingModes.Auto } }
};

var response = await client.GenerateContentAsync(Models.Gemini35Flash, request);

var functionCall = response.Candidates[0].Content.Parts.FirstOrDefault(p => p.FunctionCall is not null)?.FunctionCall;
if (functionCall is not null)
{
    Console.WriteLine($"Tool used: {functionCall.Name}");
    Console.WriteLine($"Arguments: {functionCall.Args}");
}

Using Extended Thinking

Gemini supports a thinking feature that reveals the model's reasoning process. Set ThinkingConfig.IncludeThoughts to surface it, and preserve Part.ThoughtSignature verbatim across turns so the model can validate its own reasoning chain:

var request = new GenerateContentRequest
{
    Contents = new[]
    {
        new Content { Role = Roles.User, Parts = new[] { new Part { Text = "What's the square root of 841, and how did you determine it?" } } }
    },
    GenerationConfig = new GenerationConfig
    {
        ThinkingConfig = new ThinkingConfig { ThinkingBudget = 2048, IncludeThoughts = true }
    }
};

var response = await client.GenerateContentAsync(Models.Gemini35Flash, request);

foreach (var part in response.Candidates[0].Content.Parts)
{
    if (part.Thought == true)
    {
        Console.WriteLine("Thinking Process:");
        Console.WriteLine(part.Text);
        Console.WriteLine($"Signature: {part.ThoughtSignature}");
    }
    else if (part.Text is not null)
    {
        Console.WriteLine("Final Answer:");
        Console.WriteLine(part.Text);
    }
}

Structured JSON Output

Constrain the response to a specific JSON schema via GenerationConfig.ResponseSchema. Note that Gemini's Schema dialect spells its type names in upper case (see SchemaTypes), unlike standard JSON Schema:

var request = new GenerateContentRequest
{
    Contents = new[]
    {
        new Content { Role = Roles.User, Parts = new[] { new Part { Text = "Give me a person named Alice who is 30 years old." } } }
    },
    GenerationConfig = new GenerationConfig
    {
        ResponseMimeType = "application/json",
        ResponseSchema = new Schema
        {
            Type = SchemaTypes.Object,
            Properties = new Dictionary<string, Schema>
            {
                ["name"] = new Schema { Type = SchemaTypes.String, Description = "The person's name" },
                ["age"] = new Schema { Type = SchemaTypes.Integer, Description = "The person's age" }
            },
            Required = new[] { "name", "age" }
        }
    }
};

var response = await client.GenerateContentAsync(Models.Gemini35Flash, request);
var json = response.Candidates[0].Content.Parts[0].Text;

var person = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
Console.WriteLine($"Name: {person["name"]}, Age: {person["age"]}");

Google Search Grounding

var request = new GenerateContentRequest
{
    Contents = new[]
    {
        new Content { Role = Roles.User, Parts = new[] { new Part { Text = "What was the score of the most recent Super Bowl?" } } }
    },
    Tools = new[] { new Tool { GoogleSearch = new GoogleSearch() } }
};

var response = await client.GenerateContentAsync(Models.Gemini35Flash, request);
var groundingMetadata = response.Candidates[0].GroundingMetadata;

Embeddings

var response = await client.EmbedContentAsync(Models.GeminiEmbedding2, new EmbedContentRequest
{
    Content = new Content { Parts = new[] { new Part { Text = "What is the meaning of life?" } } }
});

float[] vector = response.Embedding.Values.ToArray();

Context Caching

For large, reused prompts, cache the content once and reference it by name on subsequent requests to save on repeated processing and billed tokens:

var cached = await client.CreateCachedContentAsync(new CachedContent
{
    Model = $"models/{Models.Gemini35Flash}",
    Contents = new[] { new Content { Role = Roles.User, Parts = new[] { new Part { Text = veryLongDocument } } } },
    Ttl = "3600s"
});

var response = await client.GenerateContentAsync(Models.Gemini35Flash, new GenerateContentRequest
{
    CachedContent = cached.Name,
    Contents = new[] { new Content { Role = Roles.User, Parts = new[] { new Part { Text = "Summarize the above." } } } }
});

Uploading Files

using var stream = File.OpenRead("recording.mp3");
var file = await client.UploadFileAsync(stream, "audio/mpeg", "recording.mp3");

var response = await client.GenerateContentAsync(Models.Gemini35Flash, new GenerateContentRequest
{
    Contents = new[]
    {
        new Content
        {
            Role = Roles.User,
            Parts = new[]
            {
                new Part { FileData = new FileData { FileUri = file.Uri, MimeType = file.MimeType } },
                new Part { Text = "Transcribe this recording." }
            }
        }
    }
});

Key Classes

  • GeminiClient: The main client for interacting with the Gemini API.
  • GenerateContentRequest / GenerateContentResponse: Request/response for content generation.
  • Content / Part: The universal message and content-part shapes (text, inline media, function calls/responses, thoughts).
  • Schema: Gemini's OpenAPI-subset schema dialect, used for function parameters and structured output.
  • CountTokensRequest / CountTokensResponse: Token counting without generation.
  • CachedContent: Explicit context-caching resource.
  • GeminiFile: An uploaded file resource returned by the Files API.
  • ListModelsResponse, ListCachedContentsResponse, ListFilesResponse: Paginated list responses.

Error Handling

The client throws GeminiException for non-successful status codes, carrying the parsed ApiError (code/message/status) where the response body includes one.

Customization

GeminiClient.BaseUrl and GeminiClient.UploadBaseUrl are public constants; the client targets v1beta, the channel Google's own SDKs default to since it carries the full feature set (thinking, code execution, URL context, caching) that the stable v1 channel lags behind on.

For more detailed information about the Gemini API, please refer to the official Gemini API documentation.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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 was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Universal.Google.Gemini.Client:

Package Downloads
Universal.Operative.Sdk.GoogleGemini

Google Gemini extensions for the Universal.Operative.Sdk.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.2 33 7/28/2026
1.0.1 142 7/15/2026
1.0.0 90 7/15/2026

Updated Universal.Common.Json dependency to 1.9.0.