diff --git a/packages/types/src/model.ts b/packages/types/src/model.ts index 49e8e73edf..8c6bee53ba 100644 --- a/packages/types/src/model.ts +++ b/packages/types/src/model.ts @@ -109,6 +109,8 @@ export const modelInfoSchema = z.object({ isFree: z.boolean().optional(), // Flag to indicate if the model supports native tool calling (OpenAI-style function calling) supportsNativeTools: z.boolean().optional(), + // Flag to indicate if the model supports Google Search grounding + supportsGrounding: z.boolean().optional(), // Default tool protocol preferred by this model (if not specified, falls back to capability/provider defaults) defaultToolProtocol: z.enum(["xml", "native"]).optional(), /** diff --git a/packages/types/src/providers/gemini.ts b/packages/types/src/providers/gemini.ts index e7a73e6d0e..e744be8141 100644 --- a/packages/types/src/providers/gemini.ts +++ b/packages/types/src/providers/gemini.ts @@ -12,6 +12,7 @@ export const geminiModels = { supportsImages: true, supportsNativeTools: true, supportsPromptCache: true, + supportsGrounding: false, // Does not support Google Search grounding supportsReasoningEffort: ["low", "high"], reasoningEffort: "low", supportsTemperature: true, @@ -38,6 +39,7 @@ export const geminiModels = { supportsImages: true, supportsNativeTools: true, supportsPromptCache: true, + supportsGrounding: true, inputPrice: 2.5, // This is the pricing for prompts above 200k tokens. outputPrice: 15, cacheReadsPrice: 0.625, @@ -66,6 +68,7 @@ export const geminiModels = { supportsImages: true, supportsNativeTools: true, supportsPromptCache: true, + supportsGrounding: true, inputPrice: 2.5, // This is the pricing for prompts above 200k tokens. outputPrice: 15, cacheReadsPrice: 0.625, @@ -93,6 +96,7 @@ export const geminiModels = { supportsImages: true, supportsNativeTools: true, supportsPromptCache: true, + supportsGrounding: true, inputPrice: 2.5, // This is the pricing for prompts above 200k tokens. outputPrice: 15, cacheReadsPrice: 0.625, @@ -118,6 +122,7 @@ export const geminiModels = { supportsImages: true, supportsNativeTools: true, supportsPromptCache: true, + supportsGrounding: true, inputPrice: 2.5, // This is the pricing for prompts above 200k tokens. outputPrice: 15, cacheReadsPrice: 0.625, @@ -147,6 +152,7 @@ export const geminiModels = { supportsImages: true, supportsNativeTools: true, supportsPromptCache: true, + supportsGrounding: true, inputPrice: 0.3, outputPrice: 2.5, cacheReadsPrice: 0.075, @@ -160,6 +166,7 @@ export const geminiModels = { supportsImages: true, supportsNativeTools: true, supportsPromptCache: true, + supportsGrounding: true, inputPrice: 0.3, outputPrice: 2.5, cacheReadsPrice: 0.075, @@ -173,6 +180,7 @@ export const geminiModels = { supportsImages: true, supportsNativeTools: true, supportsPromptCache: true, + supportsGrounding: true, inputPrice: 0.3, outputPrice: 2.5, cacheReadsPrice: 0.075, @@ -188,6 +196,7 @@ export const geminiModels = { supportsImages: true, supportsNativeTools: true, supportsPromptCache: true, + supportsGrounding: true, inputPrice: 0.1, outputPrice: 0.4, cacheReadsPrice: 0.025, @@ -201,6 +210,7 @@ export const geminiModels = { supportsImages: true, supportsNativeTools: true, supportsPromptCache: true, + supportsGrounding: true, inputPrice: 0.1, outputPrice: 0.4, cacheReadsPrice: 0.025, diff --git a/src/api/providers/__tests__/gemini-handler.spec.ts b/src/api/providers/__tests__/gemini-handler.spec.ts index 541ffd5611..ec28553531 100644 --- a/src/api/providers/__tests__/gemini-handler.spec.ts +++ b/src/api/providers/__tests__/gemini-handler.spec.ts @@ -19,6 +19,40 @@ describe("GeminiHandler backend support", () => { expect(config.tools).toEqual([{ urlContext: {} }, { googleSearch: {} }]) }) + it("should not enable Google Search for gemini-3-pro-preview even when enableGrounding is true", async () => { + const options = { + apiProvider: "gemini", + apiModelId: "gemini-3-pro-preview", + enableUrlContext: false, + enableGrounding: true, + } as ApiHandlerOptions + const handler = new GeminiHandler(options) + const stub = vi.fn().mockReturnValue((async function* () {})()) + // @ts-ignore access private client + handler["client"].models.generateContentStream = stub + await handler.createMessage("instr", [] as any).next() + const config = stub.mock.calls[0][0].config + // Should not include googleSearch since model doesn't support it + expect(config.tools).toBeUndefined() + }) + + it("should enable Google Search for models that support grounding", async () => { + const options = { + apiProvider: "gemini", + apiModelId: "gemini-2.5-pro", + enableUrlContext: false, + enableGrounding: true, + } as ApiHandlerOptions + const handler = new GeminiHandler(options) + const stub = vi.fn().mockReturnValue((async function* () {})()) + // @ts-ignore access private client + handler["client"].models.generateContentStream = stub + await handler.createMessage("instr", [] as any).next() + const config = stub.mock.calls[0][0].config + // Should include googleSearch for models that support it + expect(config.tools).toEqual([{ googleSearch: {} }]) + }) + it("completePrompt passes config overrides without tools when URL context and grounding disabled", async () => { const options = { apiProvider: "gemini", diff --git a/src/api/providers/gemini.ts b/src/api/providers/gemini.ts index 89c816e815..98a250625e 100644 --- a/src/api/providers/gemini.ts +++ b/src/api/providers/gemini.ts @@ -140,7 +140,8 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl tools.push({ urlContext: {} }) } - if (this.options.enableGrounding) { + // Only enable Google Search if the model supports grounding + if (this.options.enableGrounding && info.supportsGrounding) { tools.push({ googleSearch: {} }) } } @@ -368,7 +369,8 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl if (this.options.enableUrlContext) { tools.push({ urlContext: {} }) } - if (this.options.enableGrounding) { + // Only enable Google Search if the model supports grounding + if (this.options.enableGrounding && info.supportsGrounding) { tools.push({ googleSearch: {} }) }