Skip to content

Commit 2a23f14

Browse files
committed
feat: Introduce Google Maps tool integration, including new content types and a dedicated test.
1 parent 27edb6b commit 2a23f14

4 files changed

Lines changed: 241 additions & 13 deletions

File tree

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
<groupId>io.github.glaforge</groupId>
2323
<artifactId>gemini-interactions-api-sdk</artifactId>
24-
<version>0.7.2-SNAPSHOT</version>
24+
<version>0.8.0-SNAPSHOT</version>
2525
<name>Gemini Interactions API SDK</name>
2626

2727
<properties>

src/main/java/io/github/glaforge/gemini/interactions/model/Content.java

Lines changed: 142 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@
5151
@JsonSubTypes.Type(value = Content.McpServerToolCallContent.class, name = "mcp_server_tool_call"),
5252
@JsonSubTypes.Type(value = Content.McpServerToolResultContent.class, name = "mcp_server_tool_result"),
5353
@JsonSubTypes.Type(value = Content.FileSearchCallContent.class, name = "file_search_call"),
54-
@JsonSubTypes.Type(value = Content.FileSearchResultContent.class, name = "file_search_result")
54+
@JsonSubTypes.Type(value = Content.FileSearchResultContent.class, name = "file_search_result"),
55+
@JsonSubTypes.Type(value = Content.GoogleMapsCallContent.class, name = "google_maps_call"),
56+
@JsonSubTypes.Type(value = Content.GoogleMapsResultContent.class, name = "google_maps_result")
5557
})
5658
public sealed interface Content permits
5759
Content.TextContent,
@@ -71,7 +73,9 @@ public sealed interface Content permits
7173
Content.McpServerToolCallContent,
7274
Content.McpServerToolResultContent,
7375
Content.FileSearchCallContent,
74-
Content.FileSearchResultContent {
76+
Content.FileSearchResultContent,
77+
Content.GoogleMapsCallContent,
78+
Content.GoogleMapsResultContent {
7579

7680
/**
7781
* Returns the type of content.
@@ -133,16 +137,74 @@ public TextContent(String text) {
133137

134138
/**
135139
* Annotation for text content.
136-
*
137-
* @param startIndex Start index of the annotation.
138-
* @param endIndex End index of the annotation.
139-
* @param source Source of the annotation.
140+
*/
141+
@JsonTypeInfo(
142+
use = JsonTypeInfo.Id.NAME,
143+
include = JsonTypeInfo.As.EXISTING_PROPERTY,
144+
property = "type",
145+
visible = true
146+
)
147+
@JsonSubTypes({
148+
@JsonSubTypes.Type(value = Content.UrlCitation.class, name = "url_citation"),
149+
@JsonSubTypes.Type(value = Content.FileCitation.class, name = "file_citation"),
150+
@JsonSubTypes.Type(value = Content.PlaceCitation.class, name = "place_citation")
151+
})
152+
sealed interface Annotation permits UrlCitation, FileCitation, PlaceCitation {
153+
/**
154+
* Returns the type of annotation.
155+
*
156+
* @return The annotation type.
157+
*/
158+
String type();
159+
}
160+
161+
/**
162+
* URL citation annotation.
140163
*/
141164
@JsonIgnoreProperties(ignoreUnknown = true)
142-
record Annotation(
165+
record UrlCitation(
166+
String type,
143167
@JsonProperty("start_index") Integer startIndex,
144168
@JsonProperty("end_index") Integer endIndex,
169+
String url,
170+
String title
171+
) implements Annotation {}
172+
173+
/**
174+
* File citation annotation.
175+
*/
176+
@JsonIgnoreProperties(ignoreUnknown = true)
177+
record FileCitation(
178+
String type,
179+
@JsonProperty("start_index") Integer startIndex,
180+
@JsonProperty("end_index") Integer endIndex,
181+
@JsonProperty("document_uri") String documentUri,
182+
@JsonProperty("file_name") String fileName,
145183
String source
184+
) implements Annotation {}
185+
186+
/**
187+
* Place citation annotation.
188+
*/
189+
@JsonIgnoreProperties(ignoreUnknown = true)
190+
record PlaceCitation(
191+
String type,
192+
@JsonProperty("start_index") Integer startIndex,
193+
@JsonProperty("end_index") Integer endIndex,
194+
@JsonProperty("place_id") String placeId,
195+
String name,
196+
String url,
197+
@JsonProperty("review_snippets") List<ReviewSnippet> reviewSnippets
198+
) implements Annotation {}
199+
200+
/**
201+
* Review snippet for place citation or Google Maps results.
202+
*/
203+
@JsonIgnoreProperties(ignoreUnknown = true)
204+
record ReviewSnippet(
205+
String title,
206+
String url,
207+
@JsonProperty("review_id") String reviewId
146208
) {}
147209

148210
/**
@@ -268,7 +330,8 @@ record FunctionCallContent(
268330
String type,
269331
String id,
270332
String name,
271-
Map<String, Object> arguments
333+
Map<String, Object> arguments,
334+
String signature
272335
) implements Content {}
273336

274337
/**
@@ -312,7 +375,8 @@ record ToolResult(
312375
record CodeExecutionCallContent(
313376
String type,
314377
String id,
315-
CodeExecutionCallArguments arguments
378+
CodeExecutionCallArguments arguments,
379+
String signature
316380
) implements Content {}
317381

318382
/**
@@ -358,7 +422,8 @@ record CodeExecutionResultContent(
358422
record UrlContextCallContent(
359423
String type,
360424
String id,
361-
UrlContextCallArguments arguments
425+
UrlContextCallArguments arguments,
426+
String signature
362427
) implements Content {}
363428

364429
/**
@@ -536,4 +601,71 @@ record FileSearchResult(
536601
String text,
537602
@JsonProperty("file_search_store") String fileSearchStore
538603
) {}
604+
605+
// --- Google Maps ---
606+
607+
/**
608+
* Content representing a Google Maps call.
609+
*
610+
* @param type The type of content (must be "google_maps_call").
611+
* @param id The unique identifier for the Google Maps call.
612+
* @param arguments The arguments for the Google Maps.
613+
* @param signature The signature of the call.
614+
*/
615+
@JsonIgnoreProperties(ignoreUnknown = true)
616+
record GoogleMapsCallContent(
617+
String type,
618+
String id,
619+
GoogleMapsCallArguments arguments,
620+
String signature
621+
) implements Content {}
622+
623+
/**
624+
* Arguments for a Google Maps call.
625+
*
626+
* @param queries The queries to be executed.
627+
*/
628+
@JsonIgnoreProperties(ignoreUnknown = true)
629+
record GoogleMapsCallArguments(
630+
List<String> queries
631+
) {}
632+
633+
/**
634+
* Content representing the result of a Google Maps call.
635+
*
636+
* @param type The type of content (must be "google_maps_result").
637+
* @param callId The ID of the Google Maps call.
638+
* @param signature The signature of the result.
639+
* @param result The list of Google Maps results.
640+
*/
641+
@JsonIgnoreProperties(ignoreUnknown = true)
642+
record GoogleMapsResultContent(
643+
String type,
644+
@JsonProperty("call_id") String callId,
645+
String signature,
646+
List<GoogleMapsResult> result
647+
) implements Content {}
648+
649+
/**
650+
* Result of a single Google Maps call.
651+
*
652+
* @param places The places that were found.
653+
* @param widgetContextToken Resource name of the Google Maps widget context token.
654+
*/
655+
@JsonIgnoreProperties(ignoreUnknown = true)
656+
record GoogleMapsResult(
657+
List<Places> places,
658+
@JsonProperty("widget_context_token") String widgetContextToken
659+
) {}
660+
661+
/**
662+
* Place details.
663+
*/
664+
@JsonIgnoreProperties(ignoreUnknown = true)
665+
record Places(
666+
@JsonProperty("place_id") String placeId,
667+
String name,
668+
String url,
669+
@JsonProperty("review_snippets") List<ReviewSnippet> reviewSnippets
670+
) {}
539671
}

src/main/java/io/github/glaforge/gemini/interactions/model/Tool.java

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
@JsonSubTypes.Type(value = Tool.UrlContext.class, name = "url_context"),
4040
@JsonSubTypes.Type(value = Tool.ComputerUse.class, name = "computer_use"),
4141
@JsonSubTypes.Type(value = Tool.McpServer.class, name = "mcp_server"),
42-
@JsonSubTypes.Type(value = Tool.FileSearch.class, name = "file_search")
42+
@JsonSubTypes.Type(value = Tool.FileSearch.class, name = "file_search"),
43+
@JsonSubTypes.Type(value = Tool.GoogleMaps.class, name = "google_maps")
4344
})
4445
public sealed interface Tool permits
4546
Tool.Function,
@@ -48,7 +49,8 @@ public sealed interface Tool permits
4849
Tool.UrlContext,
4950
Tool.ComputerUse,
5051
Tool.McpServer,
51-
Tool.FileSearch {
52+
Tool.FileSearch,
53+
Tool.GoogleMaps {
5254

5355
/**
5456
* Returns the type of the tool.
@@ -201,6 +203,23 @@ record FileSearch(
201203
@JsonProperty("metadata_filter") String metadataFilter
202204
) implements Tool {}
203205

206+
/**
207+
* Tool definition for Google Maps.
208+
*
209+
* @param type The type of tool (must be "google_maps").
210+
*/
211+
@JsonIgnoreProperties(ignoreUnknown = true)
212+
record GoogleMaps(
213+
String type
214+
) implements Tool {
215+
/**
216+
* Creates a new GoogleMaps tool.
217+
*/
218+
public GoogleMaps() {
219+
this("google_maps");
220+
}
221+
}
222+
204223
// --- Tool Configuration ---
205224

206225
// ToolChoice can be a String (enum) or a ToolChoiceConfig object.
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.github.glaforge.gemini.interactions;
18+
19+
import io.github.glaforge.gemini.interactions.model.Content;
20+
import io.github.glaforge.gemini.interactions.model.Content.TextContent;
21+
import io.github.glaforge.gemini.interactions.model.Interaction;
22+
import io.github.glaforge.gemini.interactions.model.InteractionParams;
23+
import io.github.glaforge.gemini.interactions.model.Tool;
24+
import org.junit.jupiter.api.Test;
25+
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
26+
27+
import java.io.IOException;
28+
import java.util.List;
29+
30+
import static org.junit.jupiter.api.Assertions.assertNotNull;
31+
import static org.junit.jupiter.api.Assertions.assertTrue;
32+
33+
public class GoogleMapsTest {
34+
35+
@Test
36+
@EnabledIfEnvironmentVariable(named = "GEMINI_API_KEY", matches = ".+")
37+
void testGoogleMaps() throws IOException, InterruptedException {
38+
String apiKey = System.getenv("GEMINI_API_KEY");
39+
if (apiKey == null) {
40+
System.out.println("GEMINI_API_KEY not set, skipping testGoogleMaps");
41+
return;
42+
}
43+
44+
GeminiInteractionsClient client = GeminiInteractionsClient.builder()
45+
.apiKey(apiKey)
46+
.build();
47+
48+
// 1. Define the Google Maps tool
49+
Tool googleMaps = new Tool.GoogleMaps();
50+
51+
// 2. Create Interaction
52+
InteractionParams.ModelInteractionParams createParams = InteractionParams.ModelInteractionParams.builder()
53+
.model("gemini-2.5-flash")
54+
.input("Can you recommend some good restaurants near the Eiffel tower in Paris?")
55+
.tools(googleMaps)
56+
.build();
57+
58+
System.out.println("Sending search request with Google Maps tool...");
59+
Interaction interaction = client.create(createParams);
60+
System.out.println("Response status: " + interaction.status());
61+
assertNotNull(interaction.outputs(), "Interaction outputs should not be null");
62+
63+
// 3. Verify Response
64+
Content lastOutput = interaction.outputs().getLast();
65+
System.out.println("Last output type: " + lastOutput.getClass().getSimpleName());
66+
67+
if (lastOutput instanceof TextContent text) {
68+
System.out.println("Model Answer: " + text.text());
69+
assertTrue(text.text().length() > 0, "Model should provide an answer");
70+
String answer = text.text().toLowerCase();
71+
assertTrue(answer.contains("paris") || answer.contains("eiffel"), "Answer should be relevant to the query");
72+
assertTrue(answer.contains("jules verne"), "Answer should mention the Jules Verne restaurant");
73+
} else {
74+
System.out.println("Output content: " + lastOutput);
75+
}
76+
}
77+
}

0 commit comments

Comments
 (0)