mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 12:21:13 -05:00
Add option to choose different models
This commit is contained in:
@@ -1,34 +1,78 @@
|
||||
import { ApiConfiguration } from "@shared/api"
|
||||
import { VSCodeDropdown, VSCodeLink, VSCodeOption, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
import React from "react"
|
||||
import React, { useMemo } from "react"
|
||||
import {
|
||||
ApiConfiguration,
|
||||
ApiModelId,
|
||||
ModelInfo,
|
||||
anthropicDefaultModelId,
|
||||
anthropicModels,
|
||||
bedrockDefaultModelId,
|
||||
bedrockModels,
|
||||
openRouterDefaultModelId,
|
||||
openRouterModels,
|
||||
} from "../../../src/shared/api"
|
||||
|
||||
interface ApiOptionsProps {
|
||||
showModelOptions: boolean
|
||||
apiConfiguration?: ApiConfiguration
|
||||
setApiConfiguration: React.Dispatch<React.SetStateAction<ApiConfiguration | undefined>>
|
||||
}
|
||||
|
||||
const ApiOptions: React.FC<ApiOptionsProps> = ({ apiConfiguration, setApiConfiguration }) => {
|
||||
const ApiOptions: React.FC<ApiOptionsProps> = ({ showModelOptions, apiConfiguration, setApiConfiguration }) => {
|
||||
const handleInputChange = (field: keyof ApiConfiguration) => (event: any) => {
|
||||
setApiConfiguration((prev) => ({ ...prev, [field]: event.target.value }))
|
||||
}
|
||||
|
||||
const { selectedProvider, selectedModelId, selectedModelInfo } = useMemo(() => {
|
||||
return normalizeApiConfiguration(apiConfiguration)
|
||||
}, [apiConfiguration])
|
||||
|
||||
/*
|
||||
VSCodeDropdown has an open bug where dynamically rendered options don't auto select the provided value prop. You can see this for yourself by comparing it with normal select/option elements, which work as expected.
|
||||
https://github.com/microsoft/vscode-webview-ui-toolkit/issues/433
|
||||
|
||||
In our case, when the user switches between providers, we recalculate the selectedModelId depending on the provider, the default model for that provider, and a modelId that the user may have selected. Unfortunately, the VSCodeDropdown component wouldn't select this calculated value, and would default to the first "Select a model..." option instead, which makes it seem like the model was cleared out when it wasn't.
|
||||
|
||||
As a workaround, we create separate instances of the dropdown for each provider, and then conditionally render the one that matches the current provider.
|
||||
*/
|
||||
const createDropdown = (models: Record<string, ModelInfo>) => {
|
||||
return (
|
||||
<VSCodeDropdown
|
||||
id="model-id"
|
||||
value={selectedModelId}
|
||||
onChange={handleInputChange("apiModelId")}
|
||||
style={{ width: "100%" }}>
|
||||
<VSCodeOption value="">Select a model...</VSCodeOption>
|
||||
{Object.keys(models).map((modelId) => (
|
||||
<VSCodeOption
|
||||
key={modelId}
|
||||
value={modelId}
|
||||
style={{
|
||||
whiteSpace: "normal",
|
||||
wordWrap: "break-word",
|
||||
maxWidth: "100%",
|
||||
}}>
|
||||
{modelId}
|
||||
</VSCodeOption>
|
||||
))}
|
||||
</VSCodeDropdown>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 5 }}>
|
||||
<div className="dropdown-container">
|
||||
<label htmlFor="api-provider">
|
||||
<span style={{ fontWeight: 500 }}>API Provider</span>
|
||||
</label>
|
||||
<VSCodeDropdown
|
||||
id="api-provider"
|
||||
value={apiConfiguration?.apiProvider || "anthropic"}
|
||||
onChange={handleInputChange("apiProvider")}>
|
||||
<VSCodeDropdown id="api-provider" value={selectedProvider} onChange={handleInputChange("apiProvider")}>
|
||||
<VSCodeOption value="anthropic">Anthropic</VSCodeOption>
|
||||
<VSCodeOption value="openrouter">OpenRouter</VSCodeOption>
|
||||
<VSCodeOption value="bedrock">AWS Bedrock</VSCodeOption>
|
||||
</VSCodeDropdown>
|
||||
</div>
|
||||
|
||||
{apiConfiguration?.apiProvider === "anthropic" && (
|
||||
{selectedProvider === "anthropic" && (
|
||||
<div>
|
||||
<VSCodeTextField
|
||||
value={apiConfiguration?.apiKey || ""}
|
||||
@@ -51,7 +95,7 @@ const ApiOptions: React.FC<ApiOptionsProps> = ({ apiConfiguration, setApiConfigu
|
||||
</div>
|
||||
)}
|
||||
|
||||
{apiConfiguration?.apiProvider === "openrouter" && (
|
||||
{selectedProvider === "openrouter" && (
|
||||
<div>
|
||||
<VSCodeTextField
|
||||
value={apiConfiguration?.openRouterApiKey || ""}
|
||||
@@ -74,7 +118,7 @@ const ApiOptions: React.FC<ApiOptionsProps> = ({ apiConfiguration, setApiConfigu
|
||||
</div>
|
||||
)}
|
||||
|
||||
{apiConfiguration?.apiProvider === "bedrock" && (
|
||||
{selectedProvider === "bedrock" && (
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 5 }}>
|
||||
<VSCodeTextField
|
||||
value={apiConfiguration?.awsAccessKey || ""}
|
||||
@@ -100,9 +144,9 @@ const ApiOptions: React.FC<ApiOptionsProps> = ({ apiConfiguration, setApiConfigu
|
||||
style={{ width: "100%" }}
|
||||
onChange={handleInputChange("awsRegion")}>
|
||||
<VSCodeOption value="">Select a region...</VSCodeOption>
|
||||
{/* Currently Claude 3.5 Sonnet is only available in us-east-1 */}
|
||||
{/* The user will have to choose a region that supports the model they use, but this shouldn't be a problem since they'd have to request access for it in that region in the first place. */}
|
||||
<VSCodeOption value="us-east-1">US East (N. Virginia)</VSCodeOption>
|
||||
{/* <VSCodeOption value="us-east-2">US East (Ohio)</VSCodeOption>
|
||||
<VSCodeOption value="us-east-2">US East (Ohio)</VSCodeOption>
|
||||
<VSCodeOption value="us-west-1">US West (N. California)</VSCodeOption>
|
||||
<VSCodeOption value="us-west-2">US West (Oregon)</VSCodeOption>
|
||||
<VSCodeOption value="af-south-1">Africa (Cape Town)</VSCodeOption>
|
||||
@@ -120,7 +164,7 @@ const ApiOptions: React.FC<ApiOptionsProps> = ({ apiConfiguration, setApiConfigu
|
||||
<VSCodeOption value="eu-west-3">Europe (Paris)</VSCodeOption>
|
||||
<VSCodeOption value="eu-north-1">Europe (Stockholm)</VSCodeOption>
|
||||
<VSCodeOption value="me-south-1">Middle East (Bahrain)</VSCodeOption>
|
||||
<VSCodeOption value="sa-east-1">South America (São Paulo)</VSCodeOption> */}
|
||||
<VSCodeOption value="sa-east-1">South America (São Paulo)</VSCodeOption>
|
||||
</VSCodeDropdown>
|
||||
</div>
|
||||
<p
|
||||
@@ -138,8 +182,91 @@ const ApiOptions: React.FC<ApiOptionsProps> = ({ apiConfiguration, setApiConfigu
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showModelOptions && (
|
||||
<>
|
||||
<div className="dropdown-container">
|
||||
<label htmlFor="model-id">
|
||||
<span style={{ fontWeight: 500 }}>Model</span>
|
||||
</label>
|
||||
{selectedProvider === "anthropic" && createDropdown(anthropicModels)}
|
||||
{selectedProvider === "openrouter" && createDropdown(openRouterModels)}
|
||||
{selectedProvider === "bedrock" && createDropdown(bedrockModels)}
|
||||
</div>
|
||||
|
||||
<ModelInfoView modelInfo={selectedModelInfo} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const ModelInfoView = ({ modelInfo }: { modelInfo: ModelInfo }) => {
|
||||
const formatPrice = (price: number) => {
|
||||
return new Intl.NumberFormat("en-US", {
|
||||
style: "currency",
|
||||
currency: "USD",
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
}).format(price)
|
||||
}
|
||||
|
||||
return (
|
||||
<p style={{ fontSize: "12px", marginTop: "2px", color: "var(--vscode-descriptionForeground)" }}>
|
||||
<span
|
||||
style={{
|
||||
fontWeight: 500,
|
||||
color: modelInfo.supportsImages
|
||||
? "var(--vscode-testing-iconPassed)"
|
||||
: "var(--vscode-errorForeground)",
|
||||
}}>
|
||||
<i
|
||||
className={`codicon codicon-${modelInfo.supportsImages ? "check" : "x"}`}
|
||||
style={{
|
||||
marginRight: 4,
|
||||
marginBottom: modelInfo.supportsImages ? 1 : -1,
|
||||
fontSize: modelInfo.supportsImages ? 11 : 13,
|
||||
fontWeight: 700,
|
||||
display: "inline-block",
|
||||
verticalAlign: "bottom",
|
||||
}}></i>
|
||||
{modelInfo.supportsImages ? "Supports images" : "Does not support images"}
|
||||
</span>
|
||||
<br />
|
||||
<span style={{ fontWeight: 500 }}>Max output:</span> {modelInfo.maxTokens.toLocaleString()} tokens
|
||||
<br />
|
||||
<span style={{ fontWeight: 500 }}>Input price:</span> {formatPrice(modelInfo.inputPrice)} per million tokens
|
||||
<br />
|
||||
<span style={{ fontWeight: 500 }}>Output price:</span> {formatPrice(modelInfo.outputPrice)} per million
|
||||
tokens
|
||||
</p>
|
||||
)
|
||||
}
|
||||
|
||||
export function normalizeApiConfiguration(apiConfiguration?: ApiConfiguration) {
|
||||
const provider = apiConfiguration?.apiProvider || "anthropic"
|
||||
const modelId = apiConfiguration?.apiModelId
|
||||
|
||||
const getProviderData = (models: Record<string, ModelInfo>, defaultId: ApiModelId) => {
|
||||
let selectedModelId: ApiModelId
|
||||
let selectedModelInfo: ModelInfo
|
||||
if (modelId && modelId in models) {
|
||||
selectedModelId = modelId
|
||||
selectedModelInfo = models[modelId]
|
||||
} else {
|
||||
selectedModelId = defaultId
|
||||
selectedModelInfo = models[defaultId]
|
||||
}
|
||||
return { selectedProvider: provider, selectedModelId, selectedModelInfo }
|
||||
}
|
||||
switch (provider) {
|
||||
case "anthropic":
|
||||
return getProviderData(anthropicModels, anthropicDefaultModelId)
|
||||
case "openrouter":
|
||||
return getProviderData(openRouterModels, openRouterDefaultModelId)
|
||||
case "bedrock":
|
||||
return getProviderData(bedrockModels, bedrockDefaultModelId)
|
||||
}
|
||||
}
|
||||
|
||||
export default ApiOptions
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { ClaudeAsk, ClaudeMessage, ClaudeSay, ClaudeSayTool } from "@shared/ExtensionMessage"
|
||||
import { VSCodeBadge, VSCodeButton, VSCodeProgressRing } from "@vscode/webview-ui-toolkit/react"
|
||||
import React from "react"
|
||||
import Markdown from "react-markdown"
|
||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
|
||||
import { ClaudeAsk, ClaudeMessage, ClaudeSay, ClaudeSayTool } from "../../../src/shared/ExtensionMessage"
|
||||
import { COMMAND_OUTPUT_STRING } from "../utils/combineCommandSequences"
|
||||
import { SyntaxHighlighterStyle } from "../utils/getSyntaxHighlighterStyleFromTheme"
|
||||
import CodeBlock from "./CodeBlock/CodeBlock"
|
||||
import Markdown from "react-markdown"
|
||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
|
||||
import Thumbnails from "./Thumbnails"
|
||||
|
||||
interface ChatRowProps {
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { ClaudeAsk, ClaudeMessage, ExtensionMessage } from "@shared/ExtensionMessage"
|
||||
import { VSCodeButton, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
|
||||
import { KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } from "react"
|
||||
import vsDarkPlus from "react-syntax-highlighter/dist/esm/styles/prism/vsc-dark-plus"
|
||||
import DynamicTextArea from "react-textarea-autosize"
|
||||
import { useEvent, useMount } from "react-use"
|
||||
import { Virtuoso, type VirtuosoHandle } from "react-virtuoso"
|
||||
import { ClaudeAsk, ClaudeMessage, ExtensionMessage } from "../../../src/shared/ExtensionMessage"
|
||||
import { combineApiRequests } from "../utils/combineApiRequests"
|
||||
import { combineCommandSequences } from "../utils/combineCommandSequences"
|
||||
import { getApiMetrics } from "../utils/getApiMetrics"
|
||||
import { getSyntaxHighlighterStyleFromTheme } from "../utils/getSyntaxHighlighterStyleFromTheme"
|
||||
import { vscode } from "../utils/vscode"
|
||||
import Announcement from "./Announcement"
|
||||
import ChatRow from "./ChatRow"
|
||||
import TaskHeader from "./TaskHeader"
|
||||
import { Virtuoso, type VirtuosoHandle } from "react-virtuoso"
|
||||
import Announcement from "./Announcement"
|
||||
import Thumbnails from "./Thumbnails"
|
||||
|
||||
interface ChatViewProps {
|
||||
@@ -21,6 +21,7 @@ interface ChatViewProps {
|
||||
isHidden: boolean
|
||||
vscodeThemeName?: string
|
||||
showAnnouncement: boolean
|
||||
selectedModelSupportsImages: boolean
|
||||
hideAnnouncement: () => void
|
||||
}
|
||||
|
||||
@@ -32,6 +33,7 @@ const ChatView = ({
|
||||
isHidden,
|
||||
vscodeThemeName,
|
||||
showAnnouncement,
|
||||
selectedModelSupportsImages,
|
||||
hideAnnouncement,
|
||||
}: ChatViewProps) => {
|
||||
//const task = messages.length > 0 ? (messages[0].say === "task" ? messages[0] : undefined) : undefined
|
||||
@@ -278,6 +280,11 @@ const ChatView = ({
|
||||
}
|
||||
|
||||
const handlePaste = async (e: React.ClipboardEvent) => {
|
||||
if (shouldDisableImages) {
|
||||
e.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
const items = e.clipboardData.items
|
||||
const acceptedTypes = ["png", "jpeg", "webp"] // supported by anthropic and openrouter (jpg is just a file extension but the image will be recognized as jpeg)
|
||||
const imageItems = Array.from(items).filter((item) => {
|
||||
@@ -412,6 +419,12 @@ const ChatView = ({
|
||||
return [text, false]
|
||||
}, [task, messages])
|
||||
|
||||
const shouldDisableImages =
|
||||
!selectedModelSupportsImages ||
|
||||
textAreaDisabled ||
|
||||
selectedImages.length >= MAX_IMAGES_PER_MESSAGE ||
|
||||
isInputPipingToStdin
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
@@ -590,9 +603,7 @@ const ChatView = ({
|
||||
height: "calc(100% - 20px)", // Full height minus top and bottom padding
|
||||
}}>
|
||||
<VSCodeButton
|
||||
disabled={
|
||||
textAreaDisabled || selectedImages.length >= MAX_IMAGES_PER_MESSAGE || isInputPipingToStdin
|
||||
}
|
||||
disabled={shouldDisableImages}
|
||||
appearance="icon"
|
||||
aria-label="Attach Images"
|
||||
onClick={selectImages}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ApiConfiguration } from "@shared/api"
|
||||
import { VSCodeButton, VSCodeDivider, VSCodeLink, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
import { VSCodeButton, VSCodeLink, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
import React, { useEffect, useState } from "react"
|
||||
import { ApiConfiguration } from "../../../src/shared/api"
|
||||
import { validateApiConfiguration, validateMaxRequestsPerTask } from "../utils/validate"
|
||||
import { vscode } from "../utils/vscode"
|
||||
import ApiOptions from "./ApiOptions"
|
||||
@@ -60,78 +60,92 @@ const SettingsView = ({
|
||||
*/
|
||||
|
||||
return (
|
||||
<div style={{ margin: "0 auto", paddingTop: "10px" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: "17px",
|
||||
}}>
|
||||
<h3 style={{ color: "var(--vscode-foreground)", margin: 0 }}>Settings</h3>
|
||||
<VSCodeButton onClick={handleSubmit}>Done</VSCodeButton>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: 5 }}>
|
||||
<ApiOptions apiConfiguration={apiConfiguration} setApiConfiguration={setApiConfiguration} />
|
||||
{apiErrorMessage && (
|
||||
<p
|
||||
style={{
|
||||
margin: "-5px 0 12px 0",
|
||||
fontSize: "12px",
|
||||
color: "var(--vscode-errorForeground)",
|
||||
}}>
|
||||
{apiErrorMessage}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: "20px" }}>
|
||||
<VSCodeTextField
|
||||
value={maxRequestsPerTask}
|
||||
style={{ width: "100%" }}
|
||||
placeholder="20"
|
||||
onInput={(e: any) => setMaxRequestsPerTask(e.target?.value)}>
|
||||
<span style={{ fontWeight: "500" }}>Maximum # Requests Per Task</span>
|
||||
</VSCodeTextField>
|
||||
<p
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
padding: "10px 18px 18px 20px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
overflow: "hidden",
|
||||
}}>
|
||||
<div style={{ flexGrow: 1, overflow: "auto" }}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
marginTop: "5px",
|
||||
color: "var(--vscode-descriptionForeground)",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: "17px",
|
||||
}}>
|
||||
If Claude Dev reaches this limit, it will pause and ask for your permission before making additional
|
||||
requests.
|
||||
</p>
|
||||
{maxRequestsErrorMessage && (
|
||||
<h3 style={{ color: "var(--vscode-foreground)", margin: 0 }}>Settings</h3>
|
||||
<VSCodeButton onClick={handleSubmit}>Done</VSCodeButton>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: 5 }}>
|
||||
<ApiOptions
|
||||
apiConfiguration={apiConfiguration}
|
||||
setApiConfiguration={setApiConfiguration}
|
||||
showModelOptions={true}
|
||||
/>
|
||||
{apiErrorMessage && (
|
||||
<p
|
||||
style={{
|
||||
margin: "-5px 0 12px 0",
|
||||
fontSize: "12px",
|
||||
color: "var(--vscode-errorForeground)",
|
||||
}}>
|
||||
{apiErrorMessage}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: "20px" }}>
|
||||
<VSCodeTextField
|
||||
value={maxRequestsPerTask}
|
||||
style={{ width: "100%" }}
|
||||
placeholder="20"
|
||||
onInput={(e: any) => setMaxRequestsPerTask(e.target?.value)}>
|
||||
<span style={{ fontWeight: "500" }}>Maximum # Requests Per Task</span>
|
||||
</VSCodeTextField>
|
||||
<p
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
marginTop: "5px",
|
||||
color: "var(--vscode-errorForeground)",
|
||||
color: "var(--vscode-descriptionForeground)",
|
||||
}}>
|
||||
{maxRequestsErrorMessage}
|
||||
If Claude Dev reaches this limit, it will pause and ask for your permission before making
|
||||
additional requests.
|
||||
</p>
|
||||
)}
|
||||
{maxRequestsErrorMessage && (
|
||||
<p
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
marginTop: "5px",
|
||||
color: "var(--vscode-errorForeground)",
|
||||
}}>
|
||||
{maxRequestsErrorMessage}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<VSCodeDivider />
|
||||
|
||||
<div
|
||||
style={{
|
||||
marginTop: "20px",
|
||||
textAlign: "center",
|
||||
color: "var(--vscode-descriptionForeground)",
|
||||
fontSize: "12px",
|
||||
lineHeight: "1.2",
|
||||
}}>
|
||||
<p style={{ wordWrap: "break-word" }}>
|
||||
<p style={{ wordWrap: "break-word", margin: 0, padding: 0 }}>
|
||||
If you have any questions or feedback, feel free to open an issue at{" "}
|
||||
<VSCodeLink href="https://github.com/saoudrizwan/claude-dev" style={{ display: "inline" }}>
|
||||
https://github.com/saoudrizwan/claude-dev
|
||||
</VSCodeLink>
|
||||
</p>
|
||||
<p style={{ fontStyle: "italic" }}>v{version}</p>
|
||||
<p style={{ fontStyle: "italic", margin: "10px 0 0 0", padding: 0 }}>v{version}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -2,8 +2,8 @@ import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
|
||||
import React, { useEffect, useRef, useState } from "react"
|
||||
import TextTruncate from "react-text-truncate"
|
||||
import { useWindowSize } from "react-use"
|
||||
import { ClaudeMessage } from "../../../src/shared/ExtensionMessage"
|
||||
import { vscode } from "../utils/vscode"
|
||||
import { ClaudeMessage } from "@shared/ExtensionMessage"
|
||||
import Thumbnails from "./Thumbnails"
|
||||
|
||||
interface TaskHeaderProps {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ApiConfiguration } from "@shared/api"
|
||||
import { ApiConfiguration } from "../../../src/shared/api"
|
||||
import { VSCodeButton, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
|
||||
import React, { useEffect, useState } from "react"
|
||||
import { validateApiConfiguration } from "../utils/validate"
|
||||
@@ -40,7 +40,11 @@ const WelcomeView: React.FC<WelcomeViewProps> = ({ apiConfiguration, setApiConfi
|
||||
<b>To get started, this extension needs an API key for Claude 3.5 Sonnet:</b>
|
||||
|
||||
<div style={{ marginTop: "15px" }}>
|
||||
<ApiOptions apiConfiguration={apiConfiguration} setApiConfiguration={setApiConfiguration} />
|
||||
<ApiOptions
|
||||
apiConfiguration={apiConfiguration}
|
||||
setApiConfiguration={setApiConfiguration}
|
||||
showModelOptions={false}
|
||||
/>
|
||||
<VSCodeButton onClick={handleSubmit} disabled={disableLetsGoButton} style={{ marginTop: "3px" }}>
|
||||
Let's go!
|
||||
</VSCodeButton>
|
||||
|
||||
Reference in New Issue
Block a user