fix(models): stale cross-provider model no longer shows as unavailable in picker (closes #829)
* fix(models): stale cross-provider model no longer shows as unavailable in picker Two bugs allowed an openai/gpt-5.4-mini stale session model to appear as '(unavailable)' under a custom provider group for users who never configured OpenAI (#829). Backend (api/routes.py): _resolve_compatible_session_model() had a blanket early-return for active_provider in {custom, openrouter} that skipped all normalization regardless of whether any catalog group could route the model's prefix. A custom_providers-only user with a stale openai/... session model was never corrected. Fixed: only skip normalization when the model prefix is actually routable (matches a catalog group provider_id, or an openrouter group is present that can route any provider/model). Frontend (static/ui.js): renderSession() injected a bare <option> (not in any <optgroup>) for models not found in the dropdown. renderModelDropdown() rendered bare options without emitting a group heading, so they visually inherited the last rendered provider heading — making the stale model appear to belong to the custom provider group. Fixed: silently reset to the first available model and fire a PATCH to persist the correction instead of injecting a misleading (unavailable) option. 5 new tests in test_provider_mismatch.py cover: - stale openai model cleared when custom_providers-only + no default_model - stale openai model cleared when custom_providers-only + default_model set - openrouter model preserved when openrouter group present - custom/ namespace always preserved - ui.js no longer injects model_unavailable option * fix(ui): declare modelSel locally in syncTopbar reset path; fix test assertion - Use const modelSel=$('modelSelect') instead of undeclared sel in the stale-model reset branch of syncTopbar() (caught in Opus review) - Fix test assertion: or → and for model_unavailable key absence check --------- Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
This commit is contained in:
28
static/ui.js
28
static/ui.js
@@ -1209,18 +1209,24 @@ function syncTopbar(){
|
||||
currentModel=modelOverride;
|
||||
} else {
|
||||
const applied=_applyModelToDropdown(currentModel,$('modelSelect'));
|
||||
// If the model isn't in the current provider list, add it as a visually marked
|
||||
// "(unavailable)" entry so the session value is preserved without misleading the user.
|
||||
// Selecting it will still attempt to send (same as before), but the label makes
|
||||
// clear it's a stale model from a previous session.
|
||||
// If the model isn't in the current provider list, silently reset to the
|
||||
// first available model so stale values don't pollute the picker (#829).
|
||||
if(!applied && currentModel){
|
||||
const opt=document.createElement('option');
|
||||
opt.value=currentModel;
|
||||
opt.textContent=getModelLabel(currentModel)+t('model_unavailable');
|
||||
opt.style.color='var(--muted, #888)';
|
||||
opt.title=t('model_unavailable_title');
|
||||
$('modelSelect').appendChild(opt);
|
||||
$('modelSelect').value=currentModel;
|
||||
// Stale session model not in the current provider catalog — reset to the
|
||||
// first available model rather than injecting an "(unavailable)" option
|
||||
// that visually appears under the wrong provider group (#829).
|
||||
const modelSel=$('modelSelect');
|
||||
const first=modelSel&&modelSel.querySelector('optgroup > option, option');
|
||||
if(first){
|
||||
modelSel.value=first.value;
|
||||
S.session.model=first.value;
|
||||
// Persist the correction so the session doesn't re-inject on next load.
|
||||
fetch(new URL('api/session/update',location.href).href,{
|
||||
method:'POST',credentials:'include',
|
||||
headers:{'Content-Type':'application/json'},
|
||||
body:JSON.stringify({session_id:S.session.id||S.session.session_id,model:first.value})
|
||||
}).catch(()=>{});
|
||||
}
|
||||
}
|
||||
}
|
||||
if(typeof syncModelChip==='function') syncModelChip();
|
||||
|
||||
Reference in New Issue
Block a user