Root cause: three interacting bugs caused the model picker to show the wrong model or flicker after a profile switch. Bug 1 — syncTopbar() fought switchToProfile(). After switchToProfile() set the picker to the profile's model, syncTopbar() was called (via renderSessionList -> loadSession, then explicitly at the end) and overwrote it with S.session.model -- the old session's model. Fix: added S._pendingProfileModel flag. switchToProfile() sets it; syncTopbar() checks it first, applies the override, then clears it. S.session.model is also updated to the resolved value so subsequent syncTopbar() calls are consistent. Bug 2 — Raw option injected at top of list for mismatched model IDs. Profile configs store model IDs like 'claude-sonnet-4-6' (hermes-agent format: hyphens, no namespace prefix) but the dropdown has 'anthropic/claude-sonnet-4.6' (OpenRouter format: dots, with prefix). The old code did sel.value = id, found no match, then injected a new <option> at the top of the list -- creating a lowercase duplicate that didn't match any real provider group entry. Fix: _findModelInDropdown() normalises both sides (strip prefix, hyphens->dots, lowercase) and finds the best matching existing option. No new options are ever injected for profile switching. Bug 3 — populateModelDropdown() injected raw option on cold load. Same issue: if default_model from /api/models didn't exactly match a dropdown value, an extra option was added. Fixed by using _applyModelToDropdown() which only selects existing options. New helpers in ui.js: _findModelInDropdown(modelId, sel) -- smart fuzzy match, returns matched value _applyModelToDropdown(modelId, sel) -- sets picker, returns resolved value Tests: 426 passed, 0 failed.
42 KiB
42 KiB