mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-27 11:22:03 +00:00
fix(model-switch): prevent custom-provider misattribution in model picker (#48305)
When the current provider is a custom endpoint (custom or custom:*), the model switch pipeline must NOT auto-switch to a native provider/OpenRouter based on a static-catalog match. The user explicitly configured their own endpoint and the same model name may be served there; silently rewriting model.provider destroys their config. - detect_static_provider_for_model(): skip the static-catalog scan when the current provider is custom/custom:* - switch_model() Step e: extend is_custom to cover custom:* so the detect_provider_for_model() last-resort fallback cannot fire Salvaged from #48351 by Elshayib (authorship preserved). Fixes #48305
This commit is contained in:
parent
b85c460540
commit
1a435a6d5d
3 changed files with 34 additions and 2 deletions
|
|
@ -1057,8 +1057,10 @@ def switch_model(
|
|||
|
||||
# --- Step e: detect_provider_for_model() as last resort ---
|
||||
_base = current_base_url or ""
|
||||
is_custom = current_provider in {"custom", "local"} or (
|
||||
"localhost" in _base or "127.0.0.1" in _base
|
||||
is_custom = (
|
||||
current_provider in {"custom", "local"}
|
||||
or current_provider.startswith("custom:")
|
||||
or ("localhost" in _base or "127.0.0.1" in _base)
|
||||
)
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -1882,6 +1882,14 @@ def detect_static_provider_for_model(
|
|||
return None
|
||||
|
||||
# --- Step 1: check static provider catalogs for a direct match ---
|
||||
# If the current provider is a custom endpoint (custom or custom:*), never
|
||||
# auto-switch away from it based on a static catalog match — the user
|
||||
# explicitly configured their own endpoint and the same model name may be
|
||||
# served there (#48305).
|
||||
_is_custom_current = (
|
||||
current_provider == "custom"
|
||||
or current_provider.startswith("custom:")
|
||||
)
|
||||
for pid, models in _PROVIDER_MODELS.items():
|
||||
if (
|
||||
pid in current_keys
|
||||
|
|
@ -1889,6 +1897,8 @@ def detect_static_provider_for_model(
|
|||
or pid in _BORROWED_MODEL_PROVIDERS
|
||||
):
|
||||
continue
|
||||
if _is_custom_current:
|
||||
continue
|
||||
if any(name_lower == m.lower() for m in models):
|
||||
return (pid, name)
|
||||
|
||||
|
|
|
|||
|
|
@ -301,6 +301,26 @@ class TestDetectProviderForModel:
|
|||
assert result is not None
|
||||
assert result[0] not in {"nous",} # nous has claude models but shouldn't be suggested
|
||||
|
||||
def test_custom_provider_not_overridden_by_static_catalog(self):
|
||||
"""When current provider is custom:*, a static-catalog match must NOT
|
||||
override it — otherwise a model served by the user's own endpoint gets
|
||||
misattributed to a native provider, rewriting model.provider (#48305).
|
||||
|
||||
`gpt-5.4` is in the static openai catalog; with current=custom:foo,
|
||||
detection must return None instead of switching to openai.
|
||||
"""
|
||||
assert detect_provider_for_model("gpt-5.4", "custom:foo") is None
|
||||
|
||||
def test_bare_custom_provider_not_overridden_by_static_catalog(self):
|
||||
"""Same protection for the bare 'custom' provider."""
|
||||
assert detect_provider_for_model("gpt-5.4", "custom") is None
|
||||
|
||||
def test_non_custom_provider_detection_unaffected(self):
|
||||
"""The custom-provider guard must NOT change detection for non-custom
|
||||
current providers — a static-catalog model still routes normally."""
|
||||
result = detect_provider_for_model("gpt-5.4", "openrouter")
|
||||
assert result is not None and result[0] == "openai"
|
||||
|
||||
|
||||
class TestIsNousFreeTier:
|
||||
"""Tests for is_nous_free_tier — account tier detection."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue