mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 04:11:10 -05:00
Merge pull request #369 from samhvw8/fix/roo-cline-select-api-config
fix api config profile
This commit is contained in:
@@ -961,10 +961,8 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
await this.configManager.SaveConfig(message.text, message.apiConfiguration);
|
||||
let listApiConfig = await this.configManager.ListConfig();
|
||||
|
||||
// Update listApiConfigMeta first to ensure UI has latest data
|
||||
await this.updateGlobalState("listApiConfigMeta", listApiConfig);
|
||||
|
||||
await Promise.all([
|
||||
this.updateGlobalState("listApiConfigMeta", listApiConfig),
|
||||
this.updateApiConfiguration(message.apiConfiguration),
|
||||
this.updateGlobalState("currentApiConfigName", message.text),
|
||||
])
|
||||
@@ -1006,12 +1004,9 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
try {
|
||||
const apiConfig = await this.configManager.LoadConfig(message.text);
|
||||
const listApiConfig = await this.configManager.ListConfig();
|
||||
const config = listApiConfig?.find(c => c.name === message.text);
|
||||
|
||||
// Update listApiConfigMeta first to ensure UI has latest data
|
||||
await this.updateGlobalState("listApiConfigMeta", listApiConfig);
|
||||
|
||||
await Promise.all([
|
||||
this.updateGlobalState("listApiConfigMeta", listApiConfig),
|
||||
this.updateGlobalState("currentApiConfigName", message.text),
|
||||
this.updateApiConfiguration(apiConfig),
|
||||
])
|
||||
|
||||
@@ -15,7 +15,7 @@ module.exports.jest = function(config) {
|
||||
|
||||
// Configure transform ignore patterns for ES modules
|
||||
config.transformIgnorePatterns = [
|
||||
'/node_modules/(?!(rehype-highlight|react-remark|unist-util-visit|unist-util-find-after|vfile|unified|bail|is-plain-obj|trough|vfile-message|unist-util-stringify-position|mdast-util-from-markdown|mdast-util-to-string|micromark|decode-named-character-reference|character-entities|markdown-table|zwitch|longest-streak|escape-string-regexp|unist-util-is|hast-util-to-text|@vscode/webview-ui-toolkit|@microsoft/fast-react-wrapper|@microsoft/fast-element|@microsoft/fast-foundation|@microsoft/fast-web-utilities|exenv-es6)/)'
|
||||
'/node_modules/(?!(rehype-highlight|react-remark|unist-util-visit|unist-util-find-after|vfile|unified|bail|is-plain-obj|trough|vfile-message|unist-util-stringify-position|mdast-util-from-markdown|mdast-util-to-string|micromark|decode-named-character-reference|character-entities|markdown-table|zwitch|longest-streak|escape-string-regexp|unist-util-is|hast-util-to-text|@vscode/webview-ui-toolkit|@microsoft/fast-react-wrapper|@microsoft/fast-element|@microsoft/fast-foundation|@microsoft/fast-web-utilities|exenv-es6|vscrui)/)'
|
||||
];
|
||||
|
||||
return config;
|
||||
|
||||
15
webview-ui/package-lock.json
generated
15
webview-ui/package-lock.json
generated
@@ -31,6 +31,7 @@
|
||||
"shell-quote": "^1.8.2",
|
||||
"styled-components": "^6.1.13",
|
||||
"typescript": "^4.9.5",
|
||||
"vscrui": "^0.2.0",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -15155,6 +15156,20 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/vscrui": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/vscrui/-/vscrui-0.2.0.tgz",
|
||||
"integrity": "sha512-fvxZM/uIYOMN3fUbE2In+R1VrNj8PKcfAdh+Us2bJaPGuG9ySkR6xkV2aJVqXxWDX77U3v/UQGc5e7URrB52Gw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/estruyf"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^17 || ^18"
|
||||
}
|
||||
},
|
||||
"node_modules/w3c-hr-time": {
|
||||
"version": "1.0.2",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"shell-quote": "^1.8.2",
|
||||
"styled-components": "^6.1.13",
|
||||
"typescript": "^4.9.5",
|
||||
"vscrui": "^0.2.0",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { Checkbox, Dropdown } from "vscrui"
|
||||
import type { DropdownOption } from "vscrui"
|
||||
import {
|
||||
VSCodeCheckbox,
|
||||
VSCodeDropdown,
|
||||
VSCodeLink,
|
||||
VSCodeOption,
|
||||
VSCodeRadio,
|
||||
VSCodeRadioGroup,
|
||||
VSCodeTextField,
|
||||
VSCodeTextField
|
||||
} from "@vscode/webview-ui-toolkit/react"
|
||||
import { Fragment, memo, useCallback, useEffect, useMemo, useState } from "react"
|
||||
import { useEvent, useInterval } from "react-use"
|
||||
@@ -95,35 +94,26 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
|
||||
}, [])
|
||||
useEvent("message", handleMessage)
|
||||
|
||||
/*
|
||||
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>) => {
|
||||
const options: DropdownOption[] = [
|
||||
{ value: "", label: "Select a model..." },
|
||||
...Object.keys(models).map((modelId) => ({
|
||||
value: modelId,
|
||||
label: modelId,
|
||||
}))
|
||||
]
|
||||
return (
|
||||
<VSCodeDropdown
|
||||
<Dropdown
|
||||
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>
|
||||
onChange={(value: unknown) => {handleInputChange("apiModelId")({
|
||||
target: {
|
||||
value: (value as DropdownOption).value
|
||||
}
|
||||
})}}
|
||||
style={{ width: "100%" }}
|
||||
options={options}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -133,24 +123,32 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
|
||||
<label htmlFor="api-provider">
|
||||
<span style={{ fontWeight: 500 }}>API Provider</span>
|
||||
</label>
|
||||
<VSCodeDropdown
|
||||
<Dropdown
|
||||
id="api-provider"
|
||||
value={selectedProvider}
|
||||
onChange={handleInputChange("apiProvider")}
|
||||
style={{ minWidth: 130, position: "relative", zIndex: OPENROUTER_MODEL_PICKER_Z_INDEX + 1 }}>
|
||||
<VSCodeOption value="openrouter">OpenRouter</VSCodeOption>
|
||||
<VSCodeOption value="anthropic">Anthropic</VSCodeOption>
|
||||
<VSCodeOption value="gemini">Google Gemini</VSCodeOption>
|
||||
<VSCodeOption value="deepseek">DeepSeek</VSCodeOption>
|
||||
<VSCodeOption value="openai-native">OpenAI</VSCodeOption>
|
||||
<VSCodeOption value="openai">OpenAI Compatible</VSCodeOption>
|
||||
<VSCodeOption value="vertex">GCP Vertex AI</VSCodeOption>
|
||||
<VSCodeOption value="bedrock">AWS Bedrock</VSCodeOption>
|
||||
<VSCodeOption value="glama">Glama</VSCodeOption>
|
||||
<VSCodeOption value="vscode-lm">VS Code LM API</VSCodeOption>
|
||||
<VSCodeOption value="lmstudio">LM Studio</VSCodeOption>
|
||||
<VSCodeOption value="ollama">Ollama</VSCodeOption>
|
||||
</VSCodeDropdown>
|
||||
onChange={(value: unknown) => {
|
||||
handleInputChange("apiProvider")({
|
||||
target: {
|
||||
value: (value as DropdownOption).value
|
||||
}
|
||||
})
|
||||
}}
|
||||
style={{ minWidth: 130, position: "relative", zIndex: OPENROUTER_MODEL_PICKER_Z_INDEX + 1 }}
|
||||
options={[
|
||||
{ value: "openrouter", label: "OpenRouter" },
|
||||
{ value: "anthropic", label: "Anthropic" },
|
||||
{ value: "gemini", label: "Google Gemini" },
|
||||
{ value: "deepseek", label: "DeepSeek" },
|
||||
{ value: "openai-native", label: "OpenAI" },
|
||||
{ value: "openai", label: "OpenAI Compatible" },
|
||||
{ value: "vertex", label: "GCP Vertex AI" },
|
||||
{ value: "bedrock", label: "AWS Bedrock" },
|
||||
{ value: "glama", label: "Glama" },
|
||||
{ value: "vscode-lm", label: "VS Code LM API" },
|
||||
{ value: "lmstudio", label: "LM Studio" },
|
||||
{ value: "ollama", label: "Ollama" }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{selectedProvider === "anthropic" && (
|
||||
@@ -164,17 +162,16 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
|
||||
<span style={{ fontWeight: 500 }}>Anthropic API Key</span>
|
||||
</VSCodeTextField>
|
||||
|
||||
<VSCodeCheckbox
|
||||
<Checkbox
|
||||
checked={anthropicBaseUrlSelected}
|
||||
onChange={(e: any) => {
|
||||
const isChecked = e.target.checked === true
|
||||
setAnthropicBaseUrlSelected(isChecked)
|
||||
if (!isChecked) {
|
||||
onChange={(checked: boolean) => {
|
||||
setAnthropicBaseUrlSelected(checked)
|
||||
if (!checked) {
|
||||
setApiConfiguration({ ...apiConfiguration, anthropicBaseUrl: "" })
|
||||
}
|
||||
}}>
|
||||
Use custom base URL
|
||||
</VSCodeCheckbox>
|
||||
</Checkbox>
|
||||
|
||||
{anthropicBaseUrlSelected && (
|
||||
<VSCodeTextField
|
||||
@@ -293,14 +290,15 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
|
||||
</span>
|
||||
)} */}
|
||||
</p>
|
||||
<VSCodeCheckbox
|
||||
<Checkbox
|
||||
checked={apiConfiguration?.openRouterUseMiddleOutTransform || false}
|
||||
onChange={(e: any) => {
|
||||
const isChecked = e.target.checked === true
|
||||
setApiConfiguration({ ...apiConfiguration, openRouterUseMiddleOutTransform: isChecked })
|
||||
onChange={(checked: boolean) => {
|
||||
handleInputChange("openRouterUseMiddleOutTransform")({
|
||||
target: { value: checked },
|
||||
})
|
||||
}}>
|
||||
Compress prompts and message chains to the context size (<a href="https://openrouter.ai/docs/transforms">OpenRouter Transforms</a>)
|
||||
</VSCodeCheckbox>
|
||||
</Checkbox>
|
||||
<br />
|
||||
</div>
|
||||
)}
|
||||
@@ -335,45 +333,44 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
|
||||
<label htmlFor="aws-region-dropdown">
|
||||
<span style={{ fontWeight: 500 }}>AWS Region</span>
|
||||
</label>
|
||||
<VSCodeDropdown
|
||||
<Dropdown
|
||||
id="aws-region-dropdown"
|
||||
value={apiConfiguration?.awsRegion || ""}
|
||||
style={{ width: "100%" }}
|
||||
onChange={handleInputChange("awsRegion")}>
|
||||
<VSCodeOption value="">Select a region...</VSCodeOption>
|
||||
{/* 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-1</VSCodeOption>
|
||||
<VSCodeOption value="us-east-2">us-east-2</VSCodeOption>
|
||||
{/* <VSCodeOption value="us-west-1">us-west-1</VSCodeOption> */}
|
||||
<VSCodeOption value="us-west-2">us-west-2</VSCodeOption>
|
||||
{/* <VSCodeOption value="af-south-1">af-south-1</VSCodeOption> */}
|
||||
{/* <VSCodeOption value="ap-east-1">ap-east-1</VSCodeOption> */}
|
||||
<VSCodeOption value="ap-south-1">ap-south-1</VSCodeOption>
|
||||
<VSCodeOption value="ap-northeast-1">ap-northeast-1</VSCodeOption>
|
||||
<VSCodeOption value="ap-northeast-2">ap-northeast-2</VSCodeOption>
|
||||
{/* <VSCodeOption value="ap-northeast-3">ap-northeast-3</VSCodeOption> */}
|
||||
<VSCodeOption value="ap-southeast-1">ap-southeast-1</VSCodeOption>
|
||||
<VSCodeOption value="ap-southeast-2">ap-southeast-2</VSCodeOption>
|
||||
<VSCodeOption value="ca-central-1">ca-central-1</VSCodeOption>
|
||||
<VSCodeOption value="eu-central-1">eu-central-1</VSCodeOption>
|
||||
<VSCodeOption value="eu-west-1">eu-west-1</VSCodeOption>
|
||||
<VSCodeOption value="eu-west-2">eu-west-2</VSCodeOption>
|
||||
<VSCodeOption value="eu-west-3">eu-west-3</VSCodeOption>
|
||||
{/* <VSCodeOption value="eu-north-1">eu-north-1</VSCodeOption> */}
|
||||
{/* <VSCodeOption value="me-south-1">me-south-1</VSCodeOption> */}
|
||||
<VSCodeOption value="sa-east-1">sa-east-1</VSCodeOption>
|
||||
<VSCodeOption value="us-gov-west-1">us-gov-west-1</VSCodeOption>
|
||||
{/* <VSCodeOption value="us-gov-east-1">us-gov-east-1</VSCodeOption> */}
|
||||
</VSCodeDropdown>
|
||||
onChange={(value: unknown) => {handleInputChange("awsRegion")({
|
||||
target: {
|
||||
value: (value as DropdownOption).value
|
||||
}
|
||||
})}}
|
||||
options={[
|
||||
{ value: "", label: "Select a region..." },
|
||||
{ value: "us-east-1", label: "us-east-1" },
|
||||
{ value: "us-east-2", label: "us-east-2" },
|
||||
{ value: "us-west-2", label: "us-west-2" },
|
||||
{ value: "ap-south-1", label: "ap-south-1" },
|
||||
{ value: "ap-northeast-1", label: "ap-northeast-1" },
|
||||
{ value: "ap-northeast-2", label: "ap-northeast-2" },
|
||||
{ value: "ap-southeast-1", label: "ap-southeast-1" },
|
||||
{ value: "ap-southeast-2", label: "ap-southeast-2" },
|
||||
{ value: "ca-central-1", label: "ca-central-1" },
|
||||
{ value: "eu-central-1", label: "eu-central-1" },
|
||||
{ value: "eu-west-1", label: "eu-west-1" },
|
||||
{ value: "eu-west-2", label: "eu-west-2" },
|
||||
{ value: "eu-west-3", label: "eu-west-3" },
|
||||
{ value: "sa-east-1", label: "sa-east-1" },
|
||||
{ value: "us-gov-west-1", label: "us-gov-west-1" }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<VSCodeCheckbox
|
||||
<Checkbox
|
||||
checked={apiConfiguration?.awsUseCrossRegionInference || false}
|
||||
onChange={(e: any) => {
|
||||
const isChecked = e.target.checked === true
|
||||
setApiConfiguration({ ...apiConfiguration, awsUseCrossRegionInference: isChecked })
|
||||
onChange={(checked: boolean) => {
|
||||
handleInputChange("awsUseCrossRegionInference")({
|
||||
target: { value: checked },
|
||||
})
|
||||
}}>
|
||||
Use cross-region inference
|
||||
</VSCodeCheckbox>
|
||||
</Checkbox>
|
||||
<p
|
||||
style={{
|
||||
fontSize: "12px",
|
||||
@@ -400,18 +397,24 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
|
||||
<label htmlFor="vertex-region-dropdown">
|
||||
<span style={{ fontWeight: 500 }}>Google Cloud Region</span>
|
||||
</label>
|
||||
<VSCodeDropdown
|
||||
<Dropdown
|
||||
id="vertex-region-dropdown"
|
||||
value={apiConfiguration?.vertexRegion || ""}
|
||||
style={{ width: "100%" }}
|
||||
onChange={handleInputChange("vertexRegion")}>
|
||||
<VSCodeOption value="">Select a region...</VSCodeOption>
|
||||
<VSCodeOption value="us-east5">us-east5</VSCodeOption>
|
||||
<VSCodeOption value="us-central1">us-central1</VSCodeOption>
|
||||
<VSCodeOption value="europe-west1">europe-west1</VSCodeOption>
|
||||
<VSCodeOption value="europe-west4">europe-west4</VSCodeOption>
|
||||
<VSCodeOption value="asia-southeast1">asia-southeast1</VSCodeOption>
|
||||
</VSCodeDropdown>
|
||||
onChange={(value: unknown) => {handleInputChange("vertexRegion")({
|
||||
target: {
|
||||
value: (value as DropdownOption).value
|
||||
}
|
||||
})}}
|
||||
options={[
|
||||
{ value: "", label: "Select a region..." },
|
||||
{ value: "us-east5", label: "us-east5" },
|
||||
{ value: "us-central1", label: "us-central1" },
|
||||
{ value: "europe-west1", label: "europe-west1" },
|
||||
{ value: "europe-west4", label: "europe-west4" },
|
||||
{ value: "asia-southeast1", label: "asia-southeast1" }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<p
|
||||
style={{
|
||||
@@ -484,29 +487,26 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
|
||||
</VSCodeTextField>
|
||||
<OpenAiModelPicker />
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<VSCodeCheckbox
|
||||
<Checkbox
|
||||
checked={apiConfiguration?.openAiStreamingEnabled ?? true}
|
||||
onChange={(e: any) => {
|
||||
const isChecked = e.target.checked
|
||||
setApiConfiguration({
|
||||
...apiConfiguration,
|
||||
openAiStreamingEnabled: isChecked
|
||||
onChange={(checked: boolean) => {
|
||||
handleInputChange("openAiStreamingEnabled")({
|
||||
target: { value: checked },
|
||||
})
|
||||
}}>
|
||||
Enable streaming
|
||||
</VSCodeCheckbox>
|
||||
</Checkbox>
|
||||
</div>
|
||||
<VSCodeCheckbox
|
||||
<Checkbox
|
||||
checked={azureApiVersionSelected}
|
||||
onChange={(e: any) => {
|
||||
const isChecked = e.target.checked === true
|
||||
setAzureApiVersionSelected(isChecked)
|
||||
if (!isChecked) {
|
||||
onChange={(checked: boolean) => {
|
||||
setAzureApiVersionSelected(checked)
|
||||
if (!checked) {
|
||||
setApiConfiguration({ ...apiConfiguration, azureApiVersion: "" })
|
||||
}
|
||||
}}>
|
||||
Set Azure API version
|
||||
</VSCodeCheckbox>
|
||||
</Checkbox>
|
||||
{azureApiVersionSelected && (
|
||||
<VSCodeTextField
|
||||
value={apiConfiguration?.azureApiVersion || ""}
|
||||
@@ -633,29 +633,28 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
|
||||
<span style={{ fontWeight: 500 }}>Language Model</span>
|
||||
</label>
|
||||
{vsCodeLmModels.length > 0 ? (
|
||||
<VSCodeDropdown
|
||||
<Dropdown
|
||||
id="vscode-lm-model"
|
||||
value={apiConfiguration?.vsCodeLmModelSelector ?
|
||||
`${apiConfiguration.vsCodeLmModelSelector.vendor ?? ""}/${apiConfiguration.vsCodeLmModelSelector.family ?? ""}` :
|
||||
""}
|
||||
onChange={(e) => {
|
||||
const value = (e.target as HTMLInputElement).value;
|
||||
const [vendor, family] = value.split('/');
|
||||
onChange={(value: unknown) => {
|
||||
const valueStr = (value as DropdownOption).value;
|
||||
const [vendor, family] = valueStr.split('/');
|
||||
setApiConfiguration({
|
||||
...apiConfiguration,
|
||||
vsCodeLmModelSelector: value ? { vendor, family } : undefined
|
||||
vsCodeLmModelSelector: valueStr ? { vendor, family } : undefined
|
||||
});
|
||||
}}
|
||||
style={{ width: "100%" }}>
|
||||
<VSCodeOption value="">Select a model...</VSCodeOption>
|
||||
{vsCodeLmModels.map((model) => (
|
||||
<VSCodeOption
|
||||
key={`${model.vendor}/${model.family}`}
|
||||
value={`${model.vendor}/${model.family}`}>
|
||||
{model.vendor} - {model.family}
|
||||
</VSCodeOption>
|
||||
))}
|
||||
</VSCodeDropdown>
|
||||
style={{ width: "100%" }}
|
||||
options={[
|
||||
{ value: "", label: "Select a model..." },
|
||||
...vsCodeLmModels.map((model) => ({
|
||||
value: `${model.vendor}/${model.family}`,
|
||||
label: `${model.vendor} - ${model.family}`
|
||||
}))
|
||||
]}
|
||||
/>
|
||||
) : (
|
||||
<p style={{
|
||||
fontSize: "12px",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { VSCodeLink, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
import debounce from "debounce"
|
||||
import { Fzf } from "fzf"
|
||||
import React, { KeyboardEvent, memo, useEffect, useMemo, useRef, useState } from "react"
|
||||
import { useRemark } from "react-remark"
|
||||
@@ -44,8 +45,24 @@ const GlamaModelPicker: React.FC = () => {
|
||||
}
|
||||
}, [apiConfiguration, searchTerm])
|
||||
|
||||
const debouncedRefreshModels = useMemo(
|
||||
() =>
|
||||
debounce(
|
||||
() => {
|
||||
vscode.postMessage({ type: "refreshGlamaModels" })
|
||||
},
|
||||
50
|
||||
),
|
||||
[]
|
||||
)
|
||||
|
||||
useMount(() => {
|
||||
vscode.postMessage({ type: "refreshGlamaModels" })
|
||||
debouncedRefreshModels()
|
||||
|
||||
// Cleanup debounced function
|
||||
return () => {
|
||||
debouncedRefreshModels.clear()
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { VSCodeLink, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
import { Fzf } from "fzf"
|
||||
import React, { KeyboardEvent, memo, useEffect, useMemo, useRef, useState } from "react"
|
||||
import debounce from "debounce"
|
||||
import { useRemark } from "react-remark"
|
||||
import styled from "styled-components"
|
||||
import { useExtensionState } from "../../context/ExtensionStateContext"
|
||||
@@ -34,18 +35,38 @@ const OpenAiModelPicker: React.FC = () => {
|
||||
}
|
||||
}, [apiConfiguration, searchTerm])
|
||||
|
||||
const debouncedRefreshModels = useMemo(
|
||||
() =>
|
||||
debounce(
|
||||
(baseUrl: string, apiKey: string) => {
|
||||
vscode.postMessage({
|
||||
type: "refreshOpenAiModels",
|
||||
values: {
|
||||
baseUrl,
|
||||
apiKey
|
||||
}
|
||||
})
|
||||
},
|
||||
50
|
||||
),
|
||||
[]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (!apiConfiguration?.openAiBaseUrl || !apiConfiguration?.openAiApiKey) {
|
||||
return
|
||||
}
|
||||
|
||||
vscode.postMessage({
|
||||
type: "refreshOpenAiModels", values: {
|
||||
baseUrl: apiConfiguration?.openAiBaseUrl,
|
||||
apiKey: apiConfiguration?.openAiApiKey
|
||||
}
|
||||
})
|
||||
}, [apiConfiguration?.openAiBaseUrl, apiConfiguration?.openAiApiKey])
|
||||
debouncedRefreshModels(
|
||||
apiConfiguration.openAiBaseUrl,
|
||||
apiConfiguration.openAiApiKey
|
||||
)
|
||||
|
||||
// Cleanup debounced function
|
||||
return () => {
|
||||
debouncedRefreshModels.clear()
|
||||
}
|
||||
}, [apiConfiguration?.openAiBaseUrl, apiConfiguration?.openAiApiKey, debouncedRefreshModels])
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { VSCodeLink, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
import debounce from "debounce"
|
||||
import { Fzf } from "fzf"
|
||||
import React, { KeyboardEvent, memo, useEffect, useMemo, useRef, useState } from "react"
|
||||
import { useRemark } from "react-remark"
|
||||
@@ -43,8 +44,24 @@ const OpenRouterModelPicker: React.FC = () => {
|
||||
}
|
||||
}, [apiConfiguration, searchTerm])
|
||||
|
||||
const debouncedRefreshModels = useMemo(
|
||||
() =>
|
||||
debounce(
|
||||
() => {
|
||||
vscode.postMessage({ type: "refreshOpenRouterModels" })
|
||||
},
|
||||
50
|
||||
),
|
||||
[]
|
||||
)
|
||||
|
||||
useMount(() => {
|
||||
vscode.postMessage({ type: "refreshOpenRouterModels" })
|
||||
debouncedRefreshModels()
|
||||
|
||||
// Cleanup debounced function
|
||||
return () => {
|
||||
debouncedRefreshModels.clear()
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,14 +1,26 @@
|
||||
import '@testing-library/jest-dom';
|
||||
|
||||
// Mock window.matchMedia
|
||||
// Mock crypto.getRandomValues
|
||||
Object.defineProperty(window, 'crypto', {
|
||||
value: {
|
||||
getRandomValues: function(buffer: Uint8Array) {
|
||||
for (let i = 0; i < buffer.length; i++) {
|
||||
buffer[i] = Math.floor(Math.random() * 256);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Mock matchMedia
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
writable: true,
|
||||
value: jest.fn().mockImplementation(query => ({
|
||||
matches: false,
|
||||
media: query,
|
||||
onchange: null,
|
||||
addListener: jest.fn(), // Deprecated
|
||||
removeListener: jest.fn(), // Deprecated
|
||||
addListener: jest.fn(), // deprecated
|
||||
removeListener: jest.fn(), // deprecated
|
||||
addEventListener: jest.fn(),
|
||||
removeEventListener: jest.fn(),
|
||||
dispatchEvent: jest.fn(),
|
||||
|
||||
Reference in New Issue
Block a user