From 85b54b33ba2dda8a6c01f6963dfe3c7b247fc158 Mon Sep 17 00:00:00 2001 From: dongqing Date: Mon, 10 Mar 2025 19:06:58 +0800 Subject: [PATCH] support custom base url for gemini in google AI studio --- src/api/providers/gemini.ts | 24 ++++++++++++----- src/core/webview/ClineProvider.ts | 6 +++++ src/shared/api.ts | 1 + .../src/components/settings/ApiOptions.tsx | 27 +++++++++++++++++++ 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/api/providers/gemini.ts b/src/api/providers/gemini.ts index 0d7179320c..6bab8cfa6d 100644 --- a/src/api/providers/gemini.ts +++ b/src/api/providers/gemini.ts @@ -17,10 +17,15 @@ export class GeminiHandler implements ApiHandler, SingleCompletionHandler { } async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream { - const model = this.client.getGenerativeModel({ - model: this.getModel().id, - systemInstruction: systemPrompt, - }) + const model = this.client.getGenerativeModel( + { + model: this.getModel().id, + systemInstruction: systemPrompt, + }, + { + baseUrl: this.options.googleGeminiBaseUrl || undefined, + }, + ) const result = await model.generateContentStream({ contents: messages.map(convertAnthropicMessageToGemini), generationConfig: { @@ -55,9 +60,14 @@ export class GeminiHandler implements ApiHandler, SingleCompletionHandler { async completePrompt(prompt: string): Promise { try { - const model = this.client.getGenerativeModel({ - model: this.getModel().id, - }) + const model = this.client.getGenerativeModel( + { + model: this.getModel().id, + }, + { + baseUrl: this.options.googleGeminiBaseUrl || undefined, + }, + ) const result = await model.generateContent({ contents: [{ role: "user", parts: [{ text: prompt }] }], diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index bb31be5dce..aba77f70a4 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -96,6 +96,7 @@ type GlobalStateKey = | "openRouterModelInfo" | "openRouterBaseUrl" | "openRouterUseMiddleOutTransform" + | "googleGeminiBaseUrl" | "allowedCommands" | "soundEnabled" | "soundVolume" @@ -1657,6 +1658,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { anthropicBaseUrl, anthropicThinking, geminiApiKey, + googleGeminiBaseUrl, openAiNativeApiKey, deepSeekApiKey, azureApiVersion, @@ -1704,6 +1706,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { this.updateGlobalState("lmStudioBaseUrl", lmStudioBaseUrl), this.updateGlobalState("anthropicBaseUrl", anthropicBaseUrl), this.updateGlobalState("anthropicThinking", anthropicThinking), + this.updateGlobalState("googleGeminiBaseUrl", googleGeminiBaseUrl), this.storeSecret("geminiApiKey", geminiApiKey), this.storeSecret("openAiNativeApiKey", openAiNativeApiKey), this.storeSecret("deepSeekApiKey", deepSeekApiKey), @@ -2516,6 +2519,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { anthropicBaseUrl, anthropicThinking, geminiApiKey, + googleGeminiBaseUrl, openAiNativeApiKey, deepSeekApiKey, mistralApiKey, @@ -2598,6 +2602,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { this.getGlobalState("lmStudioBaseUrl") as Promise, this.getGlobalState("anthropicBaseUrl") as Promise, this.getGlobalState("anthropicThinking") as Promise, + this.getGlobalState("googleGeminiBaseUrl") as Promise, this.getSecret("geminiApiKey") as Promise, this.getSecret("openAiNativeApiKey") as Promise, this.getSecret("deepSeekApiKey") as Promise, @@ -2699,6 +2704,7 @@ export class ClineProvider implements vscode.WebviewViewProvider { anthropicBaseUrl, anthropicThinking, geminiApiKey, + googleGeminiBaseUrl, openAiNativeApiKey, deepSeekApiKey, mistralApiKey, diff --git a/src/shared/api.ts b/src/shared/api.ts index cea760c776..cfa3e15369 100644 --- a/src/shared/api.ts +++ b/src/shared/api.ts @@ -51,6 +51,7 @@ export interface ApiHandlerOptions { lmStudioModelId?: string lmStudioBaseUrl?: string geminiApiKey?: string + googleGeminiBaseUrl?: string openAiNativeApiKey?: string mistralApiKey?: string mistralCodestralUrl?: string // New option for Codestral URL diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index 0b6a118656..45dfcf1eda 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -71,6 +71,9 @@ const ApiOptions = ({ const [anthropicThinkingBudget, setAnthropicThinkingBudget] = useState(apiConfiguration?.anthropicThinking) const [azureApiVersionSelected, setAzureApiVersionSelected] = useState(!!apiConfiguration?.azureApiVersion) const [openRouterBaseUrlSelected, setOpenRouterBaseUrlSelected] = useState(!!apiConfiguration?.openRouterBaseUrl) + const [googleGeminiBaseUrlSelected, setGoogleGeminiBaseUrlSelected] = useState( + !!apiConfiguration?.googleGeminiBaseUrl, + ) const [isDescriptionExpanded, setIsDescriptionExpanded] = useState(false) const inputEventTransform = (event: E) => (event as { target: HTMLInputElement })?.target?.value as any @@ -574,6 +577,30 @@ const ApiOptions = ({ placeholder="Enter API Key..."> Gemini API Key + { + setGoogleGeminiBaseUrlSelected(checked) + if (!checked) { + handleInputChange("googleGeminiBaseUrl")({ + target: { + value: "", + }, + }) + } + }}> + Use custom base URL + + + {googleGeminiBaseUrlSelected && ( + + )}