From 75c878217d7c7f67cc865a781af4b78c4b81ca8c Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Thu, 16 Jul 2026 05:44:57 -0700 Subject: [PATCH] fix(moa): route per-slot reasoning effort through the canonical parser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _clean_reasoning_effort kept its own whitelist that stopped at 'max', silently dropping 'ultra' from MoA slot configs. Route it through hermes_constants.parse_reasoning_effort — the same one-source-of-truth fix the salvaged commit applies to the gateway — so future effort levels can't drift here either. Docs updated to list ultra. Follow-up to salvaged PR #64012. --- hermes_cli/moa_config.py | 14 ++++++-------- scripts/release.py | 1 + tests/hermes_cli/test_moa_config.py | 2 ++ .../docs/user-guide/features/mixture-of-agents.md | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/hermes_cli/moa_config.py b/hermes_cli/moa_config.py index e3fc77f74..39594ee39 100644 --- a/hermes_cli/moa_config.py +++ b/hermes_cli/moa_config.py @@ -75,18 +75,16 @@ def _coerce_fanout(value: Any) -> str: def _clean_reasoning_effort(value: Any) -> str | None: """Return a canonical per-slot reasoning effort, or None when unset/invalid.""" + from hermes_constants import parse_reasoning_effort + if value is None or value is True: return None - if value is False: - return "none" - text = str(value or "").strip().lower() - if not text: + parsed = parse_reasoning_effort(value) + if parsed is None: return None - if text in {"none", "false", "disabled"}: + if parsed.get("enabled") is False: return "none" - if text in {"minimal", "low", "medium", "high", "xhigh", "max"}: - return text - return None + return parsed.get("effort") def _clean_slot(slot: Any) -> dict[str, Any] | None: diff --git a/scripts/release.py b/scripts/release.py index 5ccb8dcea..a558f3a2a 100755 --- a/scripts/release.py +++ b/scripts/release.py @@ -45,6 +45,7 @@ ACP_REGISTRY_MANIFEST = REPO_ROOT / "acp_registry" / "agent.json" # Auto-extracted from noreply emails + manual overrides AUTHOR_MAP = { + "kar.iskakov@gmail.com": "karfly", # PR #64012 salvage (gateway: surface extended reasoning efforts) "agungsubastian1963@gmail.com": "aguung", # PR #64461 salvage (gateway: multiplex secret_scope for authz/Slack/webhooks) "jtstothard@gmail.com": "jtstothard", # PR #63256 salvage (gateway: multiplex secondary adapter config validation) "doogie@spark.local": "SAMBAS123", # PR #64986 salvage (gateway: multiplex primary bot token scope) diff --git a/tests/hermes_cli/test_moa_config.py b/tests/hermes_cli/test_moa_config.py index 69b07e89f..c78631f5e 100644 --- a/tests/hermes_cli/test_moa_config.py +++ b/tests/hermes_cli/test_moa_config.py @@ -106,6 +106,7 @@ def test_normalize_moa_config_preserves_slot_reasoning_effort(): {"provider": "openai-codex", "model": "gpt-5.6-sol", "reasoning_effort": "LOW"}, {"provider": "openai-codex", "model": "gpt-5.6-sol", "reasoning_effort": False}, {"provider": "openai-codex", "model": "gpt-5.6-sol", "reasoning_effort": "nonsense"}, + {"provider": "openai-codex", "model": "gpt-5.6-sol", "reasoning_effort": "ultra"}, ], "aggregator": {"provider": "openai-codex", "model": "gpt-5.6-sol", "reasoning_effort": "xhigh"}, } @@ -117,6 +118,7 @@ def test_normalize_moa_config_preserves_slot_reasoning_effort(): assert preset["reference_models"][0]["reasoning_effort"] == "low" assert preset["reference_models"][1]["reasoning_effort"] == "none" assert "reasoning_effort" not in preset["reference_models"][2] + assert preset["reference_models"][3]["reasoning_effort"] == "ultra" assert preset["aggregator"]["reasoning_effort"] == "xhigh" diff --git a/website/docs/user-guide/features/mixture-of-agents.md b/website/docs/user-guide/features/mixture-of-agents.md index b6affbe9c..151a066dd 100644 --- a/website/docs/user-guide/features/mixture-of-agents.md +++ b/website/docs/user-guide/features/mixture-of-agents.md @@ -138,7 +138,7 @@ Reference and aggregator slots may also set `reasoning_effort`. Use this when you want the same model to contribute at different depths, or when the aggregator should think harder than the advisory references. Valid values match Hermes' normal reasoning controls: `none`, `minimal`, `low`, `medium`, `high`, -`xhigh`, and `max`. +`xhigh`, `max`, and `ultra`. ```yaml moa: