Skip to content

[AI] Maps Grounding#15911

Draft
paulb777 wants to merge 10 commits intomainfrom
pb-maps-grounding
Draft

[AI] Maps Grounding#15911
paulb777 wants to merge 10 commits intomainfrom
pb-maps-grounding

Conversation

@paulb777
Copy link
Member

@paulb777 paulb777 commented Mar 6, 2026

Inspired by firebase/firebase-js-sdk#9458

TODO: ADD text field and update integration test

@gemini-code-assist
Copy link
Contributor

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

@paulb777 paulb777 marked this pull request as draft March 6, 2026 00:39
@paulb777
Copy link
Member Author

paulb777 commented Mar 6, 2026

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for grounding with Google Maps, a valuable addition to the SDK's capabilities. The changes are well-structured, adding new data types for tool configuration and response handling, along with comprehensive unit and integration tests. My feedback includes a couple of minor suggestions: one to correct a documentation typo and another to add input validation for increased robustness. I've also proposed some refactoring in the new integration tests to enhance their clarity and conciseness.

@paulb777 paulb777 force-pushed the pb-maps-grounding branch from 6cd64a0 to 67fa59f Compare March 7, 2026 16:04
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Should we put this file in Sources/Types/Public/Tools?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

/// > Important: When using this feature, you are required to comply with the
/// "Grounding with Google Maps" usage requirements for your chosen API provider.
public struct GoogleMaps: Sendable, Encodable {
public init() {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Let's keep the initializer internal until we need to expose it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment on lines +149 to +150
public static func googleMaps(_ googleMaps: GoogleMaps = GoogleMaps()) -> Tool {
return self.init(googleMaps: googleMaps)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public static func googleMaps(_ googleMaps: GoogleMaps = GoogleMaps()) -> Tool {
return self.init(googleMaps: googleMaps)
public static func googleMaps() -> Tool {
return self.init(googleMaps: GoogleMaps())

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines +230 to +258
public let latLng: LatLng

public init(latLng: LatLng) {
self.latLng = latLng
}

enum CodingKeys: String, CodingKey {
case latLng = "lat_lng"
}
}

/// An object that represents a latitude/longitude pair.
public struct LatLng: Sendable, Encodable {
/// The latitude in degrees. It must be in the range [-90.0, +90.0].
public let latitude: Double
/// The longitude in degrees. It must be in the range [-180.0, +180.0].
public let longitude: Double

public init(latitude: Double, longitude: Double) {
precondition(
latitude >= -90.0 && latitude <= 90.0,
"Latitude must be in the range [-90.0, 90.0]."
)
precondition(
longitude >= -180.0 && longitude <= 180.0,
"Longitude must be in the range [-180.0, 180.0]."
)
self.latitude = latitude
self.longitude = longitude
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider hiding the questionably named LatLng with an initializer that takes latitude and longitude:

Suggested change
public let latLng: LatLng
public init(latLng: LatLng) {
self.latLng = latLng
}
enum CodingKeys: String, CodingKey {
case latLng = "lat_lng"
}
}
/// An object that represents a latitude/longitude pair.
public struct LatLng: Sendable, Encodable {
/// The latitude in degrees. It must be in the range [-90.0, +90.0].
public let latitude: Double
/// The longitude in degrees. It must be in the range [-180.0, +180.0].
public let longitude: Double
public init(latitude: Double, longitude: Double) {
precondition(
latitude >= -90.0 && latitude <= 90.0,
"Latitude must be in the range [-90.0, 90.0]."
)
precondition(
longitude >= -180.0 && longitude <= 180.0,
"Longitude must be in the range [-180.0, 180.0]."
)
self.latitude = latitude
self.longitude = longitude
let latLng: LatLng
init(latLng: LatLng) {
self.latLng = latLng
}
public init(latitude: Double, longitude: Double) {
assert(
latitude >= -90.0 && latitude <= 90.0,
"Latitude must be in the range [-90.0, 90.0]."
)
assert(
longitude >= -180.0 && longitude <= 180.0,
"Longitude must be in the range [-180.0, 180.0]."
)
self.latLng = LatLng(latitude: latitude, longitude: longitude)
}
}
/// An object that represents a latitude/longitude pair.
struct LatLng: Sendable, Encodable {
/// The latitude in degrees. It must be in the range [-90.0, +90.0].
let latitude: Double
/// The longitude in degrees. It must be in the range [-180.0, +180.0].
let longitude: Double
init(latitude: Double, longitude: Double) {

or using the platform-native type CLLocationCoordinate2D:

Suggested change
public let latLng: LatLng
public init(latLng: LatLng) {
self.latLng = latLng
}
enum CodingKeys: String, CodingKey {
case latLng = "lat_lng"
}
}
/// An object that represents a latitude/longitude pair.
public struct LatLng: Sendable, Encodable {
/// The latitude in degrees. It must be in the range [-90.0, +90.0].
public let latitude: Double
/// The longitude in degrees. It must be in the range [-180.0, +180.0].
public let longitude: Double
public init(latitude: Double, longitude: Double) {
precondition(
latitude >= -90.0 && latitude <= 90.0,
"Latitude must be in the range [-90.0, 90.0]."
)
precondition(
longitude >= -180.0 && longitude <= 180.0,
"Longitude must be in the range [-180.0, 180.0]."
)
self.latitude = latitude
self.longitude = longitude
let latLng: LatLng
init(latLng: LatLng) {
self.latLng = latLng
}
public init(location: CLLocationCoordinate2D) {
assert(CLLocationCoordinate2DIsValid(location), """
Latitude must be in the range [-90.0, 90.0] and longitude must be in the range [-180.0, 180.0].
""")
self.latLng = LatLng(latitude: location.latitude, longitude: location.longitude)
}
}
/// An object that represents a latitude/longitude pair.
struct LatLng: Sendable, Encodable {
/// The latitude in degrees. It must be in the range [-90.0, +90.0].
let latitude: Double
/// The longitude in degrees. It must be in the range [-180.0, +180.0].
let longitude: Double
init(latitude: Double, longitude: Double) {

The latter would require import CoreLocation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we agreed with the group that LatLng should be public across platforms?

Comment on lines +236 to +238
enum CodingKeys: String, CodingKey {
case latLng = "lat_lng"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This can be deleted.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment on lines +227 to +292
extension ToolConfig: Encodable {}
extension ToolConfig: Encodable {
enum CodingKeys: String, CodingKey {
case functionCallingConfig
case retrievalConfig = "retrieval_config"
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This should be reverted.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}

/// A grounding chunk sourced from Google Maps.
public struct GoogleMapsGroundingChunk: Sendable, Equatable, Hashable, Decodable {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Should this be nested inside GroundingMetadata to align with GroundingMetadata.WebGroundingChunk?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure. It might be better to move WebGroundingChunk to its own file to align with Maps Grounding?

Comment on lines +28 to +32
public let uri: String
/// The title of the retrieved map data.
public let title: String
/// The Place ID of the retrieved map data.
public let placeID: String
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these guaranteed to be non-nil?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a recommended way to find out?

/// A grounding chunk sourced from Google Maps.
public struct GoogleMapsGroundingChunk: Sendable, Equatable, Hashable, Decodable {
/// The URI of the retrieved map data.
public let uri: String
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be more idiomatic to provide a URL in Swift?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}

/// A grounding chunk sourced from Google Maps.
public struct GoogleMapsGroundingChunk: Sendable, Equatable, Hashable, Decodable {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ongoing discussion in the API review. I haven't been able to get text included in a response.

@danger-firebase-ios
Copy link

1 Warning
⚠️ New public headers were added, did you remember to add them to the umbrella header?

Generated by 🚫 Danger

/// The URL of the retrieved map data.
public let url: URL?
/// The title of the retrieved map data.
public let title: String
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make these either nullable or defensively decode.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants