Skip to content

Commit 7718a81

Browse files
committed
additional parameters
1 parent a56741f commit 7718a81

File tree

11 files changed

+456
-8
lines changed

11 files changed

+456
-8
lines changed

src/api/providers/openai.ts

Lines changed: 110 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,27 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
129129
stream: true as const,
130130
stream_options: { include_usage: true },
131131
}
132+
133+
// Add min_p if set
134+
if (this.options.modelMinP !== undefined && this.options.modelMinP !== null) {
135+
;(requestOptions as any).min_p = this.options.modelMinP
136+
}
137+
138+
// Add max_p (top_p) if set
139+
if (this.options.modelMaxP !== undefined && this.options.modelMaxP !== null) {
140+
requestOptions.top_p = this.options.modelMaxP
141+
}
142+
143+
// Add top_k if set
144+
if (this.options.modelTopK !== undefined && this.options.modelTopK !== null) {
145+
;(requestOptions as any).top_k = this.options.modelTopK
146+
}
147+
148+
// Add repetition_penalty if set
149+
if (this.options.modelRepetitionPenalty !== undefined && this.options.modelRepetitionPenalty !== null) {
150+
requestOptions.frequency_penalty = this.options.modelRepetitionPenalty - 1.0
151+
}
152+
132153
if (this.options.includeMaxTokens) {
133154
requestOptions.max_tokens = modelInfo.maxTokens
134155
}
@@ -184,6 +205,27 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
184205
messages: deepseekReasoner
185206
? convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
186207
: [systemMessage, ...convertToOpenAiMessages(messages)],
208+
temperature: this.options.modelTemperature ?? (deepseekReasoner ? DEEP_SEEK_DEFAULT_TEMPERATURE : 0),
209+
}
210+
211+
// Add min_p if set
212+
if (this.options.modelMinP !== undefined && this.options.modelMinP !== null) {
213+
;(requestOptions as any).min_p = this.options.modelMinP
214+
}
215+
216+
// Add max_p (top_p) if set
217+
if (this.options.modelMaxP !== undefined && this.options.modelMaxP !== null) {
218+
requestOptions.top_p = this.options.modelMaxP
219+
}
220+
221+
// Add top_k if set
222+
if (this.options.modelTopK !== undefined && this.options.modelTopK !== null) {
223+
;(requestOptions as any).top_k = this.options.modelTopK
224+
}
225+
226+
// Add repetition_penalty if set
227+
if (this.options.modelRepetitionPenalty !== undefined && this.options.modelRepetitionPenalty !== null) {
228+
requestOptions.frequency_penalty = this.options.modelRepetitionPenalty - 1.0
187229
}
188230

189231
const response = await this.client.chat.completions.create(requestOptions)
@@ -216,6 +258,27 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
216258
const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming = {
217259
model: this.getModel().id,
218260
messages: [{ role: "user", content: prompt }],
261+
temperature: this.options.modelTemperature ?? 0,
262+
}
263+
264+
// Add min_p if set
265+
if (this.options.modelMinP !== undefined && this.options.modelMinP !== null) {
266+
;(requestOptions as any).min_p = this.options.modelMinP
267+
}
268+
269+
// Add max_p (top_p) if set
270+
if (this.options.modelMaxP !== undefined && this.options.modelMaxP !== null) {
271+
requestOptions.top_p = this.options.modelMaxP
272+
}
273+
274+
// Add top_k if set
275+
if (this.options.modelTopK !== undefined && this.options.modelTopK !== null) {
276+
;(requestOptions as any).top_k = this.options.modelTopK
277+
}
278+
279+
// Add repetition_penalty if set
280+
if (this.options.modelRepetitionPenalty !== undefined && this.options.modelRepetitionPenalty !== null) {
281+
requestOptions.frequency_penalty = this.options.modelRepetitionPenalty - 1.0
219282
}
220283

