Skip to content

Commit 63b71d8

Browse files
roomote[bot]roomotedaniel-lxs
authored
feat: add Ollama API key support for Turbo mode (#7425)
* feat: add Ollama API key support for Turbo mode - Add ollamaApiKey field to ProviderSettings schema - Add ollamaApiKey to SECRET_STATE_KEYS for secure storage - Update Ollama and NativeOllama providers to use API key for authentication - Add UI field for Ollama API key (shown when custom base URL is provided) - Add test coverage for API key functionality This enables users to use Ollama Turbo with datacenter-grade hardware by providing an API key for authenticated Ollama instances or cloud services. * fix: use VSCodeTextField for Ollama API key field Remove non-existent ApiKeyField import and use standard VSCodeTextField with password type, matching other provider implementations * Add missing translation keys for Ollama API key support - Add providers.ollama.apiKey and providers.ollama.apiKeyHelp to all 18 language files - Support for authenticated Ollama instances and cloud services - Relates to PR #7425 * refactor: improve type safety for Ollama client configuration - Replace 'any' type with proper OllamaOptions (Config) type - Import Config type from ollama package for better type checking --------- Co-authored-by: Roo Code <[email protected]> Co-authored-by: Daniel Riccio <[email protected]>
1 parent f5e0525 commit 63b71d8

File tree

24 files changed

+85
-4
lines changed

24 files changed

+85
-4
lines changed

packages/types/src/global-settings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ export const SECRET_STATE_KEYS = [
178178
"awsSecretKey",
179179
"awsSessionToken",
180180
"openAiApiKey",
181+
"ollamaApiKey",
181182
"geminiApiKey",
182183
"openAiNativeApiKey",
183184
"cerebrasApiKey",

packages/types/src/provider-settings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ const openAiSchema = baseProviderSettingsSchema.extend({
188188
const ollamaSchema = baseProviderSettingsSchema.extend({
189189
ollamaModelId: z.string().optional(),
190190
ollamaBaseUrl: z.string().optional(),
191+
ollamaApiKey: z.string().optional(),
191192
})
192193

193194
const vsCodeLmSchema = baseProviderSettingsSchema.extend({

src/api/providers/__tests__/ollama.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,17 @@ describe("OllamaHandler", () => {
9292
})
9393
expect(handlerWithoutUrl).toBeInstanceOf(OllamaHandler)
9494
})
95+
96+
it("should use API key when provided", () => {
97+
const handlerWithApiKey = new OllamaHandler({
98+
apiModelId: "llama2",
99+
ollamaModelId: "llama2",
100+
ollamaBaseUrl: "https://ollama.com",
101+
ollamaApiKey: "test-api-key",
102+
})
103+
expect(handlerWithApiKey).toBeInstanceOf(OllamaHandler)
104+
// The API key will be used in the Authorization header
105+
})
95106
})
96107

97108
describe("createMessage", () => {

src/api/providers/native-ollama.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Anthropic } from "@anthropic-ai/sdk"
2-
import { Message, Ollama } from "ollama"
2+
import { Message, Ollama, type Config as OllamaOptions } from "ollama"
33
import { ModelInfo, openAiModelInfoSaneDefaults, DEEP_SEEK_DEFAULT_TEMPERATURE } from "@roo-code/types"
44
import { ApiStream } from "../transform/stream"
55
import { BaseProvider } from "./base-provider"
@@ -140,10 +140,19 @@ export class NativeOllamaHandler extends BaseProvider implements SingleCompletio
140140
private ensureClient(): Ollama {
141141
if (!this.client) {
142142
try {
143-
this.client = new Ollama({
143+
const clientOptions: OllamaOptions = {
144144
host: this.options.ollamaBaseUrl || "http://localhost:11434",
145145
// Note: The ollama npm package handles timeouts internally
146-
})
146+
}
147+
148+
// Add API key if provided (for Ollama cloud or authenticated instances)
149+
if (this.options.ollamaApiKey) {
150+
clientOptions.headers = {
151+
Authorization: `Bearer ${this.options.ollamaApiKey}`,
152+
}
153+
}
154+
155+
this.client = new Ollama(clientOptions)
147156
} catch (error: any) {
148157
throw new Error(`Error creating Ollama client: ${error.message}`)
149158
}

src/api/providers/ollama.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,20 @@ export class OllamaHandler extends BaseProvider implements SingleCompletionHandl
2525
super()
2626
this.options = options
2727

28+
// Use the API key if provided (for Ollama cloud or authenticated instances)
29+
// Otherwise use "ollama" as a placeholder for local instances
30+
const apiKey = this.options.ollamaApiKey || "ollama"
31+
32+
const headers: Record<string, string> = {}
33+
if (this.options.ollamaApiKey) {
34+
headers["Authorization"] = `Bearer ${this.options.ollamaApiKey}`
35+
}
36+
2837
this.client = new OpenAI({
2938
baseURL: (this.options.ollamaBaseUrl || "http://localhost:11434") + "/v1",
30-
apiKey: "ollama",
39+
apiKey: apiKey,
3140
timeout: getApiRequestTimeout(),
41+
defaultHeaders: headers,
3242
})
3343
}
3444

webview-ui/src/components/settings/providers/Ollama.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,19 @@ export const Ollama = ({ apiConfiguration, setApiConfigurationField }: OllamaPro
8686
className="w-full">
8787
<label className="block font-medium mb-1">{t("settings:providers.ollama.baseUrl")}</label>
8888
</VSCodeTextField>
89+
{apiConfiguration?.ollamaBaseUrl && (
90+
<VSCodeTextField
91+
value={apiConfiguration?.ollamaApiKey || ""}
92+
type="password"
93+
onInput={handleInputChange("ollamaApiKey")}
94+
placeholder={t("settings:placeholders.apiKey")}
95+
className="w-full">
96+
<label className="block font-medium mb-1">{t("settings:providers.ollama.apiKey")}</label>
97+
<div className="text-xs text-vscode-descriptionForeground mt-1">
98+
{t("settings:providers.ollama.apiKeyHelp")}
99+
</div>
100+
</VSCodeTextField>
101+
)}
89102
<VSCodeTextField
90103
value={apiConfiguration?.ollamaModelId || ""}
91104
onInput={handleInputChange("ollamaModelId")}

webview-ui/src/i18n/locales/ca/settings.json

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

webview-ui/src/i18n/locales/de/settings.json

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

webview-ui/src/i18n/locales/en/settings.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,8 @@
373373
"ollama": {
374374
"baseUrl": "Base URL (optional)",
375375
"modelId": "Model ID",
376+
"apiKey": "Ollama API Key",
377+
"apiKeyHelp": "Optional API key for authenticated Ollama instances or cloud services. Leave empty for local installations.",
376378
"description": "Ollama allows you to run models locally on your computer. For instructions on how to get started, see their quickstart guide.",
377379
"warning": "Note: Roo Code uses complex prompts and works best with Claude models. Less capable models may not work as expected."
378380
},

webview-ui/src/i18n/locales/es/settings.json

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)