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