Skip to content

Commit 0793f9c

Browse files
committed
feat(google genai): support sending labels with chat request
Signed-off-by: Gareth Evans <[email protected]>
1 parent 1e28e30 commit 0793f9c

File tree

3 files changed

+67
-4
lines changed

3 files changed

+67
-4
lines changed

models/spring-ai-google-genai/src/main/java/org/springframework/ai/google/genai/GoogleGenAiChatModel.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,8 @@ Prompt buildRequestPrompt(Prompt prompt) {
478478
runtimeOptions.getGoogleSearchRetrieval(), this.defaultOptions.getGoogleSearchRetrieval()));
479479
requestOptions.setSafetySettings(ModelOptionsUtils.mergeOption(runtimeOptions.getSafetySettings(),
480480
this.defaultOptions.getSafetySettings()));
481+
requestOptions
482+
.setLabels(ModelOptionsUtils.mergeOption(runtimeOptions.getLabels(), this.defaultOptions.getLabels()));
481483
}
482484
else {
483485
requestOptions.setInternalToolExecutionEnabled(this.defaultOptions.getInternalToolExecutionEnabled());
@@ -487,6 +489,7 @@ Prompt buildRequestPrompt(Prompt prompt) {
487489

488490
requestOptions.setGoogleSearchRetrieval(this.defaultOptions.getGoogleSearchRetrieval());
489491
requestOptions.setSafetySettings(this.defaultOptions.getSafetySettings());
492+
requestOptions.setLabels(this.defaultOptions.getLabels());
490493
}
491494

492495
ToolCallingChatOptions.validateToolCallbacks(requestOptions.getToolCallbacks());
@@ -677,6 +680,9 @@ GeminiRequest createGeminiRequest(Prompt prompt) {
677680
configBuilder
678681
.thinkingConfig(ThinkingConfig.builder().thinkingBudget(requestOptions.getThinkingBudget()).build());
679682
}
683+
if (requestOptions.getLabels() != null && !requestOptions.getLabels().isEmpty()) {
684+
configBuilder.labels(requestOptions.getLabels());
685+
}
680686

681687
// Add safety settings
682688
if (!CollectionUtils.isEmpty(requestOptions.getSafetySettings())) {

models/spring-ai-google-genai/src/main/java/org/springframework/ai/google/genai/GoogleGenAiChatOptions.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ public class GoogleGenAiChatOptions implements ToolCallingChatOptions {
144144

145145
@JsonIgnore
146146
private List<GoogleGenAiSafetySetting> safetySettings = new ArrayList<>();
147+
148+
@JsonIgnore
149+
private Map<String, String> labels = new HashMap<>();
147150
// @formatter:on
148151

149152
public static Builder builder() {
@@ -170,6 +173,7 @@ public static GoogleGenAiChatOptions fromOptions(GoogleGenAiChatOptions fromOpti
170173
options.setInternalToolExecutionEnabled(fromOptions.getInternalToolExecutionEnabled());
171174
options.setToolContext(fromOptions.getToolContext());
172175
options.setThinkingBudget(fromOptions.getThinkingBudget());
176+
options.setLabels(fromOptions.getLabels());
173177
return options;
174178
}
175179

@@ -332,6 +336,15 @@ public void setSafetySettings(List<GoogleGenAiSafetySetting> safetySettings) {
332336
this.safetySettings = safetySettings;
333337
}
334338

339+
public Map<String, String> getLabels() {
340+
return this.labels;
341+
}
342+
343+
public void setLabels(Map<String, String> labels) {
344+
Assert.notNull(labels, "labels must not be null");
345+
this.labels = labels;
346+
}
347+
335348
@Override
336349
public Map<String, Object> getToolContext() {
337350
return this.toolContext;
@@ -363,15 +376,15 @@ public boolean equals(Object o) {
363376
&& Objects.equals(this.toolNames, that.toolNames)
364377
&& Objects.equals(this.safetySettings, that.safetySettings)
365378
&& Objects.equals(this.internalToolExecutionEnabled, that.internalToolExecutionEnabled)
366-
&& Objects.equals(this.toolContext, that.toolContext);
379+
&& Objects.equals(this.toolContext, that.toolContext) && Objects.equals(this.labels, that.labels);
367380
}
368381

369382
@Override
370383
public int hashCode() {
371384
return Objects.hash(this.stopSequences, this.temperature, this.topP, this.topK, this.candidateCount,
372385
this.frequencyPenalty, this.presencePenalty, this.thinkingBudget, this.maxOutputTokens, this.model,
373386
this.responseMimeType, this.toolCallbacks, this.toolNames, this.googleSearchRetrieval,
374-
this.safetySettings, this.internalToolExecutionEnabled, this.toolContext);
387+
this.safetySettings, this.internalToolExecutionEnabled, this.toolContext, this.labels);
375388
}
376389

377390
@Override
@@ -382,7 +395,8 @@ public String toString() {
382395
+ ", candidateCount=" + this.candidateCount + ", maxOutputTokens=" + this.maxOutputTokens + ", model='"
383396
+ this.model + '\'' + ", responseMimeType='" + this.responseMimeType + '\'' + ", toolCallbacks="
384397
+ this.toolCallbacks + ", toolNames=" + this.toolNames + ", googleSearchRetrieval="
385-
+ this.googleSearchRetrieval + ", safetySettings=" + this.safetySettings + '}';
398+
+ this.googleSearchRetrieval + ", safetySettings=" + this.safetySettings + ", labels=" + this.labels
399+
+ '}';
386400
}
387401

388402
@Override
@@ -510,6 +524,12 @@ public Builder thinkingBudget(Integer thinkingBudget) {
510524
return this;
511525
}
512526

527+
public Builder labels(Map<String, String> labels) {
528+
Assert.notNull(labels, "labels must not be null");
529+
this.options.labels = labels;
530+
return this;
531+
}
532+
513533
public GoogleGenAiChatOptions build() {
514534
return this.options;
515535
}

models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiChatOptionsTest.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import org.junit.jupiter.api.Test;
2020

21+
import java.util.Map;
22+
2123
import static org.assertj.core.api.Assertions.assertThat;
2224

2325
/**
@@ -104,6 +106,29 @@ public void testEqualsAndHashCodeWithThinkingBudget() {
104106
assertThat(options1.hashCode()).isNotEqualTo(options3.hashCode());
105107
}
106108

109+
@Test
110+
public void testEqualsAndHashCodeWithLabels() {
111+
GoogleGenAiChatOptions options1 = GoogleGenAiChatOptions.builder()
112+
.model("test-model")
113+
.labels(Map.of("org", "my-org"))
114+
.build();
115+
116+
GoogleGenAiChatOptions options2 = GoogleGenAiChatOptions.builder()
117+
.model("test-model")
118+
.labels(Map.of("org", "my-org"))
119+
.build();
120+
121+
GoogleGenAiChatOptions options3 = GoogleGenAiChatOptions.builder()
122+
.model("test-model")
123+
.labels(Map.of("org", "other-org"))
124+
.build();
125+
126+
assertThat(options1).isEqualTo(options2);
127+
assertThat(options1.hashCode()).isEqualTo(options2.hashCode());
128+
assertThat(options1).isNotEqualTo(options3);
129+
assertThat(options1.hashCode()).isNotEqualTo(options3.hashCode());
130+
}
131+
107132
@Test
108133
public void testToStringWithThinkingBudget() {
109134
GoogleGenAiChatOptions options = GoogleGenAiChatOptions.builder()
@@ -116,4 +141,16 @@ public void testToStringWithThinkingBudget() {
116141
assertThat(toString).contains("test-model");
117142
}
118143

119-
}
144+
@Test
145+
public void testToStringWithLabels() {
146+
GoogleGenAiChatOptions options = GoogleGenAiChatOptions.builder()
147+
.model("test-model")
148+
.labels(Map.of("org", "my-org"))
149+
.build();
150+
151+
String toString = options.toString();
152+
assertThat(toString).contains("labels={org=my-org}");
153+
assertThat(toString).contains("test-model");
154+
}
155+
156+
}

0 commit comments

Comments
 (0)