Compare commits

...
Author SHA1 Message Date
0xtoshii 535f0b72e2 typing 2025-08-06 14:04:59 -07:00
0xtoshii 99f8093b81 toggle showing key box 2025-08-06 13:50:08 -07:00
0xtoshiiandEndoTheDev b3ceccbb20 base
Co-authored-by: EndoTheDev <endothedev@gmail.com>
2025-08-06 13:45:23 -07:00
12 changed files with 44 additions and 2 deletions
+1
View File
@@ -235,6 +235,7 @@ message ModelsApiConfiguration {
optional string hugging_face_api_key = 60;
optional string huawei_cloud_maas_api_key = 61;
optional string baseten_api_key = 62;
optional string ollama_api_key = 63;
// Plan mode configurations
optional ApiProvider plan_mode_api_provider = 100;
+1
View File
@@ -172,6 +172,7 @@ message ApiConfiguration {
optional string moonshot_api_key = 54;
optional string moonshot_api_line = 55;
optional string huawei_cloud_maas_api_key = 56;
optional string ollama_api_key = 57;
// Plan mode configurations
optional string plan_mode_api_provider = 100;
+1
View File
@@ -113,6 +113,7 @@ function createHandlerForProvider(
case "ollama":
return new OllamaHandler({
ollamaBaseUrl: options.ollamaBaseUrl,
ollamaApiKey: options.ollamaApiKey,
ollamaModelId: mode === "plan" ? options.planModeOllamaModelId : options.actModeOllamaModelId,
ollamaApiOptionsCtxNum: options.ollamaApiOptionsCtxNum,
requestTimeoutMs: options.requestTimeoutMs,
+14 -2
View File
@@ -1,5 +1,5 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { Message, Ollama } from "ollama"
import { Message, Ollama, Config } from "ollama"
import { ApiHandler } from "../"
import { ApiHandlerOptions, ModelInfo, openAiModelInfoSaneDefaults } from "../../shared/api"
import { convertToOllamaMessages } from "../transform/ollama-format"
@@ -8,6 +8,7 @@ import { withRetry } from "../retry"
interface OllamaHandlerOptions {
ollamaBaseUrl?: string
ollamaApiKey?: string
ollamaModelId?: string
ollamaApiOptionsCtxNum?: string
requestTimeoutMs?: number
@@ -24,7 +25,18 @@ export class OllamaHandler implements ApiHandler {
private ensureClient(): Ollama {
if (!this.client) {
try {
this.client = new Ollama({ host: this.options.ollamaBaseUrl || "http://localhost:11434" })
const clientOptions: Partial<Config> = {
host: this.options.ollamaBaseUrl || "http://localhost:11434",
}
// Add API key if provided (for Ollama cloud or authenticated instances)
if (this.options.ollamaApiKey) {
clientOptions.headers = {
Authorization: `Bearer ${this.options.ollamaApiKey}`,
}
}
this.client = new Ollama(clientOptions)
} catch (error) {
throw new Error(`Error creating Ollama client: ${error.message}`)
}
+5
View File
@@ -200,6 +200,7 @@ export class CacheService {
openAiApiKey,
openAiHeaders,
ollamaBaseUrl,
ollamaApiKey,
ollamaApiOptionsCtxNum,
lmStudioBaseUrl,
anthropicBaseUrl,
@@ -399,6 +400,7 @@ export class CacheService {
awsSessionToken,
awsBedrockApiKey,
openAiApiKey,
ollamaApiKey,
geminiApiKey,
openAiNativeApiKey,
deepSeekApiKey,
@@ -598,6 +600,7 @@ export class CacheService {
openAiApiKey,
openAiHeaders,
ollamaBaseUrl,
ollamaApiKey,
ollamaApiOptionsCtxNum,
lmStudioBaseUrl,
anthropicBaseUrl,
@@ -802,6 +805,7 @@ export class CacheService {
awsSessionToken,
awsBedrockApiKey,
openAiApiKey,
ollamaApiKey,
geminiApiKey,
openAiNativeApiKey,
deepSeekApiKey,
@@ -845,6 +849,7 @@ export class CacheService {
awsSessionToken: this.secretsCache.get("awsSessionToken"),
awsBedrockApiKey: this.secretsCache.get("awsBedrockApiKey"),
openAiApiKey: this.secretsCache.get("openAiApiKey"),
ollamaApiKey: this.secretsCache.get("ollamaApiKey"),
geminiApiKey: this.secretsCache.get("geminiApiKey"),
openAiNativeApiKey: this.secretsCache.get("openAiNativeApiKey"),
deepSeekApiKey: this.secretsCache.get("deepSeekApiKey"),
+1
View File
@@ -7,6 +7,7 @@ export type SecretKey =
| "awsSessionToken"
| "awsBedrockApiKey"
| "openAiApiKey"
| "ollamaApiKey"
| "geminiApiKey"
| "openAiNativeApiKey"
| "deepSeekApiKey"
+1
View File
@@ -524,6 +524,7 @@ export async function migrateWelcomeViewCompleted(context: vscode.ExtensionConte
config.awsRegion,
config.vertexProjectId,
config.openAiApiKey,
config.ollamaApiKey,
config.planModeOllamaModelId,
config.planModeLmStudioModelId,
config.actModeOllamaModelId,
+4
View File
@@ -133,6 +133,7 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
openAiApiKey,
openAiHeaders,
ollamaBaseUrl,
ollamaApiKey,
ollamaApiOptionsCtxNum,
lmStudioBaseUrl,
anthropicBaseUrl,
@@ -214,6 +215,7 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
getSecret(context, "openAiApiKey") as Promise<string | undefined>,
getGlobalState(context, "openAiHeaders") as Promise<Record<string, string> | undefined>,
getGlobalState(context, "ollamaBaseUrl") as Promise<string | undefined>,
getSecret(context, "ollamaApiKey") as Promise<string | undefined>,
getGlobalState(context, "ollamaApiOptionsCtxNum") as Promise<string | undefined>,
getGlobalState(context, "lmStudioBaseUrl") as Promise<string | undefined>,
getGlobalState(context, "anthropicBaseUrl") as Promise<string | undefined>,
@@ -468,6 +470,7 @@ export async function getAllExtensionState(context: vscode.ExtensionContext) {
openAiApiKey,
openAiHeaders: openAiHeaders || {},
ollamaBaseUrl,
ollamaApiKey,
ollamaApiOptionsCtxNum,
lmStudioBaseUrl,
anthropicBaseUrl,
@@ -617,6 +620,7 @@ export async function resetGlobalState(controller: Controller) {
"awsSessionToken",
"awsBedrockApiKey",
"openAiApiKey",
"ollamaApiKey",
"geminiApiKey",
"openAiNativeApiKey",
"deepSeekApiKey",
+1
View File
@@ -62,6 +62,7 @@ export interface ApiHandlerOptions {
openAiBaseUrl?: string
openAiApiKey?: string
ollamaBaseUrl?: string
ollamaApiKey?: string
ollamaApiOptionsCtxNum?: string
lmStudioBaseUrl?: string
geminiApiKey?: string
@@ -354,6 +354,7 @@ export function convertApiConfigurationToProto(config: ApiConfiguration): ProtoA
openAiBaseUrl: config.openAiBaseUrl,
openAiApiKey: config.openAiApiKey,
ollamaBaseUrl: config.ollamaBaseUrl,
ollamaApiKey: config.ollamaApiKey,
ollamaApiOptionsCtxNum: config.ollamaApiOptionsCtxNum,
lmStudioBaseUrl: config.lmStudioBaseUrl,
geminiApiKey: config.geminiApiKey,
@@ -485,6 +486,7 @@ export function convertProtoToApiConfiguration(protoConfig: ProtoApiConfiguratio
openAiBaseUrl: protoConfig.openAiBaseUrl,
openAiApiKey: protoConfig.openAiApiKey,
ollamaBaseUrl: protoConfig.ollamaBaseUrl,
ollamaApiKey: protoConfig.ollamaApiKey,
ollamaApiOptionsCtxNum: protoConfig.ollamaApiOptionsCtxNum,
lmStudioBaseUrl: protoConfig.lmStudioBaseUrl,
geminiApiKey: protoConfig.geminiApiKey,
@@ -34,6 +34,7 @@ export function convertApiConfigurationToProtoApiConfiguration(config: ApiConfig
openaiBaseUrl: config.openAiBaseUrl,
openaiApiKey: config.openAiApiKey,
ollamaBaseUrl: config.ollamaBaseUrl,
ollamaApiKey: config.ollamaApiKey,
ollamaApiOptionsCtxNum: config.ollamaApiOptionsCtxNum,
lmStudioBaseUrl: config.lmStudioBaseUrl,
geminiApiKey: config.geminiApiKey,
@@ -159,6 +160,7 @@ export function convertProtoApiConfigurationToApiConfiguration(protoConfig: Prot
openAiBaseUrl: protoConfig.openaiBaseUrl,
openAiApiKey: protoConfig.openaiApiKey,
ollamaBaseUrl: protoConfig.ollamaBaseUrl,
ollamaApiKey: protoConfig.ollamaApiKey,
ollamaApiOptionsCtxNum: protoConfig.ollamaApiOptionsCtxNum,
lmStudioBaseUrl: protoConfig.lmStudioBaseUrl,
geminiApiKey: protoConfig.geminiApiKey,
@@ -2,6 +2,7 @@ import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"
import { useState, useCallback, useEffect } from "react"
import { useInterval } from "react-use"
import { DebouncedTextField } from "../common/DebouncedTextField"
import { ApiKeyField } from "../common/ApiKeyField"
import { ModelsServiceClient } from "@/services/grpc-client"
import { StringRequest } from "@shared/proto/cline/common"
import OllamaModelPicker from "../OllamaModelPicker"
@@ -62,6 +63,16 @@ export const OllamaProvider = ({ showModelOptions, isPopup, currentMode }: Ollam
label="Use custom base URL"
/>
{apiConfiguration?.ollamaBaseUrl && (
<ApiKeyField
initialValue={apiConfiguration?.ollamaApiKey || ""}
onChange={(value) => handleFieldChange("ollamaApiKey", value)}
providerName="Ollama"
placeholder="Enter API Key (optional)..."
helpText="Optional API key for authenticated Ollama instances or cloud services. Leave empty for local installations."
/>
)}
{/* Model selection - use filterable picker */}
<label htmlFor="ollama-model-selection">
<span style={{ fontWeight: 500 }}>Model</span>