Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src/api/providers/__tests__/openai.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { OpenAiHandler } from "../openai"
import { ApiHandlerOptions } from "../../../shared/api"
import { ApiStream } from "../../transform/stream"
import OpenAI from "openai"
import { Anthropic } from "@anthropic-ai/sdk"

// Mock OpenAI client
Expand Down
8 changes: 5 additions & 3 deletions src/api/providers/anthropic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
import { ApiHandler, SingleCompletionHandler } from "../index"
import { ApiStream } from "../transform/stream"

const ANTHROPIC_DEFAULT_TEMPERATURE = 0

export class AnthropicHandler implements ApiHandler, SingleCompletionHandler {
private options: ApiHandlerOptions
private client: Anthropic
Expand Down Expand Up @@ -44,7 +46,7 @@ export class AnthropicHandler implements ApiHandler, SingleCompletionHandler {
{
model: modelId,
max_tokens: this.getModel().info.maxTokens || 8192,
temperature: 0,
temperature: this.options.modelTemperature ?? ANTHROPIC_DEFAULT_TEMPERATURE,
system: [{ text: systemPrompt, type: "text", cache_control: { type: "ephemeral" } }], // setting cache breakpoint for system prompt so new tasks can reuse it
messages: messages.map((message, index) => {
if (index === lastUserMsgIndex || index === secondLastMsgUserIndex) {
Expand Down Expand Up @@ -96,7 +98,7 @@ export class AnthropicHandler implements ApiHandler, SingleCompletionHandler {
stream = (await this.client.messages.create({
model: modelId,
max_tokens: this.getModel().info.maxTokens || 8192,
temperature: 0,
temperature: this.options.modelTemperature ?? ANTHROPIC_DEFAULT_TEMPERATURE,
system: [{ text: systemPrompt, type: "text" }],
messages,
// tools,
Expand Down Expand Up @@ -179,7 +181,7 @@ export class AnthropicHandler implements ApiHandler, SingleCompletionHandler {
const response = await this.client.messages.create({
model: this.getModel().id,
max_tokens: this.getModel().info.maxTokens || 8192,
temperature: 0,
temperature: this.options.modelTemperature ?? ANTHROPIC_DEFAULT_TEMPERATURE,
messages: [{ role: "user", content: prompt }],
stream: false,
})
Expand Down
6 changes: 4 additions & 2 deletions src/api/providers/bedrock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { ApiHandlerOptions, BedrockModelId, ModelInfo, bedrockDefaultModelId, be
import { ApiStream } from "../transform/stream"
import { convertToBedrockConverseMessages, convertToAnthropicMessage } from "../transform/bedrock-converse-format"

const BEDROCK_DEFAULT_TEMPERATURE = 0.3

// Define types for stream events based on AWS SDK
export interface StreamEvent {
messageStart?: {
Expand Down Expand Up @@ -104,7 +106,7 @@ export class AwsBedrockHandler implements ApiHandler, SingleCompletionHandler {
system: [{ text: systemPrompt }],
inferenceConfig: {
maxTokens: modelConfig.info.maxTokens || 5000,
temperature: 0.3,
temperature: this.options.modelTemperature ?? BEDROCK_DEFAULT_TEMPERATURE,
topP: 0.1,
...(this.options.awsUsePromptCache
? {
Expand Down Expand Up @@ -262,7 +264,7 @@ export class AwsBedrockHandler implements ApiHandler, SingleCompletionHandler {
]),
inferenceConfig: {
maxTokens: modelConfig.info.maxTokens || 5000,
temperature: 0.3,
temperature: this.options.modelTemperature ?? BEDROCK_DEFAULT_TEMPERATURE,
topP: 0.1,
},
}
Expand Down
6 changes: 4 additions & 2 deletions src/api/providers/gemini.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { ApiHandlerOptions, geminiDefaultModelId, GeminiModelId, geminiModels, M
import { convertAnthropicMessageToGemini } from "../transform/gemini-format"
import { ApiStream } from "../transform/stream"

const GEMINI_DEFAULT_TEMPERATURE = 0

export class GeminiHandler implements ApiHandler, SingleCompletionHandler {
private options: ApiHandlerOptions
private client: GoogleGenerativeAI
Expand All @@ -23,7 +25,7 @@ export class GeminiHandler implements ApiHandler, SingleCompletionHandler {
contents: messages.map(convertAnthropicMessageToGemini),
generationConfig: {
// maxOutputTokens: this.getModel().info.maxTokens,
temperature: 0,
temperature: this.options.modelTemperature ?? GEMINI_DEFAULT_TEMPERATURE,
},
})

Expand Down Expand Up @@ -60,7 +62,7 @@ export class GeminiHandler implements ApiHandler, SingleCompletionHandler {
const result = await model.generateContent({
contents: [{ role: "user", parts: [{ text: prompt }] }],
generationConfig: {
temperature: 0,
temperature: this.options.modelTemperature ?? GEMINI_DEFAULT_TEMPERATURE,
},
})

Expand Down
7 changes: 4 additions & 3 deletions src/api/providers/glama.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { ApiHandler, SingleCompletionHandler } from "../"
import { ApiHandlerOptions, ModelInfo, glamaDefaultModelId, glamaDefaultModelInfo } from "../../shared/api"
import { convertToOpenAiMessages } from "../transform/openai-format"
import { ApiStream } from "../transform/stream"
import delay from "delay"

const GLAMA_DEFAULT_TEMPERATURE = 0

export class GlamaHandler implements ApiHandler, SingleCompletionHandler {
private options: ApiHandlerOptions
Expand Down Expand Up @@ -79,7 +80,7 @@ export class GlamaHandler implements ApiHandler, SingleCompletionHandler {
}

if (this.supportsTemperature()) {
requestOptions.temperature = 0
requestOptions.temperature = this.options.modelTemperature ?? GLAMA_DEFAULT_TEMPERATURE
}

const { data: completion, response } = await this.client.chat.completions
Expand Down Expand Up @@ -172,7 +173,7 @@ export class GlamaHandler implements ApiHandler, SingleCompletionHandler {
}

if (this.supportsTemperature()) {
requestOptions.temperature = 0
requestOptions.temperature = this.options.modelTemperature ?? GLAMA_DEFAULT_TEMPERATURE
}

if (this.getModel().id.startsWith("anthropic/")) {
Expand Down
6 changes: 4 additions & 2 deletions src/api/providers/lmstudio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { ApiHandlerOptions, ModelInfo, openAiModelInfoSaneDefaults } from "../..
import { convertToOpenAiMessages } from "../transform/openai-format"
import { ApiStream } from "../transform/stream"

const LMSTUDIO_DEFAULT_TEMPERATURE = 0

export class LmStudioHandler implements ApiHandler, SingleCompletionHandler {
private options: ApiHandlerOptions
private client: OpenAI
Expand All @@ -27,7 +29,7 @@ export class LmStudioHandler implements ApiHandler, SingleCompletionHandler {
const stream = await this.client.chat.completions.create({
model: this.getModel().id,
messages: openAiMessages,
temperature: 0,
temperature: this.options.modelTemperature ?? LMSTUDIO_DEFAULT_TEMPERATURE,
stream: true,
})
for await (const chunk of stream) {
Expand Down Expand Up @@ -59,7 +61,7 @@ export class LmStudioHandler implements ApiHandler, SingleCompletionHandler {
const response = await this.client.chat.completions.create({
model: this.getModel().id,
messages: [{ role: "user", content: prompt }],
temperature: 0,
temperature: this.options.modelTemperature ?? LMSTUDIO_DEFAULT_TEMPERATURE,
stream: false,
})
return response.choices[0]?.message.content || ""
Expand Down
4 changes: 3 additions & 1 deletion src/api/providers/mistral.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
import { convertToMistralMessages } from "../transform/mistral-format"
import { ApiStream } from "../transform/stream"

const MISTRAL_DEFAULT_TEMPERATURE = 0

export class MistralHandler implements ApiHandler {
private options: ApiHandlerOptions
private client: Mistral
Expand All @@ -30,7 +32,7 @@ export class MistralHandler implements ApiHandler {
const stream = await this.client.chat.stream({
model: this.getModel().id,
// max_completion_tokens: this.getModel().info.maxTokens,
temperature: 0,
temperature: this.options.modelTemperature ?? MISTRAL_DEFAULT_TEMPERATURE,
messages: [{ role: "system", content: systemPrompt }, ...convertToMistralMessages(messages)],
stream: true,
})
Expand Down
17 changes: 12 additions & 5 deletions src/api/providers/ollama.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { ApiHandlerOptions, ModelInfo, openAiModelInfoSaneDefaults } from "../..
import { convertToOpenAiMessages } from "../transform/openai-format"
import { convertToR1Format } from "../transform/r1-format"
import { ApiStream } from "../transform/stream"
import { DEEP_SEEK_DEFAULT_TEMPERATURE } from "./openai"

const OLLAMA_DEFAULT_TEMPERATURE = 0

export class OllamaHandler implements ApiHandler, SingleCompletionHandler {
private options: ApiHandlerOptions
Expand All @@ -20,7 +23,7 @@ export class OllamaHandler implements ApiHandler, SingleCompletionHandler {

async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
const modelId = this.getModel().id
const useR1Format = modelId.toLowerCase().includes('deepseek-r1')
const useR1Format = modelId.toLowerCase().includes("deepseek-r1")
const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [
{ role: "system", content: systemPrompt },
...(useR1Format ? convertToR1Format(messages) : convertToOpenAiMessages(messages)),
Expand All @@ -29,7 +32,7 @@ export class OllamaHandler implements ApiHandler, SingleCompletionHandler {
const stream = await this.client.chat.completions.create({
model: this.getModel().id,
messages: openAiMessages,
temperature: 0,
temperature: this.options.modelTemperature ?? OLLAMA_DEFAULT_TEMPERATURE,
stream: true,
})
for await (const chunk of stream) {
Expand All @@ -53,11 +56,15 @@ export class OllamaHandler implements ApiHandler, SingleCompletionHandler {
async completePrompt(prompt: string): Promise<string> {
try {
const modelId = this.getModel().id
const useR1Format = modelId.toLowerCase().includes('deepseek-r1')
const useR1Format = modelId.toLowerCase().includes("deepseek-r1")
const response = await this.client.chat.completions.create({
model: this.getModel().id,
messages: useR1Format ? convertToR1Format([{ role: "user", content: prompt }]) : [{ role: "user", content: prompt }],
temperature: 0,
messages: useR1Format
? convertToR1Format([{ role: "user", content: prompt }])
: [{ role: "user", content: prompt }],
temperature:
this.options.modelTemperature ??
(useR1Format ? DEEP_SEEK_DEFAULT_TEMPERATURE : OLLAMA_DEFAULT_TEMPERATURE),
stream: false,
})
return response.choices[0]?.message.content || ""
Expand Down
6 changes: 4 additions & 2 deletions src/api/providers/openai-native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
import { convertToOpenAiMessages } from "../transform/openai-format"
import { ApiStream } from "../transform/stream"

const OPENAI_NATIVE_DEFAULT_TEMPERATURE = 0

export class OpenAiNativeHandler implements ApiHandler, SingleCompletionHandler {
private options: ApiHandlerOptions
private client: OpenAI
Expand Down Expand Up @@ -88,7 +90,7 @@ export class OpenAiNativeHandler implements ApiHandler, SingleCompletionHandler
): ApiStream {
const stream = await this.client.chat.completions.create({
model: modelId,
temperature: 0,
temperature: this.options.modelTemperature ?? OPENAI_NATIVE_DEFAULT_TEMPERATURE,
messages: [{ role: "system", content: systemPrompt }, ...convertToOpenAiMessages(messages)],
stream: true,
stream_options: { include_usage: true },
Expand Down Expand Up @@ -189,7 +191,7 @@ export class OpenAiNativeHandler implements ApiHandler, SingleCompletionHandler
return {
model: modelId,
messages: [{ role: "user", content: prompt }],
temperature: 0,
temperature: this.options.modelTemperature ?? OPENAI_NATIVE_DEFAULT_TEMPERATURE,
}
}
}
7 changes: 6 additions & 1 deletion src/api/providers/openai.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import { convertToR1Format } from "../transform/r1-format"
import { convertToSimpleMessages } from "../transform/simple-format"
import { ApiStream } from "../transform/stream"

export const DEEP_SEEK_DEFAULT_TEMPERATURE = 0.6
const OPENAI_DEFAULT_TEMPERATURE = 0

export class OpenAiHandler implements ApiHandler, SingleCompletionHandler {
protected options: ApiHandlerOptions
private client: OpenAI
Expand Down Expand Up @@ -70,7 +73,9 @@ export class OpenAiHandler implements ApiHandler, SingleCompletionHandler {

const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {
model: modelId,
temperature: 0,
temperature:
this.options.modelTemperature ??
(deepseekReasoner ? DEEP_SEEK_DEFAULT_TEMPERATURE : OPENAI_DEFAULT_TEMPERATURE),
messages: convertedMessages,
stream: true as const,
stream_options: { include_usage: true },
Expand Down
14 changes: 8 additions & 6 deletions src/api/providers/openrouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { ApiHandlerOptions, ModelInfo, openRouterDefaultModelId, openRouterDefau
import { convertToOpenAiMessages } from "../transform/openai-format"
import { ApiStreamChunk, ApiStreamUsageChunk } from "../transform/stream"
import delay from "delay"
import { DEEP_SEEK_DEFAULT_TEMPERATURE } from "./openai"

const OPENROUTER_DEFAULT_TEMPERATURE = 0

// Add custom interface for OpenRouter params
type OpenRouterChatCompletionParams = OpenAI.Chat.ChatCompletionCreateParams & {
Expand Down Expand Up @@ -115,7 +118,7 @@ export class OpenRouterHandler implements ApiHandler, SingleCompletionHandler {
break
}

let temperature = 0
let defaultTemperature = OPENROUTER_DEFAULT_TEMPERATURE
let topP: number | undefined = undefined

// Handle models based on deepseek-r1
Expand All @@ -124,9 +127,8 @@ export class OpenRouterHandler implements ApiHandler, SingleCompletionHandler {
this.getModel().id === "perplexity/sonar-reasoning"
) {
// Recommended temperature for DeepSeek reasoning models
temperature = 0.6
// DeepSeek highly recommends using user instead of system
// role
defaultTemperature = DEEP_SEEK_DEFAULT_TEMPERATURE
// DeepSeek highly recommends using user instead of system role
openAiMessages = convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
// Some provider support topP and 0.95 is value that Deepseek used in their benchmarks
topP = 0.95
Expand All @@ -137,7 +139,7 @@ export class OpenRouterHandler implements ApiHandler, SingleCompletionHandler {
const stream = await this.client.chat.completions.create({
model: this.getModel().id,
max_tokens: maxTokens,
temperature: temperature,
temperature: this.options.modelTemperature ?? defaultTemperature,
top_p: topP,
messages: openAiMessages,
stream: true,
Expand Down Expand Up @@ -224,7 +226,7 @@ export class OpenRouterHandler implements ApiHandler, SingleCompletionHandler {
const response = await this.client.chat.completions.create({
model: this.getModel().id,
messages: [{ role: "user", content: prompt }],
temperature: 0,
temperature: this.options.modelTemperature ?? OPENROUTER_DEFAULT_TEMPERATURE,
stream: false,
})

Expand Down
4 changes: 2 additions & 2 deletions src/api/providers/unbound.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export class UnboundHandler implements ApiHandler, SingleCompletionHandler {
{
model: this.getModel().id.split("/")[1],
max_tokens: maxTokens,
temperature: 0,
temperature: this.options.modelTemperature ?? 0,
messages: openAiMessages,
stream: true,
},
Expand Down Expand Up @@ -146,7 +146,7 @@ export class UnboundHandler implements ApiHandler, SingleCompletionHandler {
const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming = {
model: this.getModel().id.split("/")[1],
messages: [{ role: "user", content: prompt }],
temperature: 0,
temperature: this.options.modelTemperature ?? 0,
}

if (this.getModel().id.startsWith("anthropic/")) {
Expand Down
4 changes: 2 additions & 2 deletions src/api/providers/vertex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export class VertexHandler implements ApiHandler, SingleCompletionHandler {
const stream = await this.client.messages.create({
model: this.getModel().id,
max_tokens: this.getModel().info.maxTokens || 8192,
temperature: 0,
temperature: this.options.modelTemperature ?? 0,
system: systemPrompt,
messages,
stream: true,
Expand Down Expand Up @@ -89,7 +89,7 @@ export class VertexHandler implements ApiHandler, SingleCompletionHandler {
const response = await this.client.messages.create({
model: this.getModel().id,
max_tokens: this.getModel().info.maxTokens || 8192,
temperature: 0,
temperature: this.options.modelTemperature ?? 0,
messages: [{ role: "user", content: prompt }],
stream: false,
})
Expand Down
6 changes: 6 additions & 0 deletions src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ type GlobalStateKey =
| "customModes" // Array of custom modes
| "unboundModelId"
| "unboundModelInfo"
| "modelTemperature"

export const GlobalFileNames = {
apiConversationHistory: "api_conversation_history.json",
Expand Down Expand Up @@ -1587,6 +1588,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
unboundApiKey,
unboundModelId,
unboundModelInfo,
modelTemperature,
} = apiConfiguration
await this.updateGlobalState("apiProvider", apiProvider)
await this.updateGlobalState("apiModelId", apiModelId)
Expand Down Expand Up @@ -1628,6 +1630,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
await this.storeSecret("unboundApiKey", unboundApiKey)
await this.updateGlobalState("unboundModelId", unboundModelId)
await this.updateGlobalState("unboundModelInfo", unboundModelInfo)
await this.updateGlobalState("modelTemperature", modelTemperature)
if (this.cline) {
this.cline.api = buildApiHandler(apiConfiguration)
}
Expand Down Expand Up @@ -2388,6 +2391,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
unboundApiKey,
unboundModelId,
unboundModelInfo,
modelTemperature,
] = await Promise.all([
this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
this.getGlobalState("apiModelId") as Promise<string | undefined>,
Expand Down Expand Up @@ -2464,6 +2468,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
this.getSecret("unboundApiKey") as Promise<string | undefined>,
this.getGlobalState("unboundModelId") as Promise<string | undefined>,
this.getGlobalState("unboundModelInfo") as Promise<ModelInfo | undefined>,
this.getGlobalState("modelTemperature") as Promise<number | undefined>,
])

let apiProvider: ApiProvider
Expand Down Expand Up @@ -2522,6 +2527,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
unboundApiKey,
unboundModelId,
unboundModelInfo,
modelTemperature,
},
lastShownAnnouncementId,
customInstructions,
Expand Down
Loading