#!/usr/bin/env python3 """The text the two models read must agree with the code they drive. python3 tests/test_vm_prompt_consistency.py WHY THIS EXISTS Prompt text rots quietly. When the CLI/GUI split was removed, the code changed in one afternoon and the prose kept saying "in either mode" for a week. When the handover screenshot was removed, the agent's prompt went on promising "you will be handed a picture of it". Neither was caught, because nothing reads the prompts the way the model does - as fact. So this reads them. Every claim checked here is one that was found wrong in a real prompt, tool description or report, and each check is scoped to the text the model actually sees, not to comments about it. """ import os import re import sys HERE = os.path.dirname(os.path.abspath(__file__)) ROOT = os.path.join(HERE, "..") sys.path.insert(0, os.path.join(ROOT, "vmagent", "app")) import tools # noqa: E402 FAILS: list[str] = [] def check(label: str, condition: bool, detail: str = "") -> None: if condition: print(f"ok {label}") else: FAILS.append(f"{label}: {detail}") print(f"FAIL {label}\n {detail}") def read(*parts: str) -> str: return open(os.path.join(ROOT, *parts), encoding="utf-8").read() prompt = read("configs", "agent", "prompt.md") screen = read("configs", "agent", "prompt.screen.md") ubuntu = read("configs", "agent", "prompt.ubuntu.md") windows = read("configs", "agent", "prompt.windows.md") neutral = prompt + screen agent_facing = neutral + ubuntu + windows # What the sub-agent's model is actually sent: descriptions, not comments. schemas = tools.schemas("ubuntu") + tools.schemas("windows") descriptions = "\n".join( s["function"]["description"] + " " + " ".join(str(p.get("description", "")) for p in s["function"]["parameters"]["properties"].values()) for s in schemas) tool_names = {s["function"]["name"] for s in tools.schemas("ubuntu")} # The main model's side: its system prompt section and the tool docstring. system_prompt = read("configs", "assistant", "system-prompt.md") vm_src = read("app", "owuitools", "routers", "vm.py") docstring = re.search(r'async def vm_agent\(.*?"""(.*?)"""', vm_src, re.S) main_facing = system_prompt + (docstring.group(1) if docstring else "") report_src = read("vm", "vmd", "report.py") filter_src = read("owui-functions", "vm_agent_progress.py") # --- there is one kind of session, and no text may say otherwise --------- STALE = ("either mode", "CLI mode", "GUI mode", "cli mode", "gui mode", "CLI session", "GUI session", "in a desktop session") for where, text in (("agent prompts", agent_facing), ("tool descriptions", descriptions), ("main model text", main_facing), ("report", report_src)): hits = [s for s in STALE if s in text] check(f"no CLI/GUI mode language in the {where}", not hits, str(hits)) valves = re.findall(r'description="([^"]*)"', filter_src[:8000]) check("the filter's valve text does not describe modes that no longer exist", not any(("CLI" in v or "GUI" in v) for v in valves), str(valves)) # --- promises that were once true ---------------------------------------- check("the prompt no longer promises a handover screenshot", "handed a picture" not in prompt and "picture of it along" not in prompt, "the handover screenshot was removed; the model must not wait for one") # --- every tool the prompt names exists ----------------------------------- named = set(re.findall(r"`([a-z]+(?:_[a-z]+)+)`", agent_facing)) missing = sorted(n for n in named if n not in tool_names and n not in { "py_compile", # python3 -m py_compile: a command, not a tool "in_progress", # a task status, not a tool }) check("every tool the prompts name is a tool the agent has", not missing, str(missing)) # --- machine paths stay in the machine's own section ---------------------- for path in ("/tmp", "/mnt/project", "Z:\\", "C:\\Windows", "apt", "winget"): # Word-bounded, or "apt" matches "captured". check(f"the machine-neutral prompt does not say {path!r}", not re.search(r"(?