Files
codex-mmo/tests/test_tui_metadata.py
T

307 lines
14 KiB
Python
Raw Normal View History

2026-08-24 08:11:59 -07:00
from __future__ import annotations
import fcntl
import json
import os
import pty
import select
import shutil
import struct
import subprocess
import sys
import termios
import time
import tomllib
import unittest
from pathlib import Path
from typing import Any
from unittest import mock
import mmo_codex_home
import mmo_runtime
from common import ROOT, RuntimeSandbox
from mmo_runtime import create_session, finish_session
from mmo_util import read_toml, toml_dumps
from mmo_version import MMO_SCHEMA_VERSION
class TuiAndModelMetadataTests(unittest.TestCase):
def _config(self, home: str) -> dict[str, Any]:
with (Path(home) / "config.toml").open("rb") as handle:
return tomllib.load(handle)
def _catalog(self, config: dict[str, Any]) -> dict[str, dict[str, Any]]:
path = Path(config["model_catalog_json"])
payload = json.loads(path.read_text(encoding="utf-8"))
return {item["slug"]: item for item in payload["models"]}
def test_switchyard_bindings_have_exact_codex_model_metadata(self) -> None:
expected: dict[str, dict[str, Any]] = {
"routine_engineer": {
"context_window": 1000000,
"default_reasoning_level": "high",
"apply_patch_tool_type": "freeform",
},
"literal_scout": {
"context_window": 32768,
"default_reasoning_level": None,
"apply_patch_tool_type": "freeform",
},
}
with RuntimeSandbox() as box:
session = create_session(profile="access-efficient-escalation-lab", cwd=box.workspace)
try:
for agent_id, required in expected.items():
home_record = session["homes"][agent_id]
config = self._config(home_record["home"])
self.assertIn("model_catalog_json", config)
self.assertEqual(
config["model_catalog_json"], home_record["model_catalog_json"]
)
entries = self._catalog(config)
selected = config["model"]
self.assertIn(selected, entries)
metadata = entries[selected]
self.assertEqual(metadata["slug"], selected)
self.assertEqual(metadata["context_window"], required["context_window"])
self.assertEqual(metadata["max_context_window"], required["context_window"])
self.assertEqual(
metadata["default_reasoning_level"],
required["default_reasoning_level"],
)
self.assertEqual(
metadata["apply_patch_tool_type"],
required["apply_patch_tool_type"],
)
self.assertEqual(metadata["shell_type"], "shell_command")
self.assertTrue(metadata["supported_in_api"])
self.assertIn("text", metadata["input_modalities"])
self.assertEqual(metadata["default_reasoning_summary"], "none")
self.assertNotIn("base_instructions", metadata)
self.assertTrue(metadata["model_messages"]["instructions_template"])
self.assertEqual(
set(metadata["model_messages"]),
{
"instructions_template",
"instructions_variables",
"approvals",
"collaboration_modes",
"auto_review",
"permissions",
"token_budget",
},
)
self.assertNotIn("node_repl_auto_review_required", metadata)
self.assertNotIn("node_repl_disabled", metadata)
self.assertEqual(
metadata["supports_reasoning_summary_parameter"],
required["default_reasoning_level"] is not None
and agent_id != "routine_engineer",
)
self.assertNotIn("used_fallback_model_metadata", metadata)
self.assertIn("truncation_policy", metadata)
finally:
finish_session(session["session_id"], exit_code=0)
def test_function_only_model_omits_custom_patch_but_keeps_shell(self) -> None:
with RuntimeSandbox() as box:
profile = box.root / "function-only-model"
shutil.copytree(ROOT / "profiles" / "access-efficient-escalation-lab", profile)
profile_path = profile / "profile.toml"
profile_data = read_toml(profile_path)
profile_data["id"] = "function-only-model"
profile_data["catalog"] = "catalog.toml"
profile_path.write_text(toml_dumps(profile_data), encoding="utf-8")
(profile / "catalog.toml").write_text(
toml_dumps(
{
"schema_version": MMO_SCHEMA_VERSION,
"models": {
"opencode_go_openai_chat__deepseek_v4_flash": {
"supports_custom_tools": False,
}
},
}
),
encoding="utf-8",
)
session = create_session(profile=profile, cwd=box.workspace)
try:
home = session["homes"]["routine_engineer"]["home"]
config = self._config(home)
metadata = self._catalog(config)[config["model"]]
self.assertEqual(metadata["shell_type"], "shell_command")
self.assertIsNone(metadata["apply_patch_tool_type"])
finally:
finish_session(session["session_id"], exit_code=0)
def test_hybrid_catalog_preserves_bundled_models_and_adds_external_bindings(self) -> None:
with RuntimeSandbox() as box:
mmo_codex_home._BUNDLED_CODEX_CATALOGS.clear()
profile = box.root / "hybrid-native-external"
shutil.copytree(ROOT / "profiles" / "adaptive-engineering", profile)
profile_path = profile / "profile.toml"
profile_data = read_toml(profile_path)
profile_data["id"] = "hybrid-native-external"
profile_data["agents"]["implementation_specialist"]["backends"] = [
"mcp",
"native",
]
specialist = profile_data["agents"]["implementation_specialist"]
specialist["permissions"] = "read-only"
specialist["execution_mode"] = "turn"
specialist.pop("goal_token_budget")
specialist.pop("max_goal_token_budget")
profile_data["coordination"]["max_active_writers"] = 0
profile_path.write_text(toml_dumps(profile_data), encoding="utf-8")
original = mmo_runtime.bundled_codex_catalog_for_profile
with mock.patch(
"mmo_runtime.bundled_codex_catalog_for_profile", wraps=original
) as load_catalog:
session = create_session(profile=profile, cwd=box.workspace)
try:
# The active Codex catalog is queried once per session, not once
# for every generated agent home.
load_catalog.assert_called_once()
self.assertEqual(load_catalog.call_args.args[1], Path(session["codex_binary"]))
root_home = session["homes"][session["root_agent"]]["home"]
config = self._config(root_home)
self.assertIn("model_catalog_json", config)
entries = self._catalog(config)
# model_catalog_json is a startup replacement, so MMO preserves
# the exact bundled rows before adding external route bindings.
self.assertIn("gpt-5.6-terra", entries)
self.assertIn(config["model"], entries)
native_dir = Path(root_home) / "agents"
native_configs = [
tomllib.loads(path.read_text(encoding="utf-8"))
for path in native_dir.glob("*.toml")
]
external = [
item["model"] for item in native_configs if item["model"].startswith("mmo-")
]
self.assertTrue(external)
self.assertTrue(all(slug in entries for slug in external))
patch_types = {entries[slug]["apply_patch_tool_type"] for slug in external}
self.assertEqual(patch_types, {"freeform"})
finally:
finish_session(session["session_id"], exit_code=0)
def test_builtin_only_process_uses_codex_native_catalog(self) -> None:
with RuntimeSandbox() as box:
session = create_session(profile="codex-harness-team", cwd=box.workspace)
try:
config = self._config(session["homes"][session["root_agent"]]["home"])
self.assertNotIn("model_catalog_json", config)
finally:
finish_session(session["session_id"], exit_code=0)
def test_interactive_launch_preserves_tty_with_redirected_stderr(self) -> None:
with RuntimeSandbox() as box:
old = {key: os.environ.get(key) for key in ("NO_COLOR", "TERM", "FAKE_TUI_PROBE")}
os.environ.pop("NO_COLOR", None)
os.environ["TERM"] = "xterm-256color"
os.environ["FAKE_TUI_PROBE"] = "1"
try:
master, slave = pty.openpty()
fcntl.ioctl(slave, termios.TIOCSWINSZ, struct.pack("HHHH", 24, 80, 0, 0))
environment = {
**os.environ,
"PYTHONPATH": os.pathsep.join([str(ROOT / "libexec"), str(ROOT / "tests")]),
}
process = subprocess.Popen(
[
sys.executable,
str(ROOT / "tests" / "helpers" / "tui_probe_launcher.py"),
"access-efficient-escalation-lab",
str(box.workspace),
],
stdin=slave,
stdout=slave,
stderr=subprocess.PIPE,
env=environment,
start_new_session=True,
close_fds=True,
)
os.close(slave)
buffer = b""
all_output = b""
records: list[dict] = []
resized = False
deadline = time.monotonic() + 30
while time.monotonic() < deadline:
readable, _, _ = select.select([master], [], [], 0.25)
if readable:
try:
chunk = os.read(master, 65536)
except OSError:
break
if not chunk:
break
all_output += chunk
buffer += chunk
while b"\n" in buffer:
raw, buffer = buffer.split(b"\n", 1)
text = raw.decode("utf-8", errors="replace").strip().strip("\r")
if not text.startswith("{"):
continue
try:
record = json.loads(text)
except json.JSONDecodeError:
continue
records.append(record)
if record.get("event") == "ready" and not resized:
fcntl.ioctl(
master,
termios.TIOCSWINSZ,
struct.pack("HHHH", 42, 132, 0, 0),
)
resized = True
if any(
item.get("event") in {"launcher_returned", "launcher_error"}
for item in records
):
break
_unused_stdout, stderr_output = process.communicate(timeout=10)
exit_code = int(process.returncode or 0)
os.close(master)
diagnostic = {
"records": records,
"output": all_output.decode("utf-8", errors="replace"),
"stderr": stderr_output.decode("utf-8", errors="replace"),
}
self.assertEqual(exit_code, 0, diagnostic)
self.assertIn(b"\x1b[32mFAKE_TUI_COLOR\x1b[0m", all_output, diagnostic)
ready = next((item for item in records if item.get("event") == "ready"), None)
resize = next((item for item in records if item.get("event") == "resized"), None)
returned = next(
(item for item in records if item.get("event") == "launcher_returned"),
None,
)
self.assertIsNotNone(ready, diagnostic)
self.assertIsNotNone(resize, diagnostic)
self.assertIsNotNone(returned, diagnostic)
assert ready is not None and resize is not None and returned is not None
self.assertTrue(ready["stdin_isatty"])
self.assertTrue(ready["stdout_isatty"])
self.assertFalse(ready["stderr_isatty"])
self.assertIsNone(ready["no_color"])
self.assertEqual(ready["term"], "xterm-256color")
self.assertEqual(ready["pgrp"], ready["foreground_pgrp"])
self.assertEqual((resize["columns"], resize["lines"]), (132, 42))
self.assertEqual(resize["pgrp"], resize["foreground_pgrp"])
self.assertEqual(returned["exit_code"], 0)
self.assertTrue(returned["echo_enabled"], diagnostic)
self.assertTrue(returned["attributes_restored"], diagnostic)
self.assertEqual(returned["pgrp"], returned["foreground_pgrp"])
finally:
for key, value in old.items():
if value is None:
os.environ.pop(key, None)
else:
os.environ[key] = value
if __name__ == "__main__":
unittest.main()