mirror of
https://github.com/cline/cline.git
synced 2026-09-01 15:11:04 +08:00
Limit the CLI provider list to what's remotely configured (#9135)
* Limit the CLI provider list to what's remotely configured * Refactor * fix react
This commit is contained in:
+1
-1
@@ -43,7 +43,7 @@
|
||||
"a11y": "info",
|
||||
"style": {
|
||||
"useNodejsImportProtocol": "off",
|
||||
"useImportType": "info",
|
||||
"useImportType": "off",
|
||||
"useBlockStatements": "off",
|
||||
"useNamingConvention": "off",
|
||||
"useThrowOnlyError": "info",
|
||||
|
||||
@@ -19,6 +19,7 @@ import { useScrollableList } from "../hooks/useScrollableList"
|
||||
import { type DetectedSources, detectImportSources, type ImportSource } from "../utils/import-configs"
|
||||
import { isMouseEscapeSequence } from "../utils/input"
|
||||
import { applyBedrockConfig, applyProviderConfig } from "../utils/provider-config"
|
||||
import { useValidProviders } from "../utils/providers"
|
||||
import { ApiKeyInput } from "./ApiKeyInput"
|
||||
import { StaticRobotFrame } from "./AsciiMotionCli"
|
||||
import { type BedrockConfig, BedrockSetup } from "./BedrockSetup"
|
||||
@@ -30,7 +31,7 @@ import {
|
||||
} from "./FeaturedModelPicker"
|
||||
import { ImportView } from "./ImportView"
|
||||
import { getDefaultModelId, hasModelPicker, ModelPicker } from "./ModelPicker"
|
||||
import { CLI_EXCLUDED_PROVIDERS, getProviderLabel, getProviderOrder } from "./ProviderPicker"
|
||||
import { getProviderLabel } from "./ProviderPicker"
|
||||
|
||||
type AuthStep =
|
||||
| "menu"
|
||||
@@ -146,6 +147,9 @@ const TextInput: React.FC<{
|
||||
|
||||
export const AuthView: React.FC<AuthViewProps> = ({ controller, onComplete, onError, onNavigateToWelcome }) => {
|
||||
const { exit } = useApp()
|
||||
|
||||
const providers = useValidProviders()
|
||||
|
||||
const [step, setStep] = useState<AuthStep>("menu")
|
||||
const [selectedProvider, setSelectedProvider] = useState<string>(
|
||||
StateManager.get().getApiConfiguration().actModeApiProvider ||
|
||||
@@ -187,11 +191,6 @@ export const AuthView: React.FC<AuthViewProps> = ({ controller, onComplete, onEr
|
||||
onError: handleOcaAuthError,
|
||||
})
|
||||
|
||||
// Use providers.json order, filtered to exclude CLI-incompatible providers
|
||||
const sortedProviders = useMemo(() => {
|
||||
return getProviderOrder().filter((p) => !CLI_EXCLUDED_PROVIDERS.has(p))
|
||||
}, [])
|
||||
|
||||
// Main menu items - conditionally include import options
|
||||
const mainMenuItems: SelectItem[] = useMemo(() => {
|
||||
const items: SelectItem[] = [{ label: "Sign in with Cline", value: "cline_auth" }]
|
||||
@@ -217,15 +216,13 @@ export const AuthView: React.FC<AuthViewProps> = ({ controller, onComplete, onEr
|
||||
const providerItems: SelectItem[] = useMemo(() => {
|
||||
const search = providerSearch.toLowerCase()
|
||||
const filtered = providerSearch
|
||||
? sortedProviders.filter(
|
||||
(p) => p.toLowerCase().includes(search) || getProviderLabel(p).toLowerCase().includes(search),
|
||||
)
|
||||
: sortedProviders
|
||||
? providers.filter((p) => p.toLowerCase().includes(search) || getProviderLabel(p).toLowerCase().includes(search))
|
||||
: providers
|
||||
return filtered.map((p: string) => ({
|
||||
label: getProviderLabel(p),
|
||||
value: p,
|
||||
}))
|
||||
}, [sortedProviders, providerSearch])
|
||||
}, [providers, providerSearch])
|
||||
|
||||
// Use shared scrollable list hook for provider windowing
|
||||
const TOTAL_PROVIDER_ROWS = 8
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
import React, { useMemo } from "react"
|
||||
import { StateManager } from "@/core/storage/StateManager"
|
||||
import type { ApiConfiguration } from "@/shared/api"
|
||||
import { CLI_EXCLUDED_PROVIDERS, getProviderLabel, getProviderOrder } from "../utils/providers"
|
||||
import { SearchableList, SearchableListItem } from "./SearchableList"
|
||||
import { getProviderLabel, useValidProviders } from "../utils/providers"
|
||||
import { SearchableList, type SearchableListItem } from "./SearchableList"
|
||||
|
||||
// Re-export for backwards compatibility
|
||||
export { CLI_EXCLUDED_PROVIDERS, getProviderLabel, getProviderOrder }
|
||||
export { getProviderLabel }
|
||||
|
||||
/**
|
||||
* Check if a provider is configured (has required credentials/settings)
|
||||
@@ -125,17 +125,16 @@ interface ProviderPickerProps {
|
||||
export const ProviderPicker: React.FC<ProviderPickerProps> = ({ onSelect, isActive = true }) => {
|
||||
// Get API configuration to check which providers are configured
|
||||
const apiConfig = StateManager.get().getApiConfiguration()
|
||||
const sorted = useValidProviders()
|
||||
|
||||
// Use providers.json order, filtered to exclude CLI-incompatible providers
|
||||
const items: SearchableListItem[] = useMemo(() => {
|
||||
const sorted = getProviderOrder().filter((p: string) => !CLI_EXCLUDED_PROVIDERS.has(p))
|
||||
|
||||
return sorted.map((providerId: string) => ({
|
||||
id: providerId,
|
||||
label: getProviderLabel(providerId),
|
||||
suffix: isProviderConfigured(providerId, apiConfig) ? "(Configured)" : undefined,
|
||||
}))
|
||||
}, [apiConfig])
|
||||
}, [apiConfig, sorted])
|
||||
|
||||
return <SearchableList isActive={isActive} items={items} onSelect={(item) => onSelect(item.id)} />
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
* Used by both UI components and CLI commands
|
||||
*/
|
||||
|
||||
import { useMemo } from "react"
|
||||
import { StateManager } from "@/core/storage/StateManager"
|
||||
import providersData from "@/shared/providers/providers.json"
|
||||
import type { RemoteConfigFields } from "@/shared/storage/state-keys"
|
||||
|
||||
// Create a lookup map from provider value to display label
|
||||
const providerLabels: Record<string, string> = Object.fromEntries(
|
||||
@@ -17,7 +20,7 @@ const providerOrder: string[] = providersData.list.map((p: { value: string }) =>
|
||||
* Providers that are not supported in CLI.
|
||||
* - vscode-lm: Requires VS Code's Language Model API (see ENG-1490 for OAuth-based support)
|
||||
*/
|
||||
export const CLI_EXCLUDED_PROVIDERS = new Set<string>(["vscode-lm"])
|
||||
const CLI_EXCLUDED_PROVIDERS = new Set<string>(["vscode-lm"])
|
||||
|
||||
/**
|
||||
* Get the display label for a provider ID
|
||||
@@ -29,7 +32,7 @@ export function getProviderLabel(providerId: string): string {
|
||||
/**
|
||||
* Get the ordered list of all provider IDs (from providers.json)
|
||||
*/
|
||||
export function getProviderOrder(): string[] {
|
||||
function getProviderOrder(): string[] {
|
||||
return providerOrder
|
||||
}
|
||||
|
||||
@@ -46,3 +49,19 @@ export function getValidCliProviders(): string[] {
|
||||
export function isValidCliProvider(providerId: string): boolean {
|
||||
return providerOrder.includes(providerId) && !CLI_EXCLUDED_PROVIDERS.has(providerId)
|
||||
}
|
||||
|
||||
const getValidProviders = (remoteConfig: Partial<RemoteConfigFields> | undefined) => {
|
||||
if (remoteConfig?.remoteConfiguredProviders?.length) {
|
||||
return remoteConfig.remoteConfiguredProviders
|
||||
}
|
||||
|
||||
return getProviderOrder().filter((p: string) => !CLI_EXCLUDED_PROVIDERS.has(p))
|
||||
}
|
||||
|
||||
export const useValidProviders = () => {
|
||||
const remoteConfig = StateManager.get().getRemoteConfigSettings()
|
||||
|
||||
return useMemo(() => {
|
||||
return getValidProviders(remoteConfig)
|
||||
}, [remoteConfig])
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { ModelInfo as ModelInfoType } from "@shared/api"
|
||||
import { ANTHROPIC_MIN_THINKING_BUDGET, ApiProvider } from "@shared/api"
|
||||
import { ANTHROPIC_MIN_THINKING_BUDGET, type ApiProvider } from "@shared/api"
|
||||
import { StringRequest } from "@shared/proto/cline/common"
|
||||
import { UpdateSettingsRequest } from "@shared/proto/cline/state"
|
||||
import { Mode } from "@shared/storage/types"
|
||||
import type { Mode } from "@shared/storage/types"
|
||||
import { ArrowLeftRight, Brain, Check, ChevronDownIcon, Search, Settings } from "lucide-react"
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"
|
||||
import type React from "react"
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
|
||||
import { createPortal } from "react-dom"
|
||||
import { useWindowSize } from "react-use"
|
||||
import styled from "styled-components"
|
||||
@@ -163,12 +164,8 @@ const ModelPickerModal: React.FC<ModelPickerModalProps> = ({ isOpen, onOpenChang
|
||||
|
||||
// Get configured providers
|
||||
const configuredProviders = useMemo(() => {
|
||||
if (remoteConfigSettings?.remoteConfiguredProviders?.length) {
|
||||
return remoteConfigSettings.remoteConfiguredProviders
|
||||
}
|
||||
|
||||
return getConfiguredProviders(apiConfiguration)
|
||||
}, [apiConfiguration, remoteConfigSettings?.remoteConfiguredProviders])
|
||||
return getConfiguredProviders(remoteConfigSettings, apiConfiguration)
|
||||
}, [apiConfiguration, remoteConfigSettings])
|
||||
|
||||
// Get models for current provider
|
||||
const allModels = useMemo((): ModelItem[] => {
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
import { ApiConfiguration, ApiProvider } from "@shared/api"
|
||||
import type { ApiConfiguration, ApiProvider } from "@shared/api"
|
||||
import PROVIDERS from "@shared/providers/providers.json"
|
||||
import type { RemoteConfigFields } from "@shared/storage/state-keys"
|
||||
|
||||
/**
|
||||
* Returns a list of API providers that are configured (have required credentials/settings)
|
||||
* Based on validation logic from validate.ts
|
||||
*/
|
||||
export function getConfiguredProviders(apiConfiguration: ApiConfiguration | undefined): ApiProvider[] {
|
||||
export function getConfiguredProviders(
|
||||
remoteConfig: Partial<RemoteConfigFields> | undefined,
|
||||
apiConfiguration: ApiConfiguration | undefined,
|
||||
): ApiProvider[] {
|
||||
if (remoteConfig?.remoteConfiguredProviders?.length) {
|
||||
return remoteConfig.remoteConfiguredProviders
|
||||
}
|
||||
|
||||
const configured: ApiProvider[] = []
|
||||
|
||||
if (!apiConfiguration) {
|
||||
|
||||
Reference in New Issue
Block a user