Skip to content

Commit d32fa03

Browse files
authored
feat(js/plugins/google-genai): Added support for Google Maps (#3665)
1 parent f117ad5 commit d32fa03

File tree

6 files changed

+140
-1
lines changed

6 files changed

+140
-1
lines changed

js/plugins/google-genai/src/common/types.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,16 @@ export function isRetrievalTool(tool: Tool): tool is RetrievalTool {
878878
return (tool as RetrievalTool).retrieval !== undefined;
879879
}
880880

881+
export declare interface GoogleMaps {
882+
enableWidget: boolean;
883+
}
884+
export declare interface GoogleMapsTool {
885+
googleMaps?: GoogleMaps;
886+
}
887+
export function isGoogleMapsTool(tool: Tool): tool is GoogleMapsTool {
888+
return (tool as GoogleMapsTool).googleMaps !== undefined;
889+
}
890+
881891
/**
882892
* Tool to retrieve public web data for grounding, powered by Google.
883893
*/
@@ -893,6 +903,7 @@ export declare interface GoogleSearchRetrieval {
893903
export declare type Tool =
894904
| FunctionDeclarationsTool
895905
| RetrievalTool // Vertex AI Only
906+
| GoogleMapsTool // Vertex AI Only
896907
| CodeExecutionTool // Google AI Only
897908
| GoogleSearchRetrievalTool;
898909

@@ -973,10 +984,22 @@ export declare interface FunctionCallingConfig {
973984
allowedFunctionNames?: string[];
974985
}
975986

987+
export declare interface LatLng {
988+
latitude?: number;
989+
longitude?: number;
990+
}
991+
992+
export declare interface RetrievalConfig {
993+
latLng?: LatLng;
994+
languageCode?: string;
995+
}
996+
976997
/** This config is shared for all tools provided in the request. */
977998
export declare interface ToolConfig {
978999
/** Function calling config. */
9791000
functionCallingConfig?: FunctionCallingConfig;
1001+
/** Retrieval config */
1002+
retrievalConfig?: RetrievalConfig;
9801003
}
9811004

9821005
export declare interface GenerateContentRequest {

js/plugins/google-genai/src/vertexai/gemini.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,28 @@ export const GeminiConfigSchema = GenerationCommonConfigSchema.extend({
255255
'With NONE, the model is prohibited from making function calls.'
256256
)
257257
.optional(),
258+
/**
259+
* Retrieval config for search grounding and maps grounding
260+
*/
261+
retrievalConfig: z
262+
.object({
263+
/**
264+
* User location for search grounding or
265+
* place location for maps grounding.
266+
*/
267+
latLng: z
268+
.object({
269+
latitude: z.number().optional(),
270+
longitude: z.number().optional(),
271+
})
272+
.describe('User location for Google search or Google maps grounding.')
273+
.optional(),
274+
/**
275+
* Language code for the request. e.g. 'en-us'
276+
*/
277+
languageCode: z.string().optional(),
278+
})
279+
.optional(),
258280
thinkingConfig: z
259281
.object({
260282
includeThoughts: z
@@ -466,6 +488,7 @@ export function defineModel(
466488
const {
467489
apiKey: apiKeyFromConfig,
468490
functionCallingConfig,
491+
retrievalConfig,
469492
version: versionFromConfig,
470493
googleSearchRetrieval,
471494
tools: toolsFromConfig,
@@ -537,6 +560,13 @@ export function defineModel(
537560
};
538561
}
539562

563+
if (retrievalConfig) {
564+
if (!toolConfig) {
565+
toolConfig = {};
566+
}
567+
toolConfig.retrievalConfig = structuredClone(retrievalConfig);
568+
}
569+
540570
// Cannot use tools and function calling at the same time
541571
const jsonMode =
542572
(request.output?.format === 'json' || !!request.output?.schema) &&

js/plugins/google-genai/src/vertexai/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import {
2525
GenerateContentRequest,
2626
GenerateContentResponse,
2727
GenerateContentStreamResult,
28+
GoogleMaps,
29+
GoogleMapsTool,
2830
GoogleSearchRetrieval,
2931
GoogleSearchRetrievalTool,
3032
GroundingMetadata,
@@ -42,6 +44,7 @@ import {
4244
ToolConfig,
4345
isCodeExecutionTool,
4446
isFunctionDeclarationsTool,
47+
isGoogleMapsTool,
4548
isGoogleSearchRetrievalTool,
4649
isObject,
4750
isRetrievalTool,
@@ -55,6 +58,7 @@ export {
5558
TaskTypeSchema,
5659
isCodeExecutionTool,
5760
isFunctionDeclarationsTool,
61+
isGoogleMapsTool,
5862
isGoogleSearchRetrievalTool,
5963
isObject,
6064
isRetrievalTool,
@@ -66,6 +70,8 @@ export {
6670
type GenerateContentRequest,
6771
type GenerateContentResponse,
6872
type GenerateContentStreamResult,
73+
type GoogleMaps,
74+
type GoogleMapsTool,
6975
type GoogleSearchRetrieval,
7076
type GoogleSearchRetrievalTool,
7177
type GroundingMetadata,

js/plugins/google-genai/tests/vertexai/gemini_test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
HarmBlockThreshold,
3535
HarmCategory,
3636
isFunctionDeclarationsTool,
37+
isGoogleMapsTool,
3738
isGoogleSearchRetrievalTool,
3839
isRetrievalTool,
3940
} from '../../src/vertexai/types.js';
@@ -347,6 +348,34 @@ describe('Vertex AI Gemini', () => {
347348
assert.deepStrictEqual(apiRequest.labels, myLabels);
348349
});
349350

351+
it('handles retrievalConfig', async () => {
352+
mockFetchResponse(defaultApiResponse);
353+
const request: GenerateRequest<typeof GeminiConfigSchema> = {
354+
...minimalRequest,
355+
config: {
356+
retrievalConfig: {
357+
latLng: {
358+
latitude: 37.7749,
359+
longitude: -122.4194,
360+
},
361+
languageCode: 'en-US',
362+
},
363+
},
364+
};
365+
const model = defineModel('gemini-2.5-flash', clientOptions);
366+
await model.run(request);
367+
const apiRequest: GenerateContentRequest = JSON.parse(
368+
fetchStub.lastCall.args[1].body
369+
);
370+
assert.deepStrictEqual(apiRequest.toolConfig?.retrievalConfig, {
371+
latLng: {
372+
latitude: 37.7749,
373+
longitude: -122.4194,
374+
},
375+
languageCode: 'en-US',
376+
});
377+
});
378+
350379
it('constructs tools array with functionDeclarations', async () => {
351380
mockFetchResponse(defaultApiResponse);
352381
const request: GenerateRequest<typeof GeminiConfigSchema> = {
@@ -402,6 +431,29 @@ describe('Vertex AI Gemini', () => {
402431
}
403432
});
404433

434+
it('handles googleMaps tool', async () => {
435+
mockFetchResponse(defaultApiResponse);
436+
const request: GenerateRequest<typeof GeminiConfigSchema> = {
437+
...minimalRequest,
438+
config: {
439+
tools: [{ googleMaps: { enableWidget: true } } as any],
440+
},
441+
};
442+
const model = defineModel('gemini-2.5-flash', clientOptions);
443+
await model.run(request);
444+
const apiRequest: GenerateContentRequest = JSON.parse(
445+
fetchStub.lastCall.args[1].body
446+
);
447+
const mapsTool = apiRequest.tools?.find(isGoogleMapsTool);
448+
assert.ok(mapsTool, 'Expected GoogleMapsTool');
449+
if (mapsTool) {
450+
assert.ok(mapsTool.googleMaps, 'Expected googleMaps property');
451+
assert.deepStrictEqual(mapsTool, {
452+
googleMaps: { enableWidget: true },
453+
});
454+
}
455+
});
456+
405457
if (clientOptions.kind === 'regional') {
406458
it('handles vertexRetrieval tool', async () => {
407459
mockFetchResponse(defaultApiResponse);

js/testapps/basic-gemini/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"start": "node lib/index.js",
99
"build": "tsc",
1010
"build:watch": "tsc --watch",
11-
"genkit:dev": "genkit start -- npx tsx --watch src/index.ts"
11+
"genkit:dev": "genkit start -- npx tsx --watch src/index-vertexai.ts"
1212
},
1313
"keywords": [],
1414
"author": "",

js/testapps/basic-gemini/src/index-vertexai.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,34 @@ ai.defineFlow('streaming', async (_, { sendChunk }) => {
133133
return poem;
134134
});
135135

136+
// Google maps grounding
137+
ai.defineFlow('maps-grounding', async () => {
138+
const { text, raw } = await ai.generate({
139+
model: vertexAI.model('gemini-2.5-flash'),
140+
prompt: 'Describe some sights near me',
141+
config: {
142+
tools: [
143+
{
144+
googleMaps: {
145+
enableWidget: true,
146+
},
147+
},
148+
],
149+
retrievalConfig: {
150+
latLng: {
151+
latitude: 43.0896,
152+
longitude: -79.0849,
153+
},
154+
},
155+
},
156+
});
157+
158+
return {
159+
text,
160+
groundingMetadata: (raw as any)?.candidates[0]?.groundingMetadata,
161+
};
162+
});
163+
136164
// Search grounding
137165
ai.defineFlow('search-grounding', async () => {
138166
const { text, raw } = await ai.generate({

0 commit comments

Comments
 (0)