LLMs: centralize config UI into 1 function

This commit is contained in:
Enrico Ros
2025-07-16 08:55:31 -07:00
parent 0ac80b26bd
commit 9772a18bf4
19 changed files with 65 additions and 59 deletions
@@ -0,0 +1,62 @@
import * as React from 'react';
import type { DModelsService, DModelsServiceId } from '~/common/stores/llms/llms.service.types';
import { findModelVendor, ModelVendorId } from '../vendors/vendors.registry';
// direct imports for all vendor setup components - NOTE: we could lazy load if this becomes a performance issue
import { AlibabaServiceSetup } from '../vendors/alibaba/AlibabaServiceSetup';
import { AnthropicServiceSetup } from '../vendors/anthropic/AnthropicServiceSetup';
import { AzureServiceSetup } from '../vendors/azure/AzureServiceSetup';
import { DeepseekAIServiceSetup } from '../vendors/deepseek/DeepseekAIServiceSetup';
import { GeminiServiceSetup } from '../vendors/gemini/GeminiServiceSetup';
import { GroqServiceSetup } from '../vendors/groq/GroqServiceSetup';
import { LMStudioServiceSetup } from '../vendors/lmstudio/LMStudioServiceSetup';
import { LocalAIServiceSetup } from '../vendors/localai/LocalAIServiceSetup';
import { MistralServiceSetup } from '../vendors/mistral/MistralServiceSetup';
import { OllamaServiceSetup } from '../vendors/ollama/OllamaServiceSetup';
import { OpenAIServiceSetup } from '../vendors/openai/OpenAIServiceSetup';
import { OpenPipeServiceSetup } from '../vendors/openpipe/OpenPipeServiceSetup';
import { OpenRouterServiceSetup } from '../vendors/openrouter/OpenRouterServiceSetup';
import { PerplexityServiceSetup } from '../vendors/perplexity/PerplexityServiceSetup';
import { TogetherAIServiceSetup } from '../vendors/togetherai/TogetherAIServiceSetup';
import { XAIServiceSetup } from '../vendors/xai/XAIServiceSetup';
/**
* Hardcoded mapping with the setup components for each vendor.
* NOTE: we do it here to only depend on this file (even lazily) and avoid to import all the Components (UI)
* code on vendor definitions (which must be lightweight as it impacts boot time).
*/
const vendorSetupComponents: Record<ModelVendorId, React.ComponentType<{ serviceId: DModelsServiceId }>> = {
alibaba: AlibabaServiceSetup,
anthropic: AnthropicServiceSetup,
azure: AzureServiceSetup,
deepseek: DeepseekAIServiceSetup,
googleai: GeminiServiceSetup,
groq: GroqServiceSetup,
lmstudio: LMStudioServiceSetup,
localai: LocalAIServiceSetup,
mistral: MistralServiceSetup,
ollama: OllamaServiceSetup,
openai: OpenAIServiceSetup,
openpipe: OpenPipeServiceSetup,
openrouter: OpenRouterServiceSetup,
perplexity: PerplexityServiceSetup,
togetherai: TogetherAIServiceSetup,
xai: XAIServiceSetup,
} as const;
export function LLMVendorSetup(props: { service: DModelsService }) {
const vendor = findModelVendor(props.service.vId);
if (!vendor)
return 'Configuration issue: Vendor not found for Service ' + props.service.id;
const SetupComponent = vendorSetupComponents[vendor.id];
if (!SetupComponent)
return 'Configuration issue: Setup component not found for vendor ' + vendor.id;
return <SetupComponent key={props.service.id} serviceId={props.service.id} />;
}
+3 -11
View File
@@ -11,28 +11,20 @@ import { useHasLLMs, useModelsServices } from '~/common/stores/llms/llms.hooks';
import { useIsMobile } from '~/common/components/useMatchMedia';
import { LLMOptionsModal } from './LLMOptionsModal';
import { LLMVendorSetup } from '../components/LLMVendorSetup';
import { ModelsList } from './ModelsList';
import { ModelsServiceSelector } from './ModelsServiceSelector';
import { ModelsWizard } from './ModelsWizard';
import { findModelVendor } from '../vendors/vendors.registry';
// configuration
const MODELS_WIZARD_ENABLE_INITIALLY = true;
function VendorServiceSetup(props: { service: DModelsService }) {
const vendor = findModelVendor(props.service.vId);
if (!vendor)
return 'Configuration issue: Vendor not found for Service ' + props.service.id;
return <vendor.ServiceSetupComponent key={props.service.id} serviceId={props.service.id} />;
}
type TabValue = 'wizard' | 'setup' | 'defaults';
/**
* Note: the reason for this component separation from the parent state, is delayed state intitialization.
* Note: the reason for this component separation from the parent state, is delayed state initialization.
*/
function ModelsConfiguratorModal(props: {
modelsServices: DModelsService[],
@@ -148,7 +140,7 @@ function ModelsConfiguratorModal(props: {
{isTabSetup && (
<Box sx={{ display: 'grid', gap: 'var(--Card-padding)' }}>
{activeService
? <VendorServiceSetup service={activeService} />
? <LLMVendorSetup service={activeService} />
: <Box sx={{ minHeight: '7.375rem' }} />
}
</Box>
-2
View File
@@ -5,7 +5,6 @@ import type { SvgIconProps } from '@mui/joy';
import type { BackendCapabilities } from '~/modules/backend/store-backend-capabilities';
import type { DLLM } from '~/common/stores/llms/llms.types';
import type { DModelsServiceId } from '~/common/stores/llms/llms.service.types';
import type { ModelDescriptionSchema } from '../server/llm.server.types';
import type { ModelVendorId } from './vendors.registry';
@@ -24,7 +23,6 @@ export interface IModelVendor<TServiceSettings extends Record<string, any> = {},
// components
readonly Icon: React.FunctionComponent<SvgIconProps>;
readonly ServiceSetupComponent: React.ComponentType<{ serviceId: DModelsServiceId }>;
/// abstraction interface ///
-3
View File
@@ -4,8 +4,6 @@ import type { IModelVendor } from '../IModelVendor';
import type { OpenAIAccessSchema } from '../../server/openai/openai.router';
import { ModelVendorOpenAI } from '../openai/openai.vendor';
import { AlibabaServiceSetup } from './AlibabaServiceSetup';
interface DAlibabaServiceSettings {
alibabaOaiKey: string;
@@ -22,7 +20,6 @@ export const ModelVendorAlibaba: IModelVendor<DAlibabaServiceSettings, OpenAIAcc
// components
Icon: AlibabaCloudIcon,
ServiceSetupComponent: AlibabaServiceSetup,
// functions
initializeSetup: () => ({
@@ -4,8 +4,6 @@ import { apiAsync } from '~/common/util/trpc.client';
import type { AnthropicAccessSchema } from '../../server/anthropic/anthropic.router';
import type { IModelVendor } from '../IModelVendor';
import { AnthropicServiceSetup } from './AnthropicServiceSetup';
// special symbols
export const isValidAnthropicApiKey = (apiKey?: string) => !!apiKey && (apiKey.startsWith('sk-') ? apiKey.length >= 39 : apiKey.length > 1);
@@ -27,7 +25,6 @@ export const ModelVendorAnthropic: IModelVendor<DAnthropicServiceSettings, Anthr
// components
Icon: AnthropicIcon,
ServiceSetupComponent: AnthropicServiceSetup,
// functions
getTransportAccess: (partialSetup): AnthropicAccessSchema => ({
-3
View File
@@ -5,8 +5,6 @@ import type { OpenAIAccessSchema } from '../../server/openai/openai.router';
import { ModelVendorOpenAI } from '../openai/openai.vendor';
import { AzureServiceSetup } from './AzureServiceSetup';
// special symbols
export const isValidAzureApiKey = (apiKey?: string) => !!apiKey && apiKey.length >= 32;
@@ -42,7 +40,6 @@ export const ModelVendorAzure: IModelVendor<DAzureServiceSettings, OpenAIAccessS
// components
Icon: AzureIcon,
ServiceSetupComponent: AzureServiceSetup,
// functions
getTransportAccess: (partialSetup): OpenAIAccessSchema => ({
@@ -5,8 +5,6 @@ import type { OpenAIAccessSchema } from '../../server/openai/openai.router';
import { ModelVendorOpenAI } from '../openai/openai.vendor';
import { DeepseekAIServiceSetup } from './DeepseekAIServiceSetup';
export interface DDeepseekServiceSettings {
deepseekKey: string;
@@ -22,7 +20,6 @@ export const ModelVendorDeepseek: IModelVendor<DDeepseekServiceSettings, OpenAIA
// components
Icon: DeepseekIcon,
ServiceSetupComponent: DeepseekAIServiceSetup,
// functions
initializeSetup: () => ({
-3
View File
@@ -5,8 +5,6 @@ import type { GeminiAccessSchema } from '../../server/gemini/gemini.router';
import type { GeminiWire_Safety } from '~/modules/aix/server/dispatch/wiretypes/gemini.wiretypes';
import type { IModelVendor } from '../IModelVendor';
import { GeminiServiceSetup } from './GeminiServiceSetup';
interface DGeminiServiceSettings {
geminiKey: string;
@@ -35,7 +33,6 @@ export const ModelVendorGemini: IModelVendor<DGeminiServiceSettings, GeminiAcces
// components
Icon: GeminiIcon,
ServiceSetupComponent: GeminiServiceSetup,
// functions
initializeSetup: () => ({
-3
View File
@@ -5,8 +5,6 @@ import type { OpenAIAccessSchema } from '../../server/openai/openai.router';
import { ModelVendorOpenAI } from '../openai/openai.vendor';
import { GroqServiceSetup } from './GroqServiceSetup';
interface DGroqServiceSettings {
groqKey: string;
@@ -22,7 +20,6 @@ export const ModelVendorGroq: IModelVendor<DGroqServiceSettings, OpenAIAccessSch
// components
Icon: GroqIcon,
ServiceSetupComponent: GroqServiceSetup,
// functions
initializeSetup: () => ({
-2
View File
@@ -3,7 +3,6 @@ import type { OpenAIAccessSchema } from '../../server/openai/openai.router';
import { ModelVendorOpenAI } from '../openai/openai.vendor';
import { LMStudioServiceSetup } from './LMStudioServiceSetup';
import { LMStudioIcon } from '~/common/components/icons/vendors/LMStudioIcon';
@@ -20,7 +19,6 @@ export const ModelVendorLMStudio: IModelVendor<DLMStudioServiceSettings, OpenAIA
// components
Icon: LMStudioIcon,
ServiceSetupComponent: LMStudioServiceSetup,
// functions
initializeSetup: () => ({
-3
View File
@@ -5,8 +5,6 @@ import type { OpenAIAccessSchema } from '../../server/openai/openai.router';
import { ModelVendorOpenAI } from '../openai/openai.vendor';
import { LocalAIServiceSetup } from './LocalAIServiceSetup';
interface DLocalAIServiceSettings {
localAIHost: string; // use OpenAI-compatible non-default hosts (full origin path)
@@ -27,7 +25,6 @@ export const ModelVendorLocalAI: IModelVendor<DLocalAIServiceSettings, OpenAIAcc
// components
Icon: LocalAIIcon,
ServiceSetupComponent: LocalAIServiceSetup,
// functions
initializeSetup: () => ({
-3
View File
@@ -5,8 +5,6 @@ import type { OpenAIAccessSchema } from '../../server/openai/openai.router';
import { DOpenAIServiceSettings, ModelVendorOpenAI } from '../openai/openai.vendor';
import { MistralServiceSetup } from './MistralServiceSetup';
// special symbols
@@ -25,7 +23,6 @@ export const ModelVendorMistral: IModelVendor<DMistralServiceSettings, OpenAIAcc
// components
Icon: MistralIcon,
ServiceSetupComponent: MistralServiceSetup,
// functions
initializeSetup: () => ({
-3
View File
@@ -4,8 +4,6 @@ import { apiAsync } from '~/common/util/trpc.client';
import type { IModelVendor } from '../IModelVendor';
import type { OllamaAccessSchema } from '../../server/ollama/ollama.router';
import { OllamaServiceSetup } from './OllamaServiceSetup';
interface DOllamaServiceSettings {
ollamaHost: string;
@@ -23,7 +21,6 @@ export const ModelVendorOllama: IModelVendor<DOllamaServiceSettings, OllamaAcces
// components
Icon: OllamaIcon,
ServiceSetupComponent: OllamaServiceSetup,
// functions
getTransportAccess: (partialSetup): OllamaAccessSchema => ({
-2
View File
@@ -3,7 +3,6 @@ import { apiAsync } from '~/common/util/trpc.client';
import type { IModelVendor } from '../IModelVendor';
import type { OpenAIAccessSchema } from '../../server/openai/openai.router';
import { OpenAIServiceSetup } from './OpenAIServiceSetup';
// special symbols
@@ -27,7 +26,6 @@ export const ModelVendorOpenAI: IModelVendor<DOpenAIServiceSettings, OpenAIAcces
// components
Icon: OpenAIIcon,
ServiceSetupComponent: OpenAIServiceSetup,
// functions
getTransportAccess: (partialSetup): OpenAIAccessSchema => ({
-3
View File
@@ -5,8 +5,6 @@ import type { OpenAIAccessSchema } from '../../server/openai/openai.router';
import { ModelVendorOpenAI } from '../openai/openai.vendor';
import { OpenPipeServiceSetup } from './OpenPipeServiceSetup';
export interface DOpenPipeServiceSettings {
openPipeKey: string;
@@ -23,7 +21,6 @@ export const ModelVendorOpenPipe: IModelVendor<DOpenPipeServiceSettings, OpenAIA
// components
Icon: OpenPipeIcon,
ServiceSetupComponent: OpenPipeServiceSetup,
// functions
initializeSetup: () => ({
@@ -5,8 +5,6 @@ import type { OpenAIAccessSchema } from '../../server/openai/openai.router';
import { ModelVendorOpenAI } from '../openai/openai.vendor';
import { OpenRouterServiceSetup } from './OpenRouterServiceSetup';
// special symbols
export const isValidOpenRouterKey = (apiKey?: string) => !!apiKey && apiKey.startsWith('sk-or-') && apiKey.length > 40;
@@ -39,7 +37,6 @@ export const ModelVendorOpenRouter: IModelVendor<DOpenRouterServiceSettings, Ope
// components
Icon: OpenRouterIcon,
ServiceSetupComponent: OpenRouterServiceSetup,
// functions
initializeSetup: (): DOpenRouterServiceSettings => ({
@@ -5,8 +5,6 @@ import type { OpenAIAccessSchema } from '../../server/openai/openai.router';
import { ModelVendorOpenAI } from '../openai/openai.vendor';
import { PerplexityServiceSetup } from './PerplexityServiceSetup';
interface DPerpexityServiceSettings {
perplexityKey: string;
@@ -22,7 +20,6 @@ export const ModelVendorPerplexity: IModelVendor<DPerpexityServiceSettings, Open
// components
Icon: PerplexityIcon,
ServiceSetupComponent: PerplexityServiceSetup,
// functions
initializeSetup: () => ({
@@ -5,8 +5,6 @@ import type { OpenAIAccessSchema } from '../../server/openai/openai.router';
import { ModelVendorOpenAI } from '../openai/openai.vendor';
import { TogetherAIServiceSetup } from './TogetherAIServiceSetup';
interface DTogetherAIServiceSettings {
togetherKey: string;
@@ -24,7 +22,6 @@ export const ModelVendorTogetherAI: IModelVendor<DTogetherAIServiceSettings, Ope
// components
Icon: TogetherIcon,
ServiceSetupComponent: TogetherAIServiceSetup,
// functions
initializeSetup: () => ({
-3
View File
@@ -5,8 +5,6 @@ import type { OpenAIAccessSchema } from '../../server/openai/openai.router';
import { ModelVendorOpenAI } from '../openai/openai.vendor';
import { XAIServiceSetup } from './XAIServiceSetup';
export interface DXAIServiceSettings {
xaiKey: string;
@@ -22,7 +20,6 @@ export const ModelVendorXAI: IModelVendor<DXAIServiceSettings, OpenAIAccessSchem
// Components
Icon: XAIIcon,
ServiceSetupComponent: XAIServiceSetup,
// functions
initializeSetup: () => ({ xaiKey: '' }),