mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-29 15:31:38 +08:00
138 lines
4.1 KiB
Python
138 lines
4.1 KiB
Python
|
|
"""Tests for /reasoning slash command in HermesCLI."""
|
||
|
|
|
||
|
|
from unittest.mock import patch
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
|
||
|
|
def _make_cli(**kwargs):
|
||
|
|
"""Create a HermesCLI instance with minimal mocking."""
|
||
|
|
import cli as _cli_mod
|
||
|
|
from cli import HermesCLI
|
||
|
|
|
||
|
|
clean_config = {
|
||
|
|
"model": {
|
||
|
|
"default": "anthropic/claude-opus-4.6",
|
||
|
|
"base_url": "https://openrouter.ai/api/v1",
|
||
|
|
"provider": "auto",
|
||
|
|
},
|
||
|
|
"display": {"compact": False, "tool_progress": "all"},
|
||
|
|
"agent": {"reasoning_effort": "medium"},
|
||
|
|
"terminal": {"env_type": "local"},
|
||
|
|
}
|
||
|
|
|
||
|
|
clean_env = {"LLM_MODEL": "", "HERMES_MAX_ITERATIONS": ""}
|
||
|
|
|
||
|
|
with (
|
||
|
|
patch("cli.get_tool_definitions", return_value=[]),
|
||
|
|
patch.dict("os.environ", clean_env, clear=False),
|
||
|
|
patch.dict(_cli_mod.__dict__, {"CLI_CONFIG": clean_config}),
|
||
|
|
):
|
||
|
|
return HermesCLI(**kwargs)
|
||
|
|
|
||
|
|
|
||
|
|
# -- setting valid effort levels -------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.parametrize("level", ["low", "medium", "high", "xhigh"])
|
||
|
|
def test_reasoning_command_sets_effort_and_persists(level):
|
||
|
|
cli_obj = _make_cli()
|
||
|
|
cli_obj.agent = object() # ensure command forces re-init
|
||
|
|
|
||
|
|
with patch("cli.save_config_value", return_value=True) as mock_save:
|
||
|
|
keep_running = cli_obj.process_command(f"/reasoning {level}")
|
||
|
|
|
||
|
|
assert keep_running is True
|
||
|
|
assert cli_obj.reasoning_config == {"enabled": True, "effort": level}
|
||
|
|
assert cli_obj.agent is None
|
||
|
|
mock_save.assert_called_once_with("agent.reasoning_effort", level)
|
||
|
|
|
||
|
|
|
||
|
|
def test_reasoning_command_sets_none_disables_reasoning():
|
||
|
|
cli_obj = _make_cli()
|
||
|
|
cli_obj.agent = object()
|
||
|
|
|
||
|
|
with patch("cli.save_config_value", return_value=True) as mock_save:
|
||
|
|
keep_running = cli_obj.process_command("/reasoning none")
|
||
|
|
|
||
|
|
assert keep_running is True
|
||
|
|
assert cli_obj.reasoning_config == {"enabled": False}
|
||
|
|
assert cli_obj.agent is None
|
||
|
|
mock_save.assert_called_once_with("agent.reasoning_effort", "none")
|
||
|
|
|
||
|
|
|
||
|
|
# -- rejecting invalid levels ---------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.parametrize("bad_level", ["ultra", "minimal", "max", "off", "0", "150"])
|
||
|
|
def test_reasoning_command_rejects_invalid_level(capsys, bad_level):
|
||
|
|
cli_obj = _make_cli()
|
||
|
|
before = cli_obj.reasoning_config
|
||
|
|
|
||
|
|
with patch("cli.save_config_value", return_value=True) as mock_save:
|
||
|
|
keep_running = cli_obj.process_command(f"/reasoning {bad_level}")
|
||
|
|
|
||
|
|
out = capsys.readouterr().out
|
||
|
|
assert keep_running is True
|
||
|
|
assert "Invalid reasoning level" in out
|
||
|
|
assert cli_obj.reasoning_config == before
|
||
|
|
mock_save.assert_not_called()
|
||
|
|
|
||
|
|
|
||
|
|
# -- display current level -------------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
def test_reasoning_shows_current_effort(capsys):
|
||
|
|
cli_obj = _make_cli()
|
||
|
|
cli_obj.reasoning_config = {"enabled": True, "effort": "high"}
|
||
|
|
|
||
|
|
cli_obj.process_command("/reasoning")
|
||
|
|
|
||
|
|
out = capsys.readouterr().out
|
||
|
|
assert "Reasoning effort: high" in out
|
||
|
|
|
||
|
|
|
||
|
|
def test_reasoning_shows_default_when_none_set(capsys):
|
||
|
|
cli_obj = _make_cli()
|
||
|
|
cli_obj.reasoning_config = None
|
||
|
|
|
||
|
|
cli_obj.process_command("/reasoning")
|
||
|
|
|
||
|
|
out = capsys.readouterr().out
|
||
|
|
assert "medium (default)" in out
|
||
|
|
|
||
|
|
|
||
|
|
def test_reasoning_shows_disabled_when_none_effort(capsys):
|
||
|
|
cli_obj = _make_cli()
|
||
|
|
cli_obj.reasoning_config = {"enabled": False}
|
||
|
|
|
||
|
|
cli_obj.process_command("/reasoning")
|
||
|
|
|
||
|
|
out = capsys.readouterr().out
|
||
|
|
assert "none (reasoning disabled)" in out
|
||
|
|
|
||
|
|
|
||
|
|
# -- case insensitivity ----------------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
def test_reasoning_command_is_case_insensitive(capsys):
|
||
|
|
cli_obj = _make_cli()
|
||
|
|
|
||
|
|
with patch("cli.save_config_value", return_value=True):
|
||
|
|
cli_obj.process_command("/reasoning HIGH")
|
||
|
|
|
||
|
|
assert cli_obj.reasoning_config == {"enabled": True, "effort": "high"}
|
||
|
|
|
||
|
|
|
||
|
|
# -- config save failure ---------------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
def test_reasoning_shows_session_only_on_save_failure(capsys):
|
||
|
|
cli_obj = _make_cli()
|
||
|
|
|
||
|
|
with patch("cli.save_config_value", return_value=False):
|
||
|
|
cli_obj.process_command("/reasoning high")
|
||
|
|
|
||
|
|
out = capsys.readouterr().out
|
||
|
|
assert "session only" in out
|