refactor(renderer): ProviderSettings v2 migration + ClassifiableModel compat layer#14125
Open
jidan745le wants to merge 92 commits intoCherryHQ:v2from
Open
refactor(renderer): ProviderSettings v2 migration + ClassifiableModel compat layer#14125jidan745le wants to merge 92 commits intoCherryHQ:v2from
jidan745le wants to merge 92 commits intoCherryHQ:v2from
Conversation
Signed-off-by: jidan745le <420511176@qq.com>
Add v2 provider-model migration mappings and registration, then align provider handlers/services with lifecycle DI and API contracts so migration generation and node typecheck both pass. Signed-off-by: jidan745le <420511176@qq.com> Made-with: Cursor
Add an empty changeset file so CI changeset-check passes for this non-release provider/model runtime integration work. Signed-off-by: jidan745le <420511176@qq.com> Made-with: Cursor
…path Drop redundant assertions flagged by oxlint and keep only required runtime-shape casts so CI test:lint passes. Signed-off-by: jidan745le <420511176@qq.com> Made-with: Cursor
Remove duplicate 0007 migration and regenerate migration artifacts as 0009 to keep drizzle journal order consistent with existing 0007/0008 chain. Signed-off-by: jidan745le <420511176@qq.com> Made-with: Cursor
The catalog service initialization was missing from the startup sequence, causing preset provider/model data (capabilities, context windows, pricing, baseUrls) to never sync from protobuf catalog files into SQLite on each launch. Signed-off-by: jidan745le <420511176@qq.com>
Signed-off-by: jidan745le <420511176@qq.com>
…dpointConfigs Merge three separate provider endpoint fields into a single `endpointConfigs` map keyed by EndpointType. Each entry holds baseUrl, modelsApiUrls, and reasoningFormatType in one place. Also removes unused `createdAt` from ApiKeyEntry. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com>
Rename the entire provider-catalog package, service, and all related references to provider-registry for clearer naming semantics. - Package: @cherrystudio/provider-catalog → @cherrystudio/provider-registry - Directory: packages/provider-catalog → packages/provider-registry - Proto namespace: catalog.v1 → registry.v1 - Service: ProviderCatalogService → ProviderRegistryService - All type/function/variable names updated accordingly Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com>
rateLimit depends on the user's API plan, not the model itself — not appropriate for preset registry data. Also remove inherited reserved fields since registry.v1 has no legacy data to maintain compatibility with. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com>
…I design - Convert RegistryService to lifecycle-managed ProviderRegistryService (@Injectable, @ServicePhase, @dependsOn, BaseService) - Register in serviceRegistry.ts; remove manual init from index.ts - Replace singleton imports with application.get('ProviderRegistryService') - Move /models/resolve to POST /providers/:providerId/registry-models (RESTful: same resource path, different HTTP methods) - Rename ResolveModelsDto to EnrichModelsDto (providerId from URL params) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com>
…ings - Remove protobuf toolchain (proto files, buf config, generated code, @bufbuild/* dependencies) - Convert registry data from .pb binary to .json files - Replace proto-generated types with Zod-inferred types - Rewrite registry-reader to use JSON.parse + Zod validation - Simplify ProviderRegistryService and modelMerger by removing proto conversion layers (buildEndpointConfigsFromProto, CASE_TO_TYPE, extractReasoningFormatType) - Convert all enums from numeric TypeScript enum to string-valued as-const objects (EndpointType, ModelCapability, Modality, Currency, ReasoningEffort) for debuggability - Regenerate Drizzle migration to match current schema Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com>
The registry data uses "2026.03.09" format (from proto), but the VersionSchema regex only allowed "YYYY-MM-DD". This caused Zod validation to fail silently when loading registry JSON, resulting in empty model data and no enrichment of capabilities/modalities. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com>
registry-reader.ts uses node:fs which crashes in renderer. Split into a separate @cherrystudio/provider-registry/node sub-path export so the main entry stays browser-compatible. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com> Made-with: Cursor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com> Made-with: Cursor
Signed-off-by: jidan745le <420511176@qq.com> Made-with: Cursor
Signed-off-by: jidan745le <420511176@qq.com>
Signed-off-by: jidan745le <420511176@qq.com>
… DataApi Signed-off-by: jidan745le <420511176@qq.com>
Signed-off-by: jidan745le <420511176@qq.com>
Signed-off-by: jidan745le <420511176@qq.com>
Signed-off-by: jidan745le <420511176@qq.com>
Signed-off-by: jidan745le <420511176@qq.com>
Signed-off-by: jidan745le <420511176@qq.com>
…odel Migrate renderer consumer code to match the new consolidated endpointConfigs schema (replaces separate baseUrls, modelsApiUrls, reasoningFormatTypes fields) and catalog→registry rename. - Replace provider.baseUrls?.[ep] with endpointConfigs?.[ep]?.baseUrl in ProviderSetting, CherryINSettings, DMXAPISettings, ManageModelsPopup - Rename replaceBaseUrlDomain → replaceEndpointConfigDomain (preserves other EndpointConfig fields like reasoningFormatType) - Update v1ProviderShim to read baseUrl from endpointConfigs - Rename useProviderCatalogModels → useProviderRegistryModels, update endpoint from catalog-models to registry-models - Replace removed /models/resolve with /providers/:id/registry-models POST - Update tests to reflect all of the above Signed-off-by: jidan745le <420511176@qq.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com> Made-with: Cursor
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com> Made-with: Cursor
- Add void to all floating promises in ProviderSettings components - Remove closeDelay prop (not in TooltipProps) - Fix unused destructured variable with delete pattern Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com>
- ManageModelsPopup: replace Math.floor(Number(defaultChatEndpoint)) with direct string enum access (was producing NaN after string enum migration, causing model list to fail loading) - provider.v2.ts: fix replaceEndpointConfigDomain type signature from Record<number, ...> to Record<EndpointType, ...>, remove Number(key) conversions - Update test file to use string EndpointType keys Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com>
…r-registry-renderer
- A1.1: Add missing inputModalities, outputModalities, parameterSupport to ModelService.update — DTO advertised but silently dropped - A1.2: Use lookupRegistryModel in resolveModels for normalized fallback (gpt-4o:free, aihubmix-gpt-4o, claude-3.5-sonnet now resolve correctly) - A1.3: Only protect canonical preset providers (providerId === presetProviderId) from deletion — user-created providers inheriting from presets can be deleted Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com>
Backend renamed const objects (EndpointType → ENDPOINT_TYPE, ModelCapability → MODEL_CAPABILITY). Update all renderer imports and usages to match, and fix string→EndpointType cast in add-model popups. Signed-off-by: jidan745le <420511176@qq.com>
- Add sortOrder and notes to Model schema and rowToRuntimeModel (previously writable via PATCH but not readable via GET) - Add regression tests for 3 behavioral boundaries: - ProviderService.delete: canonical preset protection vs user copies - resolveModels: normalize fallback for variant/aggregator model IDs - PresetProviderSeed: insert-only behavior, no overwrite on restart - Simplify ModelService tests to meaningful edge cases only - Fix lint: replace import() type annotation with vi.importActual - Migrate ProviderRegistryService tests to unified mock system Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com>
- Build model and override indexes (4 Maps) on first load for O(1) lookup - Add idle TTL (30s default): auto-invalidate after no access, freeing ~6MB - ProviderRegistryService uses loader.findModel/findOverride instead of Array.find — eliminates O(N) scans on every query - Remove lookupRegistryModel import from ProviderRegistryService (now unused) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com>
- Add getOverridesForProvider(providerId) to RegistryLoader (O(1) via overridesByProvider Map, replaces Array.filter O(N)) - getRegistryModelsByProvider now uses loader.getOverridesForProvider + loader.findModel instead of manual Map construction and filter Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com>
- Remove enrichExistingModels and initializeProvider flow descriptions - Add RegistryLoader section (indexes, idle TTL, query API) - Add Merge Functions table (mergePresetModel/mergeModelWithUser/createCustomModel) - Update resolveModels flow (modelIds only, no SDK data overwrite) - Update preset deletion protection (canonical vs inherited) - Add parameters, sortOrder, notes to user_model table docs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com>
…-registry-renderer
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: suyao <sy20010504@gmail.com>
…-registry-renderer
…stry-renderer # Conflicts: # docs/references/data/provider-registry.md # electron.vite.config.ts # packages/provider-registry/src/registry-loader.ts # packages/shared/data/utils/modelMerger.ts # src/main/data/db/schemas/userModel.ts # src/main/data/db/seeding/presetProviderSeeding.ts # src/main/data/services/ModelService.ts # src/main/data/services/ProviderRegistryService.ts # src/main/data/services/ProviderService.ts # tsconfig.node.json
… path Signed-off-by: jidan745le <420511176@qq.com>
Signed-off-by: jidan745le <420511176@qq.com>
Signed-off-by: jidan745le <420511176@qq.com>
- Use v2 ENDPOINT_TYPE enums in endpointTypeOptions instead of legacy strings, fixing Zod validation errors on batch/single model creation - Reverse enrichment logic in ManageModelsPopup: fetched models from the provider API are now the primary source (ID, name, group, endpointTypes), with registry catalog data supplementing metadata fields only (capabilities, pricing, contextWindow, etc.) - Fix HealthCheckService passing empty models array to v1 provider shim, which caused checkApiProvider to reject the check before sending request - Use ENDPOINT_TYPE constants for form default values in add model popups Signed-off-by: jidan745le <420511176@qq.com>
- Add /models/batch POST endpoint with Zod validation for bulk model creation - Extract buildCreateValues in ModelService for shared create/batchCreate logic - Add createModelsBatch hook with cache invalidation in useModels - Encode providerId/modelId in model API paths to handle slashes - Use normalizeModelGroupName and getModelGroupLabel for consistent grouping - Add toV1ModelShim/toV1ModelForCheckApi helpers in v1ProviderShim - Export Zod schemas (ListModelsQuery, CreateModelDto, UpdateModelDto, EnrichModelsDto) - Add tests for batchCreate and slash-encoded model deletion Signed-off-by: jidan745le <420511176@qq.com>
- Add grouping.ts with normalizeModelGroupName and getModelGroupLabel - Update ProviderSetting and ApiKeyListPopup hook Signed-off-by: jidan745le <420511176@qq.com>
- ManageModelsPopup: handle optional apiModelId with fallback to parsed modelId - NewApiAddModelPopup: cast endpointType to EndpointType instead of string - VertexAISettings: derive gcpConfig inside useEffect to satisfy exhaustive-deps - AwsBedrockSettings: derive awsConfig inside useEffect to satisfy exhaustive-deps Signed-off-by: jidan745le <420511176@qq.com>
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR does
Before this PR:
@renderer/typesModel/Provider)config/models/classification functions only accept v1 Model, requiringas unknown as V1Modelcasts from v2 callersvision.tsandwebsearch.tssynchronously read Redux store viagetProviderByModelto determine provider protocol typeAfter this PR:
useProvider(),useModels(),useProviderApiKeys()config/models/classification functions acceptClassifiableModel(v1/v2 compatible interface) — zero casts needed from either sidevision.ts/websearch.tsuse model's ownendpointTypesfield instead of Redux lookup —config/models/is now pure functions with zero store dependencyModelIdWithTags,FreeTrialModelTag,getModelLogo,ProviderAvatar) accept both v1 and v2 ModelFixes #N/A
Why we need it and why it was done in this way
The following tradeoffs were made:
ClassifiableModelas a transitional compatibility interface rather than changing all 30+ v1 callers at once. This allows incremental page-by-page migration while keeping everything working.normalizeEndpointTypebridges v1 endpoint names ("openai-response") to v2 ("openai-responses") so callers only need to use v2 constants.getLowerBaseModelNameauto-strips::prefix from v2 UniqueModelIds to maintain regex matching correctness.The following alternatives were considered:
getProviderByModelRedux dependency — rejected because it makesconfig/models/impure and fails silently for v2 Models (provider-specific checks return wrong results)Breaking changes
None. All changes are backward-compatible:
ClassifiableModelis a structural supertype that both satisfySpecial notes for your reviewer
Commit structure (2 commits):
refactor(config/models): introduce ClassifiableModel v1/v2 compat layer— infrastructure: ClassifiableModel interface, helpers, all config/models functions widened, shared components widenedrefactor(ProviderSettings): migrate full UI chain to v2 DataApi— consumer: ProviderSettings pages, popups, health check, API key management all switched to v2 DataApi4 remaining
as unknown as V1Modelcasts are all at theAiProvider(aiCore) boundary —checkApi/checkModel/fetchModels. These will be removed when aiCore supports v2 types.ClassifiableModelis a transitional layer, not a permanent type. Exit plan documented indocs/provider-registry-renderer-pr.md. When all pages migrate to v2 and aiCore supports v2 types,ClassifiableModeland all its helpers will be deleted in favor of direct v2Modelusage.Checklist
Release note