Skip to content

.Net: Added Labels field in Gemini Request. #12300

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,24 @@ public void CachedContentFromPromptReturnsAsExpected()
Assert.Equal(executionSettings.CachedContent, request.CachedContent);
}

[Fact]
public void LabelsFromPromptReturnsAsExpected()
{
// Arrange
var prompt = "prompt-example";
var executionSettings = new GeminiPromptExecutionSettings
{
Labels = "Key1:Value1"
};

// Act
var request = GeminiRequest.FromPromptAndExecutionSettings(prompt, executionSettings);

// Assert
Assert.NotNull(request.Configuration);
Assert.Equal(executionSettings.Labels, request.Labels);
}

[Fact]
public void CachedContentFromChatHistoryReturnsAsExpected()
{
Expand All @@ -541,6 +559,26 @@ public void CachedContentFromChatHistoryReturnsAsExpected()
Assert.Equal(executionSettings.CachedContent, request.CachedContent);
}

[Fact]
public void LabelsFromChatHistoryReturnsAsExpected()
{
// Arrange
ChatHistory chatHistory = [];
chatHistory.AddUserMessage("user-message");
chatHistory.AddAssistantMessage("assist-message");
chatHistory.AddUserMessage("user-message2");
var executionSettings = new GeminiPromptExecutionSettings
{
Labels = "Key1:Value1"
};

// Act
var request = GeminiRequest.FromChatHistoryAndExecutionSettings(chatHistory, executionSettings);

// Assert
Assert.Equal(executionSettings.Labels, request.Labels);
}

[Fact]
public void ResponseSchemaConvertsNullableTypesToOpenApiFormat()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,35 @@ public async Task RequestCachedContentWorksCorrectlyAsync(string? cachedContent)
}
}

[Theory]
[InlineData(null)]
[InlineData("key:value")]
[InlineData("")]
public async Task RequestLabelsWorksCorrectlyAsync(string? labels)
{
// Arrange
string model = "fake-model";
var sut = new GoogleAIGeminiChatCompletionService(model, "key", httpClient: this._httpClient);

// Act
var result = await sut.GetChatMessageContentAsync("my prompt", new GeminiPromptExecutionSettings { Labels = labels });

// Assert
Assert.NotNull(result);
Assert.NotNull(this._messageHandlerStub.RequestContent);

var requestBody = UTF8Encoding.UTF8.GetString(this._messageHandlerStub.RequestContent);
if (labels is not null)
{
Assert.Contains($"\"labels\":\"{labels}\"", requestBody);
}
else
{
// Then no quality is provided, it should not be included in the request body
Assert.DoesNotContain("labels", requestBody);
}
}

[Theory]
[InlineData(null, false)]
[InlineData(0, true)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,35 @@ public async Task RequestCachedContentWorksCorrectlyAsync(string? cachedContent)
}
}

[Theory]
[InlineData(null)]
[InlineData("key:value")]
[InlineData("")]
public async Task RequestLabelsWorksCorrectlyAsync(string? labels)
{
// Arrange
string model = "fake-model";
var sut = new GoogleAIGeminiChatCompletionService(model, "key", httpClient: this._httpClient);

// Act
var result = await sut.GetChatMessageContentAsync("my prompt", new GeminiPromptExecutionSettings { Labels = labels });

// Assert
Assert.NotNull(result);
Assert.NotNull(this._messageHandlerStub.RequestContent);

var requestBody = UTF8Encoding.UTF8.GetString(this._messageHandlerStub.RequestContent);
if (labels is not null)
{
Assert.Contains($"\"labels\":\"{labels}\"", requestBody);
}
else
{
// Then no quality is provided, it should not be included in the request body
Assert.DoesNotContain("labels", requestBody);
}
}

[Theory]
[InlineData(null, false)]
[InlineData(0, true)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ internal sealed class GeminiRequest
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? CachedContent { get; set; }

[JsonPropertyName("labels")]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Labels { get; set; }

public void AddFunction(GeminiFunction function)
{
// NOTE: Currently Gemini only supports one tool i.e. function calling.
Expand Down Expand Up @@ -430,6 +434,7 @@ private static void AddSafetySettings(GeminiPromptExecutionSettings executionSet
private static void AddAdditionalBodyFields(GeminiPromptExecutionSettings executionSettings, GeminiRequest request)
{
request.CachedContent = executionSettings.CachedContent;
request.Labels = executionSettings.Labels;
if (executionSettings.ThinkingConfig is not null)
{
request.Configuration ??= new ConfigurationElement();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public sealed class GeminiPromptExecutionSettings : PromptExecutionSettings
private string? _responseMimeType;
private object? _responseSchema;
private string? _cachedContent;
private string? _labels;
private IList<GeminiSafetySetting>? _safetySettings;
private GeminiToolCallBehavior? _toolCallBehavior;
private GeminiThinkingConfig? _thinkingConfig;
Expand Down Expand Up @@ -147,6 +148,22 @@ public IList<GeminiSafetySetting>? SafetySettings
}
}

/// <summary>
/// Gets or sets the labels.
/// </summary>
/// <value>
/// Metadata that can be added to the API call in the format of key-value pairs.
/// </value>
public string? Labels
{
get => this._labels;
set
{
this.ThrowIfFrozen();
this._labels = value;
}
}

/// <summary>
/// Gets or sets the behavior for how tool calls are handled.
/// </summary>
Expand Down
Loading