😏
This commit is contained in:
@@ -0,0 +1,306 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user