fix(model): match custom provider by active base url

This commit is contained in:
helix4u 2026-05-19 13:45:57 -06:00 committed by Teknium
parent 60bb98e003
commit d9829ab45f
2 changed files with 220 additions and 54 deletions

View file

@ -327,6 +327,118 @@ class TestCustomProviderModelSwitch:
assert config["custom_providers"][0]["api_key"] == "${NEURALWATT_API_KEY}"
assert "sk-live-neuralwatt-secret" not in saved
def test_bare_custom_current_provider_matches_env_base_url_before_first_fallback(
self, config_home, monkeypatch
):
"""`hermes model` must mark the custom provider matching model.base_url
as current instead of falling back to the first saved custom provider.
Regression: with ``model.provider: custom`` and multiple
``custom_providers`` entries, the CLI resolved bare ``custom`` through
``resolve_custom_provider()``, whose compatibility fallback returns the
first entry. A config with Cerebras first and NeuralWatt active then
showed Cerebras as current.
"""
from hermes_cli.main import select_provider_and_model
config_path = config_home / "config.yaml"
config_path.write_text(
"model:\n"
" default: kimi-k2.6-fast\n"
" provider: custom\n"
" base_url: ${NEURALWATT_API_BASE}\n"
" api_key: ${NEURALWATT_API_KEY}\n"
"providers: {}\n"
"custom_providers:\n"
"- name: Cerebras.ai\n"
" base_url: ${CEREBRAS_API_BASE}\n"
" api_key: ${CEREBRAS_API_KEY}\n"
" model: qwen-3-235b-a22b-instruct-2507\n"
" models: []\n"
"- name: NeuralWatt\n"
" base_url: ${NEURALWATT_API_BASE}\n"
" api_key: ${NEURALWATT_API_KEY}\n"
" model: kimi-k2.6-fast\n"
" models: []\n"
)
monkeypatch.setenv("CEREBRAS_API_BASE", "https://api.cerebras.ai/v1")
monkeypatch.setenv("CEREBRAS_API_KEY", "sk-live-cerebras-secret")
monkeypatch.setenv("NEURALWATT_API_BASE", "https://api.neuralwatt.com/v1")
monkeypatch.setenv("NEURALWATT_API_KEY", "sk-live-neuralwatt-secret")
captured: dict = {}
def _capture_and_cancel(labels, default=0):
captured["labels"] = labels
captured["default"] = default
return len(labels) - 1 # Leave unchanged
with patch("hermes_cli.main._prompt_provider_choice",
side_effect=_capture_and_cancel), \
patch("builtins.print"):
select_provider_and_model()
labels = captured["labels"]
default_label = labels[captured["default"]]
assert "NeuralWatt" in default_label
assert "currently active" in default_label
assert "Cerebras.ai" not in default_label
assert not any(
"Cerebras.ai" in label and "currently active" in label
for label in labels
)
def test_named_custom_provider_selection_preserves_base_url_env_ref(
self, config_home, monkeypatch
):
"""Selecting an env-backed custom provider should not expand its
``base_url`` template into ``model.base_url`` on disk."""
import yaml
from hermes_cli.main import select_provider_and_model
config_path = config_home / "config.yaml"
config_path.write_text(
"model:\n"
" default: old-model\n"
" provider: openrouter\n"
"custom_providers:\n"
"- name: NeuralWatt\n"
" base_url: ${NEURALWATT_API_BASE}\n"
" api_key: ${NEURALWATT_API_KEY}\n"
" model: qwen3.6-35b-fast\n"
" models: []\n"
)
monkeypatch.setenv("NEURALWATT_API_BASE", "https://api.neuralwatt.com/v1")
monkeypatch.setenv("NEURALWATT_API_KEY", "sk-live-neuralwatt-secret")
def _pick_neuralwatt(labels, default=0):
for i, label in enumerate(labels):
if "NeuralWatt" in label:
return i
raise AssertionError(
f"NeuralWatt entry missing from provider menu: {labels}"
)
with patch("hermes_cli.main._prompt_provider_choice",
side_effect=_pick_neuralwatt), \
patch("hermes_cli.models.fetch_api_models",
return_value=["qwen3.6-35b-fast"]) as mock_fetch, \
patch.dict("sys.modules", {"simple_term_menu": None}), \
patch("builtins.input", return_value="1"), \
patch("builtins.print"):
select_provider_and_model()
mock_fetch.assert_called_once()
probe_args, _ = mock_fetch.call_args
assert probe_args[1] == "https://api.neuralwatt.com/v1"
saved = config_path.read_text()
config = yaml.safe_load(saved) or {}
assert config["model"]["base_url"] == "${NEURALWATT_API_BASE}"
assert config["model"]["api_key"] == "${NEURALWATT_API_KEY}"
assert "https://api.neuralwatt.com/v1" not in saved
assert "sk-live-neuralwatt-secret" not in saved
def test_key_env_providers_dict_entry_does_not_add_api_key(
self, config_home, monkeypatch
):