fix: avoid custom provider shadowing built-in providers

Follow up on salvaged PR #1012.
Prevents raw custom-provider names from intercepting built-in provider ids,
and keeps the regression coverage focused on current-main behavior.
This commit is contained in:
teknium1 2026-03-14 11:24:29 -07:00
parent 4422637e7a
commit 88951215d3
2 changed files with 37 additions and 13 deletions

View file

@ -5,6 +5,7 @@ from __future__ import annotations
import os import os
from typing import Any, Dict, Optional from typing import Any, Dict, Optional
from hermes_cli import auth as auth_mod
from hermes_cli.auth import ( from hermes_cli.auth import (
AuthError, AuthError,
PROVIDER_REGISTRY, PROVIDER_REGISTRY,
@ -56,6 +57,19 @@ def _get_named_custom_provider(requested_provider: str) -> Optional[Dict[str, An
if not requested_norm or requested_norm == "custom": if not requested_norm or requested_norm == "custom":
return None return None
# Raw names should only map to custom providers when they are not already
# valid built-in providers or aliases. Explicit menu keys like
# ``custom:local`` always target the saved custom provider.
if requested_norm == "auto":
return None
if not requested_norm.startswith("custom:"):
try:
auth_mod.resolve_provider(requested_norm)
except AuthError:
pass
else:
return None
config = load_config() config = load_config()
custom_providers = config.get("custom_providers") custom_providers = config.get("custom_providers")
if not isinstance(custom_providers, list): if not isinstance(custom_providers, list):

View file

@ -226,27 +226,37 @@ def test_named_custom_provider_falls_back_to_openai_api_key(monkeypatch):
assert resolved["requested_provider"] == "custom:local-llm" assert resolved["requested_provider"] == "custom:local-llm"
def test_resolve_runtime_provider_nous_api(monkeypatch): def test_named_custom_provider_does_not_shadow_builtin_provider(monkeypatch):
"""Nous Portal API key provider resolves via the api_key path."""
monkeypatch.setattr(rp, "resolve_provider", lambda *a, **k: "nous-api")
monkeypatch.setattr( monkeypatch.setattr(
rp, rp,
"resolve_api_key_provider_credentials", "load_config",
lambda pid: { lambda: {
"provider": "nous-api", "custom_providers": [
"api_key": "nous-test-key", {
"name": "nous",
"base_url": "http://localhost:1234/v1",
"api_key": "shadow-key",
}
]
},
)
monkeypatch.setattr(
rp,
"resolve_nous_runtime_credentials",
lambda **kwargs: {
"base_url": "https://inference-api.nousresearch.com/v1", "base_url": "https://inference-api.nousresearch.com/v1",
"source": "NOUS_API_KEY", "api_key": "nous-runtime-key",
"source": "portal",
"expires_at": None,
}, },
) )
resolved = rp.resolve_runtime_provider(requested="nous-api") resolved = rp.resolve_runtime_provider(requested="nous")
assert resolved["provider"] == "nous-api" assert resolved["provider"] == "nous"
assert resolved["api_mode"] == "chat_completions"
assert resolved["base_url"] == "https://inference-api.nousresearch.com/v1" assert resolved["base_url"] == "https://inference-api.nousresearch.com/v1"
assert resolved["api_key"] == "nous-test-key" assert resolved["api_key"] == "nous-runtime-key"
assert resolved["requested_provider"] == "nous-api" assert resolved["requested_provider"] == "nous"
def test_explicit_openrouter_skips_openai_base_url(monkeypatch): def test_explicit_openrouter_skips_openai_base_url(monkeypatch):