From f6a3d2e900f86880891afd58f944c250fd75540a Mon Sep 17 00:00:00 2001 From: LeonSGP43 Date: Fri, 26 Jun 2026 15:59:43 +0800 Subject: [PATCH] fix(model): preserve named custom provider slug --- hermes_cli/model_setup_flows.py | 2 +- .../test_model_provider_persistence.py | 46 ++++++++++++++++++- .../test_runtime_provider_resolution.py | 27 +++++++++++ 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/hermes_cli/model_setup_flows.py b/hermes_cli/model_setup_flows.py index 312677dabc4..b6769b69d86 100644 --- a/hermes_cli/model_setup_flows.py +++ b/hermes_cli/model_setup_flows.py @@ -1446,7 +1446,7 @@ def _model_flow_named_custom(config, provider_info): model = {"default": model} if model else {} cfg["model"] = model if provider_key: - model["provider"] = provider_key + model["provider"] = "custom:" + provider_key.strip().lower().replace(" ", "-") model.pop("base_url", None) model.pop("api_key", None) else: diff --git a/tests/hermes_cli/test_model_provider_persistence.py b/tests/hermes_cli/test_model_provider_persistence.py index 76d5ee7414d..dd007d44237 100644 --- a/tests/hermes_cli/test_model_provider_persistence.py +++ b/tests/hermes_cli/test_model_provider_persistence.py @@ -207,6 +207,51 @@ class TestProviderPersistsAfterModelSave: assert model.get("base_url") == "https://packy.example.com/v1" assert model.get("api_mode") == "codex_responses" + def test_named_custom_provider_with_builtin_slug_persists_custom_prefix( + self, config_home, monkeypatch + ): + """providers. must persist as a named custom provider.""" + import yaml + + from hermes_cli.main import _model_flow_named_custom + + config_path = config_home / "config.yaml" + config_path.write_text( + "providers:\n" + " minimax-cn:\n" + " name: MiniMax CN Proxy\n" + " api: https://mimimax.cn/v1\n" + " key_env: MINIMAX_CN_PROXY_KEY\n" + " transport: chat_completions\n" + " model: MiniMax-M3\n" + " default_model: MiniMax-M3\n" + ) + monkeypatch.setenv("MINIMAX_CN_PROXY_KEY", "proxy-secret") + + provider_info = { + "name": "MiniMax CN Proxy", + "base_url": "https://mimimax.cn/v1", + "api_key": "", + "key_env": "MINIMAX_CN_PROXY_KEY", + "model": "MiniMax-M3", + "api_mode": "chat_completions", + "provider_key": "minimax-cn", + } + + with patch("hermes_cli.auth._save_model_choice"), \ + patch("hermes_cli.auth.deactivate_provider"), \ + patch("hermes_cli.models.fetch_api_models", return_value=["MiniMax-M3"]), \ + patch("hermes_cli.curses_ui.curses_radiolist", side_effect=OSError("no tty in test")), \ + patch("builtins.input", return_value="1"): + _model_flow_named_custom({}, provider_info) + + config = yaml.safe_load(config_path.read_text()) or {} + model = config.get("model") + assert isinstance(model, dict) + assert model.get("provider") == "custom:minimax-cn" + assert "base_url" not in model + assert "api_key" not in model + def test_copilot_acp_provider_saved_when_selected(self, config_home): """_model_flow_copilot_acp should persist provider/base_url/model together.""" from hermes_cli.main import _model_flow_copilot_acp @@ -555,4 +600,3 @@ class TestZaiEndpointPicker: _select_zai_endpoint(custom_url) assert captured["default"] == expected_default - diff --git a/tests/hermes_cli/test_runtime_provider_resolution.py b/tests/hermes_cli/test_runtime_provider_resolution.py index 54f58b85808..df47efcf839 100644 --- a/tests/hermes_cli/test_runtime_provider_resolution.py +++ b/tests/hermes_cli/test_runtime_provider_resolution.py @@ -1272,6 +1272,33 @@ def test_resolve_requested_provider_precedence(monkeypatch): assert rp.resolve_requested_provider() == "auto" +def test_resolve_runtime_provider_named_custom_with_builtin_slug(monkeypatch): + monkeypatch.setenv("MINIMAX_CN_PROXY_KEY", "proxy-secret") + monkeypatch.setattr( + rp, + "load_config", + lambda: { + "model": {"provider": "custom:minimax-cn"}, + "providers": { + "minimax-cn": { + "name": "MiniMax CN Proxy", + "api": "https://mimimax.cn/v1", + "key_env": "MINIMAX_CN_PROXY_KEY", + "transport": "chat_completions", + "default_model": "MiniMax-M3", + } + }, + }, + ) + + resolved = rp.resolve_runtime_provider() + + assert resolved["provider"] == "custom" + assert resolved["base_url"] == "https://mimimax.cn/v1" + assert resolved["api_key"] == "proxy-secret" + assert resolved["api_mode"] == "chat_completions" + + # ── api_mode config override tests ──────────────────────────────────────