mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-06 08:18:39 +00:00
provider config UI changes and ExtensionStateContext loading state
This commit is contained in:
parent
605a00921b
commit
656bb9f4d0
8 changed files with 109 additions and 19 deletions
|
|
@ -72,7 +72,7 @@ const ApiOptions = ({
|
|||
setErrorMessage,
|
||||
}: ApiOptionsProps) => {
|
||||
const { t } = useAppTranslation()
|
||||
const { organizationAllowList } = useExtensionState()
|
||||
const { organizationAllowList, areProviderModelsLoading } = useExtensionState()
|
||||
|
||||
const refetchRouterModels = useCallback(() => {
|
||||
vscode.postMessage({
|
||||
|
|
@ -130,11 +130,16 @@ const ApiOptions = ({
|
|||
}
|
||||
}, [selectedModelId, setApiConfigurationField])
|
||||
|
||||
// Validation logic using the global loading state
|
||||
useEffect(() => {
|
||||
const apiValidationResult = validateApiConfiguration(apiConfiguration, organizationAllowList)
|
||||
|
||||
setErrorMessage(apiValidationResult)
|
||||
}, [apiConfiguration, organizationAllowList, setErrorMessage])
|
||||
if (!areProviderModelsLoading) {
|
||||
// Only validate if provider models are not currently loading
|
||||
const apiValidationResult = validateApiConfiguration(apiConfiguration, organizationAllowList)
|
||||
setErrorMessage(apiValidationResult)
|
||||
} else {
|
||||
setErrorMessage(undefined)
|
||||
}
|
||||
}, [apiConfiguration, organizationAllowList, setErrorMessage, areProviderModelsLoading])
|
||||
|
||||
const selectedProviderModels = useMemo(() => {
|
||||
const models = MODELS_BY_PROVIDER[selectedProvider]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useCallback } from "react"
|
||||
import { useCallback, useMemo } from "react"
|
||||
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import type { ProviderSettings, OrganizationAllowList } from "@roo-code/types"
|
||||
|
|
@ -22,7 +22,19 @@ type GlamaProps = {
|
|||
export const Glama = ({ apiConfiguration, setApiConfigurationField, uriScheme, organizationAllowList }: GlamaProps) => {
|
||||
const { t } = useAppTranslation()
|
||||
|
||||
const { models: glamaModelsData, isLoading: isLoadingModels, error: modelsError } = useProviderModels("glama")
|
||||
const providerModelsOptions = useMemo(
|
||||
() => ({
|
||||
flushCacheFirst: true,
|
||||
}),
|
||||
[],
|
||||
)
|
||||
|
||||
const {
|
||||
models: glamaModelsData,
|
||||
isLoading: isLoadingModels,
|
||||
error: modelsError,
|
||||
refetch: refetchGlamaModels,
|
||||
} = useProviderModels("glama", providerModelsOptions)
|
||||
|
||||
const handleInputChange = useCallback(
|
||||
<K extends keyof ProviderSettings, E>(
|
||||
|
|
@ -70,6 +82,7 @@ export const Glama = ({ apiConfiguration, setApiConfigurationField, uriScheme, o
|
|||
serviceName="Glama"
|
||||
serviceUrl="https://glama.ai/models"
|
||||
organizationAllowList={organizationAllowList}
|
||||
onOpenRefetch={refetchGlamaModels}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useCallback } from "react"
|
||||
import { useCallback, useMemo } from "react"
|
||||
import { VSCodeTextField, VSCodeRadioGroup, VSCodeRadio } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import type { ProviderSettings } from "@roo-code/types"
|
||||
|
|
@ -15,7 +15,20 @@ type OllamaProps = {
|
|||
export const Ollama = ({ apiConfiguration, setApiConfigurationField }: OllamaProps) => {
|
||||
const { t } = useAppTranslation()
|
||||
|
||||
const { models: ollamaModelsData, isLoading: isLoadingModels, error: modelsError } = useProviderModels("ollama")
|
||||
const providerModelsOptions = useMemo(
|
||||
() => ({
|
||||
flushCacheFirst: true,
|
||||
baseUrl: apiConfiguration?.ollamaBaseUrl,
|
||||
}),
|
||||
[apiConfiguration?.ollamaBaseUrl],
|
||||
)
|
||||
|
||||
const {
|
||||
models: ollamaModelsData,
|
||||
isLoading: isLoadingModels,
|
||||
error: modelsError,
|
||||
// refetch is not used directly by this component for now
|
||||
} = useProviderModels("ollama", providerModelsOptions)
|
||||
|
||||
const handleInputChange = useCallback(
|
||||
<K extends keyof ProviderSettings, E>(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useState, useCallback, useEffect } from "react"
|
||||
import { useState, useCallback, useEffect, useMemo } from "react"
|
||||
import { Checkbox } from "vscrui"
|
||||
import { VSCodeButton, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
|
|
@ -32,11 +32,24 @@ export const OpenAICompatible = ({
|
|||
const [azureApiVersionSelected, setAzureApiVersionSelected] = useState(!!apiConfiguration?.azureApiVersion)
|
||||
const [openAiLegacyFormatSelected, setOpenAiLegacyFormatSelected] = useState(!!apiConfiguration?.openAiLegacyFormat)
|
||||
|
||||
const providerModelsOptions = useMemo(() => {
|
||||
if (!apiConfiguration?.openAiBaseUrl) {
|
||||
return undefined
|
||||
}
|
||||
return {
|
||||
flushCacheFirst: true,
|
||||
baseUrl: apiConfiguration.openAiBaseUrl,
|
||||
apiKey: apiConfiguration?.openAiApiKey,
|
||||
openAiHeaders: apiConfiguration?.openAiHeaders,
|
||||
}
|
||||
}, [apiConfiguration?.openAiBaseUrl, apiConfiguration?.openAiApiKey, apiConfiguration?.openAiHeaders])
|
||||
|
||||
const {
|
||||
models: openAiCompatibleModels,
|
||||
isLoading: isLoadingOpenAiCompatibleModels,
|
||||
error: openAiCompatibleModelsError,
|
||||
} = useProviderModels("openai-compatible")
|
||||
refetch: refetchOpenAiCompatibleModels,
|
||||
} = useProviderModels("openai-compatible", providerModelsOptions)
|
||||
|
||||
const [customHeaders, setCustomHeaders] = useState<[string, string][]>(() => {
|
||||
const headers = apiConfiguration?.openAiHeaders || {}
|
||||
|
|
@ -131,6 +144,7 @@ export const OpenAICompatible = ({
|
|||
serviceName="OpenAI"
|
||||
serviceUrl="https://platform.openai.com"
|
||||
organizationAllowList={organizationAllowList}
|
||||
onOpenRefetch={refetchOpenAiCompatibleModels}
|
||||
/>
|
||||
<R1FormatSetting
|
||||
onChange={handleInputChange("openAiR1FormatEnabled", noTransform)}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useCallback } from "react"
|
||||
import { useCallback, useMemo } from "react"
|
||||
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import type { ProviderSettings, OrganizationAllowList } from "@roo-code/types"
|
||||
|
|
@ -23,7 +23,20 @@ type RequestyProps = {
|
|||
export const Requesty = ({ apiConfiguration, setApiConfigurationField, organizationAllowList }: RequestyProps) => {
|
||||
const { t } = useAppTranslation()
|
||||
|
||||
const { models: requestyModelsData, isLoading: isLoadingModels, error: modelsError } = useProviderModels("requesty")
|
||||
const providerModelsOptions = useMemo(
|
||||
() => ({
|
||||
flushCacheFirst: true,
|
||||
requestyApiKey: apiConfiguration?.requestyApiKey,
|
||||
}),
|
||||
[apiConfiguration?.requestyApiKey],
|
||||
)
|
||||
|
||||
const {
|
||||
models: requestyModelsData,
|
||||
isLoading: isLoadingModels,
|
||||
error: modelsError,
|
||||
refetch: refetchRequestyModels,
|
||||
} = useProviderModels("requesty", providerModelsOptions)
|
||||
|
||||
const handleInputChange = useCallback(
|
||||
<K extends keyof ProviderSettings, E>(
|
||||
|
|
@ -83,6 +96,7 @@ export const Requesty = ({ apiConfiguration, setApiConfigurationField, organizat
|
|||
serviceName="Requesty"
|
||||
serviceUrl="https://requesty.ai"
|
||||
organizationAllowList={organizationAllowList}
|
||||
onOpenRefetch={refetchRequestyModels}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useCallback, useState, useEffect, useRef } from "react"
|
||||
import { useCallback, useState, useEffect, useRef, useMemo } from "react"
|
||||
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
|
||||
import type { ProviderSettings, OrganizationAllowList } from "@roo-code/types"
|
||||
|
|
@ -20,7 +20,20 @@ type UnboundProps = {
|
|||
export const Unbound = ({ apiConfiguration, setApiConfigurationField, organizationAllowList }: UnboundProps) => {
|
||||
const { t } = useAppTranslation()
|
||||
|
||||
const { models: unboundModelsData, isLoading: isLoadingModels, error: modelsError } = useProviderModels("unbound")
|
||||
const providerModelsOptions = useMemo(
|
||||
() => ({
|
||||
flushCacheFirst: true,
|
||||
unboundApiKey: apiConfiguration?.unboundApiKey,
|
||||
}),
|
||||
[apiConfiguration?.unboundApiKey],
|
||||
)
|
||||
|
||||
const {
|
||||
models: unboundModelsData,
|
||||
isLoading: isLoadingModels,
|
||||
error: modelsError,
|
||||
refetch: refetchUnboundModels,
|
||||
} = useProviderModels("unbound", providerModelsOptions)
|
||||
|
||||
const [isInvalidKeyFeedback, setIsInvalidKeyFeedback] = useState<boolean>(false)
|
||||
const invalidKeyTimerRef = useRef<NodeJS.Timeout>()
|
||||
|
|
@ -101,6 +114,7 @@ export const Unbound = ({ apiConfiguration, setApiConfigurationField, organizati
|
|||
serviceUrl="https://api.getunbound.ai/models"
|
||||
setApiConfigurationField={setApiConfigurationField}
|
||||
organizationAllowList={organizationAllowList}
|
||||
onOpenRefetch={refetchUnboundModels}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,19 +5,20 @@ import { RouterName, ModelRecord } from "@roo/api"
|
|||
import { ExtensionMessage } from "@roo/ExtensionMessage"
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
import { useDebounceEffect } from "@src/utils/useDebounceEffect"
|
||||
import { useExtensionState } from "@src/context/ExtensionStateContext"
|
||||
|
||||
// --- START: Type definitions for provider-specific params ---
|
||||
// Inspired by GetModelsOptions from src/shared/api.ts
|
||||
// These are the *additional* params a provider might need, sent from the UI.
|
||||
export type ProviderSpecificParamsMap = {
|
||||
openrouter: Record<string, never>
|
||||
glama: Record<string, never>
|
||||
openrouter: object
|
||||
glama: object
|
||||
requesty: { requestyApiKey?: string }
|
||||
unbound: { unboundApiKey?: string }
|
||||
litellm: { litellmApiKey?: string; litellmBaseUrl?: string }
|
||||
ollama: { baseUrl?: string }
|
||||
lmstudio: { baseUrl?: string }
|
||||
vscodelm: Record<string, never>
|
||||
vscodelm: object
|
||||
"openai-compatible": {
|
||||
baseUrl: string
|
||||
apiKey?: string
|
||||
|
|
@ -103,6 +104,7 @@ export const useProviderModels = <P extends RouterName>(
|
|||
options?: UseProviderModelsOptions<P>,
|
||||
): UseProviderModelsResult => {
|
||||
const queryClient = useQueryClient()
|
||||
const { setAreProviderModelsLoading } = useExtensionState()
|
||||
|
||||
// Track if we're currently debouncing
|
||||
const debouncingRef = useRef(false)
|
||||
|
|
@ -171,6 +173,13 @@ export const useProviderModels = <P extends RouterName>(
|
|||
// Clear error when in loading state
|
||||
const error = isLoading ? undefined : queryError?.message
|
||||
|
||||
// Update global loading state
|
||||
useEffect(() => {
|
||||
if (setAreProviderModelsLoading) {
|
||||
setAreProviderModelsLoading(isLoading)
|
||||
}
|
||||
}, [isLoading, setAreProviderModelsLoading])
|
||||
|
||||
return {
|
||||
models: data,
|
||||
isLoading,
|
||||
|
|
|
|||
|
|
@ -114,6 +114,8 @@ export interface ExtensionStateContextType extends ExtensionState {
|
|||
setAutoCondenseContext: (value: boolean) => void
|
||||
autoCondenseContextPercent: number
|
||||
setAutoCondenseContextPercent: (value: number) => void
|
||||
areProviderModelsLoading?: boolean
|
||||
setAreProviderModelsLoading?: (isLoading: boolean) => void
|
||||
}
|
||||
|
||||
export const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined)
|
||||
|
|
@ -146,7 +148,9 @@ export const mergeExtensionState = (prevState: ExtensionState, newState: Extensi
|
|||
}
|
||||
|
||||
export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const [state, setState] = useState<ExtensionState & { organizationAllowList?: OrganizationAllowList }>({
|
||||
const [state, setState] = useState<
|
||||
ExtensionState & { organizationAllowList?: OrganizationAllowList; areProviderModelsLoading?: boolean }
|
||||
>({
|
||||
version: "",
|
||||
clineMessages: [],
|
||||
taskHistory: [],
|
||||
|
|
@ -206,6 +210,7 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
|
|||
codebaseIndexEmbedderModelId: "",
|
||||
},
|
||||
codebaseIndexModels: { ollama: {}, openai: {} },
|
||||
areProviderModelsLoading: false,
|
||||
})
|
||||
|
||||
const [didHydrateState, setDidHydrateState] = useState(false)
|
||||
|
|
@ -391,6 +396,9 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
|
|||
setCondensingApiConfigId: (value) => setState((prevState) => ({ ...prevState, condensingApiConfigId: value })),
|
||||
setCustomCondensingPrompt: (value) =>
|
||||
setState((prevState) => ({ ...prevState, customCondensingPrompt: value })),
|
||||
areProviderModelsLoading: state.areProviderModelsLoading,
|
||||
setAreProviderModelsLoading: (isLoading: boolean) =>
|
||||
setState((prevState) => ({ ...prevState, areProviderModelsLoading: isLoading })),
|
||||
}
|
||||
|
||||
return <ExtensionStateContext.Provider value={contextValue}>{children}</ExtensionStateContext.Provider>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue