Files
omnigent-ai--omnigent/tests/test_opencode_polly_debby_worker.py
2026-07-13 13:12:00 +08:00

69 lines
2.9 KiB
Python

"""Guards the OpenCode worker's presence in the shipped example agents.
Both polly and debby once declared an optional ``opencode`` sub-agent
(``harness: opencode-native``). Shipping a sub-agent whose harness older
clients don't recognize made every old runner/host fail to launch the agent at
all — the version-skew incident behind omnigent-ai/omnigent#1145. That incident
is now mitigated on the execution path: ``spec.load(...,
prune_invalid_sub_agents=True)`` (runner ``_entry`` + server ``agent_cache``)
gracefully DROPS a sub-agent whose harness a client doesn't recognize, so an old
client loads polly with its remaining workers instead of failing. Combined with
``opencode-native`` now being a recognized harness
(``omnigent.spec._omnigent_compat.OMNIGENT_HARNESSES``), polly re-declares its
``opencode`` worker; the positive test below guards that it stays wired.
debby, however, is still deliberately opencode-free (reverted in #1295), and the
negative test below guards that OpenCode does not creep back into that spec.
"""
from __future__ import annotations
from pathlib import Path
from omnigent.spec import load
_REPO_ROOT = Path(__file__).resolve().parents[1]
def _sub_agents(bundle: str) -> dict[str, object]:
spec = load(_REPO_ROOT / "examples" / bundle)
return {sa.name: sa for sa in (getattr(spec, "sub_agents", None) or [])}
def _config(sub_agent: object) -> dict[str, object]:
executor = getattr(sub_agent, "executor", None)
config = getattr(executor, "config", None)
if isinstance(config, dict):
return config
return {}
def test_polly_declares_opencode_worker() -> None:
"""polly declares its ``opencode`` worker on the ``opencode-native`` harness.
Safe to re-add because #1145's graceful pruning drops the worker (rather than
failing the whole agent) on any client too old to recognize the harness, and
``opencode-native`` is a recognized harness on current clients. If this ever
regresses to failing old clients, prune-on-load is the contract to check.
"""
subs = _sub_agents("polly")
assert "opencode" in subs
assert _config(subs["opencode"]).get("harness") == "opencode-native"
def test_debby_does_not_declare_opencode_head() -> None:
"""debby stays opencode-free, so an older client can load it without skew.
debby is reverted to its two-head roster (claude + gpt). Re-adding an
``opencode`` head (or any ``opencode-native`` harness override) would
reintroduce the harness that broke old clients on spec validation.
"""
subs = _sub_agents("debby")
assert "opencode" not in subs
assert {"claude", "gpt"} <= set(subs)
config_text = (_REPO_ROOT / "examples" / "debby" / "config.yaml").read_text(encoding="utf-8")
assert "opencode" not in config_text.lower()
# No head re-introduces opencode-native via a harness override either.
for sub in subs.values():
assert "opencode-native" not in (_config(sub).get("allowed_harnesses") or [])