fix: silent no-model default is GLM-5.2, never the Anthropic flagship (#64635)

When a user starts a chat without ever selecting a model (GUI Chat App
onboarding, provider-set-but-model-missing config, empty model.default),
every silent fallback path resolved to the first curated catalog entry —
anthropic/claude-fable-5, the priciest flagship. Users were silently
billed for the most expensive model without opting in.

- hermes_cli/models.py: add PREFERRED_SILENT_DEFAULT_MODEL (z-ai/glm-5.2)
  + pick_silent_default_model() helper; point the nous silent-default
  override at it and add an openrouter override (previously resolved to
  "" and let downstream paths land on the flagship).
- hermes_cli/web_server.py: /api/model/recommended-default (the endpoint
  the Desktop onboarding confirm card reads) now picks GLM-5.2 when the
  provider's list carries it instead of blindly taking entry [0].
- tui_gateway/server.py: _resolve_model()'s last-resort literal was
  anthropic/claude-sonnet-4; now PREFERRED_SILENT_DEFAULT_MODEL.
- tests: update empty-model fallback tests for the new contract.
This commit is contained in:
Teknium 2026-07-14 21:11:46 -07:00 committed by GitHub
parent 5d410355ac
commit 080daa3f42
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 68 additions and 21 deletions

View file

@ -13,12 +13,17 @@ class TestGetDefaultModelForProvider:
assert result
assert isinstance(result, str)
def test_openrouter_returns_empty(self):
"""OpenRouter uses dynamic model fetch, no static catalog entry."""
from hermes_cli.models import get_default_model_for_provider
# OpenRouter is not in _PROVIDER_MODELS — it uses live fetching
def test_openrouter_returns_preferred_silent_default(self):
"""OpenRouter has no static catalog (live fetch), but the silent
default must still resolve to the cost-safe preferred model, never
the curated list's Anthropic flagship (claude-fable-5)."""
from hermes_cli.models import (
PREFERRED_SILENT_DEFAULT_MODEL,
get_default_model_for_provider,
)
result = get_default_model_for_provider("openrouter")
assert result == ""
assert result == PREFERRED_SILENT_DEFAULT_MODEL
assert "claude" not in result.lower()
def test_unknown_provider_returns_empty(self):
from hermes_cli.models import get_default_model_for_provider