Problem
When a provider exposes many models (100+), opening /model and navigating the picker with the arrow keys becomes extremely laggy one keypress takes noticeably long to move focus.
Cause
Two independent O(n²) hot spots combined to make every keystroke expensive:
-
getModelOptions() rebuilt the option list on every keystroke. While the picker is open, each focus change re-renders ModelPicker, and the effort/display resolution path calls isGenuineSwitchProfileValue → getModelOptions() on every render; even for ordinary model ids that can never be cross-profile switch entries.
-
getModelOptions() itself was O(n²) for catalog-backed routes. optionMatchesModel ran getRouteCatalogModelOption (a full catalog scan) inside an options.some(...) loop, and getCatalogOptionValue re-filtered the entire catalog per entry. On a ~50+ entry static catalog using 9router, was practically impossible to select another model due to lag.
Fix
hasOptionValue hoists the catalog lookup out of the per-option loop.
- Duplicate api-names are precomputed once into a
Set (getDuplicateCatalogApiNames) instead of re-filtering per entry.
isGenuineSwitchProfileValue short-circuits for values that don't start with the __switch_profile__: prefix (semantics preserved, including the documented literal-prefixed-id edge case).
Measured impact: getModelOptions() on the 100+ entry NVIDIA NIM catalog went from 43.5ms → 2.0ms (~22x), and no option-list rebuild happens per keystroke anymore.
Steps to reproduce
- Configure a provider with a large model catalog (OpenAI-compatible endpoint with 100+ discovered models).
- Run the CLI, open
/model.
- Hold or tap the down arrow — navigation lags badly before the fix.
Problem
When a provider exposes many models (100+), opening
/modeland navigating the picker with the arrow keys becomes extremely laggy one keypress takes noticeably long to move focus.Cause
Two independent O(n²) hot spots combined to make every keystroke expensive:
getModelOptions()rebuilt the option list on every keystroke. While the picker is open, each focus change re-rendersModelPicker, and the effort/display resolution path callsisGenuineSwitchProfileValue→getModelOptions()on every render; even for ordinary model ids that can never be cross-profile switch entries.getModelOptions()itself was O(n²) for catalog-backed routes.optionMatchesModelrangetRouteCatalogModelOption(a full catalog scan) inside anoptions.some(...)loop, andgetCatalogOptionValuere-filtered the entire catalog per entry. On a ~50+ entry static catalog using 9router, was practically impossible to select another model due to lag.Fix
hasOptionValuehoists the catalog lookup out of the per-option loop.Set(getDuplicateCatalogApiNames) instead of re-filtering per entry.isGenuineSwitchProfileValueshort-circuits for values that don't start with the__switch_profile__:prefix (semantics preserved, including the documented literal-prefixed-id edge case).Measured impact:
getModelOptions()on the 100+ entry NVIDIA NIM catalog went from 43.5ms → 2.0ms (~22x), and no option-list rebuild happens per keystroke anymore.Steps to reproduce
/model.