Files
hermes-agent/tests/agent/test_moa_quiet_reference_output.py
Teknium a0be177aac fix(compat): pointers resolve to the object that MOVED, not a same-named stranger; stdin checker binds stdin= to the splatted definition
Review findings on #102117 (independent reviewer + itsflownium):

* hermes_cli.kanban_db.connect / connect_closing pointed at hermes_cli.projects_db (different DB, no
  board= parameter). The compat generator ranked candidate homes by path proximity when a name is
  defined in several modules. Now it requires shape compatibility with the BASE definition (same
  literal for constants, superset of parameter names for defs) and prefers the facade's own
  <stem>_* sibling. Same class fixed for tools.tts_tool.DEFAULT_XAI_BASE_URL (-> tts_tool_providers),
  and 17 constants/defs that had been pointed at same-named strangers (Matrix MAX_MESSAGE_LENGTH ->
  Signal's 8000, tts MAX_TEXT_LENGTH -> BlueBubbles', honcho/retaindb/supermemory *_SCHEMA -> another
  plugin's schema, ...) are now restored from BASE verbatim instead.
* send_yuanbao_direct (restored-def): body called adapter._outbound.send_direct, which HEAD moved to
  the sender; rewritten to adapter._outbound.sender.send_direct.
* COMPAT_MANIFEST.md states the scope explicitly: public top-level names only; private names and
  test monkeypatch seams are not preserved.
* scripts/check_subprocess_stdin.py: _splat_carries_stdin looked 30 lines ahead in the file text
  and was satisfied by an unrelated later stdin=; it now finds the splatted name's definition via AST
  and requires stdin inside that expression/body.

Tests: tests/test_compat_manifest_targets.py (pointer identity vs the facade's sibling; kanban
connect(board=) opens a Kanban DB, not projects.db; both FAIL on the previous layer),
test_subprocess_stdin_guard gains the false-negative probe, and the MoA -Q quiet-output contract
tests are back (tests/agent/test_moa_quiet_reference_output.py) against build_moa_facade.
2026-09-03 22:00:01 -07:00

38 lines
1.6 KiB
Python

"""MoA display events honour the ``-Q`` quiet contract.
``-Q`` (machine-readable CLI output) nulls ``agent.tool_progress_callback`` and sets
``tool_progress_mode = "off"``; the MoA reference relay reads the callback at emit time, so
quiet sessions must emit nothing and interactive sessions must relay every event.
"""
from types import SimpleNamespace
from unittest.mock import MagicMock, patch
import pytest
from agent.moa_loop import build_moa_facade
def _facade(agent):
with patch("agent.moa_loop.MoAClient") as client_cls:
build_moa_facade(agent, "default")
return client_cls.call_args.kwargs["reference_callback"]
def test_quiet_cli_emits_no_moa_display_events():
agent = SimpleNamespace(platform="cli", tool_progress_mode="off", tool_progress_callback=None, provider="moa", model="default")
relay = _facade(agent)
relay("moa.reference", label="m1", text="answer", index=0, count=2) # must not raise
relay("moa.aggregating", aggregator="agg")
@pytest.mark.parametrize("platform", ["cli", "telegram"])
def test_interactive_surfaces_receive_moa_events(platform):
cb = MagicMock()
agent = SimpleNamespace(platform=platform, tool_progress_mode="all", tool_progress_callback=cb, provider="moa", model="default")
relay = _facade(agent)
relay("moa.reference", label="m1", text="answer", index=0, count=2)
relay("moa.aggregating", aggregator="agg")
events = [c.args[0] for c in cb.call_args_list]
assert events == ["moa.reference", "moa.aggregating"]
assert cb.call_args_list[0].kwargs == {"moa_index": 0, "moa_count": 2}