From e7fa51abe4a2e528316d6c1947601b5603cb32c8 Mon Sep 17 00:00:00 2001 From: Emily Ploszaj Date: Thu, 26 Mar 2026 16:27:30 -0500 Subject: [PATCH] Reapply "Implement Maps Grounding (#7950)" (#7980) This reverts commit afadbf330737c80fc1a4f779485cec9958d7085d. --- ai-logic/firebase-ai/CHANGELOG.md | 1 + ai-logic/firebase-ai/api.txt | 61 ++++++++++++- ai-logic/firebase-ai/gradle.properties | 2 +- .../com/google/firebase/ai/GroundingTests.kt | 73 +++++++++++++++ .../com/google/firebase/ai/type/Candidate.kt | 37 +++++++- .../com/google/firebase/ai/type/GoogleMaps.kt | 35 ++++++++ .../com/google/firebase/ai/type/LatLng.kt | 34 +++++++ .../firebase/ai/type/RetrievalConfig.kt | 88 +++++++++++++++++++ .../com/google/firebase/ai/type/Tool.kt | 36 ++++++-- .../com/google/firebase/ai/type/ToolConfig.kt | 13 ++- .../google/firebase/ai/SerializationTests.kt | 6 +- .../firebase/ai/common/APIControllerTests.kt | 3 +- .../google/firebase/ai/JavaCompileTests.java | 11 ++- 13 files changed, 382 insertions(+), 18 deletions(-) create mode 100644 ai-logic/firebase-ai/src/androidTest/kotlin/com/google/firebase/ai/GroundingTests.kt create mode 100644 ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/GoogleMaps.kt create mode 100644 ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/LatLng.kt create mode 100644 ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/RetrievalConfig.kt diff --git a/ai-logic/firebase-ai/CHANGELOG.md b/ai-logic/firebase-ai/CHANGELOG.md index dd241558589..54f72b37109 100644 --- a/ai-logic/firebase-ai/CHANGELOG.md +++ b/ai-logic/firebase-ai/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- [feature] Added support for [Maps Grounding](https://ai.google.dev/gemini-api/docs/maps-grounding) (#7950) - [fixed] Fixed an issue causing network timeouts to throw the incorrect exception type, instead of `RequestTimeoutException` (#7966) - [fixed] Fixed an issue causing the SDK to throw an exception if an unknown message was received diff --git a/ai-logic/firebase-ai/api.txt b/ai-logic/firebase-ai/api.txt index 60d5e75fcc0..861f8d97567 100644 --- a/ai-logic/firebase-ai/api.txt +++ b/ai-logic/firebase-ai/api.txt @@ -637,6 +637,20 @@ package com.google.firebase.ai.type { method public com.google.firebase.ai.type.GenerativeBackend vertexAI(String location = "us-central1"); } + public final class GoogleMaps { + ctor public GoogleMaps(); + } + + public final class GoogleMapsGroundingChunk { + ctor public GoogleMapsGroundingChunk(String? uri, String? title, String? placeId); + method public String? getPlaceId(); + method public String? getTitle(); + method public String? getUri(); + property public final String? placeId; + property public final String? title; + property public final String? uri; + } + public final class GoogleSearch { ctor public GoogleSearch(); } @@ -650,8 +664,12 @@ package com.google.firebase.ai.type { } public final class GroundingChunk { - ctor public GroundingChunk(com.google.firebase.ai.type.WebGroundingChunk? web); + ctor public GroundingChunk(); + ctor public GroundingChunk(com.google.firebase.ai.type.WebGroundingChunk? web = null); + ctor public GroundingChunk(com.google.firebase.ai.type.WebGroundingChunk? web = null, com.google.firebase.ai.type.GoogleMapsGroundingChunk? maps = null); + method public com.google.firebase.ai.type.GoogleMapsGroundingChunk? getMaps(); method public com.google.firebase.ai.type.WebGroundingChunk? getWeb(); + property public final com.google.firebase.ai.type.GoogleMapsGroundingChunk? maps; property public final com.google.firebase.ai.type.WebGroundingChunk? web; } @@ -1167,6 +1185,17 @@ package com.google.firebase.ai.type { method public com.google.firebase.ai.type.JsonSchema string(String? description = null, boolean nullable = false, com.google.firebase.ai.type.StringFormat? format = null, String? title = null); } + public final class LatLng { + ctor public LatLng(double latitude, double longitude); + method public double component1(); + method public double component2(); + method public com.google.firebase.ai.type.LatLng copy(double latitude, double longitude); + method public double getLatitude(); + method public double getLongitude(); + property public final double latitude; + property public final double longitude; + } + @com.google.firebase.ai.type.PublicPreviewAPI public final class LiveAudioConversationConfig { field public static final com.google.firebase.ai.type.LiveAudioConversationConfig.Companion Companion; } @@ -1376,6 +1405,28 @@ package com.google.firebase.ai.type { property public final com.google.firebase.ai.type.GenerateContentResponse response; } + public final class RetrievalConfig { + method public static com.google.firebase.ai.type.RetrievalConfig.Builder builder(); + field public static final com.google.firebase.ai.type.RetrievalConfig.Companion Companion; + } + + public static final class RetrievalConfig.Builder { + ctor public RetrievalConfig.Builder(); + method public com.google.firebase.ai.type.RetrievalConfig build(); + method public com.google.firebase.ai.type.RetrievalConfig.Builder setLanguageCode(String? languageCode); + method public com.google.firebase.ai.type.RetrievalConfig.Builder setLatLng(com.google.firebase.ai.type.LatLng? latLng); + field public String? languageCode; + field public com.google.firebase.ai.type.LatLng? latLng; + } + + public static final class RetrievalConfig.Companion { + method public com.google.firebase.ai.type.RetrievalConfig.Builder builder(); + } + + public final class RetrievalConfigKt { + method public static com.google.firebase.ai.type.RetrievalConfig retrievalConfig(kotlin.jvm.functions.Function1 init); + } + public final class SafetyRating { method public Boolean? getBlocked(); method public com.google.firebase.ai.type.HarmCategory getCategory(); @@ -1618,6 +1669,8 @@ package com.google.firebase.ai.type { method public static com.google.firebase.ai.type.Tool codeExecution(); method public static com.google.firebase.ai.type.Tool functionDeclarations(java.util.List functionDeclarations); method public static com.google.firebase.ai.type.Tool functionDeclarations(java.util.List? functionDeclarations = null, java.util.List>? autoFunctionDeclarations); + method public static com.google.firebase.ai.type.Tool googleMaps(); + method public static com.google.firebase.ai.type.Tool googleMaps(com.google.firebase.ai.type.GoogleMaps googleMaps = com.google.firebase.ai.type.GoogleMaps()); method public static com.google.firebase.ai.type.Tool googleSearch(); method public static com.google.firebase.ai.type.Tool googleSearch(com.google.firebase.ai.type.GoogleSearch googleSearch = com.google.firebase.ai.type.GoogleSearch()); method public static com.google.firebase.ai.type.Tool urlContext(); @@ -1629,6 +1682,8 @@ package com.google.firebase.ai.type { method public com.google.firebase.ai.type.Tool codeExecution(); method public com.google.firebase.ai.type.Tool functionDeclarations(java.util.List functionDeclarations); method public com.google.firebase.ai.type.Tool functionDeclarations(java.util.List? functionDeclarations = null, java.util.List>? autoFunctionDeclarations); + method public com.google.firebase.ai.type.Tool googleMaps(); + method public com.google.firebase.ai.type.Tool googleMaps(com.google.firebase.ai.type.GoogleMaps googleMaps = com.google.firebase.ai.type.GoogleMaps()); method public com.google.firebase.ai.type.Tool googleSearch(); method public com.google.firebase.ai.type.Tool googleSearch(com.google.firebase.ai.type.GoogleSearch googleSearch = com.google.firebase.ai.type.GoogleSearch()); method public com.google.firebase.ai.type.Tool urlContext(); @@ -1636,7 +1691,9 @@ package com.google.firebase.ai.type { } public final class ToolConfig { - ctor public ToolConfig(com.google.firebase.ai.type.FunctionCallingConfig? functionCallingConfig); + ctor public ToolConfig(); + ctor public ToolConfig(com.google.firebase.ai.type.FunctionCallingConfig? functionCallingConfig = null); + ctor public ToolConfig(com.google.firebase.ai.type.FunctionCallingConfig? functionCallingConfig = null, com.google.firebase.ai.type.RetrievalConfig? retrievalConfig = null); } public final class Transcription { diff --git a/ai-logic/firebase-ai/gradle.properties b/ai-logic/firebase-ai/gradle.properties index 47a250ed3b9..9c7e2f88876 100644 --- a/ai-logic/firebase-ai/gradle.properties +++ b/ai-logic/firebase-ai/gradle.properties @@ -12,5 +12,5 @@ # See the License for the specific language governing permissions and # limitations under the License. -version=17.10.2 +version=17.11.0 latestReleasedVersion=17.10.1 diff --git a/ai-logic/firebase-ai/src/androidTest/kotlin/com/google/firebase/ai/GroundingTests.kt b/ai-logic/firebase-ai/src/androidTest/kotlin/com/google/firebase/ai/GroundingTests.kt new file mode 100644 index 00000000000..bfd0f8f67d7 --- /dev/null +++ b/ai-logic/firebase-ai/src/androidTest/kotlin/com/google/firebase/ai/GroundingTests.kt @@ -0,0 +1,73 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.firebase.ai + +import com.google.firebase.ai.AIModels.Companion.app +import com.google.firebase.ai.type.GenerativeBackend +import com.google.firebase.ai.type.LatLng +import com.google.firebase.ai.type.RetrievalConfig +import com.google.firebase.ai.type.Tool +import com.google.firebase.ai.type.ToolConfig +import io.kotest.matchers.shouldBe +import kotlinx.coroutines.runBlocking +import org.junit.Test + +class GroundingTests { + + @Test + fun groundingTests_canRecognizeAreas(): Unit = runBlocking { + val model = setupModel(config = ToolConfig()) + val response = model.generateContent("Where is a good place to grab a coffee near Alameda, CA?") + + response.candidates.isEmpty() shouldBe false + response.candidates[0].groundingMetadata?.groundingChunks?.any { it.maps != null } shouldBe true + } + + @Test + fun groundingTests_canRecognizeLatLng(): Unit = runBlocking { + val model = + setupModel( + config = + ToolConfig( + retrievalConfig = + RetrievalConfig( + latLng = LatLng(latitude = 30.2672, longitude = -97.7431), + languageCode = "en_US", + ), + ) + ) + val response = model.generateContent("Find bookstores in my area.") + + response.candidates.isEmpty() shouldBe false + response.candidates[0].groundingMetadata?.groundingChunks?.any { it.maps != null } shouldBe true + } + + companion object { + + @JvmStatic + fun setupModel(config: ToolConfig): GenerativeModel { + val model = + FirebaseAI.getInstance(app(), GenerativeBackend.vertexAI()) + .generativeModel( + modelName = "gemini-2.5-flash", + toolConfig = config, + tools = listOf(Tool.googleMaps()), + ) + return model + } + } +} diff --git a/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Candidate.kt b/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Candidate.kt index 40014f518d0..29b3062927e 100644 --- a/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Candidate.kt +++ b/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Candidate.kt @@ -336,6 +336,12 @@ public class FinishReason private constructor(public val name: String, public va * Vertex AI Gemini API (see [Service Terms](https://cloud.google.com/terms/service-terms) section * within the Service Specific Terms). * + * If using Grounding with Google Maps, you are required to comply with the "Grounding with Google + * Maps" usage requirements for your chosen API provider: + * [Gemini Developer API](https://ai.google.dev/gemini-api/terms#grounding-with-google-maps) or + * Vertex AI Gemini API (see [Service Terms](https://cloud.google.com/terms/service-terms) section + * within the Service Specific Terms). + * * @property webSearchQueries The list of web search queries that the model performed to gather the * grounding information. These can be used to allow users to explore the search results themselves. * @property searchEntryPoint Google Search entry point for web searches. This contains an HTML/CSS @@ -408,15 +414,40 @@ public class SearchEntryPoint( * Represents a chunk of retrieved data that supports a claim in the model's response. * * @property web Contains details if the grounding chunk is from a web source. + * @property maps Contains details if the grounding chunk is from a Google Maps source. */ -public class GroundingChunk( - public val web: WebGroundingChunk?, +public class GroundingChunk +@JvmOverloads +constructor( + public val web: WebGroundingChunk? = null, + public val maps: GoogleMapsGroundingChunk? = null, ) { + @Serializable internal data class Internal( val web: WebGroundingChunk.Internal?, + val maps: GoogleMapsGroundingChunk.Internal?, ) { - internal fun toPublic() = GroundingChunk(web = web?.toPublic()) + internal fun toPublic() = GroundingChunk(web = web?.toPublic(), maps?.toPublic()) + } +} + +/** + * A grounding chunk from Google Maps. + * + * @property uri The URI of the place. + * @property title The title of the place. + * @property placeId This Place's resource name, in `places/{place_id}` format. This can be used to + * look up the place using the Google Maps API. + */ +public class GoogleMapsGroundingChunk( + public val uri: String?, + public val title: String?, + public val placeId: String?, +) { + @Serializable + internal data class Internal(val uri: String?, val title: String?, val placeId: String?) { + fun toPublic() = GoogleMapsGroundingChunk(uri, title, placeId) } } diff --git a/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/GoogleMaps.kt b/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/GoogleMaps.kt new file mode 100644 index 00000000000..5a29dbb0d7a --- /dev/null +++ b/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/GoogleMaps.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.firebase.ai.type + +import kotlinx.serialization.Serializable + +/** + * A tool that allows a Gemini model to connect to Google Maps to access and incorporate + * location-based information into its responses. + * + * Important: If using Grounding with Google Maps, you are required to comply with the "Grounding + * with Google Maps" usage requirements for your chosen API provider: {@link + * https://ai.google.dev/gemini-api/terms#grounding-with-google-maps | Gemini Developer API} or + * Vertex AI Gemini API (see {@link https://cloud.google.com/terms/service-terms | Service Terms} + * section within the Service Specific Terms). + */ +public class GoogleMaps { + @Serializable internal class Internal() + + internal fun toInternal() = Internal() +} diff --git a/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/LatLng.kt b/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/LatLng.kt new file mode 100644 index 00000000000..1d665cb6bca --- /dev/null +++ b/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/LatLng.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.firebase.ai.type + +import kotlinx.serialization.Serializable + +/** + * An object that represents a latitude/longitude pair. + * + * @param latitude The latitude in degrees. It must be in the range [-90.0, +90.0]. + * @param longitude The longitude in degrees. It must be in the range [-180.0, +180.0]. + */ +public data class LatLng(val latitude: Double, val longitude: Double) { + @Serializable + internal data class Internal(val latitude: Double, val longitude: Double) { + fun toPublic() = LatLng(latitude, longitude) + } + + internal fun toInternal() = Internal(latitude, longitude) +} diff --git a/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/RetrievalConfig.kt b/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/RetrievalConfig.kt new file mode 100644 index 00000000000..5e3a1219a51 --- /dev/null +++ b/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/RetrievalConfig.kt @@ -0,0 +1,88 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.firebase.ai.type + +import com.google.firebase.ai.type.RetrievalConfig.Builder +import kotlinx.serialization.Serializable + +/** + * The configuration that specifies information which can be used by tools during inference calls. + * + * See the static methods in the `companion object` for the list of available behaviors. + */ +public class RetrievalConfig +internal constructor( + internal val latLng: LatLng? = null, + internal val languageCode: String? = null +) { + + internal fun toInternal() = Internal(latLng?.toInternal(), languageCode) + + /** + * Builder for creating a [RetrievalConfig]. + * + * Mainly intended for Java interop. Kotlin consumers should use [retrievalConfig] for a more + * idiomatic experience. + * + * @property latLng See [RetrievalConfig.latLng]. + * @property languageCode See [RetrievalConfig.languageCode]. + */ + public class Builder { + @JvmField public var latLng: LatLng? = null + @JvmField public var languageCode: String? = null + + public fun setLatLng(latLng: LatLng?): Builder = apply { this.latLng = latLng } + public fun setLanguageCode(languageCode: String?): Builder = apply { + this.languageCode = languageCode + } + + /** Create a new [RetrievalConfig] with the attached arguments. */ + public fun build(): RetrievalConfig { + return RetrievalConfig(latLng, languageCode) + } + } + + @Serializable + internal class Internal(val latLng: LatLng.Internal? = null, val languageCode: String? = null) {} + + public companion object { + /** + * Alternative casing for [RetrievalConfig.Builder]: + * ``` + * val config = RetrievalConfig.builder() + * ``` + */ + @JvmStatic public fun builder(): Builder = Builder() + } +} + +/** + * Helper method to construct a [RetrievalConfig] in a DSL-like manner. + * + * Example Usage: + * ``` + * retrievalConfig { + * latLng = aLatLng + * languageCode = "en_US" + * } + * ``` + */ +public fun retrievalConfig(init: RetrievalConfig.Builder.() -> Unit): RetrievalConfig { + val builder = Builder() + init(builder) + return builder.build() +} diff --git a/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Tool.kt b/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Tool.kt index 7ea8f9ee645..04ac948d58e 100644 --- a/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Tool.kt +++ b/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/Tool.kt @@ -32,6 +32,7 @@ internal constructor( internal val googleSearch: GoogleSearch?, internal val codeExecution: JsonObject?, internal val urlContext: UrlContext?, + internal val googleMaps: GoogleMaps?, ) { @OptIn(PublicPreviewAPI::class) @@ -43,7 +44,8 @@ internal constructor( }, googleSearch = this.googleSearch?.toInternal(), codeExecution = this.codeExecution, - urlContext = this.urlContext?.toInternal() + urlContext = this.urlContext?.toInternal(), + googleMaps = this.googleMaps?.toInternal(), ) @OptIn(InternalSerializationApi::class) @@ -54,12 +56,13 @@ internal constructor( // This is a json object because it is not possible to make a data class with no parameters. val codeExecution: JsonObject? = null, val urlContext: UrlContext.Internal? = null, + val googleMaps: GoogleMaps.Internal? = null, ) public companion object { @OptIn(PublicPreviewAPI::class) private val codeExecutionInstance by lazy { - Tool(null, null, null, JsonObject(emptyMap()), null) + Tool(null, null, null, JsonObject(emptyMap()), null, null) } /** @@ -71,7 +74,8 @@ internal constructor( public fun functionDeclarations( functionDeclarations: List, ): Tool { - @OptIn(PublicPreviewAPI::class) return Tool(functionDeclarations, null, null, null, null) + @OptIn(PublicPreviewAPI::class) + return Tool(functionDeclarations, null, null, null, null, null) } /** @@ -87,7 +91,7 @@ internal constructor( autoFunctionDeclarations: List>? ): Tool { @OptIn(PublicPreviewAPI::class) - return Tool(functionDeclarations, autoFunctionDeclarations, null, null, null) + return Tool(functionDeclarations, autoFunctionDeclarations, null, null, null, null) } /** Creates a [Tool] instance that allows the model to use code execution. */ @@ -107,7 +111,7 @@ internal constructor( @JvmStatic @JvmOverloads public fun urlContext(urlContext: UrlContext = UrlContext()): Tool { - return Tool(null, null, null, null, urlContext) + return Tool(null, null, null, null, urlContext, null) } /** @@ -129,7 +133,27 @@ internal constructor( @JvmStatic @JvmOverloads public fun googleSearch(googleSearch: GoogleSearch = GoogleSearch()): Tool { - @OptIn(PublicPreviewAPI::class) return Tool(null, null, googleSearch, null, null) + @OptIn(PublicPreviewAPI::class) return Tool(null, null, googleSearch, null, null, null) + } + + /** + * Creates a [Tool] instance that allows the model to use grounding with Google Maps. + * + * Grounding with Google Maps can be used to allow the model to connect to Google Maps to + * incorporate location-based information into its responses. + * + * When using this feature, you are required to comply with the "Grounding with Google Maps" + * usage requirements for your chosen API provider: {@link + * https://ai.google.dev/gemini-api/terms#grounding-with-google-maps | Gemini Developer API} or + * Vertex AI Gemini API (see {@link https://cloud.google.com/terms/service-terms | Service + * Terms} section within the Service Specific Terms). + * + * @return A [Tool] configured for Google Maps. + */ + @JvmStatic + @JvmOverloads + public fun googleMaps(googleMaps: GoogleMaps = GoogleMaps()): Tool { + @OptIn(PublicPreviewAPI::class) return Tool(null, null, null, null, null, googleMaps) } } } diff --git a/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/ToolConfig.kt b/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/ToolConfig.kt index 43d20ec3fd6..6c9f6be010b 100644 --- a/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/ToolConfig.kt +++ b/ai-logic/firebase-ai/src/main/kotlin/com/google/firebase/ai/type/ToolConfig.kt @@ -25,7 +25,12 @@ import kotlinx.serialization.Serializable * * @param functionCallingConfig The config for function calling */ -public class ToolConfig(internal val functionCallingConfig: FunctionCallingConfig?) { +public class ToolConfig +@JvmOverloads +constructor( + internal val functionCallingConfig: FunctionCallingConfig? = null, + internal val retrievalConfig: RetrievalConfig? = null, +) { internal fun toInternal() = Internal( @@ -38,12 +43,14 @@ public class ToolConfig(internal val functionCallingConfig: FunctionCallingConfi }, it.allowedFunctionNames ) - } + }, + retrievalConfig?.toInternal() ) @Serializable internal data class Internal( @SerialName("function_calling_config") - val functionCallingConfig: FunctionCallingConfig.Internal? + val functionCallingConfig: FunctionCallingConfig.Internal?, + val retrievalConfig: RetrievalConfig.Internal?, ) } diff --git a/ai-logic/firebase-ai/src/test/java/com/google/firebase/ai/SerializationTests.kt b/ai-logic/firebase-ai/src/test/java/com/google/firebase/ai/SerializationTests.kt index db92327c496..a2447fb5870 100644 --- a/ai-logic/firebase-ai/src/test/java/com/google/firebase/ai/SerializationTests.kt +++ b/ai-logic/firebase-ai/src/test/java/com/google/firebase/ai/SerializationTests.kt @@ -229,7 +229,8 @@ internal class SerializationTests { "id": "GroundingChunk", "type": "object", "properties": { - "web": { "${'$'}ref": "WebGroundingChunk" } + "web": { "${'$'}ref": "WebGroundingChunk" }, + "maps": { "${'$'}ref": "GoogleMapsGroundingChunk" } } } """ @@ -506,6 +507,9 @@ internal class SerializationTests { }, "urlContext": { "${'$'}ref": "UrlContext" + }, + "googleMaps": { + "${'$'}ref": "GoogleMaps" } } } diff --git a/ai-logic/firebase-ai/src/test/java/com/google/firebase/ai/common/APIControllerTests.kt b/ai-logic/firebase-ai/src/test/java/com/google/firebase/ai/common/APIControllerTests.kt index 72949d409d6..3ca82c4a1b1 100644 --- a/ai-logic/firebase-ai/src/test/java/com/google/firebase/ai/common/APIControllerTests.kt +++ b/ai-logic/firebase-ai/src/test/java/com/google/firebase/ai/common/APIControllerTests.kt @@ -253,7 +253,8 @@ internal class RequestFormatTests { FunctionCallingConfig.Internal( mode = FunctionCallingConfig.Internal.Mode.ANY, allowedFunctionNames = listOf("allowedFunctionName") - ) + ), + null ) ), ) diff --git a/ai-logic/firebase-ai/src/testUtil/java/com/google/firebase/ai/JavaCompileTests.java b/ai-logic/firebase-ai/src/testUtil/java/com/google/firebase/ai/JavaCompileTests.java index a3dbcf26691..e492f2067d2 100644 --- a/ai-logic/firebase-ai/src/testUtil/java/com/google/firebase/ai/JavaCompileTests.java +++ b/ai-logic/firebase-ai/src/testUtil/java/com/google/firebase/ai/JavaCompileTests.java @@ -55,6 +55,7 @@ import com.google.firebase.ai.type.ImagenMaskReference; import com.google.firebase.ai.type.InlineData; import com.google.firebase.ai.type.InlineDataPart; +import com.google.firebase.ai.type.LatLng; import com.google.firebase.ai.type.LiveGenerationConfig; import com.google.firebase.ai.type.LiveServerContent; import com.google.firebase.ai.type.LiveServerMessage; @@ -67,10 +68,12 @@ import com.google.firebase.ai.type.PromptFeedback; import com.google.firebase.ai.type.PublicPreviewAPI; import com.google.firebase.ai.type.ResponseModality; +import com.google.firebase.ai.type.RetrievalConfig; import com.google.firebase.ai.type.SafetyRating; import com.google.firebase.ai.type.Schema; import com.google.firebase.ai.type.SpeechConfig; import com.google.firebase.ai.type.TextPart; +import com.google.firebase.ai.type.ToolConfig; import com.google.firebase.ai.type.UsageMetadata; import com.google.firebase.ai.type.Voice; import com.google.firebase.concurrent.FirebaseExecutors; @@ -105,7 +108,7 @@ public void initializeJava() throws Exception { getGenerationConfig(), /* safetySettings */ null, /* tools */ null, - /* toolConfig */ null, + /* toolConfig */ new ToolConfig(null), /* systemInstruction */ null, /* requestOptions */ null, new OnDeviceConfig(InferenceMode.ONLY_ON_DEVICE, /* maxOutputTokens */ 500)); @@ -229,6 +232,12 @@ public void onComplete() { }); } + public void testMapsGrounding() { + RetrievalConfig retrievalConfig = + RetrievalConfig.builder().setLatLng(new LatLng(10, 10)).setLanguageCode("en_US").build(); + ToolConfig toolConfig = new ToolConfig(null, retrievalConfig); + } + public void validateCountTokensResponse(CountTokensResponse response) { int tokens = response.getTotalTokens(); Integer billable = response.getTotalBillableCharacters();