mirror of https://github.com/aliasrobotics/cai.git
180 lines
5.0 KiB
Python
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…"
|