cai/tests/util/test_wait_hints_compact.py

180 lines
5.0 KiB
Python

from io import StringIO
from types import SimpleNamespace
import pytest
from rich.console import Console
from rich.text import Text
import cai.util.streaming as streaming
import cai.util.wait_hints as wait_hints
from cai.output import TaskRecord
from cai.repl.ui.compact_renderer import CompactCLIHandler, _row_for_record
def test_compact_owner_suppresses_legacy_footer_refresh(monkeypatch):
calls = []
def fake_refresh():
calls.append("refresh")
monkeypatch.setattr(
"cai.util.streaming.refresh_tool_wait_displays",
fake_refresh,
)
wait_hints.set_compact_live_owner(True)
try:
wait_hints._request_footer_ui_refresh()
finally:
wait_hints.set_compact_live_owner(False)
assert calls == []
def test_clear_wait_hints_removes_published_body():
wait_hints._set_model_wait_body("model wait")
wait_hints._set_tool_wait_body("tool wait")
assert wait_hints.get_current_wait_hint_body()
wait_hints.clear_wait_hints()
assert wait_hints.get_current_wait_hint_body() is None
@pytest.mark.asyncio
async def test_tool_wait_loop_under_compact_owner_only_publishes_body(monkeypatch):
monkeypatch.setattr(wait_hints, "tool_wait_hints_enabled", lambda: True)
wait_hints.set_compact_live_owner(True)
loop = wait_hints._WaitHintLoop(
mode="tool",
tool_label="generic_linux_command",
exec_summary="sleep 10",
)
try:
await loop.start()
assert wait_hints.get_current_wait_hint_body()
assert wait_hints.get_tool_wait_footer_renderable() is None
finally:
await loop.stop()
wait_hints.set_compact_live_owner(False)
def test_compact_final_dismiss_releases_ownership_on_flush(monkeypatch):
owner_changes = []
def fake_set_owner(active):
owner_changes.append(active)
monkeypatch.setattr("cai.util.wait_hints.set_compact_live_owner", fake_set_owner)
handler = CompactCLIHandler(
Console(file=StringIO(), force_terminal=True, width=80)
)
handler._owns_wait_hints = True
handler.dismiss_for_final_output()
assert owner_changes == []
handler.flush()
assert owner_changes == [False]
def test_finish_agent_streaming_clears_wait_ui_before_final(monkeypatch):
calls = []
def fake_prepare():
calls.append("prepare")
monkeypatch.setattr(streaming, "_prepare_terminal_for_final_agent_output", fake_prepare)
monkeypatch.setattr(streaming, "_print_pricing_footer", lambda *args, **kwargs: None)
context = {
"content": Text("final answer"),
"is_started": False,
"context_key": "test",
"header": Text("Agent"),
"live": None,
}
streaming.create_agent_streaming_context._active_streaming = {"test": context}
assert streaming.finish_agent_streaming(context, {"has_tool_calls": False}) is True
assert calls == ["prepare"]
def test_cli_print_agent_messages_clears_wait_ui_before_final(monkeypatch):
calls = []
def fake_prepare():
calls.append("prepare")
monkeypatch.setattr(streaming, "_prepare_terminal_for_final_agent_output", fake_prepare)
monkeypatch.setattr(streaming, "_print_pricing_footer", lambda *args, **kwargs: None)
streaming.cli_print_agent_messages(
agent_name="Agent",
message=SimpleNamespace(content="final answer", tool_calls=None),
counter=1,
model="test-model",
debug=False,
suppress_empty=True,
)
assert calls == ["prepare"]
def test_compact_row_hides_primary_agent_id_and_agent_label():
row = _row_for_record(
TaskRecord(
task_id="task-1",
turn_id="turn-1",
agent_name="Red Team Agent",
agent_id="P0",
tool_name="generic_linux_command",
label="nmap -sV 127.0.0.1",
started_at=0.0,
call_id="call-1",
),
now=1.0,
tick=0,
)
assert "Red Team Agent ─ nmap" in row.plain
assert "[P0]" not in row.plain
assert " AGENT " not in row.plain
def test_compact_row_keeps_parallel_agent_id():
row = _row_for_record(
TaskRecord(
task_id="task-1",
turn_id="turn-1",
agent_name="Red Team Agent",
agent_id="P1",
tool_name="generic_linux_command",
label="nmap -sV 127.0.0.1",
started_at=0.0,
call_id="call-1",
),
now=1.0,
tick=0,
)
assert "Red Team Agent [P1] ─ nmap" in row.plain
assert " AGENT " not in row.plain
def test_set_model_wait_retry_overlay_overrides_model_body():
"""``set_model_wait_retry_overlay`` shadows the default body and ``None`` clears it."""
try:
wait_hints.set_model_wait_retry_overlay("Rate budget reached, pacing for 5s…")
assert (
wait_hints._model_body(0.0, {})
== "Rate budget reached, pacing for 5s…"
)
finally:
wait_hints.set_model_wait_retry_overlay(None)
assert wait_hints._model_body(0.0, {}) != "Rate budget reached, pacing for 5s…"