File size: 7,454 Bytes
5ddf32a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4553f46
 
 
 
 
 
 
 
 
 
 
 
 
008c4fa
 
 
 
 
4553f46
 
 
 
 
5ddf32a
 
 
 
 
 
 
 
 
 
 
 
 
 
0db945a
1a3a101
 
 
 
 
0db945a
 
 
1a3a101
 
 
 
 
 
 
0db945a
 
 
 
 
 
5ddf32a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
"""Run the real boot patcher against a clean upstream tree and attest it.

This is the end-to-end proof that the patch layer no longer substitutes a
decision method: the patcher is executed, then the attestation is run on the
resulting tree.
"""
from __future__ import annotations

import os
import shutil
import subprocess
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
SIM = Path(os.environ.get("PATCH_SIM_ROOT", r"C:\Users\PCGAME~1\AppData\Local\Temp\kilo\patchsim"))
UPSTREAM_HOME = Path(
    os.environ.get("VOYAGER_UPSTREAM_REF")
    or r"C:\Users\PCGAME~1\AppData\Local\Temp\kilo\voyager-upstream-ref"
)

sys.path.insert(0, str(ROOT))

import voyager_runtime_contract as contract  # noqa: E402
import voyager_stack as stack_module  # noqa: E402


def _without_comments(source: str) -> str:
    return "\n".join(
        line for line in source.splitlines() if not line.strip().startswith("//")
    )


def _fresh_tree() -> Path:
    live = SIM / "Voyager"
    if live.exists():
        shutil.rmtree(live)
    live.mkdir(parents=True)
    shutil.copytree(UPSTREAM_HOME / "voyager", live / "voyager")
    return live


