diff --git a/batch_runner.py b/batch_runner.py index 1a65f473ff4f..026effd6b5a9 100644 --- a/batch_runner.py +++ b/batch_runner.py @@ -1161,7 +1161,7 @@ def main( providers_order (str): Comma-separated list of OpenRouter providers to try in order (e.g. "anthropic,openai,google") provider_sort (str): Sort providers by "price", "throughput", or "latency" (OpenRouter only) max_tokens (int): Maximum tokens for model responses (optional, uses model default if not set) - reasoning_effort (str): OpenRouter reasoning effort level: "none", "minimal", "low", "medium", "high", "xhigh" (default: "medium") + reasoning_effort (str): OpenRouter reasoning effort level: "none", "minimal", "low", "medium", "high", "xhigh", "max" (default: "medium") reasoning_disabled (bool): Completely disable reasoning/thinking tokens (default: False) prefill_messages_file (str): Path to JSON file containing prefill messages (list of {role, content} dicts) max_samples (int): Only process the first N samples from the dataset (optional, processes all if not set) @@ -1230,7 +1230,7 @@ def main( print("🧠 Reasoning: DISABLED (effort=none)") elif reasoning_effort: # Use specified effort level - valid_efforts = ["none", "minimal", "low", "medium", "high", "xhigh"] + valid_efforts = ["none", "minimal", "low", "medium", "high", "xhigh", "max"] if reasoning_effort not in valid_efforts: print(f"❌ Error: --reasoning_effort must be one of: {', '.join(valid_efforts)}") return diff --git a/cli.py b/cli.py index 8aa8bb03f111..7f3e5aea501c 100644 --- a/cli.py +++ b/cli.py @@ -6449,7 +6449,7 @@ def _handle_reasoning_command(self, cmd: str): Usage: /reasoning Show current effort level and display state - /reasoning Set reasoning effort (none, minimal, low, medium, high, xhigh) + /reasoning Set reasoning effort (none, minimal, low, medium, high, xhigh, max) /reasoning show|on Show model thinking/reasoning in output /reasoning hide|off Hide model thinking/reasoning from output """ @@ -6493,7 +6493,7 @@ def _handle_reasoning_command(self, cmd: str): parsed = _parse_reasoning_config(arg) if parsed is None: _cprint(f" {_DIM}(._.) Unknown argument: {arg}{_RST}") - _cprint(f" {_DIM}Valid levels: none, minimal, low, medium, high, xhigh{_RST}") + _cprint(f" {_DIM}Valid levels: none, minimal, low, medium, high, xhigh, max{_RST}") _cprint(f" {_DIM}Display: show, hide{_RST}") return diff --git a/gateway/run.py b/gateway/run.py index 1525ad147766..92c050566b6e 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -1189,7 +1189,7 @@ def _load_reasoning_config() -> dict | None: """Load reasoning effort from config.yaml. Reads agent.reasoning_effort from config.yaml. Valid: "none", - "minimal", "low", "medium", "high", "xhigh". Returns None to use + "minimal", "low", "medium", "high", "xhigh", "max". Returns None to use default (medium). """ from hermes_constants import parse_reasoning_effort @@ -6371,7 +6371,7 @@ async def _handle_reasoning_command(self, event: MessageEvent) -> str: Usage: /reasoning Show current effort level and display state - /reasoning Set reasoning effort (none, minimal, low, medium, high, xhigh) + /reasoning Set reasoning effort (none, minimal, low, medium, high, xhigh, max) /reasoning show|on Show model reasoning in responses /reasoning hide|off Hide model reasoning from responses """ @@ -6438,12 +6438,12 @@ def _save_config_key(key_path: str, value): effort = args.strip() if effort == "none": parsed = {"enabled": False} - elif effort in ("minimal", "low", "medium", "high", "xhigh"): + elif effort in ("minimal", "low", "medium", "high", "xhigh", "max"): parsed = {"enabled": True, "effort": effort} else: return ( f"⚠️ Unknown argument: `{effort}`\n\n" - "**Valid levels:** none, minimal, low, medium, high, xhigh\n" + "**Valid levels:** none, minimal, low, medium, high, xhigh, max\n" "**Display:** show, hide" ) diff --git a/hermes_cli/commands.py b/hermes_cli/commands.py index 681e6f9b2659..37d305a52d84 100644 --- a/hermes_cli/commands.py +++ b/hermes_cli/commands.py @@ -119,7 +119,7 @@ class CommandDef: "Configuration"), CommandDef("reasoning", "Manage reasoning effort and display", "Configuration", args_hint="[level|show|hide]", - subcommands=("none", "minimal", "low", "medium", "high", "xhigh", "show", "hide", "on", "off")), + subcommands=("none", "minimal", "low", "medium", "high", "xhigh", "max", "show", "hide", "on", "off")), CommandDef("fast", "Toggle fast mode — OpenAI Priority Processing / Anthropic Fast Mode (Normal/Fast)", "Configuration", args_hint="[normal|fast|status]", subcommands=("normal", "fast", "status", "on", "off")), diff --git a/hermes_cli/main.py b/hermes_cli/main.py index ce02c2e72c41..a805f48151ab 100644 --- a/hermes_cli/main.py +++ b/hermes_cli/main.py @@ -2872,7 +2872,7 @@ def _prompt_reasoning_effort_selection(efforts, current_effort=""): str(effort).strip().lower() for effort in efforts if str(effort).strip() ) ) - canonical_order = ("minimal", "low", "medium", "high", "xhigh") + canonical_order = ("minimal", "low", "medium", "high", "xhigh", "max") ordered = [effort for effort in canonical_order if effort in deduped] ordered.extend(effort for effort in deduped if effort not in canonical_order) if not ordered: diff --git a/hermes_constants.py b/hermes_constants.py index 35dbf86ab229..26fd66b73e38 100644 --- a/hermes_constants.py +++ b/hermes_constants.py @@ -138,13 +138,13 @@ def get_subprocess_home() -> str | None: return None -VALID_REASONING_EFFORTS = ("minimal", "low", "medium", "high", "xhigh") +VALID_REASONING_EFFORTS = ("minimal", "low", "medium", "high", "xhigh", "max") def parse_reasoning_effort(effort: str) -> dict | None: """Parse a reasoning effort level into a config dict. - Valid levels: "none", "minimal", "low", "medium", "high", "xhigh". + Valid levels: "none", "minimal", "low", "medium", "high", "xhigh", "max". Returns None when the input is empty or unrecognized (caller uses default). Returns {"enabled": False} for "none". Returns {"enabled": True, "effort": } for valid effort levels. diff --git a/skills/autonomous-ai-agents/hermes-agent/SKILL.md b/skills/autonomous-ai-agents/hermes-agent/SKILL.md index 362841f395fd..f02068c6fd69 100644 --- a/skills/autonomous-ai-agents/hermes-agent/SKILL.md +++ b/skills/autonomous-ai-agents/hermes-agent/SKILL.md @@ -250,7 +250,7 @@ Type these during an interactive chat session. /model [name] Show or change model /provider Show provider info /personality [name] Set personality -/reasoning [level] Set reasoning (none|minimal|low|medium|high|xhigh|show|hide) +/reasoning [level] Set reasoning (none|minimal|low|medium|high|xhigh|max|show|hide) /verbose Cycle: off → new → all → verbose /voice [on|off|tts] Voice mode /yolo Toggle approval bypass diff --git a/tests/cli/test_reasoning_command.py b/tests/cli/test_reasoning_command.py index 228d2904b16a..8085d6324fba 100644 --- a/tests/cli/test_reasoning_command.py +++ b/tests/cli/test_reasoning_command.py @@ -30,7 +30,7 @@ def test_none_disables(self): self.assertEqual(result, {"enabled": False}) def test_valid_levels(self): - for level in ("low", "medium", "high", "xhigh", "minimal"): + for level in ("low", "medium", "high", "xhigh", "max", "minimal"): result = self._parse(level) self.assertIsNotNone(result) self.assertTrue(result.get("enabled")) diff --git a/tests/gateway/test_reasoning_command.py b/tests/gateway/test_reasoning_command.py index e39ed1123d6c..3e5bf71b9a22 100644 --- a/tests/gateway/test_reasoning_command.py +++ b/tests/gateway/test_reasoning_command.py @@ -118,6 +118,25 @@ async def test_handle_reasoning_command_updates_config_and_cache(self, tmp_path, assert runner._reasoning_config == {"enabled": True, "effort": "low"} assert "takes effect on next message" in result + @pytest.mark.asyncio + async def test_handle_reasoning_command_accepts_max(self, tmp_path, monkeypatch): + hermes_home = tmp_path / "hermes" + hermes_home.mkdir() + config_path = hermes_home / "config.yaml" + config_path.write_text("agent:\n reasoning_effort: medium\n", encoding="utf-8") + + monkeypatch.setattr(gateway_run, "_hermes_home", hermes_home) + + runner = _make_runner() + runner._reasoning_config = {"enabled": True, "effort": "medium"} + + result = await runner._handle_reasoning_command(_make_event("/reasoning max")) + + saved = yaml.safe_load(config_path.read_text(encoding="utf-8")) + assert saved["agent"]["reasoning_effort"] == "max" + assert runner._reasoning_config == {"enabled": True, "effort": "max"} + assert "takes effect on next message" in result + def test_run_agent_reloads_reasoning_config_per_message(self, tmp_path, monkeypatch): hermes_home = tmp_path / "hermes" hermes_home.mkdir() diff --git a/tests/hermes_cli/test_reasoning_effort_menu.py b/tests/hermes_cli/test_reasoning_effort_menu.py index 3d360a4f2f6f..4641124723c1 100644 --- a/tests/hermes_cli/test_reasoning_effort_menu.py +++ b/tests/hermes_cli/test_reasoning_effort_menu.py @@ -32,3 +32,21 @@ def test_reasoning_menu_orders_minimal_before_low(monkeypatch): " medium ← currently in use", " high", ] + + +def test_reasoning_menu_places_max_after_xhigh(monkeypatch): + fake_module = types.SimpleNamespace(TerminalMenu=_FakeTerminalMenu) + monkeypatch.setitem(sys.modules, "simple_term_menu", fake_module) + + selected = _prompt_reasoning_effort_selection( + ["max", "medium", "xhigh", "high"], + current_effort="max", + ) + + assert selected == "max" + assert _FakeTerminalMenu.last_choices[:4] == [ + " medium", + " high", + " xhigh", + " max ← currently in use", + ] diff --git a/website/docs/user-guide/configuration.md b/website/docs/user-guide/configuration.md index dbc6b0e47e6b..da60d389251a 100644 --- a/website/docs/user-guide/configuration.md +++ b/website/docs/user-guide/configuration.md @@ -795,7 +795,7 @@ Control how much "thinking" the model does before responding: ```yaml agent: - reasoning_effort: "" # empty = medium (default). Options: none, minimal, low, medium, high, xhigh (max) + reasoning_effort: "" # empty = medium (default). Options: none, minimal, low, medium, high, xhigh, max ``` When unset (default), reasoning effort defaults to "medium" — a balanced level that works well for most tasks. Setting a value overrides it — higher reasoning effort gives better results on complex tasks at the cost of more tokens and latency. diff --git a/website/docs/user-guide/features/batch-processing.md b/website/docs/user-guide/features/batch-processing.md index 59554e34dff4..0bebd21ee83a 100644 --- a/website/docs/user-guide/features/batch-processing.md +++ b/website/docs/user-guide/features/batch-processing.md @@ -79,7 +79,7 @@ Entries can optionally include: | Parameter | Description | |-----------|-------------| -| `--reasoning_effort` | Effort level: `none`, `minimal`, `low`, `medium`, `high`, `xhigh` | +| `--reasoning_effort` | Effort level: `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max` | | `--reasoning_disabled` | Completely disable reasoning/thinking tokens | ### Advanced Options