Skip to content

Commit 705b3ba

Browse files
authored
Merge pull request #1534 from dqroid/support-custom-baseUrl-for-google-ai-studio-gemini
support custom base url for gemini in google AI studio
2 parents 5b7ed8e + 7ece065 commit 705b3ba

File tree

6 files changed

+63
-14
lines changed

6 files changed

+63
-14
lines changed

src/api/providers/__tests__/gemini.test.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,15 @@ describe("GeminiHandler", () => {
101101
})
102102

103103
// Verify the model configuration
104-
expect(mockGetGenerativeModel).toHaveBeenCalledWith({
105-
model: "gemini-2.0-flash-thinking-exp-1219",
106-
systemInstruction: systemPrompt,
107-
})
104+
expect(mockGetGenerativeModel).toHaveBeenCalledWith(
105+
{
106+
model: "gemini-2.0-flash-thinking-exp-1219",
107+
systemInstruction: systemPrompt,
108+
},
109+
{
110+
baseUrl: undefined,
111+
},
112+
)
108113

109114
// Verify generation config
110115
expect(mockGenerateContentStream).toHaveBeenCalledWith(
@@ -149,9 +154,14 @@ describe("GeminiHandler", () => {
149154

150155
const result = await handler.completePrompt("Test prompt")
151156
expect(result).toBe("Test response")
152-
expect(mockGetGenerativeModel).toHaveBeenCalledWith({
153-
model: "gemini-2.0-flash-thinking-exp-1219",
154-
})
157+
expect(mockGetGenerativeModel).toHaveBeenCalledWith(
158+
{
159+
model: "gemini-2.0-flash-thinking-exp-1219",
160+
},
161+
{
162+
baseUrl: undefined,
163+
},
164+
)
155165
expect(mockGenerateContent).toHaveBeenCalledWith({
156166
contents: [{ role: "user", parts: [{ text: "Test prompt" }] }],
157167
generationConfig: {

src/api/providers/gemini.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,15 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
1919
}
2020

2121
override async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
22-
const model = this.client.getGenerativeModel({
23-
model: this.getModel().id,
24-
systemInstruction: systemPrompt,
25-
})
22+
const model = this.client.getGenerativeModel(
23+
{
24+
model: this.getModel().id,
25+
systemInstruction: systemPrompt,
26+
},
27+
{
28+
baseUrl: this.options.googleGeminiBaseUrl || undefined,
29+
},
30+
)
2631
const result = await model.generateContentStream({
2732
contents: messages.map(convertAnthropicMessageToGemini),
2833
generationConfig: {
@@ -57,9 +62,14 @@ export class GeminiHandler extends BaseProvider implements SingleCompletionHandl
5762

5863
async completePrompt(prompt: string): Promise<string> {
5964
try {
60-
const model = this.client.getGenerativeModel({
61-
model: this.getModel().id,
62-
})
65+
const model = this.client.getGenerativeModel(
66+
{
67+
model: this.getModel().id,
68+
},
69+
{
70+
baseUrl: this.options.googleGeminiBaseUrl || undefined,
71+
},
72+
)
6373

6474
const result = await model.generateContent({
6575
contents: [{ role: "user", parts: [{ text: prompt }] }],

src/exports/roo-code.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ export type GlobalStateKey =
154154
| "openRouterModelInfo"
155155
| "openRouterBaseUrl"
156156
| "openRouterUseMiddleOutTransform"
157+
| "googleGeminiBaseUrl"
157158
| "allowedCommands"
158159
| "soundEnabled"
159160
| "soundVolume"

src/shared/api.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export interface ApiHandlerOptions {
5656
lmStudioDraftModelId?: string
5757
lmStudioSpeculativeDecodingEnabled?: boolean
5858
geminiApiKey?: string
59+
googleGeminiBaseUrl?: string
5960
openAiNativeApiKey?: string
6061
mistralApiKey?: string
6162
mistralCodestralUrl?: string // New option for Codestral URL
@@ -115,6 +116,7 @@ export const API_CONFIG_KEYS: GlobalStateKey[] = [
115116
"lmStudioBaseUrl",
116117
"lmStudioDraftModelId",
117118
"lmStudioSpeculativeDecodingEnabled",
119+
"googleGeminiBaseUrl",
118120
"mistralCodestralUrl",
119121
"azureApiVersion",
120122
"openRouterUseMiddleOutTransform",

src/shared/globalState.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export const GLOBAL_STATE_KEYS = [
7272
"openRouterModelInfo",
7373
"openRouterBaseUrl",
7474
"openRouterUseMiddleOutTransform",
75+
"googleGeminiBaseUrl",
7576
"allowedCommands",
7677
"soundEnabled",
7778
"soundVolume",

webview-ui/src/components/settings/ApiOptions.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ const ApiOptions = ({
116116
const [anthropicBaseUrlSelected, setAnthropicBaseUrlSelected] = useState(!!apiConfiguration?.anthropicBaseUrl)
117117
const [azureApiVersionSelected, setAzureApiVersionSelected] = useState(!!apiConfiguration?.azureApiVersion)
118118
const [openRouterBaseUrlSelected, setOpenRouterBaseUrlSelected] = useState(!!apiConfiguration?.openRouterBaseUrl)
119+
const [googleGeminiBaseUrlSelected, setGoogleGeminiBaseUrlSelected] = useState(
120+
!!apiConfiguration?.googleGeminiBaseUrl,
121+
)
119122
const [isDescriptionExpanded, setIsDescriptionExpanded] = useState(false)
120123

121124
const noTransform = <T,>(value: T) => value
@@ -646,6 +649,28 @@ const ApiOptions = ({
646649
Get Gemini API Key
647650
</VSCodeButtonLink>
648651
)}
652+
<div>
653+
<Checkbox
654+
checked={googleGeminiBaseUrlSelected}
655+
onChange={(checked: boolean) => {
656+
setGoogleGeminiBaseUrlSelected(checked)
657+
658+
if (!checked) {
659+
setApiConfigurationField("googleGeminiBaseUrl", "")
660+
}
661+
}}>
662+
Use custom base URL
663+
</Checkbox>
664+
{googleGeminiBaseUrlSelected && (
665+
<VSCodeTextField
666+
value={apiConfiguration?.googleGeminiBaseUrl || ""}
667+
type="url"
668+
onInput={handleInputChange("googleGeminiBaseUrl")}
669+
placeholder="https://generativelanguage.googleapis.com"
670+
className="w-full mt-1"
671+
/>
672+
)}
673+
</div>
649674
</>
650675
)}
651676

0 commit comments

Comments
 (0)