221284
const response = await this.client.chat.completions.create(requestOptions)
@@ -234,7 +297,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
234297
messages: Anthropic.Messages.MessageParam[],
235298
): ApiStream {
236299
if (this.options.openAiStreamingEnabled ?? true) {
237-
const stream = await this.client.chat.completions.create({
300+
const streamOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {
238301
model: "o3-mini",
239302
messages: [
240303
{
@@ -243,10 +306,33 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
243306
},
244307
...convertToOpenAiMessages(messages),
245308
],
246-
stream: true,
309+
stream: true as const,
247310
stream_options: { include_usage: true },
248311
reasoning_effort: this.getModel().info.reasoningEffort,
249-
})
312+
temperature: this.options.modelTemperature ?? 0,
313+
} as any
314+
315+
// Add min_p if set
316+
if (this.options.modelMinP !== undefined && this.options.modelMinP !== null) {
317+
;(streamOptions as any).min_p = this.options.modelMinP
318+
}
319+
320+
// Add max_p (top_p) if set
321+
if (this.options.modelMaxP !== undefined && this.options.modelMaxP !== null) {
322+
streamOptions.top_p = this.options.modelMaxP
323+
}
324+
325+
// Add top_k if set
326+
if (this.options.modelTopK !== undefined && this.options.modelTopK !== null) {
327+
;(streamOptions as any).top_k = this.options.modelTopK
328+
}
329+
330+
// Add repetition_penalty if set
331+
if (this.options.modelRepetitionPenalty !== undefined && this.options.modelRepetitionPenalty !== null) {
332+
streamOptions.frequency_penalty = this.options.modelRepetitionPenalty - 1.0
333+
}
334+
335+
const stream = await this.client.chat.completions.create(streamOptions)
250336

251337
yield* this.handleStreamResponse(stream)
252338
} else {
@@ -259,6 +345,27 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
259345
},
260346
...convertToOpenAiMessages(messages),
261347
],
348+
temperature: this.options.modelTemperature ?? 0,
349+
}
350+
351+
// Add min_p if set
352+
if (this.options.modelMinP !== undefined && this.options.modelMinP !== null) {
353+
;(requestOptions as any).min_p = this.options.modelMinP
354+
}
355+
356+
// Add max_p (top_p) if set
357+
if (this.options.modelMaxP !== undefined && this.options.modelMaxP !== null) {
358+
requestOptions.top_p = this.options.modelMaxP
359+
}
360+
361+
// Add top_k if set
362+
if (this.options.modelTopK !== undefined && this.options.modelTopK !== null) {
363+
;(requestOptions as any).top_k = this.options.modelTopK
364+
}
365+
366+
// Add repetition_penalty if set
367+
if (this.options.modelRepetitionPenalty !== undefined && this.options.modelRepetitionPenalty !== null) {
368+
requestOptions.frequency_penalty = this.options.modelRepetitionPenalty - 1.0
262369
}
263370

264371
const response = await this.client.chat.completions.create(requestOptions)

src/exports/roo-code.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,10 @@ export type GlobalStateKey =
243243
| "requestyModelInfo"
244244
| "unboundModelInfo"
245245
| "modelTemperature"
246+
| "modelMinP"
247+
| "modelMaxP"
248+
| "modelTopK"
249+
| "modelRepetitionPenalty"
246250
| "modelMaxTokens"
247251
| "mistralCodestralUrl"
248252
| "maxOpenTabsContext"

