Download tests/test_cli_model_command.py from lenson78/hermes: direct link, hf CLI and curl.
- Browser
- Download file 5.66 kB
-
https://huggingface.co/spaces/lenson78/hermes/resolve/main/tests/test_cli_model_command.py
- Command line
-
hf download hf://spaces/lenson78/hermes/tests/test_cli_model_command.py
-
curl -L -o test_cli_model_command.py https://huggingface.co/spaces/lenson78/hermes/resolve/main/tests/test_cli_model_command.py
5.66 kB
| """Regression tests for the `/model` slash command in the interactive CLI.""" | |
| from unittest.mock import patch, MagicMock | |
| from cli import HermesCLI | |
| class TestModelCommand: | |
| def _make_cli(self): | |
| cli_obj = HermesCLI.__new__(HermesCLI) | |
| cli_obj.model = "anthropic/claude-opus-4.6" | |
| cli_obj.agent = object() | |
| cli_obj.provider = "openrouter" | |
| cli_obj.requested_provider = "openrouter" | |
| cli_obj.base_url = "https://openrouter.ai/api/v1" | |
| cli_obj.api_key = "test-key" | |
| cli_obj._explicit_api_key = None | |
| cli_obj._explicit_base_url = None | |
| return cli_obj | |
| def test_valid_model_from_api_saved_to_config(self, capsys): | |
| cli_obj = self._make_cli() | |
| with patch("hermes_cli.models.fetch_api_models", | |
| return_value=["anthropic/claude-sonnet-4.5", "openai/gpt-5.4"]), \ | |
| patch("cli.save_config_value", return_value=True) as save_mock: | |
| cli_obj.process_command("/model anthropic/claude-sonnet-4.5") | |
| output = capsys.readouterr().out | |
| assert "saved to config" in output | |
| assert cli_obj.model == "anthropic/claude-sonnet-4.5" | |
| save_mock.assert_called_once_with("model.default", "anthropic/claude-sonnet-4.5") | |
| def test_unlisted_model_accepted_with_warning(self, capsys): | |
| cli_obj = self._make_cli() | |
| with patch("hermes_cli.models.fetch_api_models", | |
| return_value=["anthropic/claude-opus-4.6"]), \ | |
| patch("cli.save_config_value") as save_mock: | |
| cli_obj.process_command("/model anthropic/fake-model") | |
| output = capsys.readouterr().out | |
| assert "not found" in output or "Model changed" in output | |
| assert cli_obj.model == "anthropic/fake-model" # accepted | |
| def test_api_unreachable_accepts_and_persists(self, capsys): | |
| cli_obj = self._make_cli() | |
| with patch("hermes_cli.models.fetch_api_models", return_value=None), \ | |
| patch("cli.save_config_value") as save_mock: | |
| cli_obj.process_command("/model anthropic/claude-sonnet-next") | |
| output = capsys.readouterr().out | |
| assert "saved to config" in output | |
| assert cli_obj.model == "anthropic/claude-sonnet-next" | |
| save_mock.assert_called_once() | |
| def test_no_slash_model_accepted_with_warning(self, capsys): | |
| cli_obj = self._make_cli() | |
| with 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 gpt-5.4") | |
| output = capsys.readouterr().out | |
| # Auto-detection remaps bare model names to proper OpenRouter slugs | |
| assert cli_obj.model == "openai/gpt-5.4" | |
| def test_validation_crash_falls_back_to_save(self, capsys): | |
| cli_obj = self._make_cli() | |
| with patch("hermes_cli.models.validate_requested_model", | |
| side_effect=RuntimeError("boom")), \ | |
| patch("cli.save_config_value", return_value=True) as save_mock: | |
| cli_obj.process_command("/model anthropic/claude-sonnet-4.5") | |
| output = capsys.readouterr().out | |
| assert "saved to config" in output | |
| assert cli_obj.model == "anthropic/claude-sonnet-4.5" | |
| save_mock.assert_called_once() | |
| def test_show_model_when_no_argument(self, capsys): | |
| cli_obj = self._make_cli() | |
| cli_obj.process_command("/model") | |
| output = capsys.readouterr().out | |
| assert "anthropic/claude-opus-4.6" in output | |
| assert "OpenRouter" in output | |
| assert "Authenticated providers" in output or "Switch model" in output | |
| assert "provider" in output and "model" in output | |
| # -- provider switching tests ------------------------------------------- | |
| def test_provider_colon_model_switches_provider(self, capsys): | |
| cli_obj = self._make_cli() | |
| with patch("hermes_cli.runtime_provider.resolve_runtime_provider", return_value={ | |
| "provider": "zai", | |
| "api_key": "zai-key", | |
| "base_url": "https://api.z.ai/api/paas/v4", | |
| }), \ | |
| patch("hermes_cli.models.fetch_api_models", | |
| return_value=["glm-5", "glm-4.7"]), \ | |
| patch("cli.save_config_value", return_value=True) as save_mock: | |
| cli_obj.process_command("/model zai:glm-5") | |
| output = capsys.readouterr().out | |
| assert "glm-5" in output | |
| assert "provider:" in output.lower() or "Z.AI" in output | |
| assert cli_obj.model == "glm-5" | |
| assert cli_obj.provider == "zai" | |
| assert cli_obj.base_url == "https://api.z.ai/api/paas/v4" | |
| # Model, provider, and base_url should be saved | |
| assert save_mock.call_count == 3 | |
| save_calls = [c.args for c in save_mock.call_args_list] | |
| assert ("model.default", "glm-5") in save_calls | |
| assert ("model.provider", "zai") in save_calls | |
| # base_url is also persisted on provider change (Phase 2 fix) | |
| assert any(c[0] == "model.base_url" for c in save_calls) | |
| def test_provider_switch_fails_on_bad_credentials(self, capsys): | |
| cli_obj = self._make_cli() | |
| with patch("hermes_cli.runtime_provider.resolve_runtime_provider", | |
| side_effect=Exception("No API key found")): | |
| cli_obj.process_command("/model nous:hermes-3") | |
| output = capsys.readouterr().out | |
| assert "Could not resolve credentials" in output | |
| assert cli_obj.model == "anthropic/claude-opus-4.6" # unchanged | |
| assert cli_obj.provider == "openrouter" # unchanged | |