def test_patcher_runs_and_attestation_passes(monkeypatch):
    live = _fresh_tree()
    monkeypatch.setattr(stack_module, "ROOT", SIM)
    monkeypatch.setattr(stack_module, "SRC", live)
    stack = stack_module.VoyagerStack()
    stack._patch_runtime_source()

    # The snapshot must exist and be pristine.
    reference = live / contract.REFERENCE_DIR / "voyager/agents/action.py"
    expected = live / contract.REFERENCE_DIR / "voyager/agents/curriculum.py"
    assert reference.exists() and expected.exists()
    assert expected.read_text(encoding="utf-8") == (
        UPSTREAM_HOME / "voyager/agents/curriculum.py"
    ).read_text(encoding="utf-8")

    # The patched tree must still contain the official action parser.
    action = (live / "voyager/agents/action.py").read_text(encoding="utf-8")
    assert '"\\n\\n".join(function["body"] for function in functions)' in action
    assert "canonical_place_code" not in action
    curriculum = (live / "voyager/agents/curriculum.py").read_text(encoding="utf-8")
    assert "choice_id" not in curriculum
    assert "generate_affordances" not in curriculum
    assert "run_qa_step2_answer_questions" in curriculum, "official QA context removed"

    # Every action.py patch must be present in the tree that actually runs. A
    # str.replace that misses its marker leaves the file byte-identical, and the
    # Space then boots looking healthy on a pristine upstream agent.
    action_markers = {
        "base skills": '"creativeGiveItem",',
        "max_tokens": "max_tokens=2048",
        "error bound": "error_messages[-4:]",
        "chat-log bound": "chat_messages[-6:]",
        "context bound": "{context[:1400]}",
        "critique bound": "{critique[:1200]}",
    }
    for what, marker in action_markers.items():
        assert marker in action, f"action {what} patch did not apply"
    # The previous program must reach the model whole. Truncating it hid the
    # function the model had just declared, so it redeclared it and upstream's
    # Babel rejected the duplicate identifier.
    assert "Code from the last round" in action
    assert "code[:3200]" not in action, "previous code is still truncated"
    # The official Action contract is untouched by those integration bounds.
    assert "max_tokens" not in (
        UPSTREAM_HOME / "voyager/agents/action.py"
    ).read_text(encoding="utf-8"), "upstream action.py is expected to set no max_tokens"

    # No local build template may be installed. Comments may still explain the
    # removal, so compare against executable code only.
    place = _without_comments(
        (live / "voyager/control_primitives/placeItem.js").read_text(encoding="utf-8")
    )
    assert "buildProject" not in place
    assert "_voyagerProjectBlueprint" not in place
    assert not (live / "voyager/control_primitives_context/buildProject.js").exists()
    assert not (live / "voyager/control_primitives_context/placeBlocks.js").exists()

    # The official critic prompt must survive untouched.
    critic = (live / "voyager/prompts/critic.txt").read_text(encoding="utf-8")
    assert len(critic.splitlines()) > 50

    # The world is a flat resource map, so mining must be able to reach the blocks
    # under the bot's feet. The first attempt used `Math.floor(bot.y) - 2` for
    # that, but a floor measured FROM THE BOT travels down with it: it always
    # excluded the next layer, so iron at y=48 stayed visible and unmineable while
    # the bot stood at y=63. The floor must be an absolute depth budget, and the
    # primitive must be able to dig toward a layer it knows is below.
    mine = _without_comments(
        (live / "voyager/control_primitives/mineBlock.js").read_text(encoding="utf-8")
    )
    assert "MAX_DIG_DEPTH" in mine
    assert "const searchFloorY = Math.max(" in mine
    assert "Math.floor(bot.entity.position.y) - MAX_DIG_DEPTH" in mine
    assert "const playerFloorY = Math.floor(bot.entity.position.y) - 2;" not in mine
    assert "descendToward" in mine
    assert "steps < MAX_DIG_DEPTH" in mine
    assert 'under.name !== "bedrock"' in mine

    # The pathfinder must keep its upstream digging ability, otherwise a bot that
    # mines its own shaft can never path out of it again.
    index = (live / "voyager/env/mineflayer/index.js").read_text(encoding="utf-8")
    assert "movements.canDig = false" not in _without_comments(index)

    # The learning loop and recovery integration fixes must still be present.
    engine = (live / "voyager/voyager.py").read_text(encoding="utf-8")
    assert "self.skill_manager.add_new_skill(info)" in engine
    assert "deterministic_action_result" not in engine
    assert "traceback.print_exc()" in engine


def test_attestation_accepts_the_patched_tree(monkeypatch):
    live = _fresh_tree()
    monkeypatch.setattr(stack_module, "ROOT", SIM)
    monkeypatch.setattr(stack_module, "SRC", live)
    stack_module.VoyagerStack()._patch_runtime_source()

    # Import the patched agents directly. Their third-party dependencies
    # (gymnasium, langchain, chromadb) are not installed here, so the classes
    # are built from their source the same way the attestation reads them.
    from test_voyager_official_contract import _load_class

    engine_cls = _load_class(live / "voyager/voyager.py", "Voyager")
    engine = engine_cls.__new__(engine_cls)
    for relative, class_name, attribute in (
        ("voyager/agents/curriculum.py", "CurriculumAgent", "curriculum_agent"),
        ("voyager/agents/action.py", "ActionAgent", "action_agent"),
        ("voyager/agents/critic.py", "CriticAgent", "critic_agent"),
        ("voyager/agents/skill.py", "SkillManager", "skill_manager"),
    ):
        cls = _load_class(live / relative, class_name)
        setattr(engine, attribute, cls.__new__(cls))

    monkeypatch.setattr(
        contract.subprocess,
        "check_output",
        lambda *a, **k: contract.UPSTREAM_COMMIT,
    )
    attestation = contract.attest_original_runtime(engine, live)
    assert attestation["checkout_verified"] is True
    assert "action.process_ai_message" in attestation["decision_methods_verified"]
    assert "critic.check_task_success" in attestation["decision_methods_verified"]
    assert set(attestation["declared_adaptations"]) == {"curriculum.propose_next_ai_task"}