src/shared/WebviewMessage.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ export interface WebviewMessage {
106106
| "humanRelayResponse"
107107
| "humanRelayCancel"
108108
| "browserToolEnabled"
109+
| "modelTemperature"
110+
| "modelMinP"
111+
| "modelMaxP"
112+
| "modelTopK"
113+
| "modelRepetitionPenalty"
109114
| "telemetrySetting"
110115
| "showRooIgnoredFiles"
111116
| "testBrowserConnection"

src/shared/api.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ export interface ApiHandlerOptions {
7474
requestyModelId?: string
7575
requestyModelInfo?: ModelInfo
7676
modelTemperature?: number | null
77+
modelMinP?: number | null
78+
modelMaxP?: number | null
79+
modelTopK?: number | null
80+
modelRepetitionPenalty?: number | null
7781
modelMaxTokens?: number
7882
modelMaxThinkingTokens?: number
7983
}
@@ -132,6 +136,10 @@ export const API_CONFIG_KEYS: GlobalStateKey[] = [
132136
"requestyModelId",
133137
"requestyModelInfo",
134138
"modelTemperature",
139+
"modelMinP",
140+
"modelMaxP",
141+
"modelTopK",
142+
"modelRepetitionPenalty",
135143
"modelMaxTokens",
136144
"modelMaxThinkingTokens",
137145
]

src/shared/globalState.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ export const GLOBAL_STATE_KEYS = [
111111
"requestyModelInfo",
112112
"unboundModelInfo",
113113
"modelTemperature",
114+
"modelMinP",
115+
"modelMaxP",
116+
"modelTopK",
117+
"modelRepetitionPenalty",
114118
"modelMaxTokens",
115119
"mistralCodestralUrl",
116120
"maxOpenTabsContext",

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

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ import { VSCodeButtonLink } from "../common/VSCodeButtonLink"
4949
import { ModelInfoView } from "./ModelInfoView"
5050
import { ModelPicker } from "./ModelPicker"
5151
import { TemperatureControl } from "./TemperatureControl"
52+
import { MinPControl } from "./MinPControl"
53+
import { MaxPControl } from "./MaxPControl"
54+
import { TopKControl } from "./TopKControl"
55+
import { RepetitionPenaltyControl } from "./RepetitionPenaltyControl"
5256
import { validateApiConfiguration, validateModelId, validateBedrockArn } from "@/utils/validate"
5357
import { ApiErrorMessage } from "./ApiErrorMessage"
5458
import { ThinkingBudget } from "./ThinkingBudget"
@@ -1565,11 +1569,29 @@ const ApiOptions = ({
15651569
)}
15661570

15671571
{!fromWelcomeView && (
1568-
<TemperatureControl
1569-
value={apiConfiguration?.modelTemperature}
1570-
onChange={handleInputChange("modelTemperature", noTransform)}
1571-
maxValue={2}
1572-
/>
1572+
<>
1573+
<TemperatureControl
1574+
value={apiConfiguration?.modelTemperature}
1575+
onChange={handleInputChange("modelTemperature", noTransform)}
1576+
maxValue={2}
1577+
/>
1578+
<MinPControl
1579+
value={apiConfiguration?.modelMinP}
1580+
onChange={handleInputChange("modelMinP", noTransform)}
1581+
/>
1582+
<MaxPControl
1583+
value={apiConfiguration?.modelMaxP}
1584+
onChange={handleInputChange("modelMaxP", noTransform)}
1585+
/>
1586+
<TopKControl
1587+
value={apiConfiguration?.modelTopK}
1588+
onChange={handleInputChange("modelTopK", noTransform)}
1589+
/>
1590+
<RepetitionPenaltyControl
1591+
value={apiConfiguration?.modelRepetitionPenalty}
1592+
onChange={handleInputChange("modelRepetitionPenalty", noTransform)}
1593+
/>
1594+
</>
15731595
)}
15741596
</div>
15751597
)
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
2+
import { useEffect, useState } from "react"
3+
import { useAppTranslation } from "@/i18n/TranslationContext"
4+
import { useDebounce } from "react-use"
5+
6+
interface MaxPControlProps {
7+
value: number | undefined | null
8+
onChange: (value: number | undefined | null) => void
9+
}
10+
11+
export const MaxPControl = ({ value, onChange }: MaxPControlProps) => {
12+
const { t } = useAppTranslation()
13+
const [isCustomMaxP, setIsCustomMaxP] = useState(value !== undefined)
14+
const [inputValue, setInputValue] = useState(value)
15+
useDebounce(() => onChange(inputValue), 50, [onChange, inputValue])
16+
17+
// Sync internal state with prop changes when switching profiles
18+
useEffect(() => {
19+
const hasCustomMaxP = value !== undefined && value !== null
20+
setIsCustomMaxP(hasCustomMaxP)
21+
setInputValue(value)
22+
}, [value])
23+
24+
return (
25+
<>
26+
<div>
27+
<VSCodeCheckbox
28+
checked={isCustomMaxP}
29+
onChange={(e: any) => {
30+
const isChecked = e.target.checked
31+
setIsCustomMaxP(isChecked)
32+
if (!isChecked) {
33+
setInputValue(null) // Unset the max_p, note that undefined is unserializable
34+
} else {
35+
setInputValue(value ?? 0) // Use the value from apiConfiguration, if set
36+
}
37+
}}>
38+
<span className="font-medium">{t("settings:maxP.useCustom")}</span>
39+
</VSCodeCheckbox>
40+
<div className="text-sm text-vscode-descriptionForeground">{t("settings:maxP.description")}</div>
41+
</div>
42+
43+
{isCustomMaxP && (
44+
<div
45+
style={{
46+
marginLeft: 0,
47+
paddingLeft: 10,
48+
borderLeft: "2px solid var(--vscode-button-background)",
49+
}}>
50+
<div style={{ display: "flex", alignItems: "center", gap: "5px" }}>
51+
<input
52+
type="range"
53+
min="0"
54+
max="1"
55+
step="0.01"
56+
value={inputValue ?? 0}
57+
className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
58+
onChange={(e) => setInputValue(parseFloat(e.target.value))}
59+
/>
60+
<span>{inputValue}</span>
61+
</div>
62+
<p className="text-vscode-descriptionForeground text-sm mt-1">
63+
{t("settings:maxP.rangeDescription")}
64+
</p>
65+
</div>
66+
)}
67+
</>
68+
)
69+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
2+
import { useEffect, useState } from "react"
3+
import { useAppTranslation } from "@/i18n/TranslationContext"
4+
import { useDebounce } from "react-use"
5+
6+
interface MinPControlProps {
7+
value: number | undefined | null
8+
onChange: (value: number | undefined | null) => void
9+
}
10+
11+
export const MinPControl = ({ value, onChange }: MinPControlProps) => {
12+
const { t } = useAppTranslation()
13+
const [isCustomMinP, setIsCustomMinP] = useState(value !== undefined)
14+
const [inputValue, setInputValue] = useState(value)
15+
useDebounce(() => onChange(inputValue), 50, [onChange, inputValue])
16+
17+
// Sync internal state with prop changes when switching profiles
18+
useEffect(() => {
19+
const hasCustomMinP = value !== undefined && value !== null
20+
setIsCustomMinP(hasCustomMinP)
21+
setInputValue(value)
22+
}, [value])
23+
24+
return (
25+
<>
26+
<div>
27+
<VSCodeCheckbox
28+
checked={isCustomMinP}
29+
onChange={(e: any) => {
30+
const isChecked = e.target.checked
31+
setIsCustomMinP(isChecked)
32+
if (!isChecked) {
33+
setInputValue(null) // Unset the min_p, note that undefined is unserializable
34+
} else {
35+
setInputValue(value ?? 0) // Use the value from apiConfiguration, if set
36+
}
37+
}}>
38+
<span className="font-medium">{t("settings:minP.useCustom")}</span>
39+
</VSCodeCheckbox>
40+
<div className="text-sm text-vscode-descriptionForeground">{t("settings:minP.description")}</div>
41+
</div>
42+
43+
{isCustomMinP && (
44+
<div
45+
style={{
46+
marginLeft: 0,
47+
paddingLeft: 10,
48+
borderLeft: "2px solid var(--vscode-button-background)",
49+
}}>
50+
<div style={{ display: "flex", alignItems: "center", gap: "5px" }}>
51+
<input
52+
type="range"
53+
min="0"
54+
max="1"
55+
step="0.01"
56+
value={inputValue ?? 0}
57+
className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
58+
onChange={(e) => setInputValue(parseFloat(e.target.value))}
59+
/>
60+
<span>{inputValue}</span>
61+
</div>
62+
<p className="text-vscode-descriptionForeground text-sm mt-1">
63+
{t("settings:minP.rangeDescription")}
64+
</p>
65+
</div>
66+
)}
67+
</>
68+
)
69+
}

0 commit comments

Comments
 (0)