Просмотр исходного кода

Feat: Adding Gemini tools - URL Context and Grounding with Google Search (#5959)

* feat: Adding more settings and control over Gemini

- with topP, topK, maxOutputTokens
- allow users to enable URL context and Grounding Research

* feat: Adding parameter titles and descriptions + translation to all languages

* feat: adding more translations

* feat: adding `contextLimit` implementation from `maxContextWindow` PR + working with profile-specific thresholding

* feat: max value for context limit to model's limit + converting description and titles to settings for translation purposes

* feat: all languages translated

* feat: changing profile-specific threshold in context management setting will also change in Gemini context management

- sync between Context Management Settting <-> Gemini Context Management with regards to thresholding

* feat: max value of maxOutputTokens is model's maxTokens + adding more tests

* feat: improve unit tests and adding `data-testid` to slider and checkbox components

* fix: small changes in geminiContextManagement descriptions + minor fix

* fix: Switching from "Gemini Context Management" to "Token Management

- better naming and correct purpose

* fix: input field showed NaN -> annoying UX

* fix: Removing redundant "tokens" after the "set context limit"'s checkbox + removing the lengthy description

* fix: Changing the translation to be consistent with the english one

* fix: more translations

* fix: translations

* fix: removing contextLimit and token management related code

- due to the decision in: https://github.com/RooCodeInc/Roo-Code/issues/3717

* fix: removing `contextLimit` test and removing token management in translations

* fix: changing from `Advanced Features` to `Tools` to be consistent with Gemini docs/AI studio

* fix: adding `try-catch` block for `generateContentStream`

* feat: Include citations + improved type safety

* feat: adding citation for streams (generateContextStream)

* fix: set default values for `topP`, `topK` and `maxOutputTokens`

* fix: changing UI/UX according to the review/feedback from `daniel-lxs`

* fix: updating the `Gemini.spec.tsx` unit test

- testing when it is hidden
- testing when users click on the collapsible trigger and model configuration appears

* fix: more changes from the feedback/review from `daniel-lxs`

* fix: adding sources at the end of the stream to preserve

* fix: change the description for grounding with google search and url context

* fix: adding translations

* fix: removing redundant extra translations - a mistake made by the agent

* fix: remove duplicate translation keys in geminiSections and geminiParameters

- Fixed duplicate keys in 13 localization files (es, fr, hi, id, it, ja, ko, nl, pl, pt-BR, ru, tr, vi)
- Removed second occurrence of geminiSections and geminiParameters keys
- Kept first occurrence which contains more comprehensive descriptions
- All JSON files validated for syntax correctness
- Translation completeness verified with missing translations script

Resolves duplicate key issue identified in PR #4895

* fix: delete topK, topP and maxOutputTokens from Gemini

* fix: deleting topK, topP and maxOutputTokens from translations/locales

* fix: adjust spacing between labels and descriptions + sentence casing

* fix: adding maxOutputTokens back and removing unknown type

* fix: internalizing error Gemini error message

* fix: updating tests in Gemini and Vertex to adjust to the new error logging

* fix: address PR review feedback for Gemini tools feature

- Fix Hindi translation grammatical error in settings.json
- Internationalize 'Sources:' string and error messages in gemini.ts
- Add comprehensive error scenario tests to gemini-handler.spec.ts
- Remove unused currentModelId prop from Gemini component
- Update all locale files with new translation keys

---------

Co-authored-by: Roo Code <[email protected]>
Co-authored-by: Matt Rubens <[email protected]>
Co-authored-by: Daniel Riccio <[email protected]>
Ton Hoang Nguyen (Bill) 5 месяцев назад
Родитель
Сommit
342ee70fb4
44 измененных файлов с 706 добавлено и 50 удалено
  1. 2 0
      packages/types/src/provider-settings.ts
  2. 137 0
      src/api/providers/__tests__/gemini-handler.spec.ts
  3. 2 1
      src/api/providers/__tests__/gemini.spec.ts
  4. 2 1
      src/api/providers/__tests__/vertex.spec.ts
  5. 123 46
      src/api/providers/gemini.ts
  6. 0 1
      src/core/sliding-window/__tests__/sliding-window.spec.ts
  7. 5 0
      src/i18n/locales/ca/common.json
  8. 5 0
      src/i18n/locales/de/common.json
  9. 5 0
      src/i18n/locales/en/common.json
  10. 5 0
      src/i18n/locales/es/common.json
  11. 5 0
      src/i18n/locales/fr/common.json
  12. 5 0
      src/i18n/locales/hi/common.json
  13. 5 0
      src/i18n/locales/id/common.json
  14. 5 0
      src/i18n/locales/it/common.json
  15. 5 0
      src/i18n/locales/ja/common.json
  16. 5 0
      src/i18n/locales/ko/common.json
  17. 5 0
      src/i18n/locales/nl/common.json
  18. 5 0
      src/i18n/locales/pl/common.json
  19. 5 0
      src/i18n/locales/pt-BR/common.json
  20. 5 0
      src/i18n/locales/ru/common.json
  21. 5 0
      src/i18n/locales/tr/common.json
  22. 5 0
      src/i18n/locales/vi/common.json
  23. 5 0
      src/i18n/locales/zh-CN/common.json
  24. 5 0
      src/i18n/locales/zh-TW/common.json
  25. 23 1
      webview-ui/src/components/settings/providers/Gemini.tsx
  26. 130 0
      webview-ui/src/components/settings/providers/__tests__/Gemini.spec.tsx
  27. 11 0
      webview-ui/src/i18n/locales/ca/settings.json
  28. 11 0
      webview-ui/src/i18n/locales/de/settings.json
  29. 10 0
      webview-ui/src/i18n/locales/en/settings.json
  30. 11 0
      webview-ui/src/i18n/locales/es/settings.json
  31. 11 0
      webview-ui/src/i18n/locales/fr/settings.json
  32. 11 0
      webview-ui/src/i18n/locales/hi/settings.json
  33. 11 0
      webview-ui/src/i18n/locales/id/settings.json
  34. 11 0
      webview-ui/src/i18n/locales/it/settings.json
  35. 11 0
      webview-ui/src/i18n/locales/ja/settings.json
  36. 11 0
      webview-ui/src/i18n/locales/ko/settings.json
  37. 11 0
      webview-ui/src/i18n/locales/nl/settings.json
  38. 11 0
      webview-ui/src/i18n/locales/pl/settings.json
  39. 11 0
      webview-ui/src/i18n/locales/pt-BR/settings.json
  40. 11 0
      webview-ui/src/i18n/locales/ru/settings.json
  41. 11 0
      webview-ui/src/i18n/locales/tr/settings.json
  42. 11 0
      webview-ui/src/i18n/locales/vi/settings.json
  43. 11 0
      webview-ui/src/i18n/locales/zh-CN/settings.json
  44. 11 0
      webview-ui/src/i18n/locales/zh-TW/settings.json

+ 2 - 0
packages/types/src/provider-settings.ts

@@ -169,6 +169,8 @@ const lmStudioSchema = baseProviderSettingsSchema.extend({
 const geminiSchema = apiModelIdProviderModelSchema.extend({
 	geminiApiKey: z.string().optional(),
 	googleGeminiBaseUrl: z.string().optional(),
+	enableUrlContext: z.boolean().optional(),
+	enableGrounding: z.boolean().optional(),
 })
 
 const geminiCliSchema = apiModelIdProviderModelSchema.extend({

+ 137 - 0
src/api/providers/__tests__/gemini-handler.spec.ts

@@ -0,0 +1,137 @@
+import { describe, it, expect, vi } from "vitest"
+import { t } from "i18next"
+import { GeminiHandler } from "../gemini"
+import type { ApiHandlerOptions } from "../../../shared/api"
+
+describe("GeminiHandler backend support", () => {
+	it("passes tools for URL context and grounding in config", async () => {
+		const options = {
+			apiProvider: "gemini",
+			enableUrlContext: true,
+			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
+		expect(config.tools).toEqual([{ urlContext: {} }, { googleSearch: {} }])
+	})
+
+	it("completePrompt passes config overrides without tools when URL context and grounding disabled", async () => {
+		const options = {
+			apiProvider: "gemini",
+			enableUrlContext: false,
+			enableGrounding: false,
+		} as ApiHandlerOptions
+		const handler = new GeminiHandler(options)
+		const stub = vi.fn().mockResolvedValue({ text: "ok" })
+		// @ts-ignore access private client
+		handler["client"].models.generateContent = stub
+		const res = await handler.completePrompt("hi")
+		expect(res).toBe("ok")
+		const promptConfig = stub.mock.calls[0][0].config
+		expect(promptConfig.tools).toBeUndefined()
+	})
+
+	describe("error scenarios", () => {
+		it("should handle grounding metadata extraction failure gracefully", async () => {
+			const options = {
+				apiProvider: "gemini",
+				enableGrounding: true,
+			} as ApiHandlerOptions
+			const handler = new GeminiHandler(options)
+
+			const mockStream = async function* () {
+				yield {
+					candidates: [
+						{
+							groundingMetadata: {
+								// Invalid structure - missing groundingChunks
+							},
+							content: { parts: [{ text: "test response" }] },
+						},
+					],
+					usageMetadata: { promptTokenCount: 10, candidatesTokenCount: 5 },
+				}
+			}
+
+			const stub = vi.fn().mockReturnValue(mockStream())
+			// @ts-ignore access private client
+			handler["client"].models.generateContentStream = stub
+
+			const messages = []
+			for await (const chunk of handler.createMessage("test", [] as any)) {
+				messages.push(chunk)
+			}
+
+			// Should still return the main content without sources
+			expect(messages.some((m) => m.type === "text" && m.text === "test response")).toBe(true)
+			expect(messages.some((m) => m.type === "text" && m.text?.includes("Sources:"))).toBe(false)
+		})
+
+		it("should handle malformed grounding metadata", async () => {
+			const options = {
+				apiProvider: "gemini",
+				enableGrounding: true,
+			} as ApiHandlerOptions
+			const handler = new GeminiHandler(options)
+
+			const mockStream = async function* () {
+				yield {
+					candidates: [
+						{
+							groundingMetadata: {
+								groundingChunks: [
+									{ web: null }, // Missing URI
+									{ web: { uri: "https://example.com" } }, // Valid
+									{}, // Missing web property entirely
+								],
+							},
+							content: { parts: [{ text: "test response" }] },
+						},
+					],
+					usageMetadata: { promptTokenCount: 10, candidatesTokenCount: 5 },
+				}
+			}
+
+			const stub = vi.fn().mockReturnValue(mockStream())
+			// @ts-ignore access private client
+			handler["client"].models.generateContentStream = stub
+
+			const messages = []
+			for await (const chunk of handler.createMessage("test", [] as any)) {
+				messages.push(chunk)
+			}
+
+			// Should only include valid citations
+			const sourceMessage = messages.find((m) => m.type === "text" && m.text?.includes("[2]"))
+			expect(sourceMessage).toBeDefined()
+			if (sourceMessage && "text" in sourceMessage) {
+				expect(sourceMessage.text).toContain("https://example.com")
+				expect(sourceMessage.text).not.toContain("[1]")
+				expect(sourceMessage.text).not.toContain("[3]")
+			}
+		})
+
+		it("should handle API errors when tools are enabled", async () => {
+			const options = {
+				apiProvider: "gemini",
+				enableUrlContext: true,
+				enableGrounding: true,
+			} as ApiHandlerOptions
+			const handler = new GeminiHandler(options)
+
+			const mockError = new Error("API rate limit exceeded")
+			const stub = vi.fn().mockRejectedValue(mockError)
+			// @ts-ignore access private client
+			handler["client"].models.generateContentStream = stub
+
+			await expect(async () => {
+				const generator = handler.createMessage("test", [] as any)
+				await generator.next()
+			}).rejects.toThrow(t("common:errors.gemini.generate_stream", { error: "API rate limit exceeded" }))
+		})
+	})
+})

+ 2 - 1
src/api/providers/__tests__/gemini.spec.ts

@@ -4,6 +4,7 @@ import { Anthropic } from "@anthropic-ai/sdk"
 
 import { type ModelInfo, geminiDefaultModelId } from "@roo-code/types"
 
+import { t } from "i18next"
 import { GeminiHandler } from "../gemini"
 
 const GEMINI_20_FLASH_THINKING_NAME = "gemini-2.0-flash-thinking-exp-1219"
@@ -129,7 +130,7 @@ describe("GeminiHandler", () => {
 			;(handler["client"].models.generateContent as any).mockRejectedValue(mockError)
 
 			await expect(handler.completePrompt("Test prompt")).rejects.toThrow(
-				"Gemini completion error: Gemini API error",
+				t("common:errors.gemini.generate_complete_prompt", { error: "Gemini API error" }),
 			)
 		})
 

+ 2 - 1
src/api/providers/__tests__/vertex.spec.ts

@@ -7,6 +7,7 @@ import { Anthropic } from "@anthropic-ai/sdk"
 
 import { ApiStreamChunk } from "../../transform/stream"
 
+import { t } from "i18next"
 import { VertexHandler } from "../vertex"
 
 describe("VertexHandler", () => {
@@ -105,7 +106,7 @@ describe("VertexHandler", () => {
 			;(handler["client"].models.generateContent as any).mockRejectedValue(mockError)
 
 			await expect(handler.completePrompt("Test prompt")).rejects.toThrow(
-				"Gemini completion error: Vertex API error",
+				t("common:errors.gemini.generate_complete_prompt", { error: "Vertex API error" }),
 			)
 		})
 

+ 123 - 46
src/api/providers/gemini.ts

@@ -4,6 +4,7 @@ import {
 	type GenerateContentResponseUsageMetadata,
 	type GenerateContentParameters,
 	type GenerateContentConfig,
+	type GroundingMetadata,
 } from "@google/genai"
 import type { JWTInput } from "google-auth-library"
 
@@ -13,6 +14,7 @@ import type { ApiHandlerOptions } from "../../shared/api"
 import { safeJsonParse } from "../../shared/safeJsonParse"
 
 import { convertAnthropicContentToGemini, convertAnthropicMessageToGemini } from "../transform/gemini-format"
+import { t } from "i18next"
 import type { ApiStream } from "../transform/stream"
 import { getModelParams } from "../transform/model-params"
 
@@ -67,72 +69,103 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
 
 		const contents = messages.map(convertAnthropicMessageToGemini)
 
+		const tools: GenerateContentConfig["tools"] = []
+		if (this.options.enableUrlContext) {
+			tools.push({ urlContext: {} })
+		}
+
+		if (this.options.enableGrounding) {
+			tools.push({ googleSearch: {} })
+		}
+
 		const config: GenerateContentConfig = {
 			systemInstruction,
 			httpOptions: this.options.googleGeminiBaseUrl ? { baseUrl: this.options.googleGeminiBaseUrl } : undefined,
 			thinkingConfig,
 			maxOutputTokens: this.options.modelMaxTokens ?? maxTokens ?? undefined,
 			temperature: this.options.modelTemperature ?? 0,
+			...(tools.length > 0 ? { tools } : {}),
 		}
 
 		const params: GenerateContentParameters = { model, contents, config }
 
-		const result = await this.client.models.generateContentStream(params)
+		try {
+			const result = await this.client.models.generateContentStream(params)
+
+			let lastUsageMetadata: GenerateContentResponseUsageMetadata | undefined
+			let pendingGroundingMetadata: GroundingMetadata | undefined
 
-		let lastUsageMetadata: GenerateContentResponseUsageMetadata | undefined
+			for await (const chunk of result) {
+				// Process candidates and their parts to separate thoughts from content
+				if (chunk.candidates && chunk.candidates.length > 0) {
+					const candidate = chunk.candidates[0]
 
-		for await (const chunk of result) {
-			// Process candidates and their parts to separate thoughts from content
-			if (chunk.candidates && chunk.candidates.length > 0) {
-				const candidate = chunk.candidates[0]
-				if (candidate.content && candidate.content.parts) {
-					for (const part of candidate.content.parts) {
-						if (part.thought) {
-							// This is a thinking/reasoning part
-							if (part.text) {
-								yield { type: "reasoning", text: part.text }
-							}
-						} else {
-							// This is regular content
-							if (part.text) {
-								yield { type: "text", text: part.text }
+					if (candidate.groundingMetadata) {
+						pendingGroundingMetadata = candidate.groundingMetadata
+					}
+
+					if (candidate.content && candidate.content.parts) {
+						for (const part of candidate.content.parts) {
+							if (part.thought) {
+								// This is a thinking/reasoning part
+								if (part.text) {
+									yield { type: "reasoning", text: part.text }
+								}
+							} else {
+								// This is regular content
+								if (part.text) {
+									yield { type: "text", text: part.text }
+								}
 							}
 						}
 					}
 				}
-			}
 
-			// Fallback to the original text property if no candidates structure
-			else if (chunk.text) {
-				yield { type: "text", text: chunk.text }
+				// Fallback to the original text property if no candidates structure
+				else if (chunk.text) {
+					yield { type: "text", text: chunk.text }
+				}
+
+				if (chunk.usageMetadata) {
+					lastUsageMetadata = chunk.usageMetadata
+				}
 			}
 
-			if (chunk.usageMetadata) {
-				lastUsageMetadata = chunk.usageMetadata
+			if (pendingGroundingMetadata) {
+				const citations = this.extractCitationsOnly(pendingGroundingMetadata)
+				if (citations) {
+					yield { type: "text", text: `\n\n${t("common:errors.gemini.sources")} ${citations}` }
+				}
 			}
-		}
 
-		if (lastUsageMetadata) {
-			const inputTokens = lastUsageMetadata.promptTokenCount ?? 0
-			const outputTokens = lastUsageMetadata.candidatesTokenCount ?? 0
-			const cacheReadTokens = lastUsageMetadata.cachedContentTokenCount
-			const reasoningTokens = lastUsageMetadata.thoughtsTokenCount
-
-			yield {
-				type: "usage",
-				inputTokens,
-				outputTokens,
-				cacheReadTokens,
-				reasoningTokens,
-				totalCost: this.calculateCost({ info, inputTokens, outputTokens, cacheReadTokens }),
+			if (lastUsageMetadata) {
+				const inputTokens = lastUsageMetadata.promptTokenCount ?? 0
+				const outputTokens = lastUsageMetadata.candidatesTokenCount ?? 0
+				const cacheReadTokens = lastUsageMetadata.cachedContentTokenCount
+				const reasoningTokens = lastUsageMetadata.thoughtsTokenCount
+
+				yield {
+					type: "usage",
+					inputTokens,
+					outputTokens,
+					cacheReadTokens,
+					reasoningTokens,
+					totalCost: this.calculateCost({ info, inputTokens, outputTokens, cacheReadTokens }),
+				}
 			}
+		} catch (error) {
+			if (error instanceof Error) {
+				throw new Error(t("common:errors.gemini.generate_stream", { error: error.message }))
+			}
+
+			throw error
 		}
 	}
 
 	override getModel() {
 		const modelId = this.options.apiModelId
 		let id = modelId && modelId in geminiModels ? (modelId as GeminiModelId) : geminiDefaultModelId
-		const info: ModelInfo = geminiModels[id]
+		let info: ModelInfo = geminiModels[id]
 		const params = getModelParams({ format: "gemini", modelId: id, model: info, settings: this.options })
 
 		// The `:thinking` suffix indicates that the model is a "Hybrid"
@@ -142,25 +175,69 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
 		return { id: id.endsWith(":thinking") ? id.replace(":thinking", "") : id, info, ...params }
 	}
 
+	private extractCitationsOnly(groundingMetadata?: GroundingMetadata): string | null {
+		const chunks = groundingMetadata?.groundingChunks
+
+		if (!chunks) {
+			return null
+		}
+
+		const citationLinks = chunks
+			.map((chunk, i) => {
+				const uri = chunk.web?.uri
+				if (uri) {
+					return `[${i + 1}](${uri})`
+				}
+				return null
+			})
+			.filter((link): link is string => link !== null)
+
+		if (citationLinks.length > 0) {
+			return citationLinks.join(", ")
+		}
+
+		return null
+	}
+
 	async completePrompt(prompt: string): Promise<string> {
 		try {
 			const { id: model } = this.getModel()
 
+			const tools: GenerateContentConfig["tools"] = []
+			if (this.options.enableUrlContext) {
+				tools.push({ urlContext: {} })
+			}
+			if (this.options.enableGrounding) {
+				tools.push({ googleSearch: {} })
+			}
+			const promptConfig: GenerateContentConfig = {
+				httpOptions: this.options.googleGeminiBaseUrl
+					? { baseUrl: this.options.googleGeminiBaseUrl }
+					: undefined,
+				temperature: this.options.modelTemperature ?? 0,
+				...(tools.length > 0 ? { tools } : {}),
+			}
+
 			const result = await this.client.models.generateContent({
 				model,
 				contents: [{ role: "user", parts: [{ text: prompt }] }],
-				config: {
-					httpOptions: this.options.googleGeminiBaseUrl
-						? { baseUrl: this.options.googleGeminiBaseUrl }
-						: undefined,
-					temperature: this.options.modelTemperature ?? 0,
-				},
+				config: promptConfig,
 			})
 
-			return result.text ?? ""
+			let text = result.text ?? ""
+
+			const candidate = result.candidates?.[0]
+			if (candidate?.groundingMetadata) {
+				const citations = this.extractCitationsOnly(candidate.groundingMetadata)
+				if (citations) {
+					text += `\n\n${t("common:errors.gemini.sources")} ${citations}`
+				}
+			}
+
+			return text
 		} catch (error) {
 			if (error instanceof Error) {
-				throw new Error(`Gemini completion error: ${error.message}`)
+				throw new Error(t("common:errors.gemini.generate_complete_prompt", { error: error.message }))
 			}
 
 			throw error

+ 0 - 1
src/core/sliding-window/__tests__/sliding-window.spec.ts

@@ -250,7 +250,6 @@ describe("Sliding Window", () => {
 			{ role: "assistant", content: "Fourth message" },
 			{ role: "user", content: "Fifth message" },
 		]
-
 		it("should not truncate if tokens are below max tokens threshold", async () => {
 			const modelInfo = createModelInfo(100000, 30000)
 			const dynamicBuffer = modelInfo.contextWindow * TOKEN_BUFFER_PERCENTAGE // 10000

+ 5 - 0
src/i18n/locales/ca/common.json

@@ -81,6 +81,11 @@
 			"stoppedWithReason": "Claude Code s'ha aturat per la raó: {{reason}}",
 			"apiKeyModelPlanMismatch": "Les claus API i els plans de subscripció permeten models diferents. Assegura't que el model seleccionat estigui inclòs al teu pla."
 		},
+		"gemini": {
+			"generate_stream": "Error del flux de context de generació de Gemini: {{error}}",
+			"generate_complete_prompt": "Error de finalització de Gemini: {{error}}",
+			"sources": "Fonts:"
+		},
 		"mode_import_failed": "Ha fallat la importació del mode: {{error}}"
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/de/common.json

@@ -77,6 +77,11 @@
 			"processExitedWithError": "Claude Code Prozess wurde mit Code {{exitCode}} beendet. Fehlerausgabe: {{output}}",
 			"stoppedWithReason": "Claude Code wurde mit Grund gestoppt: {{reason}}",
 			"apiKeyModelPlanMismatch": "API-Schlüssel und Abonnement-Pläne erlauben verschiedene Modelle. Stelle sicher, dass das ausgewählte Modell in deinem Plan enthalten ist."
+		},
+		"gemini": {
+			"generate_stream": "Fehler beim Generieren des Kontext-Streams von Gemini: {{error}}",
+			"generate_complete_prompt": "Fehler bei der Vervollständigung durch Gemini: {{error}}",
+			"sources": "Quellen:"
 		}
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/en/common.json

@@ -77,6 +77,11 @@
 			"processExitedWithError": "Claude Code process exited with code {{exitCode}}. Error output: {{output}}",
 			"stoppedWithReason": "Claude Code stopped with reason: {{reason}}",
 			"apiKeyModelPlanMismatch": "API keys and subscription plans allow different models. Make sure the selected model is included in your plan."
+		},
+		"gemini": {
+			"generate_stream": "Gemini generate context stream error: {{error}}",
+			"generate_complete_prompt": "Gemini completion error: {{error}}",
+			"sources": "Sources:"
 		}
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/es/common.json

@@ -77,6 +77,11 @@
 			"processExitedWithError": "El proceso de Claude Code terminó con código {{exitCode}}. Salida de error: {{output}}",
 			"stoppedWithReason": "Claude Code se detuvo por la razón: {{reason}}",
 			"apiKeyModelPlanMismatch": "Las claves API y los planes de suscripción permiten diferentes modelos. Asegúrate de que el modelo seleccionado esté incluido en tu plan."
+		},
+		"gemini": {
+			"generate_stream": "Error del stream de contexto de generación de Gemini: {{error}}",
+			"generate_complete_prompt": "Error de finalización de Gemini: {{error}}",
+			"sources": "Fuentes:"
 		}
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/fr/common.json

@@ -77,6 +77,11 @@
 			"processExitedWithError": "Le processus Claude Code s'est terminé avec le code {{exitCode}}. Sortie d'erreur : {{output}}",
 			"stoppedWithReason": "Claude Code s'est arrêté pour la raison : {{reason}}",
 			"apiKeyModelPlanMismatch": "Les clés API et les plans d'abonnement permettent différents modèles. Assurez-vous que le modèle sélectionné est inclus dans votre plan."
+		},
+		"gemini": {
+			"generate_stream": "Erreur du flux de contexte de génération Gemini : {{error}}",
+			"generate_complete_prompt": "Erreur d'achèvement de Gemini : {{error}}",
+			"sources": "Sources :"
 		}
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/hi/common.json

@@ -77,6 +77,11 @@
 			"processExitedWithError": "Claude Code प्रक्रिया कोड {{exitCode}} के साथ समाप्त हुई। त्रुटि आउटपुट: {{output}}",
 			"stoppedWithReason": "Claude Code इस कारण से रुका: {{reason}}",
 			"apiKeyModelPlanMismatch": "API कुंजी और सब्सक्रिप्शन प्लान अलग-अलग मॉडल की अनुमति देते हैं। सुनिश्चित करें कि चयनित मॉडल आपकी योजना में शामिल है।"
+		},
+		"gemini": {
+			"generate_stream": "जेमिनी जनरेट कॉन्टेक्स्ट स्ट्रीम त्रुटि: {{error}}",
+			"generate_complete_prompt": "जेमिनी समापन त्रुटि: {{error}}",
+			"sources": "स्रोत:"
 		}
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/id/common.json

@@ -77,6 +77,11 @@
 			"processExitedWithError": "Proses Claude Code keluar dengan kode {{exitCode}}. Output error: {{output}}",
 			"stoppedWithReason": "Claude Code berhenti karena alasan: {{reason}}",
 			"apiKeyModelPlanMismatch": "Kunci API dan paket berlangganan memungkinkan model yang berbeda. Pastikan model yang dipilih termasuk dalam paket Anda."
+		},
+		"gemini": {
+			"generate_stream": "Kesalahan aliran konteks pembuatan Gemini: {{error}}",
+			"generate_complete_prompt": "Kesalahan penyelesaian Gemini: {{error}}",
+			"sources": "Sumber:"
 		}
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/it/common.json

@@ -77,6 +77,11 @@
 			"processExitedWithError": "Il processo Claude Code è terminato con codice {{exitCode}}. Output di errore: {{output}}",
 			"stoppedWithReason": "Claude Code si è fermato per il motivo: {{reason}}",
 			"apiKeyModelPlanMismatch": "Le chiavi API e i piani di abbonamento consentono modelli diversi. Assicurati che il modello selezionato sia incluso nel tuo piano."
+		},
+		"gemini": {
+			"generate_stream": "Errore del flusso di contesto di generazione Gemini: {{error}}",
+			"generate_complete_prompt": "Errore di completamento Gemini: {{error}}",
+			"sources": "Fonti:"
 		}
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/ja/common.json

@@ -77,6 +77,11 @@
 			"processExitedWithError": "Claude Code プロセスがコード {{exitCode}} で終了しました。エラー出力:{{output}}",
 			"stoppedWithReason": "Claude Code が理由により停止しました:{{reason}}",
 			"apiKeyModelPlanMismatch": "API キーとサブスクリプションプランでは異なるモデルが利用可能です。選択したモデルがプランに含まれていることを確認してください。"
+		},
+		"gemini": {
+			"generate_stream": "Gemini 生成コンテキスト ストリーム エラー: {{error}}",
+			"generate_complete_prompt": "Gemini 完了エラー: {{error}}",
+			"sources": "ソース:"
 		}
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/ko/common.json

@@ -77,6 +77,11 @@
 			"processExitedWithError": "Claude Code 프로세스가 코드 {{exitCode}}로 종료되었습니다. 오류 출력: {{output}}",
 			"stoppedWithReason": "Claude Code가 다음 이유로 중지되었습니다: {{reason}}",
 			"apiKeyModelPlanMismatch": "API 키와 구독 플랜에서 다른 모델을 허용합니다. 선택한 모델이 플랜에 포함되어 있는지 확인하세요."
+		},
+		"gemini": {
+			"generate_stream": "Gemini 생성 컨텍스트 스트림 오류: {{error}}",
+			"generate_complete_prompt": "Gemini 완료 오류: {{error}}",
+			"sources": "출처:"
 		}
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/nl/common.json

@@ -77,6 +77,11 @@
 			"processExitedWithError": "Claude Code proces beëindigd met code {{exitCode}}. Foutuitvoer: {{output}}",
 			"stoppedWithReason": "Claude Code gestopt om reden: {{reason}}",
 			"apiKeyModelPlanMismatch": "API-sleutels en abonnementsplannen staan verschillende modellen toe. Zorg ervoor dat het geselecteerde model is opgenomen in je plan."
+		},
+		"gemini": {
+			"generate_stream": "Fout bij het genereren van contextstream door Gemini: {{error}}",
+			"generate_complete_prompt": "Fout bij het voltooien door Gemini: {{error}}",
+			"sources": "Bronnen:"
 		}
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/pl/common.json

@@ -77,6 +77,11 @@
 			"processExitedWithError": "Proces Claude Code zakończył się kodem {{exitCode}}. Wyjście błędu: {{output}}",
 			"stoppedWithReason": "Claude Code zatrzymał się z powodu: {{reason}}",
 			"apiKeyModelPlanMismatch": "Klucze API i plany subskrypcji pozwalają na różne modele. Upewnij się, że wybrany model jest zawarty w twoim planie."
+		},
+		"gemini": {
+			"generate_stream": "Błąd strumienia kontekstu generowania Gemini: {{error}}",
+			"generate_complete_prompt": "Błąd uzupełniania Gemini: {{error}}",
+			"sources": "Źródła:"
 		}
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/pt-BR/common.json

@@ -81,6 +81,11 @@
 			"processExitedWithError": "O processo Claude Code saiu com código {{exitCode}}. Saída de erro: {{output}}",
 			"stoppedWithReason": "Claude Code parou pela razão: {{reason}}",
 			"apiKeyModelPlanMismatch": "Chaves de API e planos de assinatura permitem modelos diferentes. Certifique-se de que o modelo selecionado esteja incluído no seu plano."
+		},
+		"gemini": {
+			"generate_stream": "Erro de fluxo de contexto de geração do Gemini: {{error}}",
+			"generate_complete_prompt": "Erro de conclusão do Gemini: {{error}}",
+			"sources": "Fontes:"
 		}
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/ru/common.json

@@ -77,6 +77,11 @@
 			"processExitedWithError": "Процесс Claude Code завершился с кодом {{exitCode}}. Вывод ошибки: {{output}}",
 			"stoppedWithReason": "Claude Code остановился по причине: {{reason}}",
 			"apiKeyModelPlanMismatch": "API-ключи и планы подписки позволяют использовать разные модели. Убедитесь, что выбранная модель включена в ваш план."
+		},
+		"gemini": {
+			"generate_stream": "Ошибка потока контекста генерации Gemini: {{error}}",
+			"generate_complete_prompt": "Ошибка завершения Gemini: {{error}}",
+			"sources": "Источники:"
 		}
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/tr/common.json

@@ -77,6 +77,11 @@
 			"processExitedWithError": "Claude Code işlemi {{exitCode}} koduyla çıktı. Hata çıktısı: {{output}}",
 			"stoppedWithReason": "Claude Code şu nedenle durdu: {{reason}}",
 			"apiKeyModelPlanMismatch": "API anahtarları ve abonelik planları farklı modellere izin verir. Seçilen modelin planınıza dahil olduğundan emin olun."
+		},
+		"gemini": {
+			"generate_stream": "Gemini oluşturma bağlam akışı hatası: {{error}}",
+			"generate_complete_prompt": "Gemini tamamlama hatası: {{error}}",
+			"sources": "Kaynaklar:"
 		}
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/vi/common.json

@@ -77,6 +77,11 @@
 			"processExitedWithError": "Tiến trình Claude Code thoát với mã {{exitCode}}. Đầu ra lỗi: {{output}}",
 			"stoppedWithReason": "Claude Code dừng lại vì lý do: {{reason}}",
 			"apiKeyModelPlanMismatch": "Khóa API và gói đăng ký cho phép các mô hình khác nhau. Đảm bảo rằng mô hình đã chọn được bao gồm trong gói của bạn."
+		},
+		"gemini": {
+			"generate_stream": "Lỗi luồng ngữ cảnh tạo Gemini: {{error}}",
+			"generate_complete_prompt": "Lỗi hoàn thành Gemini: {{error}}",
+			"sources": "Nguồn:"
 		}
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/zh-CN/common.json

@@ -82,6 +82,11 @@
 			"processExitedWithError": "Claude Code 进程退出,退出码:{{exitCode}}。错误输出:{{output}}",
 			"stoppedWithReason": "Claude Code 停止,原因:{{reason}}",
 			"apiKeyModelPlanMismatch": "API 密钥和订阅计划支持不同的模型。请确保所选模型包含在您的计划中。"
+		},
+		"gemini": {
+			"generate_stream": "Gemini 生成上下文流错误:{{error}}",
+			"generate_complete_prompt": "Gemini 完成错误:{{error}}",
+			"sources": "来源:"
 		}
 	},
 	"warnings": {

+ 5 - 0
src/i18n/locales/zh-TW/common.json

@@ -77,6 +77,11 @@
 			"stoppedWithReason": "Claude Code 停止,原因:{{reason}}",
 			"apiKeyModelPlanMismatch": "API 金鑰和訂閱方案允許不同的模型。請確保所選模型包含在您的方案中。"
 		},
+		"gemini": {
+			"generate_stream": "Gemini 產生內容串流錯誤:{{error}}",
+			"generate_complete_prompt": "Gemini 完成錯誤:{{error}}",
+			"sources": "來源:"
+		},
 		"mode_import_failed": "匯入模式失敗:{{error}}"
 	},
 	"warnings": {

+ 23 - 1
webview-ui/src/components/settings/providers/Gemini.tsx

@@ -50,12 +50,13 @@ export const Gemini = ({ apiConfiguration, setApiConfigurationField }: GeminiPro
 					{t("settings:providers.getGeminiApiKey")}
 				</VSCodeButtonLink>
 			)}
+
 			<div>
 				<Checkbox
+					data-testid="checkbox-custom-base-url"
 					checked={googleGeminiBaseUrlSelected}
 					onChange={(checked: boolean) => {
 						setGoogleGeminiBaseUrlSelected(checked)
-
 						if (!checked) {
 							setApiConfigurationField("googleGeminiBaseUrl", "")
 						}
@@ -71,6 +72,27 @@ export const Gemini = ({ apiConfiguration, setApiConfigurationField }: GeminiPro
 						className="w-full mt-1"
 					/>
 				)}
+
+				<Checkbox
+					className="mt-6"
+					data-testid="checkbox-url-context"
+					checked={!!apiConfiguration.enableUrlContext}
+					onChange={(checked: boolean) => setApiConfigurationField("enableUrlContext", checked)}>
+					{t("settings:providers.geminiParameters.urlContext.title")}
+				</Checkbox>
+				<div className="text-sm text-vscode-descriptionForeground mb-3 mt-1.5">
+					{t("settings:providers.geminiParameters.urlContext.description")}
+				</div>
+
+				<Checkbox
+					data-testid="checkbox-grounding-search"
+					checked={!!apiConfiguration.enableGrounding}
+					onChange={(checked: boolean) => setApiConfigurationField("enableGrounding", checked)}>
+					{t("settings:providers.geminiParameters.groundingSearch.title")}
+				</Checkbox>
+				<div className="text-sm text-vscode-descriptionForeground mb-3 mt-1.5">
+					{t("settings:providers.geminiParameters.groundingSearch.description")}
+				</div>
 			</div>
 		</>
 	)

+ 130 - 0
webview-ui/src/components/settings/providers/__tests__/Gemini.spec.tsx

@@ -0,0 +1,130 @@
+import { render, screen } from "@testing-library/react"
+import userEvent from "@testing-library/user-event"
+import { Gemini } from "../Gemini"
+import type { ProviderSettings } from "@roo-code/types"
+
+vi.mock("@vscode/webview-ui-toolkit/react", () => ({
+	VSCodeTextField: ({ children, value, onInput, type }: any) => (
+		<div>
+			{children}
+			<input type={type} value={value} onChange={(e) => onInput(e)} />
+		</div>
+	),
+}))
+
+vi.mock("vscrui", () => ({
+	Checkbox: ({ children, checked, onChange, "data-testid": testId, _ }: any) => (
+		<label data-testid={testId}>
+			<input type="checkbox" checked={checked} onChange={(e) => onChange(e.target.checked)} />
+			{children}
+		</label>
+	),
+}))
+
+vi.mock("@src/i18n/TranslationContext", () => ({
+	useAppTranslation: () => ({ t: (key: string) => key }),
+}))
+
+vi.mock("@src/components/common/VSCodeButtonLink", () => ({
+	VSCodeButtonLink: ({ children, href }: any) => <a href={href}>{children}</a>,
+}))
+
+describe("Gemini", () => {
+	const defaultApiConfiguration: ProviderSettings = {
+		geminiApiKey: "",
+		enableUrlContext: false,
+		enableGrounding: false,
+	}
+
+	const mockSetApiConfigurationField = vi.fn()
+
+	beforeEach(() => {
+		vi.clearAllMocks()
+	})
+
+	describe("URL Context Checkbox", () => {
+		it("should render URL context checkbox unchecked by default", () => {
+			render(
+				<Gemini
+					apiConfiguration={defaultApiConfiguration}
+					setApiConfigurationField={mockSetApiConfigurationField}
+				/>,
+			)
+
+			const urlContextCheckbox = screen.getByTestId("checkbox-url-context")
+			const checkbox = urlContextCheckbox.querySelector("input[type='checkbox']") as HTMLInputElement
+			expect(checkbox.checked).toBe(false)
+		})
+
+		it("should render URL context checkbox checked when enableUrlContext is true", () => {
+			const apiConfiguration = { ...defaultApiConfiguration, enableUrlContext: true }
+			render(
+				<Gemini apiConfiguration={apiConfiguration} setApiConfigurationField={mockSetApiConfigurationField} />,
+			)
+
+			const urlContextCheckbox = screen.getByTestId("checkbox-url-context")
+			const checkbox = urlContextCheckbox.querySelector("input[type='checkbox']") as HTMLInputElement
+			expect(checkbox.checked).toBe(true)
+		})
+
+		it("should call setApiConfigurationField with correct parameters when URL context checkbox is toggled", async () => {
+			const user = userEvent.setup()
+			render(
+				<Gemini
+					apiConfiguration={defaultApiConfiguration}
+					setApiConfigurationField={mockSetApiConfigurationField}
+				/>,
+			)
+
+			const urlContextCheckbox = screen.getByTestId("checkbox-url-context")
+			const checkbox = urlContextCheckbox.querySelector("input[type='checkbox']") as HTMLInputElement
+
+			await user.click(checkbox)
+
+			expect(mockSetApiConfigurationField).toHaveBeenCalledWith("enableUrlContext", true)
+		})
+	})
+
+	describe("Grounding with Google Search Checkbox", () => {
+		it("should render grounding search checkbox unchecked by default", () => {
+			render(
+				<Gemini
+					apiConfiguration={defaultApiConfiguration}
+					setApiConfigurationField={mockSetApiConfigurationField}
+				/>,
+			)
+
+			const groundingCheckbox = screen.getByTestId("checkbox-grounding-search")
+			const checkbox = groundingCheckbox.querySelector("input[type='checkbox']") as HTMLInputElement
+			expect(checkbox.checked).toBe(false)
+		})
+
+		it("should render grounding search checkbox checked when enableGrounding is true", () => {
+			const apiConfiguration = { ...defaultApiConfiguration, enableGrounding: true }
+			render(
+				<Gemini apiConfiguration={apiConfiguration} setApiConfigurationField={mockSetApiConfigurationField} />,
+			)
+
+			const groundingCheckbox = screen.getByTestId("checkbox-grounding-search")
+			const checkbox = groundingCheckbox.querySelector("input[type='checkbox']") as HTMLInputElement
+			expect(checkbox.checked).toBe(true)
+		})
+
+		it("should call setApiConfigurationField with correct parameters when grounding search checkbox is toggled", async () => {
+			const user = userEvent.setup()
+			render(
+				<Gemini
+					apiConfiguration={defaultApiConfiguration}
+					setApiConfigurationField={mockSetApiConfigurationField}
+				/>,
+			)
+
+			const groundingCheckbox = screen.getByTestId("checkbox-grounding-search")
+			const checkbox = groundingCheckbox.querySelector("input[type='checkbox']") as HTMLInputElement
+
+			await user.click(checkbox)
+
+			expect(mockSetApiConfigurationField).toHaveBeenCalledWith("enableGrounding", true)
+		})
+	})
+})

+ 11 - 0
webview-ui/src/i18n/locales/ca/settings.json

@@ -304,6 +304,17 @@
 		"cacheUsageNote": "Nota: Si no veieu l'ús de la caché, proveu de seleccionar un model diferent i després tornar a seleccionar el model desitjat.",
 		"vscodeLmModel": "Model de llenguatge",
 		"vscodeLmWarning": "Nota: Aquesta és una integració molt experimental i el suport del proveïdor variarà. Si rebeu un error sobre un model no compatible, és un problema del proveïdor.",
+
+		"geminiParameters": {
+			"urlContext": {
+				"title": "Activa el context d'URL",
+				"description": "Permet a Gemini llegir pàgines enllaçades per extreure, comparar i sintetitzar el seu contingut en respostes informades."
+			},
+			"groundingSearch": {
+				"title": "Activa la Fonamentació amb la Cerca de Google",
+				"description": "Connecta Gemini a dades web en temps real per a respostes precises i actualitzades amb citacions verificables."
+			}
+		},
 		"googleCloudSetup": {
 			"title": "Per utilitzar Google Cloud Vertex AI, necessiteu:",
 			"step1": "1. Crear un compte de Google Cloud, habilitar l'API de Vertex AI i habilitar els models Claude necessaris.",

+ 11 - 0
webview-ui/src/i18n/locales/de/settings.json

@@ -304,6 +304,17 @@
 		"cacheUsageNote": "Hinweis: Wenn Sie keine Cache-Nutzung sehen, versuchen Sie ein anderes Modell auszuwählen und dann Ihr gewünschtes Modell erneut auszuwählen.",
 		"vscodeLmModel": "Sprachmodell",
 		"vscodeLmWarning": "Hinweis: Dies ist eine sehr experimentelle Integration und die Anbieterunterstützung variiert. Wenn Sie einen Fehler über ein nicht unterstütztes Modell erhalten, liegt das Problem auf Anbieterseite.",
+
+		"geminiParameters": {
+			"urlContext": {
+				"title": "URL-Kontext aktivieren",
+				"description": "Ermöglicht Gemini, verlinkte Seiten zu lesen, um deren Inhalt zu extrahieren, zu vergleichen und in fundierte Antworten zu synthetisieren."
+			},
+			"groundingSearch": {
+				"title": "Grounding mit Google Suche aktivieren",
+				"description": "Verbindet Gemini mit Echtzeit-Webdaten für genaue, aktuelle Antworten mit überprüfbaren Zitaten."
+			}
+		},
 		"googleCloudSetup": {
 			"title": "Um Google Cloud Vertex AI zu verwenden, müssen Sie:",
 			"step1": "1. Ein Google Cloud-Konto erstellen, die Vertex AI API aktivieren & die gewünschten Claude-Modelle aktivieren.",

+ 10 - 0
webview-ui/src/i18n/locales/en/settings.json

@@ -304,6 +304,16 @@
 		"cacheUsageNote": "Note: If you don't see cache usage, try selecting a different model and then selecting your desired model again.",
 		"vscodeLmModel": "Language Model",
 		"vscodeLmWarning": "Note: This is a very experimental integration and provider support will vary. If you get an error about a model not being supported, that's an issue on the provider's end.",
+		"geminiParameters": {
+			"urlContext": {
+				"title": "Enable URL context",
+				"description": "Lets Gemini read linked pages to extract, compare, and synthesize their content into informed responses."
+			},
+			"groundingSearch": {
+				"title": "Enable Grounding with Google search",
+				"description": "Connects Gemini to real‑time web data for accurate, up‑to‑date answers with verifiable citations."
+			}
+		},
 		"googleCloudSetup": {
 			"title": "To use Google Cloud Vertex AI, you need to:",
 			"step1": "1. Create a Google Cloud account, enable the Vertex AI API & enable the desired Claude models.",

+ 11 - 0
webview-ui/src/i18n/locales/es/settings.json

@@ -304,6 +304,17 @@
 		"cacheUsageNote": "Nota: Si no ve el uso del caché, intente seleccionar un modelo diferente y luego seleccionar nuevamente su modelo deseado.",
 		"vscodeLmModel": "Modelo de lenguaje",
 		"vscodeLmWarning": "Nota: Esta es una integración muy experimental y el soporte del proveedor variará. Si recibe un error sobre un modelo no compatible, es un problema del proveedor.",
+		"geminiParameters": {
+			"urlContext": {
+				"title": "Habilitar contexto de URL",
+				"description": "Permite que Gemini acceda y procese URLs para contexto adicional al generar respuestas. Útil para tareas que requieren análisis de contenido web."
+			},
+			"groundingSearch": {
+				"title": "Habilitar grounding con búsqueda en Google",
+				"description": "Permite que Gemini busque en Google información actual y fundamente las respuestas en datos en tiempo real. Útil para consultas que requieren información actualizada."
+			}
+		},
+
 		"googleCloudSetup": {
 			"title": "Para usar Google Cloud Vertex AI, necesita:",
 			"step1": "1. Crear una cuenta de Google Cloud, habilitar la API de Vertex AI y habilitar los modelos Claude deseados.",

+ 11 - 0
webview-ui/src/i18n/locales/fr/settings.json

@@ -304,6 +304,17 @@
 		"cacheUsageNote": "Remarque : Si vous ne voyez pas l'utilisation du cache, essayez de sélectionner un modèle différent puis de sélectionner à nouveau votre modèle souhaité.",
 		"vscodeLmModel": "Modèle de langage",
 		"vscodeLmWarning": "Remarque : Il s'agit d'une intégration très expérimentale et le support des fournisseurs variera. Si vous recevez une erreur concernant un modèle non pris en charge, c'est un problème du côté du fournisseur.",
+		"geminiParameters": {
+			"urlContext": {
+				"title": "Activer le contexte d'URL",
+				"description": "Permet à Gemini d'accéder et de traiter les URL pour un contexte supplémentaire lors de la génération des réponses. Utile pour les tâches nécessitant l'analyse de contenu web."
+			},
+			"groundingSearch": {
+				"title": "Activer la mise en contexte via la recherche Google",
+				"description": "Permet à Gemini d'effectuer des recherches sur Google pour obtenir des informations actuelles et fonder les réponses sur des données en temps réel. Utile pour les requêtes nécessitant des informations à jour."
+			}
+		},
+
 		"googleCloudSetup": {
 			"title": "Pour utiliser Google Cloud Vertex AI, vous devez :",
 			"step1": "1. Créer un compte Google Cloud, activer l'API Vertex AI et activer les modèles Claude souhaités.",

+ 11 - 0
webview-ui/src/i18n/locales/hi/settings.json

@@ -304,6 +304,17 @@
 		"cacheUsageNote": "नोट: यदि आप कैश उपयोग नहीं देखते हैं, तो एक अलग मॉडल चुनने का प्रयास करें और फिर अपने वांछित मॉडल को पुनः चुनें।",
 		"vscodeLmModel": "भाषा मॉडल",
 		"vscodeLmWarning": "नोट: यह एक बहुत ही प्रायोगिक एकीकरण है और प्रदाता समर्थन भिन्न होगा। यदि आपको किसी मॉडल के समर्थित न होने की त्रुटि मिलती है, तो यह प्रदाता की ओर से एक समस्या है।",
+		"geminiParameters": {
+			"urlContext": {
+				"title": "URL संदर्भ सक्षम करें",
+				"description": "जब प्रतिक्रिया उत्पन्न होती है, अतिरिक्त संदर्भ के लिए Gemini को URL तक पहुंचने और संसाधित करने की अनुमति देता है। वेब सामग्री विश्लेषण वाली कार्यों के लिए उपयोगी।"
+			},
+			"groundingSearch": {
+				"title": "Google खोज के साथ ग्राउंडिंग सक्षम करें",
+				"description": "Gemini को वास्तविक समय के डेटा पर आधारित उत्तर प्रदान करने के लिए Google पर जानकारी खोजने और उत्तरों को ग्राउंड करने की अनुमति देता है। अद्यतित जानकारी की आवश्यकता वाली क्वेरीज़ के लिए उपयोगी।"
+			}
+		},
+
 		"googleCloudSetup": {
 			"title": "Google Cloud Vertex AI का उपयोग करने के लिए, आपको आवश्यकता है:",
 			"step1": "1. Google Cloud खाता बनाएं, Vertex AI API सक्षम करें और वांछित Claude मॉडल सक्षम करें।",

+ 11 - 0
webview-ui/src/i18n/locales/id/settings.json

@@ -308,6 +308,17 @@
 		"cacheUsageNote": "Catatan: Jika kamu tidak melihat penggunaan cache, coba pilih model yang berbeda lalu pilih model yang kamu inginkan lagi.",
 		"vscodeLmModel": "Model Bahasa",
 		"vscodeLmWarning": "Catatan: Ini adalah integrasi yang sangat eksperimental dan dukungan provider akan bervariasi. Jika kamu mendapat error tentang model yang tidak didukung, itu adalah masalah di sisi provider.",
+		"geminiParameters": {
+			"urlContext": {
+				"title": "Aktifkan konteks URL",
+				"description": "Memungkinkan Gemini mengakses dan memproses URL untuk konteks tambahan saat menghasilkan respons. Berguna untuk tugas yang memerlukan analisis konten web."
+			},
+			"groundingSearch": {
+				"title": "Aktifkan Grounding dengan Pencarian Google",
+				"description": "Memungkinkan Gemini mencari informasi terkini di Google dan mendasarkan respons pada data waktu nyata. Berguna untuk kueri yang memerlukan informasi terkini."
+			}
+		},
+
 		"googleCloudSetup": {
 			"title": "Untuk menggunakan Google Cloud Vertex AI, kamu perlu:",
 			"step1": "1. Buat akun Google Cloud, aktifkan Vertex AI API & aktifkan model Claude yang diinginkan.",

+ 11 - 0
webview-ui/src/i18n/locales/it/settings.json

@@ -304,6 +304,17 @@
 		"cacheUsageNote": "Nota: Se non vedi l'utilizzo della cache, prova a selezionare un modello diverso e poi seleziona nuovamente il modello desiderato.",
 		"vscodeLmModel": "Modello linguistico",
 		"vscodeLmWarning": "Nota: Questa è un'integrazione molto sperimentale e il supporto del fornitore varierà. Se ricevi un errore relativo a un modello non supportato, si tratta di un problema del fornitore.",
+		"geminiParameters": {
+			"urlContext": {
+				"title": "Abilita contesto URL",
+				"description": "Consente a Gemini di accedere e processare URL per contesto aggiuntivo durante la generazione delle risposte. Utile per attività che richiedono analisi di contenuti web."
+			},
+			"groundingSearch": {
+				"title": "Abilita grounding con ricerca Google",
+				"description": "Consente a Gemini di cercare informazioni aggiornate su Google e basare le risposte su dati in tempo reale. Utile per query che richiedono informazioni aggiornate."
+			}
+		},
+
 		"googleCloudSetup": {
 			"title": "Per utilizzare Google Cloud Vertex AI, è necessario:",
 			"step1": "1. Creare un account Google Cloud, abilitare l'API Vertex AI e abilitare i modelli Claude desiderati.",

+ 11 - 0
webview-ui/src/i18n/locales/ja/settings.json

@@ -304,6 +304,17 @@
 		"cacheUsageNote": "注意:キャッシュの使用が表示されない場合は、別のモデルを選択してから希望のモデルを再度選択してみてください。",
 		"vscodeLmModel": "言語モデル",
 		"vscodeLmWarning": "注意:これは非常に実験的な統合であり、プロバイダーのサポートは異なります。モデルがサポートされていないというエラーが表示された場合、それはプロバイダー側の問題です。",
+		"geminiParameters": {
+			"urlContext": {
+				"title": "URLコンテキストを有効にする",
+				"description": "応答を生成する際に、追加のコンテキストとしてGeminiがURLにアクセスして処理できるようにします。Webコンテンツの分析を必要とするタスクに役立ちます。"
+			},
+			"groundingSearch": {
+				"title": "Google検索でのグラウンディングを有効にする",
+				"description": "GeminiがGoogleを検索して最新情報を取得し、リアルタイムデータに基づいて応答をグラウンディングできるようにします。最新情報が必要なクエリに便利です。"
+			}
+		},
+
 		"googleCloudSetup": {
 			"title": "Google Cloud Vertex AIを使用するには:",
 			"step1": "1. Google Cloudアカウントを作成し、Vertex AI APIを有効にして、希望するClaudeモデルを有効にします。",

+ 11 - 0
webview-ui/src/i18n/locales/ko/settings.json

@@ -304,6 +304,17 @@
 		"cacheUsageNote": "참고: 캐시 사용이 표시되지 않는 경우, 다른 모델을 선택한 다음 원하는 모델을 다시 선택해 보세요.",
 		"vscodeLmModel": "언어 모델",
 		"vscodeLmWarning": "참고: 이는 매우 실험적인 통합이며, 공급자 지원은 다를 수 있습니다. 모델이 지원되지 않는다는 오류가 발생하면, 이는 공급자 측의 문제입니다.",
+		"geminiParameters": {
+			"urlContext": {
+				"title": "URL 컨텍스트 활성화",
+				"description": "응답을 생성할 때 추가 컨텍스트를 위해 Gemini가 URL에 액세스하고 처리할 수 있도록 합니다. 웹 콘텐츠 분석이 필요한 작업에 유용합니다."
+			},
+			"groundingSearch": {
+				"title": "Google 검색과 함께 근거 지정 활성화",
+				"description": "Gemini가 최신 정보를 얻기 위해 Google을 검색하고 응답을 실시간 데이터에 근거하도록 합니다. 최신 정보가 필요한 쿼리에 유용합니다."
+			}
+		},
+
 		"googleCloudSetup": {
 			"title": "Google Cloud Vertex AI를 사용하려면:",
 			"step1": "1. Google Cloud 계정을 만들고, Vertex AI API를 활성화하고, 원하는 Claude 모델을 활성화하세요.",

+ 11 - 0
webview-ui/src/i18n/locales/nl/settings.json

@@ -304,6 +304,17 @@
 		"cacheUsageNote": "Let op: als je geen cachegebruik ziet, probeer dan een ander model te selecteren en vervolgens weer je gewenste model.",
 		"vscodeLmModel": "Taalmodel",
 		"vscodeLmWarning": "Let op: dit is een zeer experimentele integratie en ondersteuning door providers kan variëren. Krijg je een foutmelding dat een model niet wordt ondersteund, dan ligt dat aan de provider.",
+		"geminiParameters": {
+			"urlContext": {
+				"title": "URL-context inschakelen",
+				"description": "Staat Gemini toe om URL's te openen en te verwerken voor extra context bij het genereren van antwoorden. Handig voor taken die webinhoudsanalyse vereisen."
+			},
+			"groundingSearch": {
+				"title": "Grounding met Google-zoekopdracht inschakelen",
+				"description": "Staat Gemini toe om Google te doorzoeken voor actuele informatie en antwoorden op realtime gegevens te baseren. Handig voor vragen die actuele informatie vereisen."
+			}
+		},
+
 		"googleCloudSetup": {
 			"title": "Om Google Cloud Vertex AI te gebruiken, moet je:",
 			"step1": "1. Maak een Google Cloud-account aan, schakel de Vertex AI API in en activeer de gewenste Claude-modellen.",

+ 11 - 0
webview-ui/src/i18n/locales/pl/settings.json

@@ -304,6 +304,17 @@
 		"cacheUsageNote": "Uwaga: Jeśli nie widzisz użycia bufora, spróbuj wybrać inny model, a następnie ponownie wybrać żądany model.",
 		"vscodeLmModel": "Model językowy",
 		"vscodeLmWarning": "Uwaga: To bardzo eksperymentalna integracja, a wsparcie dostawcy może się różnić. Jeśli otrzymasz błąd dotyczący nieobsługiwanego modelu, jest to problem po stronie dostawcy.",
+		"geminiParameters": {
+			"urlContext": {
+				"title": "Włącz kontekst URL",
+				"description": "Pozwala Gemini uzyskiwać dostęp i przetwarzać adresy URL w celu uzyskania dodatkowego kontekstu podczas generowania odpowiedzi. Przydatne w zadaniach wymagających analizy zawartości sieci Web."
+			},
+			"groundingSearch": {
+				"title": "Włącz grounding przy użyciu wyszukiwarki Google",
+				"description": "Pozwala Gemini przeszukiwać Google w celu uzyskania aktualnych informacji i opierać odpowiedzi na danych w czasie rzeczywistym. Przydatne w zapytaniach wymagających najnowszych informacji."
+			}
+		},
+
 		"googleCloudSetup": {
 			"title": "Aby korzystać z Google Cloud Vertex AI, potrzebujesz:",
 			"step1": "1. Utworzyć konto Google Cloud, włączyć API Vertex AI i włączyć żądane modele Claude.",

+ 11 - 0
webview-ui/src/i18n/locales/pt-BR/settings.json

@@ -304,6 +304,17 @@
 		"cacheUsageNote": "Nota: Se você não vir o uso do cache, tente selecionar um modelo diferente e depois selecionar novamente o modelo desejado.",
 		"vscodeLmModel": "Modelo de Linguagem",
 		"vscodeLmWarning": "Nota: Esta é uma integração muito experimental e o suporte do provedor pode variar. Se você receber um erro sobre um modelo não ser suportado, isso é um problema do lado do provedor.",
+		"geminiParameters": {
+			"urlContext": {
+				"title": "Ativar contexto de URL",
+				"description": "Permite que o Gemini acesse e processe URLs para contexto adicional ao gerar respostas. Útil para tarefas que exijam análise de conteúdo da web."
+			},
+			"groundingSearch": {
+				"title": "Ativar grounding com pesquisa no Google",
+				"description": "Permite que o Gemini pesquise informações atuais no Google e fundamente as respostas em dados em tempo real. Útil para consultas que requerem informações atualizadas."
+			}
+		},
+
 		"googleCloudSetup": {
 			"title": "Para usar o Google Cloud Vertex AI, você precisa:",
 			"step1": "1. Criar uma conta Google Cloud, ativar a API Vertex AI e ativar os modelos Claude desejados.",

+ 11 - 0
webview-ui/src/i18n/locales/ru/settings.json

@@ -304,6 +304,17 @@
 		"cacheUsageNote": "Примечание: если вы не видите использование кэша, попробуйте выбрать другую модель, а затем вернуться к нужной.",
 		"vscodeLmModel": "Языковая модель",
 		"vscodeLmWarning": "Внимание: это очень экспериментальная интеграция, поддержка провайдера может отличаться. Если возникает ошибка о неподдерживаемой модели — проблема на стороне провайдера.",
+		"geminiParameters": {
+			"urlContext": {
+				"title": "Включить контекст URL",
+				"description": "Позволяет Gemini получать доступ к URL-адресам и обрабатывать их для дополнительного контекста при генерации ответов. Полезно для задач, требующих анализа веб-контента."
+			},
+			"groundingSearch": {
+				"title": "Включить grounding через поиск Google",
+				"description": "Позволяет Gemini искать актуальную информацию в Google и основывать ответы на данных в реальном времени. Полезно для запросов, требующих актуальной информации."
+			}
+		},
+
 		"googleCloudSetup": {
 			"title": "Для использования Google Cloud Vertex AI необходимо:",
 			"step1": "1. Создайте аккаунт Google Cloud, включите Vertex AI API и нужные модели Claude.",

+ 11 - 0
webview-ui/src/i18n/locales/tr/settings.json

@@ -304,6 +304,17 @@
 		"cacheUsageNote": "Not: Önbellek kullanımını görmüyorsanız, farklı bir model seçip ardından istediğiniz modeli tekrar seçmeyi deneyin.",
 		"vscodeLmModel": "Dil Modeli",
 		"vscodeLmWarning": "Not: Bu çok deneysel bir entegrasyondur ve sağlayıcı desteği değişebilir. Bir modelin desteklenmediğine dair bir hata alırsanız, bu sağlayıcı tarafındaki bir sorundur.",
+		"geminiParameters": {
+			"urlContext": {
+				"title": "URL bağlamını etkinleştir",
+				"description": "Yanıtlar oluşturulurken ek bağlam için Gemini'nin URL'lere erişmesine ve işlemesine izin verir. Web içeriği analizi gerektiren görevler için faydalıdır."
+			},
+			"groundingSearch": {
+				"title": "Google Aramasıyla Grounding Etkinleştir",
+				"description": "Gemini'nin güncel bilgileri almak için Google'da arama yapmasına ve yanıtları gerçek zamanlı verilere dayandırmasına izin verir. Güncel bilgi gerektiren sorgular için kullanışlıdır."
+			}
+		},
+
 		"googleCloudSetup": {
 			"title": "Google Cloud Vertex AI'yi kullanmak için şunları yapmanız gerekir:",
 			"step1": "1. Google Cloud hesabı oluşturun, Vertex AI API'sini etkinleştirin ve istediğiniz Claude modellerini etkinleştirin.",

+ 11 - 0
webview-ui/src/i18n/locales/vi/settings.json

@@ -304,6 +304,17 @@
 		"cacheUsageNote": "Lưu ý: Nếu bạn không thấy việc sử dụng bộ nhớ đệm, hãy thử chọn một mô hình khác và sau đó chọn lại mô hình mong muốn của bạn.",
 		"vscodeLmModel": "Mô hình ngôn ngữ",
 		"vscodeLmWarning": "Lưu ý: Đây là tích hợp thử nghiệm và hỗ trợ nhà cung cấp có thể khác nhau. Nếu bạn nhận được lỗi về mô hình không được hỗ trợ, đó là vấn đề từ phía nhà cung cấp.",
+		"geminiParameters": {
+			"urlContext": {
+				"title": "Bật ngữ cảnh URL",
+				"description": "Cho phép Gemini truy cập và xử lý URL để có thêm ngữ cảnh khi tạo phản hồi. Hữu ích cho các tác vụ yêu cầu phân tích nội dung web."
+			},
+			"groundingSearch": {
+				"title": "Bật grounding với tìm kiếm Google",
+				"description": "Cho phép Gemini tìm kiếm trên Google để lấy thông tin mới nhất và căn cứ phản hồi dựa trên dữ liệu thời gian thực. Hữu ích cho các truy vấn yêu cầu thông tin cập nhật."
+			}
+		},
+
 		"googleCloudSetup": {
 			"title": "Để sử dụng Google Cloud Vertex AI, bạn cần:",
 			"step1": "1. Tạo tài khoản Google Cloud, kích hoạt Vertex AI API và kích hoạt các mô hình Claude mong muốn.",

+ 11 - 0
webview-ui/src/i18n/locales/zh-CN/settings.json

@@ -304,6 +304,17 @@
 		"cacheUsageNote": "提示:若未显示缓存使用情况,请切换模型后重新选择",
 		"vscodeLmModel": "VSCode LM 模型",
 		"vscodeLmWarning": "注意:这是一个非常实验性的集成,提供商支持会有所不同。如果您收到有关不支持模型的错误,则这是提供商方面的问题。",
+
+		"geminiParameters": {
+			"urlContext": {
+				"title": "启用 URL 上下文",
+				"description": "让 Gemini 读取链接的页面以提取、比较和综合其内容,从而提供明智的答复。"
+			},
+			"groundingSearch": {
+				"title": "启用 Google 搜索基础",
+				"description": "将 Gemini 连接到实时网络数据,以获得包含可验证引用的准确、最新的答案。"
+			}
+		},
 		"googleCloudSetup": {
 			"title": "要使用 Google Cloud Vertex AI,您需要:",
 			"step1": "1. 注册Google Cloud账号并启用Vertex AI API",

+ 11 - 0
webview-ui/src/i18n/locales/zh-TW/settings.json

@@ -304,6 +304,17 @@
 		"cacheUsageNote": "注意:如果您沒有看到快取使用情況,請嘗試選擇其他模型,然後重新選擇您想要的模型。",
 		"vscodeLmModel": "語言模型",
 		"vscodeLmWarning": "注意:此整合功能仍處於實驗階段,各供應商的支援程度可能不同。如果出現模型不支援的錯誤,通常是供應商方面的問題。",
+
+		"geminiParameters": {
+			"urlContext": {
+				"title": "啟用 URL 上下文",
+				"description": "讓 Gemini 讀取連結的頁面以提取、比較和綜合其內容,從而提供明智的答覆。"
+			},
+			"groundingSearch": {
+				"title": "啟用 Google 搜尋基礎",
+				"description": "將 Gemini 連接到即時網路數據,以獲得包含可驗證引用的準確、最新的答案。"
+			}
+		},
 		"googleCloudSetup": {
 			"title": "要使用 Google Cloud Vertex AI,您需要:",
 			"step1": "1. 建立 Google Cloud 帳戶,啟用 Vertex AI API 並啟用所需的 Claude 模型。",