hermes-agent/tests/agent/test_intent_ack_continuation.py
Teknium 6b81590c55
test: prune low-value tests suite-wide (wave 1) — 46,820 → 28,106 test functions
Systematic prune per AGENTS.md test policy, one pass over every major
test tree (gateway, hermes_cli, tools, agent, run_agent, plugins, cli,
cron, tui_gateway, honcho/openviking, root-level):

- DELETE: source-reading tests (read_text/getsource on prod files),
  change-detector tests (exact catalog counts, model-name snapshots,
  config version literals), mock-echo tests (assert a mock returns what
  it was told), assertion-free/trivial tests, near-duplicate
  parametrizations (boundaries + one representative kept), async/sync
  twin duplicates, cosmetic within-file variations.
- KEEP (mandatory): security/redaction/approval guards, message-role
  alternation invariants, prompt-caching/deterministic-call-id
  invariants, issue-number regression tests (deduped), E2E tests.
- 6 test files deleted outright (script-style/no-assert or fully
  redundant); conftest.py, fakes/, fixtures/ untouched.
- tests/acp/conftest.py added: autouse fixture stubs the live
  models.dev/GitHub/Copilot/Anthropic inventory fetches that ACP server
  tests performed on every session create — test_server.py 147s → 3.4s,
  and the tests are now genuinely hermetic.
- Sleep-based slowness shrunk where safe (codex_ttfb_watchdog,
  compression_concurrent_fork, etc.); no wall-clock assertion tightened.

Verification: full hermetic suite via scripts/run_tests.sh —
2439 files, 31,130 tests passed, 0 failed, 0 flaky retries, 315s wall
(baseline: 583s wall, 13,564s subprocess CPU).
2026-07-29 13:10:23 -07:00

127 lines
4.6 KiB
Python

"""Intent-ack continuation gate + detector behavior.
Covers the config-driven generalization of the codex intent-ack continuation
(issue #27881): the historical ``codex_responses``-only path is byte-stable
under the default ``"auto"`` mode, while an explicit ``true``/model-list opt-in
extends the "you announced an action but called no tool — keep going" nudge to
every api_mode and relaxes the codebase/workspace requirement so general
autonomous workflows ("I'll run a health check on the server") are caught.
These are invariant assertions about how the mode string and the detector
gates relate, not snapshots of the marker lists.
"""
from types import SimpleNamespace
from typing import Union
from agent.agent_runtime_helpers import (
intent_ack_continuation_enabled,
intent_ack_continuation_mode,
looks_like_codex_intermediate_ack,
)
def _agent(
mode: Union[str, bool, list] = "auto",
api_mode="chat_completions",
model="anthropic/claude-sonnet-4",
):
# _strip_think_blocks is a no-op for these plain-text fixtures.
return SimpleNamespace(
_intent_ack_continuation=mode,
api_mode=api_mode,
model=model,
_strip_think_blocks=lambda c: c,
)
# The reporter's exact repro (#27881): server-ops task, no filesystem reference.
REPRO_USER = (
"check the current status of the server, grab the latest error logs, "
"and let me know if there's anything critical"
)
REPRO_ACK = "I will start by running a health check command on the server to see its current status."
# The codex-coding case the detector was originally built for.
CODE_USER = "review the codebase in /app"
CODE_ACK = "Let me inspect the repository files first."
# ── mode resolution ────────────────────────────────────────────────────────
def test_true_is_all_api_modes():
for am in ("chat_completions", "anthropic", "codex_responses"):
assert intent_ack_continuation_mode(_agent(True, am)) == "all"
for s in ("true", "always", "yes", "on", "ON"):
assert intent_ack_continuation_mode(_agent(s, "chat_completions")) == "all"
def test_missing_attr_defaults_to_auto():
bare = SimpleNamespace(api_mode="chat_completions", model="x", _strip_think_blocks=lambda c: c)
assert intent_ack_continuation_mode(bare) == "off"
bare_codex = SimpleNamespace(api_mode="codex_responses", model="x", _strip_think_blocks=lambda c: c)
assert intent_ack_continuation_mode(bare_codex) == "codex_only"
def test_enabled_is_mode_not_off():
assert intent_ack_continuation_enabled(_agent(True, "chat_completions")) is True
assert intent_ack_continuation_enabled(_agent("auto", "codex_responses")) is True
assert intent_ack_continuation_enabled(_agent("auto", "chat_completions")) is False
assert intent_ack_continuation_enabled(_agent(False, "codex_responses")) is False
# ── detector: workspace requirement ─────────────────────────────────────────
def test_multipart_user_message_does_not_crash_on_workspace_path():
"""#9562: vision requests forward ``user_message`` as a multi-part list.
The OpenAI-compat API server passes the raw ``content`` field straight
through for vision turns, so ``user_message`` reaches the detector as
``[{type:"text",...}, {type:"image_url",...}]``. The ``require_workspace``
path flattened it with ``(user_message or "").strip()`` — a truthy list
survived and ``.strip()`` raised ``AttributeError``, killing the turn.
The text part still has to drive workspace detection.
"""
a = _agent("auto", "codex_responses")
multipart = [
{"type": "text", "text": CODE_USER},
{"type": "image_url", "image_url": {"url": "data:image/png;base64,AAAA"}},
]
msgs = [{"role": "user", "content": multipart}]
# No crash, and the text part ("review the codebase in /app") still
# satisfies the workspace requirement so the ack fires.
assert looks_like_codex_intermediate_ack(
a, multipart, CODE_ACK, msgs, require_workspace=True
)
def test_all_path_drops_workspace_requirement():
"""The #27881 fix: opted-in turns catch non-codebase intent acks."""
a = _agent(True, "chat_completions")
msgs = [{"role": "user", "content": REPRO_USER}]
assert looks_like_codex_intermediate_ack(
a, REPRO_USER, REPRO_ACK, msgs, require_workspace=False
)
# ── detector: guardrails that hold regardless of workspace ───────────────────