diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index 682514b0fa..4322b9f550 100644 --- a/packages/types/src/provider-settings.ts +++ b/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({ diff --git a/src/api/providers/__tests__/gemini-handler.spec.ts b/src/api/providers/__tests__/gemini-handler.spec.ts new file mode 100644 index 0000000000..7c61639cfd --- /dev/null +++ b/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" })) + }) + }) +}) diff --git a/src/api/providers/__tests__/gemini.spec.ts b/src/api/providers/__tests__/gemini.spec.ts index 8a7fd24fe3..812c1ae1a6 100644 --- a/src/api/providers/__tests__/gemini.spec.ts +++ b/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" }), ) }) diff --git a/src/api/providers/__tests__/vertex.spec.ts b/src/api/providers/__tests__/vertex.spec.ts index 8e9add524d..d147e79ba8 100644 --- a/src/api/providers/__tests__/vertex.spec.ts +++ b/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" }), ) }) diff --git a/src/api/providers/gemini.ts b/src/api/providers/gemini.ts index 6765c8676d..5e547edbdc 100644 --- a/src/api/providers/gemini.ts +++ b/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 { 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 diff --git a/src/core/sliding-window/__tests__/sliding-window.spec.ts b/src/core/sliding-window/__tests__/sliding-window.spec.ts index 393d50307e..0f2c70c81b 100644 --- a/src/core/sliding-window/__tests__/sliding-window.spec.ts +++ b/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 diff --git a/src/i18n/locales/ca/common.json b/src/i18n/locales/ca/common.json index 39bc1df8f8..cbe2c032b4 100644 --- a/src/i18n/locales/ca/common.json +++ b/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": { diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json index fbd800f602..95d315e103 100644 --- a/src/i18n/locales/de/common.json +++ b/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": { diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index db6341c312..4150e12f84 100644 --- a/src/i18n/locales/en/common.json +++ b/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": { diff --git a/src/i18n/locales/es/common.json b/src/i18n/locales/es/common.json index cc04abfdae..d47b95be7e 100644 --- a/src/i18n/locales/es/common.json +++ b/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": { diff --git a/src/i18n/locales/fr/common.json b/src/i18n/locales/fr/common.json index 73f3e3d396..e239358bbf 100644 --- a/src/i18n/locales/fr/common.json +++ b/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": { diff --git a/src/i18n/locales/hi/common.json b/src/i18n/locales/hi/common.json index 03f74e1af5..d5ba036f63 100644 --- a/src/i18n/locales/hi/common.json +++ b/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": { diff --git a/src/i18n/locales/id/common.json b/src/i18n/locales/id/common.json index 822341f529..b261f69e24 100644 --- a/src/i18n/locales/id/common.json +++ b/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": { diff --git a/src/i18n/locales/it/common.json b/src/i18n/locales/it/common.json index 7ae45cc4c5..f5e15398ed 100644 --- a/src/i18n/locales/it/common.json +++ b/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": { diff --git a/src/i18n/locales/ja/common.json b/src/i18n/locales/ja/common.json index da8124b48c..9b43f64bcf 100644 --- a/src/i18n/locales/ja/common.json +++ b/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": { diff --git a/src/i18n/locales/ko/common.json b/src/i18n/locales/ko/common.json index a95908ffec..2bfbacad32 100644 --- a/src/i18n/locales/ko/common.json +++ b/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": { diff --git a/src/i18n/locales/nl/common.json b/src/i18n/locales/nl/common.json index ac7df81e42..645a371754 100644 --- a/src/i18n/locales/nl/common.json +++ b/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": { diff --git a/src/i18n/locales/pl/common.json b/src/i18n/locales/pl/common.json index e24960af89..45251e1ab4 100644 --- a/src/i18n/locales/pl/common.json +++ b/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": { diff --git a/src/i18n/locales/pt-BR/common.json b/src/i18n/locales/pt-BR/common.json index 6007beb41a..29c951fb39 100644 --- a/src/i18n/locales/pt-BR/common.json +++ b/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": { diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json index 4d3daaf743..5f8fdf34c1 100644 --- a/src/i18n/locales/ru/common.json +++ b/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": { diff --git a/src/i18n/locales/tr/common.json b/src/i18n/locales/tr/common.json index e2dfca734b..c7feb38ef6 100644 --- a/src/i18n/locales/tr/common.json +++ b/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": { diff --git a/src/i18n/locales/vi/common.json b/src/i18n/locales/vi/common.json index 15e4ef8b77..84b8b409dc 100644 --- a/src/i18n/locales/vi/common.json +++ b/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": { diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json index edbbb6ae8c..7798a8bbdb 100644 --- a/src/i18n/locales/zh-CN/common.json +++ b/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": { diff --git a/src/i18n/locales/zh-TW/common.json b/src/i18n/locales/zh-TW/common.json index e7887025f1..c6105c2bf9 100644 --- a/src/i18n/locales/zh-TW/common.json +++ b/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": { diff --git a/webview-ui/src/components/settings/providers/Gemini.tsx b/webview-ui/src/components/settings/providers/Gemini.tsx index 21056f12d5..eadafb81e6 100644 --- a/webview-ui/src/components/settings/providers/Gemini.tsx +++ b/webview-ui/src/components/settings/providers/Gemini.tsx @@ -50,12 +50,13 @@ export const Gemini = ({ apiConfiguration, setApiConfigurationField }: GeminiPro {t("settings:providers.getGeminiApiKey")} )} +
{ setGoogleGeminiBaseUrlSelected(checked) - if (!checked) { setApiConfigurationField("googleGeminiBaseUrl", "") } @@ -71,6 +72,27 @@ export const Gemini = ({ apiConfiguration, setApiConfigurationField }: GeminiPro className="w-full mt-1" /> )} + + setApiConfigurationField("enableUrlContext", checked)}> + {t("settings:providers.geminiParameters.urlContext.title")} + +
+ {t("settings:providers.geminiParameters.urlContext.description")} +
+ + setApiConfigurationField("enableGrounding", checked)}> + {t("settings:providers.geminiParameters.groundingSearch.title")} + +
+ {t("settings:providers.geminiParameters.groundingSearch.description")} +
) diff --git a/webview-ui/src/components/settings/providers/__tests__/Gemini.spec.tsx b/webview-ui/src/components/settings/providers/__tests__/Gemini.spec.tsx new file mode 100644 index 0000000000..cc3f4bd9f0 --- /dev/null +++ b/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) => ( +
+ {children} + onInput(e)} /> +
+ ), +})) + +vi.mock("vscrui", () => ({ + Checkbox: ({ children, checked, onChange, "data-testid": testId, _ }: any) => ( + + ), +})) + +vi.mock("@src/i18n/TranslationContext", () => ({ + useAppTranslation: () => ({ t: (key: string) => key }), +})) + +vi.mock("@src/components/common/VSCodeButtonLink", () => ({ + VSCodeButtonLink: ({ children, href }: any) => {children}, +})) + +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( + , + ) + + 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( + , + ) + + 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( + , + ) + + 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( + , + ) + + 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( + , + ) + + 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( + , + ) + + 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) + }) + }) +}) diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 828790cbb4..aed9413f27 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/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.", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 83662adb48..36970cb920 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/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.", diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 2b4d3b8fe0..cd83190326 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/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.", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 45b7209797..fbee37507d 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/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.", diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 1f846f1e68..ce3e2526de 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/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.", diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index ebe8524aa5..9fe2ca57b5 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/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 मॉडल सक्षम करें।", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index bddc9a98c1..82a10a05f4 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/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.", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 4e3038c242..f5c12b5c75 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/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.", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 0aa402d139..f91dc6a174 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/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モデルを有効にします。", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 25b79b795f..f1f4347887 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/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 모델을 활성화하세요.", diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index 36f5f50c4e..07f86818a2 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/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.", diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 455beebfda..b787d85a81 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/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.", diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index 0e77668246..e35df63d15 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/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.", diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 2750202856..1a0d533792 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/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.", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index a6d8a2b6b9..c05beb0eb3 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/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.", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index b0e0fb7edf..016079f0cc 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/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.", diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 509176a6f4..7a4bd26fb8 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/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", diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 044ac0a751..b3d57e998a 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/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 模型。",