fix(model dropdown): stop injecting default into unrelated providers

This commit is contained in:
Frank Song
2026-04-18 23:26:25 +08:00
parent 352354790f
commit 75e4f8b201
3 changed files with 69 additions and 18 deletions

View File

@@ -245,6 +245,10 @@ def _available_models_with_full_cfg(provider, default, base_url):
'default': default,
'base_url': base_url,
}
try:
_cfg._cfg_mtime = _cfg.Path(_cfg._get_config_path()).stat().st_mtime
except Exception:
pass
# Clear model-override env vars to prevent the real profile from leaking in
_model_env_keys = ('HERMES_MODEL', 'OPENAI_MODEL', 'LLM_MODEL')
_saved_env = {k: os.environ.pop(k, None) for k in _model_env_keys}
@@ -318,16 +322,59 @@ def test_default_model_lands_under_active_provider_group(monkeypatch):
)
groups = {g['provider']: [m['id'] for m in g['models']] for g in result['groups']}
assert 'OpenAI Codex' in groups, f"OpenAI Codex group missing: {list(groups)}"
assert 'gpt-5.4' in groups['OpenAI Codex'], (
norm = lambda mid: mid.split('/', 1)[-1].split(':', 1)[-1]
assert 'gpt-5.4' in {norm(mid) for mid in groups['OpenAI Codex']}, (
f"gpt-5.4 not in OpenAI Codex group; contents: {groups['OpenAI Codex']}"
)
# And crucially, it must NOT have landed in the alphabetically-first
# group (Anthropic) via the fallback path.
assert 'gpt-5.4' not in groups.get('Anthropic', []), (
assert 'gpt-5.4' not in {norm(mid) for mid in groups.get('Anthropic', [])}, (
f"gpt-5.4 leaked into Anthropic group via fallback: {groups.get('Anthropic')}"
)
def test_unknown_providers_do_not_inherit_default_model(monkeypatch):
"""Detected providers without their own model catalog must not be filled
with the global default_model placeholder.
Regression guard for the bug where Alibaba / Minimax-Cn ended up showing
gpt-5.4-mini even though those providers do not serve it.
"""
import sys, types
fake_mod = types.ModuleType('hermes_cli.models')
fake_mod.list_available_providers = lambda: [
{'id': 'openai-codex', 'authenticated': True},
{'id': 'alibaba', 'authenticated': True},
{'id': 'minimax-cn', 'authenticated': True},
]
fake_auth = types.ModuleType('hermes_cli.auth')
fake_auth.get_auth_status = lambda pid: {'key_source': 'env'}
monkeypatch.setitem(sys.modules, 'hermes_cli.models', fake_mod)
monkeypatch.setitem(sys.modules, 'hermes_cli.auth', fake_auth)
result = _available_models_with_full_cfg(
provider='openai-codex',
default='gpt-5.4-mini',
base_url='',
)
groups = {g['provider']: [m['id'] for m in g['models']] for g in result['groups']}
norm = lambda mid: mid.split('/', 1)[-1].split(':', 1)[-1]
assert 'Alibaba' not in groups, (
f"Alibaba should not inherit the default model placeholder: {groups}"
)
assert 'Minimax-Cn' not in groups, (
f"Minimax-Cn should not inherit the default model placeholder: {groups}"
)
assert not any(
norm(mid) == 'gpt-5.4-mini'
for mid in groups.get('Alibaba', []) + groups.get('Minimax-Cn', [])
), (
f"Unknown provider groups still inherited the default model: {groups}"
)
def test_custom_endpoint_uses_model_config_api_key_for_model_discovery(monkeypatch):
"""Custom endpoint model discovery must use model.api_key from config.yaml,
not only environment variables, otherwise the dropdown collapses to the
@@ -342,6 +389,10 @@ def test_custom_endpoint_uses_model_config_api_key_for_model_discovery(monkeypat
'base_url': 'https://example.test/v1',
'api_key': 'sk-test-model-key',
}
try:
_cfg._cfg_mtime = _cfg.Path(_cfg._get_config_path()).stat().st_mtime
except Exception:
pass
_cfg.cfg.pop('providers', None)
captured = {}