diff --git a/hermes_cli/models.py b/hermes_cli/models.py index 60825da6d..cbcfc405f 100644 --- a/hermes_cli/models.py +++ b/hermes_cli/models.py @@ -177,23 +177,6 @@ def validate_requested_model( "message": "Model names cannot contain spaces.", } - # OpenRouter requires provider/model format - if normalized == "openrouter": - if "/" not in requested or requested.startswith("/") or requested.endswith("/"): - known_models = provider_model_ids(normalized) - suggestion = get_close_matches(requested, known_models, n=1, cutoff=0.6) - suggestion_text = f" Did you mean `{suggestion[0]}`?" if suggestion else "" - return { - "accepted": False, - "persist": False, - "recognized": False, - "message": ( - "OpenRouter model IDs should use the `provider/model` format " - "(for example `anthropic/claude-opus-4.6`)." - f"{suggestion_text}" - ), - } - # Probe the live API to check if the model actually exists api_models = fetch_api_models(api_key, base_url) diff --git a/tests/hermes_cli/test_model_validation.py b/tests/hermes_cli/test_model_validation.py index b85f317bc..d473a411c 100644 --- a/tests/hermes_cli/test_model_validation.py +++ b/tests/hermes_cli/test_model_validation.py @@ -103,18 +103,16 @@ class TestValidateFormatChecks: assert result["accepted"] is False assert "spaces" in result["message"].lower() - def test_openrouter_requires_slash(self): - result = _validate("claude-opus-4.6") - assert result["accepted"] is False - assert "provider/model" in result["message"] + def test_no_slash_model_still_probes_api(self): + """Models without '/' should still be checked via API (not all providers need it).""" + result = _validate("gpt-5.4", api_models=["gpt-5.4", "gpt-5.4-pro"]) + assert result["accepted"] is True + assert result["persist"] is True - def test_openrouter_rejects_leading_slash(self): - result = _validate("/claude-opus-4.6") - assert result["accepted"] is False - - def test_openrouter_rejects_trailing_slash(self): - result = _validate("anthropic/") + def test_no_slash_model_rejected_if_not_in_api(self): + result = _validate("gpt-5.4", api_models=["openai/gpt-5.4"]) assert result["accepted"] is False + assert "not a valid model" in result["message"] # -- validate_requested_model — API probe found model ------------------------ diff --git a/tests/test_cli_model_command.py b/tests/test_cli_model_command.py index 41757de1e..a43b96379 100644 --- a/tests/test_cli_model_command.py +++ b/tests/test_cli_model_command.py @@ -62,18 +62,20 @@ class TestModelCommand: assert cli_obj.agent is None save_mock.assert_not_called() - def test_bad_format_rejected_without_api_call(self, capsys): + def test_no_slash_model_probes_api_and_rejects(self, capsys): + """Model without '/' is still probed via API — not rejected on format alone.""" cli_obj = self._make_cli() with patch("hermes_cli.auth.resolve_provider", return_value="openrouter"), \ - patch("hermes_cli.models.fetch_api_models") as fetch_mock, \ + patch("hermes_cli.models.fetch_api_models", + return_value=["openai/gpt-5.4"]) as fetch_mock, \ patch("cli.save_config_value") as save_mock: - cli_obj.process_command("/model invalid-no-slash") + cli_obj.process_command("/model gpt-5.4") output = capsys.readouterr().out - assert "provider/model" in output + assert "not a valid model" in output assert cli_obj.model == "anthropic/claude-opus-4.6" # unchanged - fetch_mock.assert_not_called() # no API call for format errors + fetch_mock.assert_called_once() # API was probed save_mock.assert_not_called() def test_validation_crash_falls_back_to_save(self, capsys):