mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-08 13:12:08 +00:00
feat(moa): show each reference model's output as a labelled block before the aggregator (#53793)
When a MoA preset is selected, each reference model's answer now renders in the CLI as a thinking-style block labelled with its source model, BEFORE the aggregator responds — so the mixture-of-agents process is visible instead of a silent pause. The aggregator's response (and its tool actions) follow as normal. Mechanism (shared seam, all surfaces): - MoAChatCompletions/MoAClient take an optional reference_callback and emit 'moa.reference' (index/count/label/text) per reference, then 'moa.aggregating' (aggregator label) once. agent_init wires this to the agent's tool_progress_callback, which every surface already consumes — so the events reach CLI/TUI/desktop/gateway with no new plumbing. - CLI _on_tool_progress renders 'moa.reference' as a labelled '┊ ◇ Reference i/n — <model>' header + a thinking-style preview (reusing _emit_reasoning_ preview), and 'moa.aggregating' as a spinner transition. Display-only; never touches message history (cache-safe). Turn-scoped reference cache: the agent loop calls the facade once per tool-loop iteration, but the advisory message view is identical across iterations within a turn, so references are now run AND displayed once per user turn (keyed by the advisory view's signature) instead of re-running/re-spamming on every iteration. This also cuts reference API cost from O(iterations) back to O(turns). Verified live via interactive PTY on the opus-gpt preset (gpt-5.5 + opus refs): reference blocks render once per turn, labelled by model, before the aggregator; fresh blocks on each new turn; aggregator tool actions still execute. Follow-up: TUI/desktop rich rendering + gateway batched-summary already receive the events via tool_progress_callback; their surface-specific renderers are a separate change.
This commit is contained in:
parent
dbbf102b8e
commit
3b44a3c8bb
5 changed files with 319 additions and 10 deletions
|
|
@ -251,3 +251,45 @@ class TestToolProgressScrollback:
|
|||
# First entry consumed, second remains
|
||||
assert len(cli._pending_tool_info.get("terminal", [])) == 1
|
||||
assert cli._pending_tool_info["terminal"][0] == {"command": "pwd"}
|
||||
|
||||
|
||||
class TestMoAReferenceBlocks:
|
||||
"""moa.reference renders a labelled thinking-style block; moa.aggregating
|
||||
updates the spinner. Both are display-only and must commit regardless of
|
||||
tool_progress_mode (MoA is non-streaming)."""
|
||||
|
||||
def test_reference_event_prints_labelled_block(self):
|
||||
cli = _make_cli(tool_progress="all")
|
||||
with patch.object(_cli_mod, "_cprint") as mock_print:
|
||||
cli._on_tool_progress(
|
||||
"moa.reference",
|
||||
"openrouter:openai/gpt-5.5",
|
||||
"Paris is the capital.",
|
||||
None,
|
||||
moa_index=1,
|
||||
moa_count=2,
|
||||
)
|
||||
printed = " ".join(str(c.args[0]) for c in mock_print.call_args_list)
|
||||
# Header names the source model + index/count; body carries the text.
|
||||
assert "openrouter:openai/gpt-5.5" in printed
|
||||
assert "Reference 1/2" in printed
|
||||
assert "Paris is the capital." in printed
|
||||
|
||||
def test_reference_event_prints_even_when_progress_off(self):
|
||||
"""Reference blocks are the MoA process view, not tool progress — they
|
||||
must show even with tool_progress: off."""
|
||||
cli = _make_cli(tool_progress="off")
|
||||
with patch.object(_cli_mod, "_cprint") as mock_print:
|
||||
cli._on_tool_progress(
|
||||
"moa.reference", "openrouter:anthropic/claude-opus-4.8", "Four.", None,
|
||||
moa_index=2, moa_count=2,
|
||||
)
|
||||
assert mock_print.called
|
||||
|
||||
def test_aggregating_event_updates_spinner_only(self):
|
||||
cli = _make_cli(tool_progress="all")
|
||||
with patch.object(_cli_mod, "_cprint") as mock_print:
|
||||
cli._on_tool_progress("moa.aggregating", "openrouter:anthropic/claude-opus-4.8", None, None)
|
||||
assert "aggregating" in cli._spinner_text
|
||||
# aggregating is a spinner-only transition; no committed scrollback line.
|
||||
mock_print.assert_not_called()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue