Skip to content

Commit cbf8fc2

Browse files
shethaaditAdit Sheth
and
Adit Sheth
authored
.Net: Added Labels field in Gemini Request. (#12300)
### Motivation and Context ### Description Added `Labels` field in Gemini Request. ### Contribution Checklist - [Y] The code builds clean without any errors or warnings - [Y] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [Y] All unit tests pass, and I have added new tests where possible - [Y] I didn't break anyone 😄 Fixes #12257 --------- Co-authored-by: Adit Sheth <adsheth@microsoft.com>
1 parent b4ea851 commit cbf8fc2

File tree

5 files changed

+118
-0
lines changed

5 files changed

+118
-0
lines changed

dotnet/src/Connectors/Connectors.Google.UnitTests/Core/Gemini/GeminiRequestTests.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,24 @@ public void CachedContentFromPromptReturnsAsExpected()
521521
Assert.Equal(executionSettings.CachedContent, request.CachedContent);
522522
}
523523

524+
[Fact]
525+
public void LabelsFromPromptReturnsAsExpected()
526+
{
527+
// Arrange
528+
var prompt = "prompt-example";
529+
var executionSettings = new GeminiPromptExecutionSettings
530+
{
531+
Labels = "Key1:Value1"
532+
};
533+
534+
// Act
535+
var request = GeminiRequest.FromPromptAndExecutionSettings(prompt, executionSettings);
536+
537+
// Assert
538+
Assert.NotNull(request.Configuration);
539+
Assert.Equal(executionSettings.Labels, request.Labels);
540+
}
541+
524542
[Fact]
525543
public void CachedContentFromChatHistoryReturnsAsExpected()
526544
{
@@ -541,6 +559,26 @@ public void CachedContentFromChatHistoryReturnsAsExpected()
541559
Assert.Equal(executionSettings.CachedContent, request.CachedContent);
542560
}
543561

562+
[Fact]
563+
public void LabelsFromChatHistoryReturnsAsExpected()
564+
{
565+
// Arrange
566+
ChatHistory chatHistory = [];
567+
chatHistory.AddUserMessage("user-message");
568+
chatHistory.AddAssistantMessage("assist-message");
569+
chatHistory.AddUserMessage("user-message2");
570+
var executionSettings = new GeminiPromptExecutionSettings
571+
{
572+
Labels = "Key1:Value1"
573+
};
574+
575+
// Act
576+
var request = GeminiRequest.FromChatHistoryAndExecutionSettings(chatHistory, executionSettings);
577+
578+
// Assert
579+
Assert.Equal(executionSettings.Labels, request.Labels);
580+
}
581+
544582
[Fact]
545583
public void ResponseSchemaConvertsNullableTypesToOpenApiFormat()
546584
{

dotnet/src/Connectors/Connectors.Google.UnitTests/Services/GoogleAIGeminiChatCompletionServiceTests.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,35 @@ public async Task RequestCachedContentWorksCorrectlyAsync(string? cachedContent)
6969
}
7070
}
7171

72+
[Theory]
73+
[InlineData(null)]
74+
[InlineData("key:value")]
75+
[InlineData("")]
76+
public async Task RequestLabelsWorksCorrectlyAsync(string? labels)
77+
{
78+
// Arrange
79+
string model = "fake-model";
80+
var sut = new GoogleAIGeminiChatCompletionService(model, "key", httpClient: this._httpClient);
81+
82+
// Act
83+
var result = await sut.GetChatMessageContentAsync("my prompt", new GeminiPromptExecutionSettings { Labels = labels });
84+
85+
// Assert
86+
Assert.NotNull(result);
87+
Assert.NotNull(this._messageHandlerStub.RequestContent);
88+
89+
var requestBody = UTF8Encoding.UTF8.GetString(this._messageHandlerStub.RequestContent);
90+
if (labels is not null)
91+
{
92+
Assert.Contains($"\"labels\":\"{labels}\"", requestBody);
93+
}
94+
else
95+
{
96+
// Then no quality is provided, it should not be included in the request body
97+
Assert.DoesNotContain("labels", requestBody);
98+
}
99+
}
100+
72101
[Theory]
73102
[InlineData(null, false)]
74103
[InlineData(0, true)]

dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAIGeminiChatCompletionServiceTests.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,35 @@ public async Task RequestCachedContentWorksCorrectlyAsync(string? cachedContent)
8080
}
8181
}
8282

83+
[Theory]
84+
[InlineData(null)]
85+
[InlineData("key:value")]
86+
[InlineData("")]
87+
public async Task RequestLabelsWorksCorrectlyAsync(string? labels)
88+
{
89+
// Arrange
90+
string model = "fake-model";
91+
var sut = new GoogleAIGeminiChatCompletionService(model, "key", httpClient: this._httpClient);
92+
93+
// Act
94+
var result = await sut.GetChatMessageContentAsync("my prompt", new GeminiPromptExecutionSettings { Labels = labels });
95+
96+
// Assert
97+
Assert.NotNull(result);
98+
Assert.NotNull(this._messageHandlerStub.RequestContent);
99+
100+
var requestBody = UTF8Encoding.UTF8.GetString(this._messageHandlerStub.RequestContent);
101+
if (labels is not null)
102+
{
103+
Assert.Contains($"\"labels\":\"{labels}\"", requestBody);
104+
}
105+
else
106+
{
107+
// Then no quality is provided, it should not be included in the request body
108+
Assert.DoesNotContain("labels", requestBody);
109+
}
110+
}
111+
83112
[Theory]
84113
[InlineData(null, false)]
85114
[InlineData(0, true)]

dotnet/src/Connectors/Connectors.Google/Core/Gemini/Models/GeminiRequest.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ internal sealed class GeminiRequest
4646
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
4747
public string? CachedContent { get; set; }
4848

49+
[JsonPropertyName("labels")]
50+
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
51+
public string? Labels { get; set; }
52+
4953
public void AddFunction(GeminiFunction function)
5054
{
5155
// NOTE: Currently Gemini only supports one tool i.e. function calling.
@@ -430,6 +434,7 @@ private static void AddSafetySettings(GeminiPromptExecutionSettings executionSet
430434
private static void AddAdditionalBodyFields(GeminiPromptExecutionSettings executionSettings, GeminiRequest request)
431435
{
432436
request.CachedContent = executionSettings.CachedContent;
437+
request.Labels = executionSettings.Labels;
433438
if (executionSettings.ThinkingConfig is not null)
434439
{
435440
request.Configuration ??= new ConfigurationElement();

dotnet/src/Connectors/Connectors.Google/GeminiPromptExecutionSettings.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public sealed class GeminiPromptExecutionSettings : PromptExecutionSettings
2828
private string? _responseMimeType;
2929
private object? _responseSchema;
3030
private string? _cachedContent;
31+
private string? _labels;
3132
private IList<GeminiSafetySetting>? _safetySettings;
3233
private GeminiToolCallBehavior? _toolCallBehavior;
3334
private GeminiThinkingConfig? _thinkingConfig;
@@ -147,6 +148,22 @@ public IList<GeminiSafetySetting>? SafetySettings
147148
}
148149
}
149150

151+
/// <summary>
152+
/// Gets or sets the labels.
153+
/// </summary>
154+
/// <value>
155+
/// Metadata that can be added to the API call in the format of key-value pairs.
156+
/// </value>
157+
public string? Labels
158+
{
159+
get => this._labels;
160+
set
161+
{
162+
this.ThrowIfFrozen();
163+
this._labels = value;
164+
}
165+
}
166+
150167
/// <summary>
151168
/// Gets or sets the behavior for how tool calls are handled.
152169
/// </summary>

0 commit comments

Comments
 (0)