This document details the Model Configuration Management system, which is responsible for managing text model configurations in the Prompt Optimizer application. The ModelManager service handles storage, validation, initialization, and migration of model configurations across all platforms (web, desktop, browser extension).
Key Responsibilities:
TextModelConfig structures for all text-based LLM providersModelConfig data to the new TextModelConfig formatRelated Pages:
Sources: README.md packages/core/src/services/model/manager.ts packages/core/src/services/model/types.ts
ModelManager Position in System
The ModelManager sits at the intersection of configuration sources, storage backends, and the adapter registry. It serves as the single source of truth for model configurations, handling both user-defined and built-in models.
Sources: packages/core/src/services/model/manager.ts1-238 packages/ui/src/components/TextModelManager.vue1-153
The TextModelConfig interface represents the modern, self-contained model configuration format introduced in the adapter architecture refactor.
Key Design Principles:
TextModelConfig contains complete copies of providerMeta and modelMeta, eliminating the need for runtime lookupsModelConfig—this is a clean, new structurecustomParamOverrides field is retained for reading old data but removed on saveSources: packages/core/src/services/model/types.ts42-80 packages/core/src/services/llm/types.ts8-116
The legacy ModelConfig format is maintained for backward compatibility during migration.
| Field | Type | Description |
|---|---|---|
name | string | Display name |
baseURL | string | API endpoint URL |
apiKey | string (optional) | API key |
models | string[] (optional) | Available model IDs |
defaultModel | string | Selected model ID |
enabled | boolean | Enable status |
provider | string | Provider identifier (deepseek, gemini, custom, zhipu, etc.) |
llmParams | Record<string, any> (optional) | Mixed built-in and custom parameters |
Migration Strategy:
The ModelManager automatically detects legacy configurations and converts them to TextModelConfig format during initialization and read operations. The conversion is handled by converter functions that map old field names to new structures.
Sources: packages/core/src/services/model/types.ts84-93 packages/core/src/services/model/converter.ts
Provider and model metadata are obtained from the TextAdapterRegistry, which maintains static definitions for all supported providers.
Provider Metadata (TextProvider):
adapter.getProvider()corsRestricted flag to warn users about browser CORS limitationsModel Metadata (TextModel):
adapter.getModels()Metadata Patching:
The ModelManager patches stored configurations to backfill missing metadata fields (e.g., corsRestricted) introduced in newer versions:
[manager.ts:244-292] patchProviderMeta()
This ensures configurations created with older versions of the application display correct warnings in the UI.
Sources: packages/core/src/services/llm/types.ts14-76 packages/core/src/services/model/manager.ts244-292
Initialization Steps:
Environment Variable Sync (Electron only): manager.ts80-85
ElectronConfigManager.getInstance().syncFromMainProcess()Storage Check: manager.ts88-93
CORE_SERVICE_KEYS.MODELSDefault Model Generation: manager.ts96-110
getDefaultModels() to generate configurations for all built-in providersFormat Migration: manager.ts144-165
ModelConfig structures via isLegacyConfig()convertLegacyToTextModelConfigWithRegistry() or fallback converterMetadata Patching: manager.ts115-129
providerMeta or modelMeta fields from registryAuto-Enable Logic: manager.ts132-143
shouldAutoEnableBuiltinModel() for each built-in modelSources: packages/core/src/services/model/manager.ts75-193 packages/core/src/services/model/defaults.ts40-96
The default model generation system reads API keys and other configuration from environment variables using the getEnvVar() utility.
Provider-to-Environment Variable Mapping:
Generation Process defaults.ts40-96:
PROVIDER_ENV_KEYSregistry.getAdapter(providerId)getEnvVar(envKey)enabled status based on API key presence: enabled: !!apiKeyparamOverrides with model's defaultParameterValuesCustom Model Configuration:
The custom provider is handled separately defaults.ts71-93:
VITE_CUSTOM_API_KEY, VITE_CUSTOM_API_BASE_URL, VITE_CUSTOM_API_MODELDynamic Custom Models:
Multiple custom models can be configured using suffix patterns (e.g., VITE_CUSTOM_API_KEY_ollama). These are generated by generateDynamicModels() model-utils.ts and merged with static models in getAllModels() defaults.ts103-115
Sources: packages/core/src/services/model/defaults.ts1-119 packages/core/src/utils/environment.ts1-300
The ModelManager automatically enables built-in models when their API keys are detected during initialization. This feature improves the user experience by reducing manual configuration.
Auto-Enable Conditions manager.ts611-640:
Execution Flow:
enabled: trueAuto-enabled builtin model with new API key: ${key}This logic ensures that when users deploy the application with environment variables (e.g., Docker deployment), built-in models are automatically enabled without requiring manual UI configuration.
Sources: packages/core/src/services/model/manager.ts611-640 packages/core/src/services/model/manager.ts132-143
The ModelManager receives an IStorageProvider instance during construction manager.ts28-36:
The StorageAdapter wraps the provided storage implementation to ensure consistency across different backends (IndexedDB, filesystem, memory).
Storage Operations:
this.storage.getItem(this.storageKey) manager.ts299-308this.storage.setItem(this.storageKey, JSON.stringify(models)) manager.ts171this.storage.updateData<Record<string, any>>(this.storageKey, callback) manager.ts411-426The updateData() method is particularly important—it provides transactional semantics to prevent race conditions when multiple operations modify the same model configuration.
Sources: packages/core/src/services/model/manager.ts28-36 packages/core/src/services/storage/adapter.ts
Model configurations are stored under a centralized storage key defined in the constants:
This key is accessed via manager.ts23:
Key Benefits:
Sources: packages/core/src/services/model/manager.ts23 packages/core/src/constants/storage-keys.ts
Models are stored as a JSON-serialized object mapping model IDs to TextModelConfig objects:
Storage Format Evolution:
To maintain forward compatibility, the ModelManager removes the deprecated customParamOverrides field when saving manager.ts406-409:
However, it still reads and migrates this field when loading old data manager.ts216-238 ensuring backward compatibility.
Sources: packages/core/src/services/model/manager.ts298-308 packages/core/src/services/model/manager.ts406-409
The ModelManager implements the IModelManager interface, providing comprehensive CRUD operations for model configurations.
Create (Add Model) manager.ts401-427:
Read (Get Model) manager.ts357-395:
Update (Update Model) manager.ts432-506:
Delete (Delete Model) manager.ts511-526:
List (Get All Models) manager.ts313-352:
Sources: packages/core/src/services/model/manager.ts313-526
The ModelManager validates TextModelConfig structures before storage using validateTextModelConfig() manager.ts645-697:
Validation Rules:
| Check | Error Message |
|---|---|
Missing id | "Missing configuration id" |
Missing name | "Missing model name (name)" |
Invalid providerMeta | "Missing or invalid provider metadata (providerMeta)" |
Invalid modelMeta | "Missing or invalid model metadata (modelMeta)" |
Missing connectionConfig | "Missing connection configuration (connectionConfig)" |
Invalid paramOverrides structure | "paramOverrides must be an object" |
Invalid customParamOverrides structure | "customParamOverrides must be an object" |
Parameter Validation:
The validator also calls validateOverrides() manager.ts674-685 to check parameter values against the model's parameterDefinitions schema. This ensures:
Validation Errors:
If validation fails, a ModelConfigError is thrown with concatenated error messages manager.ts694-696:
Sources: packages/core/src/services/model/manager.ts645-697 packages/core/src/services/model/parameter-utils.ts
The ModelManager provides dedicated methods for toggling model availability without requiring full configuration updates.
Enable Model manager.ts531-567:
Disable Model manager.ts572-604:
Get Enabled Models manager.ts704-708:
Key Behaviors:
enableModel() performs full validation before enabling (ensures configuration is valid)disableModel() does not validate (allows disabling broken configurations)updateData() for race condition safetySources: packages/core/src/services/model/manager.ts531-708
The migration system uses type guard functions to detect configuration formats.
Type Guards converter.ts:
Detection Flow:
The ModelManager performs this detection during:
getModel() operations manager.ts369-378getAllModels() operations manager.ts318-336Sources: packages/core/src/services/model/converter.ts packages/core/src/services/model/manager.ts110-165
The conversion system provides two conversion paths: registry-based (preferred) and fallback (hardcoded).
Registry-Based Conversion converter.ts:
Fallback Conversion converter.ts:
The fallback converter uses hardcoded default values when the registry is unavailable (e.g., during early initialization or in error scenarios). It constructs minimal but valid TextModelConfig structures.
Parameter Splitting:
The legacy llmParams field mixed built-in parameters (defined in schema) with custom parameters (ad-hoc user additions). The converter splits these using splitOverridesBySchema() parameter-utils.ts:
Sources: packages/core/src/services/model/converter.ts packages/core/src/services/model/parameter-utils.ts
The migration system ensures smooth transitions between versions while maintaining data integrity.
Read-Time Migration manager.ts216-238:
When loading configurations, the ModelManager automatically merges customParamOverrides into paramOverrides:
Write-Time Cleanup manager.ts406-409:
When saving configurations, the deprecated field is removed:
Version Compatibility:
| Version | customParamOverrides | paramOverrides | Behavior |
|---|---|---|---|
| Old (< 2.0) | Used | Partial | Only built-in params |
| Current (2.x) | Deprecated | Primary | All params merged |
| Future (3.0+) | Removed | Primary | Only paramOverrides exists |
Rollback Safety:
The customParamOverrides field is retained (but undefined) during save operations to support potential version rollbacks. If a user downgrades to an older version that expects this field, the data structure remains valid.
Sources: packages/core/src/services/model/manager.ts216-238 packages/core/src/services/model/manager.ts406-409
Over time, new fields may be added to TextProvider and TextModel interfaces. The ModelManager patches stored configurations to backfill missing fields with current adapter definitions.
Provider Metadata Patching manager.ts244-292:
Patching Triggers:
Metadata patching occurs in:
getAllModels() manager.ts338-351getModel() manager.ts383-395Patching Strategy:
undefined in stored configSources: packages/core/src/services/model/manager.ts244-292
The corsRestricted flag in TextProvider metadata warns users about API endpoints that cannot be accessed directly from browsers due to CORS policies.
CORS-Restricted Providers:
From adapter implementations:
corsRestricted: truecorsRestricted: trueUI Integration:
The UI displays CORS warnings in multiple places:
Model List TextModelList.vue46-52:
Connection Test Dialog TextModelManager.vue59-78:
Model Edit Modal TextModelEditModal.vue274-291:
Recommendation Flow:
Desktop Application Advantage:
The desktop application (Electron) bypasses all CORS restrictions because it runs core services in the main process with full Node.js capabilities README.md103-105:
✅ 无跨域限制:作为原生桌面应用,它能彻底摆脱浏览器跨域(CORS)问题的困扰
Sources: packages/core/src/services/llm/adapters/modelscope-adapter.ts38 packages/ui/src/components/TextModelList.vue46-52 packages/ui/src/components/TextModelManager.vue59-78
The ModelManager integrates with Electron's main process to access environment variables that are not available in the renderer process.
ElectronConfigManager Synchronization manager.ts80-85:
ElectronConfigManager electron-config.ts:
The ElectronConfigManager is a singleton that:
isElectronRenderer()window.electronAPI.syncEnvironmentVariables() via IPCgenerateDefaultModels() method that uses synced valuesConfiguration Flow:
Why This Is Needed:
In Electron, the renderer process is sandboxed and does not have direct access to Node.js process.env. The contextBridge in the preload script exposes a limited API for secure IPC communication with the main process, where environment variables are accessible.
Sources: packages/core/src/services/model/manager.ts80-85 packages/core/src/services/model/electron-config.ts packages/desktop/electron/preload.js
In browser environments (web application, browser extension), the ModelManager reads environment variables using Vite's import.meta.env mechanism.
Environment Variable Access environment.ts215-300:
Vite Environment Variable Processing:
Vite processes environment variables at build time:
.env.local, .env, etc.VITE_ into the bundleimport.meta.env in browser codeSecurity Considerations:
VITE_ are exposed to browser codeDocker Environment Variable Injection:
In Docker deployments, environment variables are injected at runtime using a script that replaces placeholders in the built JavaScript docker/inject-env.sh:
__VITE_*__ placeholders in bundled JS filesSources: packages/core/src/utils/environment.ts215-300 docker/inject-env.sh vercel.json24-31
Refresh this wiki