Skip to content

Commit 9efc90d

Browse files
committed
feat(settings): add rate limit control for API configuration
Introduce a new RateLimitControl component to manage per-profile rate limiting. The API configuration now includes a rateLimitSeconds option, allowing users to set a custom rate limit. This change also updates the AdvancedSettings and ApiOptions components to integrate the new rate limit functionality. Add translations for the new rate limit settings in multiple languages.
1 parent 8b368e9 commit 9efc90d

File tree

20 files changed

+134
-32
lines changed

20 files changed

+134
-32
lines changed

src/shared/api.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export interface ApiHandlerOptions {
2626
glamaModelId?: string
2727
glamaModelInfo?: ModelInfo
2828
glamaApiKey?: string
29+
rateLimitSeconds?: number // Added for per-profile rate limiting
2930
openRouterApiKey?: string
3031
openRouterModelId?: string
3132
openRouterModelInfo?: ModelInfo
@@ -134,6 +135,7 @@ export const API_CONFIG_KEYS: GlobalStateKey[] = [
134135
"modelTemperature",
135136
"modelMaxTokens",
136137
"modelMaxThinkingTokens",
138+
"rateLimitSeconds", // Added for per-profile rate limiting
137139
]
138140

139141
// Models

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

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,14 @@ import { SectionHeader } from "./SectionHeader"
1313
import { Section } from "./Section"
1414

1515
type AdvancedSettingsProps = HTMLAttributes<HTMLDivElement> & {
16-
rateLimitSeconds: number
1716
terminalShellIntegrationTimeout: number | undefined
1817
diffEnabled?: boolean
1918
fuzzyMatchThreshold?: number
20-
setCachedStateField: SetCachedStateField<
21-
"rateLimitSeconds" | "diffEnabled" | "fuzzyMatchThreshold" | "terminalShellIntegrationTimeout"
22-
>
19+
setCachedStateField: SetCachedStateField<"diffEnabled" | "fuzzyMatchThreshold" | "terminalShellIntegrationTimeout">
2320
experiments: Record<ExperimentId, boolean>
2421
setExperimentEnabled: SetExperimentEnabled
2522
}
2623
export const AdvancedSettings = ({
27-
rateLimitSeconds,
2824
terminalShellIntegrationTimeout,
2925
diffEnabled,
3026
fuzzyMatchThreshold,
@@ -45,27 +41,6 @@ export const AdvancedSettings = ({
4541
</SectionHeader>
4642

4743
<Section>
48-
<div>
49-
<div className="flex flex-col gap-2">
50-
<span className="font-medium">{t("settings:advanced.rateLimit.label")}</span>
51-
<div className="flex items-center gap-2">
52-
<input
53-
type="range"
54-
min="0"
55-
max="60"
56-
step="1"
57-
value={rateLimitSeconds}
58-
onChange={(e) => setCachedStateField("rateLimitSeconds", parseInt(e.target.value))}
59-
className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
60-
/>
61-
<span style={{ ...sliderLabelStyle }}>{rateLimitSeconds}s</span>
62-
</div>
63-
</div>
64-
<p className="text-vscode-descriptionForeground text-sm mt-0">
65-
{t("settings:advanced.rateLimit.description")}
66-
</p>
67-
</div>
68-
6944
<div>
7045
<div className="flex flex-col gap-2">
7146
<span className="font-medium">Terminal shell integration timeout</span>

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import { VSCodeButtonLink } from "../common/VSCodeButtonLink"
5151
import { ModelInfoView } from "./ModelInfoView"
5252
import { ModelPicker } from "./ModelPicker"
5353
import { TemperatureControl } from "./TemperatureControl"
54+
import { RateLimitControl } from "./RateLimitControl"
5455
import { validateApiConfiguration, validateModelId, validateBedrockArn } from "@/utils/validate"
5556
import { ApiErrorMessage } from "./ApiErrorMessage"
5657
import { ThinkingBudget } from "./ThinkingBudget"
@@ -1526,11 +1527,20 @@ const ApiOptions = ({
15261527
)}
15271528

15281529
{!fromWelcomeView && (
1529-
<TemperatureControl
1530-
value={apiConfiguration?.modelTemperature}
1531-
onChange={handleInputChange("modelTemperature", noTransform)}
1532-
maxValue={2}
1533-
/>
1530+
<>
1531+
<TemperatureControl
1532+
value={apiConfiguration?.modelTemperature}
1533+
onChange={handleInputChange("modelTemperature", noTransform)}
1534+
maxValue={2}
1535+
/>
1536+
<RateLimitControl
1537+
value={apiConfiguration?.rateLimitSeconds}
1538+
onChange={(value) =>
1539+
setApiConfigurationField("rateLimitSeconds", value === null ? undefined : value)
1540+
}
1541+
maxValue={60}
1542+
/>
1543+
</>
15341544
)}
15351545
</div>
15361546
)
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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 RateLimitControlProps {
7+
value: number | undefined | null
8+
onChange: (value: number | undefined | null) => void
9+
maxValue?: number
10+
}
11+
12+
export const RateLimitControl = ({ value, onChange, maxValue = 60 }: RateLimitControlProps) => {
13+
const { t } = useAppTranslation()
14+
const [isCustomRateLimit, setIsCustomRateLimit] = useState(value !== undefined)
15+
const [inputValue, setInputValue] = useState(value)
16+
useDebounce(() => onChange(inputValue), 50, [onChange, inputValue])
17+
// Sync internal state with prop changes when switching profiles
18+
useEffect(() => {
19+
const hasCustomRateLimit = value !== undefined && value !== null
20+
setIsCustomRateLimit(hasCustomRateLimit)
21+
setInputValue(value)
22+
}, [value])
23+
24+
return (
25+
<>
26+
<div>
27+
<VSCodeCheckbox
28+
checked={isCustomRateLimit}
29+
onChange={(e: any) => {
30+
const isChecked = e.target.checked
31+
setIsCustomRateLimit(isChecked)
32+
if (!isChecked) {
33+
setInputValue(null) // Unset the rate limit, 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:rateLimit.useCustom")}</span>
39+
</VSCodeCheckbox>
40+
<div className="text-sm text-vscode-descriptionForeground">
41+
{t("settings:advanced.rateLimit.description")}
42+
</div>
43+
</div>
44+
45+
{isCustomRateLimit && (
46+
<div
47+
style={{
48+
marginLeft: 0,
49+
paddingLeft: 10,
50+
borderLeft: "2px solid var(--vscode-button-background)",
51+
}}>
52+
<div style={{ display: "flex", alignItems: "center", gap: "5px" }}>
53+
<input
54+
type="range"
55+
min="0"
56+
max={maxValue}
57+
step="1"
58+
value={inputValue ?? 0}
59+
className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
60+
onChange={(e) => setInputValue(parseInt(e.target.value))}
61+
/>
62+
<span>{inputValue}s</span>
63+
</div>
64+
<p className="text-vscode-descriptionForeground text-sm mt-1">
65+
{t("settings:advanced.rateLimit.description")}
66+
</p>
67+
</div>
68+
)}
69+
</>
70+
)
71+
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -465,7 +465,6 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
465465

466466
<div ref={advancedRef}>
467467
<AdvancedSettings
468-
rateLimitSeconds={rateLimitSeconds}
469468
terminalShellIntegrationTimeout={terminalShellIntegrationTimeout}
470469
diffEnabled={diffEnabled}
471470
fuzzyMatchThreshold={fuzzyMatchThreshold}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,9 @@
276276
"description": "Temps màxim d'espera per a la inicialització de la integració de shell abans d'executar comandes. Per a usuaris amb temps d'inici de shell llargs, aquest valor pot necessitar ser augmentat si veieu errors \"Shell Integration Unavailable\" al terminal."
277277
}
278278
},
279+
"rateLimit": {
280+
"useCustom": "Utilitzar límit de freqüència personalitzat"
281+
},
279282
"advanced": {
280283
"rateLimit": {
281284
"label": "Límit de freqüència",

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,9 @@
276276
"description": "Maximale Wartezeit für die Shell-Integration, bevor Befehle ausgeführt werden. Für Benutzer mit langen Shell-Startzeiten muss dieser Wert möglicherweise erhöht werden, wenn Sie Fehler vom Typ \"Shell Integration Unavailable\" im Terminal sehen."
277277
}
278278
},
279+
"rateLimit": {
280+
"useCustom": "Benutzerdefinierte Ratenbegrenzung verwenden"
281+
},
279282
"advanced": {
280283
"rateLimit": {
281284
"label": "Ratenbegrenzung",

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,9 @@
276276
"description": "Maximum time to wait for shell integration to initialize before executing commands. For users with long shell startup times, this value may need to be increased if you see \"Shell Integration Unavailable\" errors in the terminal."
277277
}
278278
},
279+
"rateLimit": {
280+
"useCustom": "Use custom rate limit"
281+
},
279282
"advanced": {
280283
"rateLimit": {
281284
"label": "Rate limit",

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,9 @@
276276
"description": "Tiempo máximo de espera para la inicialización de la integración del shell antes de ejecutar comandos. Para usuarios con tiempos de inicio de shell largos, este valor puede necesitar ser aumentado si ve errores \"Shell Integration Unavailable\" en el terminal."
277277
}
278278
},
279+
"rateLimit": {
280+
"useCustom": "Usar límite de tasa personalizado"
281+
},
279282
"advanced": {
280283
"rateLimit": {
281284
"label": "Límite de tasa",

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,9 @@
276276
"description": "Temps maximum d'attente pour l'initialisation de l'intégration du shell avant d'exécuter des commandes. Pour les utilisateurs avec des temps de démarrage de shell longs, cette valeur peut nécessiter d'être augmentée si vous voyez des erreurs \"Shell Integration Unavailable\" dans le terminal."
277277
}
278278
},
279+
"rateLimit": {
280+
"useCustom": "Utiliser une limite de débit personnalisée"
281+
},
279282
"advanced": {
280283
"rateLimit": {
281284
"label": "Limite de débit",

0 commit comments

Comments
 (0)