File size: 3,956 Bytes
eee14a2 8f6b7b7 eee14a2 8f6b7b7 eee14a2 cd0a5b6 eee14a2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | """Behavioral checks for keyless supervision and evidence of completion."""
import importlib.util
import json
import os
from pathlib import Path
import pytest
spec = importlib.util.spec_from_file_location("opencode_config", Path(__file__).parents[1] / "opencode_config.py")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
def test_coach_uses_muse_only_without_authentication():
# The AltoClef coach runs SOLELY on the free OpenCode Muse model: default
# and small models are Muse, and no Mine/Qwen provider exists here, so no
# title/small task can fall back to Mine. No key material anywhere.
config = module.configuration()
assert config["enabled_providers"] == ["opencode"]
assert config["model"] == "opencode/muse-spark-1.3-contributor-free"
assert config["small_model"] == "opencode/muse-spark-1.3-contributor-free"
assert module.MUSE_MODEL == config["model"]
assert "mine" not in config.get("provider", {})
dumped = json.dumps(config)
assert "apiKey" not in dumped
assert "Authorization" not in dumped
assert "qwen" not in dumped.lower() and "granite" not in dumped.lower()
def test_coach_uses_builtin_plan_agent_only():
# Probed 2026-10-03 against Zen (keyless, isolated HOME, empty stdin):
# the tested override shapes reproduce
# `FreeTierError: ... can only be used from within OpenCode` (403):
# prompt override, tools lockdown, blanket permission deny, even a
# read-only permission shape. Bare description+mode and the built-ins
# (build, plan) succeed. So there is no custom agent at all: the
# built-in `plan` agent (read-only by design, official Muse system
# prompt intact) supervises from user-level instructions.
config = module.configuration()
assert config["default_agent"] == "plan"
assert "agent" not in config
def test_coach_instructions_live_at_user_level():
message = module.coach_user_message({"connected": True, "task_active": True})
assert "reply only with one compact json object" in message.lower()
assert '"connected": true' in message
assert "no tools" in message.lower()
def test_credentials_are_not_inherited(monkeypatch, tmp_path):
for name in ["GEMINI_BOT_KEY_1", "OPENAI_API_KEY", "VOYAGER_API_KEY", "HF_TOKEN"]:
monkeypatch.setenv(name, "private-secret")
monkeypatch.setenv("PATH", "executable-search-path")
env = module.child_environment(tmp_path)
assert env["PATH"] == "executable-search-path"
assert not any(env.get(name) for name in ["GEMINI_BOT_KEY_1", "OPENAI_API_KEY", "VOYAGER_API_KEY", "HF_TOKEN"])
assert env["XDG_DATA_HOME"] == str(tmp_path / "data")
def event(text):
return json.dumps({"type":"text","part":{"text":text}})
def test_accepts_fragmented_opencode_decision():
output = "\n".join([event('{"action":"start",'), event('"reason":"Task is inactive"}')])
assert module.parse_decision(output)["action"] == "start"
@pytest.mark.parametrize("text", ['{"action":"shell","reason":"run a command"}',
'Dragon defeated!', '{}', '[]'])
def test_rejects_unsupported_or_invented_decisions(text):
with pytest.raises(RuntimeError):
module.parse_decision(event(text))
def test_provider_error_is_not_a_valid_decision():
with pytest.raises(RuntimeError):
module.parse_decision(json.dumps({"type":"error","error":{"message":"quota exceeded"}}))
@pytest.mark.parametrize("observation", [
{"connected":False, "task_active":False},
{"entered_end":True, "dragon_seen":False, "task_active":False},
{"entered_end":True, "returned_from_end":True},
{"credits_observed":True},
])
def test_disconnect_or_unloaded_dragon_never_proves_completion(observation):
assert not module.goal_completed(observation)
def test_credits_after_entering_end_prove_completion():
assert module.goal_completed({"entered_end":True,"credits_observed":True})
|