From 95a3affc2e4ea47235b3a54dba8b994a44dcce29 Mon Sep 17 00:00:00 2001 From: helix4u <4317663+helix4u@users.noreply.github.com> Date: Fri, 19 Jun 2026 20:05:55 -0600 Subject: [PATCH] fix(model): keep Nous picker from restoring stale custom keys --- hermes_cli/model_setup_flows.py | 3 + tests/cli/test_cli_provider_resolution.py | 70 +++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/hermes_cli/model_setup_flows.py b/hermes_cli/model_setup_flows.py index 1af46ab40aa..18776fd0678 100644 --- a/hermes_cli/model_setup_flows.py +++ b/hermes_cli/model_setup_flows.py @@ -325,6 +325,9 @@ def _model_flow_nous(config, current_model="", args=None): # Reactivate Nous as the provider and update config inference_url = creds.get("base_url", "") _update_config_for_provider("nous", inference_url) + # Reload after the auth helper writes provider state. The incoming + # config object may still contain stale custom-provider fields. + config = load_config() current_model_cfg = config.get("model") if isinstance(current_model_cfg, dict): model_cfg = dict(current_model_cfg) diff --git a/tests/cli/test_cli_provider_resolution.py b/tests/cli/test_cli_provider_resolution.py index 07d16366d04..5dbfca1ae6f 100644 --- a/tests/cli/test_cli_provider_resolution.py +++ b/tests/cli/test_cli_provider_resolution.py @@ -308,6 +308,76 @@ def test_model_flow_nous_prints_subscription_guidance_without_mutating_explicit_ assert config["browser"]["cloud_provider"] == "browser-use" +def test_model_flow_nous_does_not_restore_stale_custom_api_key(tmp_path, monkeypatch): + import yaml + + config_home = tmp_path / "hermes" + config_home.mkdir() + monkeypatch.setenv("HERMES_HOME", str(config_home)) + + config_path = config_home / "config.yaml" + config_path.write_text( + yaml.safe_dump( + { + "model": { + "provider": "custom", + "default": "glm-5.2", + "base_url": "https://api.neuralwatt.com/v1", + "api_key": "${NEURALWATT_API_KEY}", + "api_mode": "chat_completions", + } + }, + sort_keys=False, + ) + ) + + stale_config = yaml.safe_load(config_path.read_text()) or {} + selected_model = "deepseek/deepseek-v4-flash" + + monkeypatch.setattr( + "hermes_cli.auth.get_provider_auth_state", + lambda provider: { + "access_token": "nous-token", + "portal_base_url": "https://portal.example.com", + }, + ) + monkeypatch.setattr( + "hermes_cli.auth.resolve_nous_runtime_credentials", + lambda *args, **kwargs: { + "base_url": "https://inference-api.nousresearch.com/v1", + "api_key": "nous-key", + }, + ) + monkeypatch.setattr( + "hermes_cli.models.get_curated_nous_model_ids", + lambda: [selected_model], + ) + monkeypatch.setattr("hermes_cli.models.get_pricing_for_provider", lambda provider: {}) + monkeypatch.setattr("hermes_cli.models.check_nous_free_tier", lambda **kwargs: False) + monkeypatch.setattr( + "hermes_cli.models.union_with_portal_paid_recommendations", + lambda model_ids, pricing, portal_url: (model_ids, pricing), + ) + monkeypatch.setattr( + "hermes_cli.auth._prompt_model_selection", + lambda *args, **kwargs: selected_model, + ) + monkeypatch.setattr( + "hermes_cli.nous_subscription.prompt_enable_tool_gateway", + lambda config: None, + ) + + hermes_main._model_flow_nous(stale_config, current_model="glm-5.2") + + config = yaml.safe_load(config_path.read_text()) or {} + model = config.get("model") + assert model["provider"] == "nous" + assert model["default"] == selected_model + assert model["base_url"] == "https://inference-api.nousresearch.com/v1" + assert "api_key" not in model + assert "api_mode" not in model + + def test_model_flow_nous_offers_tool_gateway_prompt_when_unconfigured(monkeypatch, capsys): from hermes_cli.nous_account import NousPortalAccountInfo