Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
This commit is contained in:
@@ -640,9 +640,12 @@ def get_available_models() -> dict:
|
|||||||
# Ensure the user's configured default_model always appears in the dropdown.
|
# Ensure the user's configured default_model always appears in the dropdown.
|
||||||
# It may be missing if the model isn't in any hardcoded list (e.g. openrouter/free,
|
# It may be missing if the model isn't in any hardcoded list (e.g. openrouter/free,
|
||||||
# a custom local model, or any model.default not in _FALLBACK_MODELS).
|
# a custom local model, or any model.default not in _FALLBACK_MODELS).
|
||||||
|
# Normalize before comparing: strip provider prefix so 'anthropic/claude-opus-4.6'
|
||||||
|
# matches 'claude-opus-4.6' already in the list and avoids a duplicate entry.
|
||||||
if default_model:
|
if default_model:
|
||||||
all_ids = {m['id'] for g in groups for m in g.get('models', [])}
|
_norm = lambda mid: mid.split('/', 1)[-1] if '/' in mid else mid
|
||||||
if default_model not in all_ids:
|
all_ids_norm = {_norm(m['id']) for g in groups for m in g.get('models', [])}
|
||||||
|
if _norm(default_model) not in all_ids_norm:
|
||||||
# Determine which group to inject into
|
# Determine which group to inject into
|
||||||
label = default_model.split('/')[-1] if '/' in default_model else default_model
|
label = default_model.split('/')[-1] if '/' in default_model else default_model
|
||||||
injected = False
|
injected = False
|
||||||
|
|||||||
@@ -424,11 +424,16 @@ function syncTopbar(){
|
|||||||
} else {
|
} else {
|
||||||
const m=S.session.model||'';
|
const m=S.session.model||'';
|
||||||
const applied=_applyModelToDropdown(m,$('modelSelect'));
|
const applied=_applyModelToDropdown(m,$('modelSelect'));
|
||||||
// If the model isn't in the list at all, add it so the session value is preserved
|
// 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(!applied && m){
|
if(!applied && m){
|
||||||
const opt=document.createElement('option');
|
const opt=document.createElement('option');
|
||||||
opt.value=m;
|
opt.value=m;
|
||||||
opt.textContent=getModelLabel(m);
|
opt.textContent=getModelLabel(m)+' (unavailable)';
|
||||||
|
opt.style.color='var(--muted, #888)';
|
||||||
|
opt.title='This model is no longer in your current provider list';
|
||||||
$('modelSelect').appendChild(opt);
|
$('modelSelect').appendChild(opt);
|
||||||
$('modelSelect').value=m;
|
$('modelSelect').value=m;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,6 +163,33 @@ def test_non_default_provider_models_use_hint_prefix():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_duplicate_when_default_model_is_prefixed():
|
||||||
|
"""Issue #147 Bug 2: 'anthropic/claude-opus-4.6' as default_model must not
|
||||||
|
inject a duplicate alongside the existing bare 'claude-opus-4.6' entry in
|
||||||
|
the same provider group."""
|
||||||
|
import api.config as _cfg
|
||||||
|
old_cfg = dict(_cfg.cfg)
|
||||||
|
_cfg.cfg['model'] = {
|
||||||
|
'provider': 'anthropic',
|
||||||
|
'default': 'anthropic/claude-opus-4.6',
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
result = _cfg.get_available_models()
|
||||||
|
norm = lambda mid: mid.split('/', 1)[-1] if '/' in mid else mid
|
||||||
|
# Check each group individually: no group should have two entries that
|
||||||
|
# normalize to the same bare model name
|
||||||
|
for g in result['groups']:
|
||||||
|
bare_ids = [norm(m['id']) for m in g['models']]
|
||||||
|
duplicates = [mid for mid in set(bare_ids) if bare_ids.count(mid) > 1]
|
||||||
|
assert not duplicates, (
|
||||||
|
f"Provider group '{g['provider']}' has duplicate models after normalization: "
|
||||||
|
f"{duplicates}\nFull group: {[m['id'] for m in g['models']]}"
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
_cfg.cfg.clear()
|
||||||
|
_cfg.cfg.update(old_cfg)
|
||||||
|
|
||||||
|
|
||||||
def test_default_provider_models_not_prefixed():
|
def test_default_provider_models_not_prefixed():
|
||||||
"""The active provider's models remain bare (no @prefix added)."""
|
"""The active provider's models remain bare (no @prefix added)."""
|
||||||
import api.config as _cfg
|
import api.config as _cfg
|
||||||
|
|||||||
Reference in New Issue
Block a user