diff --git a/open-sse/config/registryUtils.ts b/open-sse/config/registryUtils.ts index 55dc5b2c48..9bec2635d0 100644 --- a/open-sse/config/registryUtils.ts +++ b/open-sse/config/registryUtils.ts @@ -22,6 +22,29 @@ export interface BaseProvider { models: M[]; } +/** + * Per-registry ``modelId → providerId`` index for the bare-model lookup below. + * The media registries (image/video/audio/music) are static module-level objects, so the + * index is built once per registry and reused. First-wins insertion preserves the original + * Object.entries() iteration order (the same provider the linear scan would have returned). + */ +const registryModelIndexCache = new WeakMap>(); +function getRegistryModelIndex

( + registry: Record +): Map { + let index = registryModelIndexCache.get(registry); + if (!index) { + index = new Map(); + for (const [providerId, config] of Object.entries(registry)) { + for (const model of config.models) { + if (!index.has(model.id)) index.set(model.id, providerId); + } + } + registryModelIndexCache.set(registry, index); + } + return index; +} + /** * Parse a "provider/model" string against a registry. * Supports both "provider/model" prefix and bare "model" lookup. @@ -42,11 +65,11 @@ export function parseModelFromRegistry

( } } - // No provider prefix — try to find the model in every provider - for (const [providerId, config] of Object.entries(registry)) { - if (config.models.some((m) => m.id === modelStr)) { - return { provider: providerId, model: modelStr }; - } + // No provider prefix — find the model via the precomputed index (was an O(providers × models) + // scan on every call). + const providerId = getRegistryModelIndex(registry).get(modelStr); + if (providerId) { + return { provider: providerId, model: modelStr }; } return { provider: null, model: modelStr };