Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
5 changes: 5 additions & 0 deletions .changeset/five-pigs-talk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"roo-cline": patch
---

Organize provider settings into separate components
126 changes: 126 additions & 0 deletions webview-ui/src/components/settings/providers/Bedrock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { useCallback } from "react"
import { Checkbox } from "vscrui"
import { VSCodeTextField, VSCodeRadio, VSCodeRadioGroup } from "@vscode/webview-ui-toolkit/react"

import { ApiConfiguration, ModelInfo } from "@roo/shared/api"

import { useAppTranslation } from "@src/i18n/TranslationContext"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@src/components/ui"

import { AWS_REGIONS } from "../constants"
import { inputEventTransform, noTransform } from "../transforms"

type BedrockProps = {
apiConfiguration: ApiConfiguration
setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
selectedModelInfo?: ModelInfo
}

export const Bedrock = ({ apiConfiguration, setApiConfigurationField, selectedModelInfo }: BedrockProps) => {
const { t } = useAppTranslation()

const handleInputChange = useCallback(
<K extends keyof ApiConfiguration, E>(
field: K,
transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
) =>
(event: E | Event) => {
setApiConfigurationField(field, transform(event as E))
},
[setApiConfigurationField],
)

return (
<>
<VSCodeRadioGroup
value={apiConfiguration?.awsUseProfile ? "profile" : "credentials"}
onChange={handleInputChange(
"awsUseProfile",
(e) => (e.target as HTMLInputElement).value === "profile",
)}>
<VSCodeRadio value="credentials">{t("settings:providers.awsCredentials")}</VSCodeRadio>
<VSCodeRadio value="profile">{t("settings:providers.awsProfile")}</VSCodeRadio>
</VSCodeRadioGroup>
<div className="text-sm text-vscode-descriptionForeground -mt-3">
{t("settings:providers.apiKeyStorageNotice")}
</div>
{apiConfiguration?.awsUseProfile ? (
<VSCodeTextField
value={apiConfiguration?.awsProfile || ""}
onInput={handleInputChange("awsProfile")}
placeholder={t("settings:placeholders.profileName")}
className="w-full">
<label className="block font-medium mb-1">{t("settings:providers.awsProfileName")}</label>
</VSCodeTextField>
) : (
<>
<VSCodeTextField
value={apiConfiguration?.awsAccessKey || ""}
type="password"
onInput={handleInputChange("awsAccessKey")}
placeholder={t("settings:placeholders.accessKey")}
className="w-full">
<label className="block font-medium mb-1">{t("settings:providers.awsAccessKey")}</label>
</VSCodeTextField>
<VSCodeTextField
value={apiConfiguration?.awsSecretKey || ""}
type="password"
onInput={handleInputChange("awsSecretKey")}
placeholder={t("settings:placeholders.secretKey")}
className="w-full">
<label className="block font-medium mb-1">{t("settings:providers.awsSecretKey")}</label>
</VSCodeTextField>
<VSCodeTextField
value={apiConfiguration?.awsSessionToken || ""}
type="password"
onInput={handleInputChange("awsSessionToken")}
placeholder={t("settings:placeholders.sessionToken")}
className="w-full">
<label className="block font-medium mb-1">{t("settings:providers.awsSessionToken")}</label>
</VSCodeTextField>
</>
)}
<div>
<label className="block font-medium mb-1">{t("settings:providers.awsRegion")}</label>
<Select
value={apiConfiguration?.awsRegion || ""}
onValueChange={(value) => setApiConfigurationField("awsRegion", value)}>
<SelectTrigger className="w-full">
<SelectValue placeholder={t("settings:common.select")} />
</SelectTrigger>
<SelectContent>
{AWS_REGIONS.map(({ value, label }) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<Checkbox
checked={apiConfiguration?.awsUseCrossRegionInference || false}
onChange={handleInputChange("awsUseCrossRegionInference", noTransform)}>
{t("settings:providers.awsCrossRegion")}
</Checkbox>
{selectedModelInfo?.supportsPromptCache && (
<Checkbox
checked={apiConfiguration?.awsUsePromptCache || false}
onChange={handleInputChange("awsUsePromptCache", noTransform)}>
<div className="flex items-center gap-1">
<span>{t("settings:providers.enablePromptCaching")}</span>
<i
className="codicon codicon-info text-vscode-descriptionForeground"
title={t("settings:providers.enablePromptCachingTitle")}
style={{ fontSize: "12px" }}
/>
</div>
</Checkbox>
)}
<div>
<div className="text-sm text-vscode-descriptionForeground ml-6 mt-1">
{t("settings:providers.cacheUsageNote")}
</div>
</div>
</>
)
}
152 changes: 152 additions & 0 deletions webview-ui/src/components/settings/providers/LMStudio.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { useCallback, useState } from "react"
import { useEvent } from "react-use"
import { Trans } from "react-i18next"
import { Checkbox } from "vscrui"
import { VSCodeLink, VSCodeRadio, VSCodeRadioGroup, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"

import { ApiConfiguration } from "@roo/shared/api"

import { useAppTranslation } from "@src/i18n/TranslationContext"
import { ExtensionMessage } from "@roo/shared/ExtensionMessage"

import { inputEventTransform } from "../transforms"

type LMStudioProps = {
apiConfiguration: ApiConfiguration
setApiConfigurationField: (field: keyof ApiConfiguration, value: ApiConfiguration[keyof ApiConfiguration]) => void
}

export const LMStudio = ({ apiConfiguration, setApiConfigurationField }: LMStudioProps) => {
const { t } = useAppTranslation()

const [lmStudioModels, setLmStudioModels] = useState<string[]>([])

const handleInputChange = useCallback(
<K extends keyof ApiConfiguration, E>(
field: K,
transform: (event: E) => ApiConfiguration[K] = inputEventTransform,
) =>
(event: E | Event) => {
setApiConfigurationField(field, transform(event as E))
},
[setApiConfigurationField],
)

const onMessage = useCallback((event: MessageEvent) => {
const message: ExtensionMessage = event.data

switch (message.type) {
case "lmStudioModels":
{
const newModels = message.lmStudioModels ?? []
setLmStudioModels(newModels)
}
break
}
}, [])

useEvent("message", onMessage)

return (
<>
<VSCodeTextField
value={apiConfiguration?.lmStudioBaseUrl || ""}
type="url"
onInput={handleInputChange("lmStudioBaseUrl")}
placeholder={t("settings:defaults.lmStudioUrl")}
className="w-full">
<label className="block font-medium mb-1">{t("settings:providers.lmStudio.baseUrl")}</label>
</VSCodeTextField>
<VSCodeTextField
value={apiConfiguration?.lmStudioModelId || ""}
onInput={handleInputChange("lmStudioModelId")}
placeholder={t("settings:placeholders.modelId.lmStudio")}
className="w-full">
<label className="block font-medium mb-1">{t("settings:providers.lmStudio.modelId")}</label>
</VSCodeTextField>
{lmStudioModels.length > 0 && (
<VSCodeRadioGroup
value={
lmStudioModels.includes(apiConfiguration?.lmStudioModelId || "")
? apiConfiguration?.lmStudioModelId
: ""
}
onChange={handleInputChange("lmStudioModelId")}>
{lmStudioModels.map((model) => (
<VSCodeRadio key={model} value={model} checked={apiConfiguration?.lmStudioModelId === model}>
{model}
</VSCodeRadio>
))}
</VSCodeRadioGroup>
)}
<Checkbox
checked={apiConfiguration?.lmStudioSpeculativeDecodingEnabled === true}
onChange={(checked) => {
setApiConfigurationField("lmStudioSpeculativeDecodingEnabled", checked)
}}>
{t("settings:providers.lmStudio.speculativeDecoding")}
</Checkbox>
{apiConfiguration?.lmStudioSpeculativeDecodingEnabled && (
<>
<div>
<VSCodeTextField
value={apiConfiguration?.lmStudioDraftModelId || ""}
onInput={handleInputChange("lmStudioDraftModelId")}
placeholder={t("settings:placeholders.modelId.lmStudioDraft")}
className="w-full">
<label className="block font-medium mb-1">
{t("settings:providers.lmStudio.draftModelId")}
</label>
</VSCodeTextField>
<div className="text-sm text-vscode-descriptionForeground">
{t("settings:providers.lmStudio.draftModelDesc")}
</div>
</div>
{lmStudioModels.length > 0 && (
<>
<div className="font-medium">{t("settings:providers.lmStudio.selectDraftModel")}</div>
<VSCodeRadioGroup
value={
lmStudioModels.includes(apiConfiguration?.lmStudioDraftModelId || "")
? apiConfiguration?.lmStudioDraftModelId
: ""
}
onChange={handleInputChange("lmStudioDraftModelId")}>
{lmStudioModels.map((model) => (
<VSCodeRadio key={`draft-${model}`} value={model}>
{model}
</VSCodeRadio>
))}
</VSCodeRadioGroup>
{lmStudioModels.length === 0 && (
<div
className="text-sm rounded-xs p-2"
style={{
backgroundColor: "var(--vscode-inputValidation-infoBackground)",
border: "1px solid var(--vscode-inputValidation-infoBorder)",
color: "var(--vscode-inputValidation-infoForeground)",
}}>
{t("settings:providers.lmStudio.noModelsFound")}
</div>
)}
</>
)}
</>
)}
<div className="text-sm text-vscode-descriptionForeground">
<Trans
i18nKey="settings:providers.lmStudio.description"
components={{
a: <VSCodeLink href="https://lmstudio.ai/docs" />,
b: <VSCodeLink href="https://lmstudio.ai/docs/basics/server" />,
span: (
<span className="text-vscode-errorForeground ml-1">
<span className="font-medium">Note:</span>
</span>
),
}}
/>
</div>
</>
)
}
Loading
Loading