tiny-computer-agent / showcase.py
hkblockchaintechnology's picture
Gallery: cover the 2.0 operator layer in the coverage check
8d672b3 verified
Raw History Blame Contribute Delete
8.21 kB
"""Build the capability gallery: one screenshot per thing the harness can do.
python showcase.py # every capability
python showcase.py --list # list the ids without rendering
python showcase.py --only decisions # render a subset by id substring
The shared state - the catalogue, the renderers, the display - lives in
:mod:`showcase_core`, and the capabilities themselves in :mod:`showcase_catalog`,
so importing this file never makes a second copy of either.
"""
from __future__ import annotations
import json
import sys
import showcase_catalog # noqa: F401 (importing it registers every shot)
from showcase_core import (
CATALOG, GALLERY, ROOT, ensure_display, render_desktop, render_terminal, save,
)
def main(argv: list[str] | None = None) -> int:
args = list(argv if argv is not None else sys.argv[1:])
only = args[args.index("--only") + 1] if "--only" in args else None
wanted = (args[args.index("--ids") + 1].split(",") if "--ids" in args else None)
if "--card" in args:
print("card section written:", write_card(_read_index()).name)
return 0
display = ensure_display()
picked = [s for s in CATALOG
if (s.id in wanted if wanted else (not only or only.lower() in s.id.lower()))]
print(f"display: {display} | {len(picked)}/{len(CATALOG)} capabilities")
if "--list" in args:
for s in picked:
print(f" {s.id:36} {s.kind:8} {s.category}: {s.title}")
return 0
GALLERY.mkdir(exist_ok=True)
if "--reindex" in args or only:
# an index built from the catalogue, not from what this run happened to draw
_write_index()
if "--reindex" in args:
print(f"reindexed {len(_read_index())} pictures in {GALLERY}")
return 0
tmp = ROOT / ".showcase-tmp"
tmp.mkdir(exist_ok=True)
made = []
for s in picked:
try:
image = render_desktop(s, tmp) if s.kind == "desktop" else render_terminal(s, tmp)
path = save(image, s.id)
made.append(s)
print(f" ok {s.id:34} {path.name:34} {image.size[0]}x{image.size[1]}")
except Exception as exc:
print(f" FAIL {s.id:34} {type(exc).__name__}: {exc}")
_write_index()
print(f"wrote {len(made)} images to {GALLERY}")
return 0
def _entry(s):
return {"id": s.id, "category": s.category, "title": s.title, "shows": s.shows,
"note": s.note, "kind": s.kind}
def _write_index():
"""Index every capability whose picture exists, in catalogue order."""
entries = [_entry(s) for s in CATALOG if (GALLERY / f"{s.id}.png").exists()]
(GALLERY / "index.json").write_text(json.dumps(entries, indent=2))
return entries
def _read_index():
return json.loads((GALLERY / "index.json").read_text())
def api_surface() -> tuple[list[str], list[str]]:
"""(callables, constants) - the public surface a picture has to cover.
Introspected rather than hard-coded, so the gallery's promise is checked
against the package instead of against a list someone forgot to update.
"""
import importlib
import inspect
names, constants = [], []
modules = ["actions", "act", "observe", "perception", "brain", "models", "loop",
"safety", "desktop", "demo", "trace", "accessibility", "__main__",
# 2.0: the operator layer. A picture that ignores it would let the gallery's
# promise quietly mean "the pre-2.0 API", which is exactly the kind of claim
# this repository is supposed to be too honest to make.
"diff", "gates", "runner", "skills", "watchdog", "audit"]
for module_name in modules:
module = importlib.import_module(f"tiny_computer_agent.{module_name}")
for name, obj in vars(module).items():
if name.startswith("_"):
continue
if inspect.isfunction(obj) or inspect.isclass(obj):
if getattr(obj, "__module__", "") != module.__name__:
continue # imported, not defined here
names.append(name)
if inspect.isclass(obj):
for member, value in vars(obj).items():
if member.startswith("_"):
continue
if inspect.isfunction(value) or isinstance(value, property):
names.append(f"{name}.{member}")
elif name.isupper() and isinstance(obj, (str, int, float, tuple, frozenset)):
constants.append(name)
return names, constants
def write_card(entries: list[dict]) -> Path:
"""Write the gallery page, and the section the model card embeds.
Every entry carries the callables it demonstrates, so the card can promise -
and a reader can check - that no part of the public API is left without a
picture.
"""
areas: dict[str, list[dict]] = {}
for entry in entries:
areas.setdefault(entry["category"], []).append(entry)
pictured = sorted({name for entry in entries for name in entry["shows"]})
callables, constants = api_surface()
missing = sorted(set(callables) - set(pictured))
if missing:
print(f" WARNING: {len(missing)} public callables are not pictured: {missing}")
lines = [
"## Capability gallery",
"",
f"**{len(entries)} capabilities, one screenshot each - and "
f"{len(set(callables) & set(pictured))} of the package's {len(callables)} public "
f"callables (functions, methods, classes and protocols) appear in at least one of "
f"them**, together with {len(set(constants) & set(pictured))} of its public "
f"constants.",
"",
(f"_Not yet pictured: {len(missing)} callables added in 2.0 - the gate, skill, "
f"runner, diff, watchdog and audit layers. They are covered by tests; the "
f"roadmap tracks the pictures._" if missing else
"_Every public callable in the package is pictured._"),
"",
"Nothing here is a mock-up. Each picture is produced by "
"[`showcase.py`](showcase.py): a command or a call is run for real, and its actual "
"output - or the real desktop it acted on - is what you see. The desktop shots are "
"real screen captures on a real X server (Xvfb, 1280x800), including a real mouse "
"click verified by the target application's own reaction.",
"",
"> **An honest note on the platform.** These were captured on Linux, because the "
"sandbox that builds this card has no Windows: no KVM, no QEMU and no Windows image. "
"The harness is OS-agnostic (pyautogui uses `SendInput` on Windows, and `GrabScreen` "
"falls back to Pillow's `ImageGrab`), so these are the same code paths - but they are "
"not Windows pixels. The Windows twins are generated by the same script in "
"[`.github/workflows/live-desktop.yml`](.github/workflows/live-desktop.yml).",
"",
"Regenerate it with `python showcase.py` (`--list` to see the ids, `--only <id>` for a "
"subset, `--card` to rewrite this section). It runs the calls for real, so a broken "
"capability fails loudly instead of shipping a stale picture.",
"",
"| area | capabilities |",
"|---|---:|",
]
lines += [f"| {area} | {len(items)} |" for area, items in areas.items()]
lines += ["", "---", ""]
for area, items in areas.items():
lines += [f"### {area}", ""]
for entry in items:
lines += [f"**{entry['title']}**", ""]
if entry["note"]:
lines += [f"*{entry['note']}*", ""]
lines += [f'<img src="gallery/{entry["id"]}.png" width="860">', ""]
lines += ["`shows:` " + ", ".join(f"`{name}`" for name in entry["shows"]), ""]
text = "\n".join(lines)
(GALLERY / "_card_section.md").write_text(text)
(GALLERY / "README.md").write_text(
"---\ntitle: Capability gallery\n---\n\n" + text + "\n")
return GALLERY / "_card_section.md"
if __name__ == "__main__":
raise SystemExit(main())