mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-06 08:18:39 +00:00
Configure per-configuration temperature
This commit is contained in:
parent
e29ce276c5
commit
bc9773ff9a
16 changed files with 124 additions and 30 deletions
|
|
@ -44,7 +44,7 @@ export class AnthropicHandler implements ApiHandler, SingleCompletionHandler {
|
|||
{
|
||||
model: modelId,
|
||||
max_tokens: this.getModel().info.maxTokens || 8192,
|
||||
temperature: 0,
|
||||
temperature: this.options.modelTemperature ?? 0,
|
||||
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) {
|
||||
|
|
@ -96,7 +96,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 ?? 0,
|
||||
system: [{ text: systemPrompt, type: "text" }],
|
||||
messages,
|
||||
// tools,
|
||||
|
|
@ -179,7 +179,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 ?? 0,
|
||||
messages: [{ role: "user", content: prompt }],
|
||||
stream: false,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ export class AwsBedrockHandler implements ApiHandler, SingleCompletionHandler {
|
|||
system: [{ text: systemPrompt }],
|
||||
inferenceConfig: {
|
||||
maxTokens: modelConfig.info.maxTokens || 5000,
|
||||
temperature: 0.3,
|
||||
temperature: this.options.modelTemperature ?? 0.3,
|
||||
topP: 0.1,
|
||||
...(this.options.awsUsePromptCache
|
||||
? {
|
||||
|
|
@ -262,7 +262,7 @@ export class AwsBedrockHandler implements ApiHandler, SingleCompletionHandler {
|
|||
]),
|
||||
inferenceConfig: {
|
||||
maxTokens: modelConfig.info.maxTokens || 5000,
|
||||
temperature: 0.3,
|
||||
temperature: this.options.modelTemperature ?? 0.3,
|
||||
topP: 0.1,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export class GeminiHandler implements ApiHandler, SingleCompletionHandler {
|
|||
contents: messages.map(convertAnthropicMessageToGemini),
|
||||
generationConfig: {
|
||||
// maxOutputTokens: this.getModel().info.maxTokens,
|
||||
temperature: 0,
|
||||
temperature: this.options.modelTemperature ?? 0,
|
||||
},
|
||||
})
|
||||
|
||||
|
|
@ -60,7 +60,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 ?? 0,
|
||||
},
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ export class GlamaHandler implements ApiHandler, SingleCompletionHandler {
|
|||
}
|
||||
|
||||
if (this.supportsTemperature()) {
|
||||
requestOptions.temperature = 0
|
||||
requestOptions.temperature = this.options.modelTemperature ?? 0
|
||||
}
|
||||
|
||||
const { data: completion, response } = await this.client.chat.completions
|
||||
|
|
@ -172,7 +172,7 @@ export class GlamaHandler implements ApiHandler, SingleCompletionHandler {
|
|||
}
|
||||
|
||||
if (this.supportsTemperature()) {
|
||||
requestOptions.temperature = 0
|
||||
requestOptions.temperature = this.options.modelTemperature ?? 0
|
||||
}
|
||||
|
||||
if (this.getModel().id.startsWith("anthropic/")) {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,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 ?? 0,
|
||||
stream: true,
|
||||
})
|
||||
for await (const chunk of stream) {
|
||||
|
|
@ -59,7 +59,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 ?? 0,
|
||||
stream: false,
|
||||
})
|
||||
return response.choices[0]?.message.content || ""
|
||||
|
|
|
|||
|
|
@ -30,7 +30,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 ?? 0,
|
||||
messages: [{ role: "system", content: systemPrompt }, ...convertToMistralMessages(messages)],
|
||||
stream: true,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -20,7 +20,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)),
|
||||
|
|
@ -29,7 +29,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 ?? 0,
|
||||
stream: true,
|
||||
})
|
||||
for await (const chunk of stream) {
|
||||
|
|
@ -53,11 +53,13 @@ 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 ?? 0,
|
||||
stream: false,
|
||||
})
|
||||
return response.choices[0]?.message.content || ""
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ export class OpenAiNativeHandler implements ApiHandler, SingleCompletionHandler
|
|||
): ApiStream {
|
||||
const stream = await this.client.chat.completions.create({
|
||||
model: modelId,
|
||||
temperature: 0,
|
||||
temperature: this.options.modelTemperature ?? 0,
|
||||
messages: [{ role: "system", content: systemPrompt }, ...convertToOpenAiMessages(messages)],
|
||||
stream: true,
|
||||
stream_options: { include_usage: true },
|
||||
|
|
@ -189,7 +189,7 @@ export class OpenAiNativeHandler implements ApiHandler, SingleCompletionHandler
|
|||
return {
|
||||
model: modelId,
|
||||
messages: [{ role: "user", content: prompt }],
|
||||
temperature: 0,
|
||||
temperature: this.options.modelTemperature ?? 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ export class OpenAiHandler implements ApiHandler, SingleCompletionHandler {
|
|||
}
|
||||
const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {
|
||||
model: modelId,
|
||||
temperature: 0,
|
||||
temperature: this.options.modelTemperature ?? (deepseekReasoner ? 0.6 : 0),
|
||||
messages: deepseekReasoner
|
||||
? convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
|
||||
: [systemMessage, ...convertToOpenAiMessages(messages)],
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ export class OpenRouterHandler implements ApiHandler, SingleCompletionHandler {
|
|||
break
|
||||
}
|
||||
|
||||
let temperature = 0
|
||||
let defaultTemperature = 0
|
||||
let topP: number | undefined = undefined
|
||||
|
||||
// Handle models based on deepseek-r1
|
||||
|
|
@ -124,9 +124,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 = 0.6
|
||||
// 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
|
||||
|
|
@ -137,7 +136,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,
|
||||
|
|
@ -224,7 +223,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 ?? 0,
|
||||
stream: false,
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
|
|
@ -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/")) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ type GlobalStateKey =
|
|||
| "autoApprovalEnabled"
|
||||
| "customModes" // Array of custom modes
|
||||
| "unboundModelId"
|
||||
| "modelTemperature"
|
||||
|
||||
export const GlobalFileNames = {
|
||||
apiConversationHistory: "api_conversation_history.json",
|
||||
|
|
@ -1538,6 +1539,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
mistralApiKey,
|
||||
unboundApiKey,
|
||||
unboundModelId,
|
||||
modelTemperature,
|
||||
} = apiConfiguration
|
||||
await this.updateGlobalState("apiProvider", apiProvider)
|
||||
await this.updateGlobalState("apiModelId", apiModelId)
|
||||
|
|
@ -1578,6 +1580,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
await this.storeSecret("mistralApiKey", mistralApiKey)
|
||||
await this.storeSecret("unboundApiKey", unboundApiKey)
|
||||
await this.updateGlobalState("unboundModelId", unboundModelId)
|
||||
await this.updateGlobalState("modelTemperature", modelTemperature)
|
||||
if (this.cline) {
|
||||
this.cline.api = buildApiHandler(apiConfiguration)
|
||||
}
|
||||
|
|
@ -2254,6 +2257,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
experiments,
|
||||
unboundApiKey,
|
||||
unboundModelId,
|
||||
modelTemperature,
|
||||
] = await Promise.all([
|
||||
this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
|
||||
this.getGlobalState("apiModelId") as Promise<string | undefined>,
|
||||
|
|
@ -2328,6 +2332,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
this.getGlobalState("experiments") as Promise<Record<ExperimentId, boolean> | undefined>,
|
||||
this.getSecret("unboundApiKey") as Promise<string | undefined>,
|
||||
this.getGlobalState("unboundModelId") as Promise<string | undefined>,
|
||||
this.getGlobalState("modelTemperature") as Promise<number | undefined>,
|
||||
])
|
||||
|
||||
let apiProvider: ApiProvider
|
||||
|
|
@ -2385,6 +2390,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||
vsCodeLmModelSelector,
|
||||
unboundApiKey,
|
||||
unboundModelId,
|
||||
modelTemperature,
|
||||
},
|
||||
lastShownAnnouncementId,
|
||||
customInstructions,
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ export interface ApiHandlerOptions {
|
|||
includeMaxTokens?: boolean
|
||||
unboundApiKey?: string
|
||||
unboundModelId?: string
|
||||
modelTemperature?: number
|
||||
}
|
||||
|
||||
export type ApiConfiguration = ApiHandlerOptions & {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { memo, useCallback, useEffect, useMemo, useState } from "react"
|
|||
import { useEvent, useInterval } from "react-use"
|
||||
import { Checkbox, Dropdown, Pane, type DropdownOption } from "vscrui"
|
||||
import { VSCodeLink, VSCodeRadio, VSCodeRadioGroup, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
import { TemperatureControl } from "./TemperatureControl"
|
||||
import * as vscodemodels from "vscode"
|
||||
|
||||
import {
|
||||
|
|
@ -1361,6 +1362,18 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
|
|||
</>
|
||||
)}
|
||||
|
||||
<div style={{ marginTop: "10px" }}>
|
||||
<TemperatureControl
|
||||
value={apiConfiguration?.modelTemperature}
|
||||
onChange={(value) => {
|
||||
handleInputChange("modelTemperature")({
|
||||
target: { value },
|
||||
})
|
||||
}}
|
||||
maxValue={2}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{modelIdErrorMessage && (
|
||||
<p
|
||||
style={{
|
||||
|
|
|
|||
73
webview-ui/src/components/settings/TemperatureControl.tsx
Normal file
73
webview-ui/src/components/settings/TemperatureControl.tsx
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import { Checkbox } from "vscrui"
|
||||
import { useEffect, useState } from "react"
|
||||
|
||||
interface TemperatureControlProps {
|
||||
value: number | undefined
|
||||
onChange: (value: number | undefined) => void
|
||||
maxValue?: number // Some providers like OpenAI use 0-2 range
|
||||
}
|
||||
|
||||
export const TemperatureControl = ({ value, onChange, maxValue = 1 }: TemperatureControlProps) => {
|
||||
const [isCustomTemperature, setIsCustomTemperature] = useState(value !== undefined)
|
||||
|
||||
// Sync internal state with prop changes when switching profiles
|
||||
useEffect(() => {
|
||||
setIsCustomTemperature(value !== undefined)
|
||||
}, [value])
|
||||
|
||||
return (
|
||||
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
|
||||
<Checkbox
|
||||
checked={isCustomTemperature}
|
||||
onChange={(checked: boolean) => {
|
||||
setIsCustomTemperature(checked)
|
||||
if (!checked) {
|
||||
onChange(undefined) // Reset to provider default
|
||||
} else {
|
||||
onChange(0) // Set initial value when enabling
|
||||
}
|
||||
}}>
|
||||
<span style={{ fontWeight: 500 }}>Use custom temperature</span>
|
||||
</Checkbox>
|
||||
|
||||
{isCustomTemperature && (
|
||||
<>
|
||||
<i
|
||||
className="codicon codicon-info"
|
||||
title={`Controls randomness in the model's responses. Higher values (e.g. 0.8) make output more random, lower values (e.g. 0.2) make it more deterministic. Range: 0-${maxValue}`}
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
color: "var(--vscode-descriptionForeground)",
|
||||
cursor: "help",
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max={maxValue}
|
||||
step="0.05"
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
const newValue = parseFloat(e.target.value)
|
||||
onChange(isNaN(newValue) ? undefined : newValue)
|
||||
}}
|
||||
style={{
|
||||
flexGrow: 1,
|
||||
accentColor: "var(--vscode-button-background)",
|
||||
height: "2px",
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
color: "var(--vscode-descriptionForeground)",
|
||||
minWidth: "36px",
|
||||
textAlign: "right",
|
||||
}}>
|
||||
{value?.toFixed(2)}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue