mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-20 15:33:54 +00:00
refactor(moa): drop auxiliary-task reasoning knob in favor of per-slot preset config
The just-merged auxiliary.<task>.reasoning_effort shorthand applied
ensemble-wide to MoA (one value for every advisor) — wrong granularity.
Per-slot preset config supersedes it:
moa:
presets:
deep_review:
reference_models:
- {provider: ..., model: ..., reasoning_effort: low}
- {provider: ..., model: ..., reasoning_effort: xhigh}
aggregator:
{provider: ..., model: ..., reasoning_effort: high}
- Remove reasoning_effort from the moa_reference/moa_aggregator
DEFAULT_CONFIG blocks; _get_task_extra_body now warns-and-ignores the
key on MoA tasks, pointing at the preset config
- Guard tests: MoA aux blocks must not regrow the key; task-level value
is rejected with the pointer warning
- Docs: configuration.md notes the MoA exception and links the MoA page
This commit is contained in:
parent
5646dbdd5b
commit
0bb3a82c53
4 changed files with 45 additions and 3 deletions
|
|
@ -6175,6 +6175,12 @@ def _get_task_extra_body(task: str) -> Dict[str, Any]:
|
|||
chat.completions passes it through, the Codex Responses adapter maps it
|
||||
to top-level ``reasoning``/``include``, and the Anthropic auxiliary
|
||||
client maps it to ``build_anthropic_kwargs(reasoning_config=...)``.
|
||||
|
||||
MoA tasks are excluded by design: reasoning depth for MoA is a per-slot
|
||||
setting in the MoA preset (``moa.presets.<name>.reference_models[].
|
||||
reasoning_effort`` / ``aggregator.reasoning_effort``), not an
|
||||
auxiliary-task knob — an ensemble-wide value would override the
|
||||
per-slot ones.
|
||||
"""
|
||||
task_config = _get_auxiliary_task_config(task)
|
||||
raw = task_config.get("extra_body")
|
||||
|
|
@ -6182,6 +6188,15 @@ def _get_task_extra_body(task: str) -> Dict[str, Any]:
|
|||
if "reasoning" not in result:
|
||||
effort = task_config.get("reasoning_effort")
|
||||
if effort is not None and effort != "":
|
||||
if task in ("moa_reference", "moa_aggregator"):
|
||||
logger.warning(
|
||||
"auxiliary.%s.reasoning_effort is not supported — MoA "
|
||||
"reasoning depth is per-slot: set reasoning_effort on the "
|
||||
"preset's reference_models entries / aggregator instead "
|
||||
"(moa.presets.<name>...). Ignoring.",
|
||||
task,
|
||||
)
|
||||
return result
|
||||
from hermes_constants import parse_reasoning_effort
|
||||
parsed = parse_reasoning_effort(effort)
|
||||
if parsed is not None:
|
||||
|
|
|
|||
|
|
@ -1756,7 +1756,10 @@ DEFAULT_CONFIG = {
|
|||
"api_key": "",
|
||||
"timeout": 900,
|
||||
"extra_body": {},
|
||||
"reasoning_effort": "", # per-task thinking level: none|minimal|low|medium|high|xhigh|max|ultra (empty = provider default)
|
||||
# NOTE: no reasoning_effort here by design — MoA reasoning depth is
|
||||
# configured PER SLOT in the MoA preset (moa.presets.<name>.
|
||||
# reference_models[].reasoning_effort / aggregator.reasoning_effort),
|
||||
# not at the auxiliary-task level.
|
||||
},
|
||||
"moa_aggregator": {
|
||||
"provider": "auto",
|
||||
|
|
@ -1765,7 +1768,7 @@ DEFAULT_CONFIG = {
|
|||
"api_key": "",
|
||||
"timeout": 900,
|
||||
"extra_body": {},
|
||||
"reasoning_effort": "", # per-task thinking level: none|minimal|low|medium|high|xhigh|max|ultra (empty = provider default)
|
||||
# NOTE: no reasoning_effort here by design — see moa_reference above.
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -3331,6 +3331,28 @@ class TestAuxiliaryTaskExtraBody:
|
|||
with patch("hermes_cli.config.load_config", return_value=config):
|
||||
assert _get_task_extra_body("session_search") == {}
|
||||
|
||||
@pytest.mark.parametrize("moa_task", ["moa_reference", "moa_aggregator"])
|
||||
def test_moa_tasks_reject_task_level_reasoning_effort(self, moa_task, caplog):
|
||||
"""MoA reasoning is per-slot in the preset — the auxiliary-task
|
||||
shorthand is ignored with a warning pointing at the preset config."""
|
||||
from agent.auxiliary_client import _get_task_extra_body
|
||||
|
||||
config = {"auxiliary": {moa_task: {"reasoning_effort": "xhigh"}}}
|
||||
with patch("hermes_cli.config.load_config", return_value=config), \
|
||||
caplog.at_level(logging.WARNING, logger="agent.auxiliary_client"):
|
||||
result = _get_task_extra_body(moa_task)
|
||||
|
||||
assert "reasoning" not in result
|
||||
assert any("per-slot" in rec.message for rec in caplog.records)
|
||||
|
||||
@pytest.mark.parametrize("moa_task", ["moa_reference", "moa_aggregator"])
|
||||
def test_moa_default_config_has_no_reasoning_effort(self, moa_task):
|
||||
"""Invariant: the shipped MoA auxiliary blocks must not grow a
|
||||
reasoning_effort key — per-slot preset config is the only surface."""
|
||||
from hermes_cli.config import DEFAULT_CONFIG
|
||||
|
||||
assert "reasoning_effort" not in DEFAULT_CONFIG["auxiliary"][moa_task]
|
||||
|
||||
def test_anthropic_aux_client_forwards_extra_body_reasoning(self):
|
||||
"""_AnthropicCompletionsAdapter passes extra_body.reasoning into
|
||||
build_anthropic_kwargs as reasoning_config."""
|
||||
|
|
|
|||
|
|
@ -980,7 +980,9 @@ Auxiliary task blocks additionally accept a `reasoning_effort` knob:
|
|||
|-----|-------------|---------|
|
||||
| `reasoning_effort` | Thinking level for that task's LLM calls: `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`, `ultra` | not set (provider default) |
|
||||
|
||||
This is the per-task counterpart of the global `agent.reasoning_effort`: run compression at `low` or vision at `none` to cut side-task latency and cost when your main model is an expensive reasoning model, without touching your main chat behavior. It works on every auxiliary task block (`vision`, `web_extract`, `compression`, `title_generation`, `curator`, `background_review`, `moa_reference`, `moa_aggregator`, ...), across all three auxiliary wire formats (chat completions, Codex Responses, Anthropic Messages). An explicit `extra_body.reasoning` on the same task wins over the shorthand.
|
||||
This is the per-task counterpart of the global `agent.reasoning_effort`: run compression at `low` or vision at `none` to cut side-task latency and cost when your main model is an expensive reasoning model, without touching your main chat behavior. It works on every auxiliary task block (`vision`, `web_extract`, `compression`, `title_generation`, `curator`, `background_review`, ...), across all three auxiliary wire formats (chat completions, Codex Responses, Anthropic Messages). An explicit `extra_body.reasoning` on the same task wins over the shorthand.
|
||||
|
||||
MoA is the one exception: reasoning depth for Mixture-of-Agents is configured **per slot** in the MoA preset (`moa.presets.<name>.reference_models[].reasoning_effort` / `aggregator.reasoning_effort`), not on the `moa_reference`/`moa_aggregator` auxiliary blocks — see [Mixture of Agents](/user-guide/features/mixture-of-agents).
|
||||
|
||||
```yaml
|
||||
auxiliary:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue