"""
Visual artifact generator for the MoUI agent-controllable runtime.
Runs the agent_counter MCP server in a SINGLE process and rasterizes the
compositor's rendered frame (get_frame → DrawText content, exactly what a
window backend rasterizes to the physical screen) to PNG, before and after an
agent clicks Increment via MCP dispatch_event.
Output:
/tmp/agent_counter_before.png — painted frame shows "Count: 0"
/tmp/agent_counter_after.png — painted frame shows "Count: 1"
This is the visual record of a genuine agent-driven model change through the
standard MCP protocol. Physical screen capture (screencapture) is blocked by
macOS TCC screen-recording permission in automated environments; this script
renders the identical compositor content the window would display.
Requires: Pillow (python3 -m pip install Pillow).
"""
import json, subprocess, sys, os
from PIL import Image, ImageDraw, ImageFont
REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
BIN = os.path.join(REPO_ROOT, "_build/native/debug/build/examples/agent_counter/main/main.exe")
W, H = 240, 260
OUT_BEFORE = "/tmp/agent_counter_before.png"
OUT_AFTER = "/tmp/agent_counter_after.png"
REQUESTS = [
{"jsonrpc": "2.0", "id": 1, "method": "initialize"},
{"jsonrpc": "2.0", "id": "before", "method": "tools/call",
"params": {"name": "get_frame", "arguments": {}}},
{"jsonrpc": "2.0", "id": 2, "method": "tools/call",
"params": {"name": "dispatch_event",
"arguments": {"event": {"kind": "Pointer",
"position": {"x": 100, "y": 106},
"phase": "Down"}}}},
{"jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": {"name": "dispatch_event",
"arguments": {"event": {"kind": "Pointer",
"position": {"x": 100, "y": 106},
"phase": "Up"}}}},
{"jsonrpc": "2.0", "id": "after", "method": "tools/call",
"params": {"name": "get_frame", "arguments": {}}},
]
payload = "\n".join(json.dumps(r) for r in REQUESTS) + "\n"
proc = subprocess.run([BIN], input=payload, capture_output=True, text=True, timeout=20)
results = {}
for line in proc.stdout.strip().splitlines():
try:
r = json.loads(line)
if r.get("id") in ("before", "after"):
results[r["id"]] = r
except Exception:
pass
def painted(rid):
content = results.get(rid, {}).get("result", {}).get("content", [])
if content:
try:
return json.loads(content[0]["text"]).get("texts", [])
except Exception:
return []
return []
texts_before = painted("before")
texts_after = painted("after")
print("painted BEFORE:", texts_before)
print("painted AFTER :", texts_after)
def render(texts, out_path, caption):
img = Image.new("RGB", (W, H), (245, 245, 248))
d = ImageDraw.Draw(img)
try:
font_title = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", 18)
font_body = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", 16)
except Exception:
font_title = ImageFont.load_default()
font_body = font_title
y = 16
d.text((12, y), "Agent Counter", fill=(20, 20, 20), font=font_title)
y += 32
for t in texts:
if t == "Agent Counter":
continue
d.text((12, y), t, fill=(20, 20, 20), font=font_body)
y += 28
d.text((12, H - 20), caption, fill=(120, 120, 120), font=ImageFont.load_default())
img.save(out_path)
print(f"wrote {out_path}")
render(texts_before, OUT_BEFORE, "before agent click")
render(texts_after, OUT_AFTER, "after agent click")
assert any("Count: 0" in t for t in texts_before), "expected Count: 0 before click"
assert any("Count: 1" in t for t in texts_after), "expected Count: 1 after click"
print("OK: agent click changed rendered frame Count: 0 -> Count: 1")