File size: 4,776 Bytes
627c6cf e2f048d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | import pytest
import platform
from tiny_computer_agent import (
AgentLoop, DryRunExecutor, Element, FakeScreen, MockBrain, PlannerBrain,
PyAutoGuiExecutor,
)
from tiny_computer_agent.desktop import (
DEFAULT_KILL_SWITCH, Check, build_agent, display_available, doctor, run_checks,
)
FRAME = FakeScreen([(Element("Save"),)])
class StubDetector:
name = "stub"
def detect(self, image):
return ()
def test_display_detection_follows_the_environment(monkeypatch):
monkeypatch.delenv("DISPLAY", raising=False)
monkeypatch.delenv("WAYLAND_DISPLAY", raising=False)
ok, detail = display_available()
if platform.system() in ("Linux", "FreeBSD"):
assert ok is False and "DISPLAY" in detail
monkeypatch.setenv("DISPLAY", ":0")
assert display_available()[0] is True
def test_checks_cover_every_piece_the_harness_needs():
names = [c.name for c in run_checks(brain="planner", detector="ocr")]
for expected in ("display server", "pillow", "element detector (ocr)",
"execution mode", "kill switch"):
assert expected in names
def test_pyautogui_is_only_required_for_real_input():
dry = {c.name: c for c in run_checks(real_input=False)}
live = {c.name: c for c in run_checks(real_input=True)}
assert dry["input backend (pyautogui)"].required is False
assert live["input backend (pyautogui)"].required is True
assert live["execution mode"].detail.startswith("REAL")
def test_the_planner_needs_no_model_runtime():
checks = {c.name: c for c in run_checks(brain="planner")}
assert checks["model runtime"].ok
assert "no weights" in checks["model runtime"].detail
def test_a_model_brain_reports_its_runtime():
checks = {c.name: c for c in run_checks(brain="text-planner")}
assert "model runtime" in checks
assert "transformers" in checks["model runtime"].detail
def test_doctor_gives_a_verdict_and_a_fix(monkeypatch):
monkeypatch.delenv("DISPLAY", raising=False)
monkeypatch.delenv("WAYLAND_DISPLAY", raising=False)
report = doctor(brain="planner")
assert "preflight" in report
assert "fix:" in report or "READY" in report
def test_a_check_renders_its_fix_hint():
rendered = Check("display server", False, "no display", fix="run on the desktop").render()
assert "[FAIL]" in rendered and "fix: run on the desktop" in rendered
def test_build_agent_defaults_to_dry_run_and_the_planner():
loop = build_agent(screen=FRAME, detector=StubDetector(), brain="planner")
assert isinstance(loop, AgentLoop)
assert isinstance(loop.brain, PlannerBrain)
assert isinstance(loop.executor, DryRunExecutor)
assert loop.policy.dry_run is True
assert loop.policy.step_budget == 10
def test_build_agent_real_input_swaps_the_executor():
loop = build_agent(screen=FRAME, detector=StubDetector(), brain=MockBrain([]),
dry_run=False, max_steps=3)
assert isinstance(loop.executor, PyAutoGuiExecutor)
assert loop.policy.dry_run is False
def test_build_agent_wires_the_kill_switch(tmp_path):
marker = tmp_path / "STOP"
loop = build_agent(screen=FRAME, detector=StubDetector(), brain=MockBrain([]),
kill_switch_path=str(marker))
assert loop.policy.kill_switch_path == str(marker)
assert DEFAULT_KILL_SWITCH.endswith("tiny-computer-agent.STOP")
def test_the_one_call_builder_can_wire_learned_skills_and_a_gate():
"""2.0: one call wires the desktop, what it has learned, and the operator's gate."""
from tiny_computer_agent import (AllowOnlyLabels, Element, FakeScreen, Policy, Skill,
SkillBrain, SkillLibrary, SkillStep, Action, build_agent)
library = SkillLibrary()
library.add(Skill(name="save", goal="click 'Save' to save the document", verified=True,
steps=(SkillStep(Action("click", label="Save"), aimed_at="Save"),)))
gate = AllowOnlyLabels(["Save"])
loop = build_agent(brain="planner", screen=FakeScreen([(Element("Save", x=10, y=10, width=60, height=20),)]),
detector="ocr", dry_run=True, skills=library, gate=gate)
assert isinstance(loop.brain, SkillBrain)
assert loop.gate is gate
episode = loop.run("click 'Save' to save the document")
assert [s.action.label for s in episode.steps if s.action and s.action.kind == "click"] == ["Save"]
def test_without_skills_the_builder_leaves_the_brain_alone():
from tiny_computer_agent import Element, FakeScreen, PlannerBrain, build_agent
loop = build_agent(brain="planner", screen=FakeScreen([(Element("Save", x=1, y=1, width=9, height=9),)]),
detector="ocr")
assert isinstance(loop.brain, PlannerBrain) and loop.gate is None
|