import json import subprocess from unittest.mock import MagicMock, patch import pytest from glas_harness.contract import Rein, SandboxHandle, ToolCall from glas_harness.reins.rein_openweights import ReinOpenWeights, ReinOpenWeightsNotInstalled def test_is_rein_subclass() -> None: assert issubclass(ReinOpenWeights, Rein) def test_bin_raises_if_not_installed() -> None: rein = ReinOpenWeights(cli_bin="does-not-exist-binary") with pytest.raises(ReinOpenWeightsNotInstalled): rein._bin() def test_start_session_writes_task_file_and_captures_head(tmp_path) -> None: repo = tmp_path / "repo" repo.mkdir() subprocess.run(["git", "init", "-q"], cwd=repo, check=True) subprocess.run(["git", "commit", "-q", "--allow-empty", "-m", "init"], cwd=repo, check=True) rein = ReinOpenWeights() sandbox = SandboxHandle(sandbox_id="abc", host="localhost", reachability={"workspace_dir": str(repo)}) session = rein.start_session( profile={"id": "harness.agent-dev-local"}, inputs={"title": "t", "description": "d"}, sandbox=sandbox, ) assert session["target_repo"] == str(repo) assert session["head_before"] task_spec = json.loads(open(session["task_file"]).read()) assert task_spec["title"] == "t" assert task_spec["target_repo"] == str(repo) def test_start_session_requires_resolvable_target_repo() -> None: rein = ReinOpenWeights() sandbox = SandboxHandle(sandbox_id="abc", host="localhost", reachability={}) with pytest.raises(ValueError, match="target_repo"): rein.start_session(profile={}, inputs={"title": "t", "description": "d"}, sandbox=sandbox) def test_dispatch_tool_invokes_rein_openweights_cli() -> None: rein = ReinOpenWeights() session = {"task_file": "/tmp/task.json"} fake_result = MagicMock(returncode=0, stdout="ok", stderr="") with patch.object(rein, "_bin", return_value="/usr/bin/rein-openweights"): with patch("glas_harness.reins.rein_openweights.subprocess.run", return_value=fake_result) as run: result = rein.dispatch_tool(session, ToolCall(name="run_task")) argv = run.call_args.args[0] assert argv[:3] == ["/usr/bin/rein-openweights", "run", "--task-file"] assert "--no-hub" in argv assert result.ok is True assert result.output == "ok" def test_dispatch_tool_passes_model_when_set() -> None: rein = ReinOpenWeights(model="meta-llama/llama-3.1-70b-instruct") session = {"task_file": "/tmp/task.json"} fake_result = MagicMock(returncode=0, stdout="ok", stderr="") with patch.object(rein, "_bin", return_value="/usr/bin/rein-openweights"): with patch("glas_harness.reins.rein_openweights.subprocess.run", return_value=fake_result) as run: rein.dispatch_tool(session, ToolCall(name="run_task")) argv = run.call_args.args[0] assert "--model" in argv assert "meta-llama/llama-3.1-70b-instruct" in argv def test_dispatch_tool_reports_failure() -> None: rein = ReinOpenWeights() session = {"task_file": "/tmp/task.json"} fake_result = MagicMock(returncode=1, stdout="", stderr="boom") with patch.object(rein, "_bin", return_value="/usr/bin/rein-openweights"): with patch("glas_harness.reins.rein_openweights.subprocess.run", return_value=fake_result): result = rein.dispatch_tool(session, ToolCall(name="run_task")) assert result.ok is False assert result.error == "boom" def test_end_session_detects_new_commit(tmp_path) -> None: repo = tmp_path / "repo" repo.mkdir() subprocess.run(["git", "init", "-q"], cwd=repo, check=True) subprocess.run(["git", "commit", "-q", "--allow-empty", "-m", "init"], cwd=repo, check=True) rein = ReinOpenWeights() from glas_harness.reins._shared import git_head head_before = git_head(str(repo)) subprocess.run(["git", "commit", "-q", "--allow-empty", "-m", "task"], cwd=repo, check=True) summary = rein.end_session({"target_repo": str(repo), "head_before": head_before}) assert summary["committed"] == "True" assert summary["commit_sha"] != head_before