Files
2026-07-13 13:12:33 +08:00

173 lines
5.8 KiB
Python

from __future__ import annotations
import json
import subprocess
from pathlib import Path
from opensquilla.engine.agent import Agent
from opensquilla.engine.runtime_state_capsule import (
build_runtime_state_capsule,
runtime_state_capsule_message,
)
from opensquilla.engine.turn_runner.agent_bootstrap_stage import (
_runtime_state_capsule_mode_from_env,
)
from opensquilla.engine.types import AgentConfig
from opensquilla.provider.types import Message
from opensquilla.tools.mutation_receipts import (
fingerprint_file,
record_semantic_mutation_receipt,
)
from opensquilla.tools.types import ToolContext
def _init_git_workspace(path: Path) -> None:
subprocess.run(["git", "init"], cwd=path, check=True, stdout=subprocess.DEVNULL)
subprocess.run(
["git", "config", "user.email", "test@example.com"],
cwd=path,
check=True,
)
subprocess.run(["git", "config", "user.name", "Test User"], cwd=path, check=True)
def _commit_file(workspace: Path, relative_path: str, text: str) -> Path:
target = workspace / relative_path
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text(text, encoding="utf-8")
subprocess.run(["git", "add", relative_path], cwd=workspace, check=True)
subprocess.run(["git", "commit", "-m", "initial"], cwd=workspace, check=True)
return target
def test_runtime_state_capsule_reports_source_diff_and_last_mutation(
tmp_path: Path,
) -> None:
workspace = tmp_path / "workspace"
workspace.mkdir()
_init_git_workspace(workspace)
source = _commit_file(workspace, "src/app.py", "print('base')\n")
ctx = ToolContext(workspace_dir=str(workspace), workspace_epoch=0)
before = fingerprint_file(source)
source.write_text("print('changed')\n", encoding="utf-8")
after = fingerprint_file(source)
record_semantic_mutation_receipt(
tool_name="edit_source",
path=source,
operation="edit_source",
before=before,
after=after,
partial=False,
ctx=ctx,
)
capsule = build_runtime_state_capsule(workspace=workspace, tool_context=ctx)
assert capsule["schema"] == "runtime_state_capsule_v1"
assert capsule["workspace"]["epoch"] == 1
assert capsule["workspace"]["source_diff"] is True
assert capsule["workspace"]["source_paths"] == ["src/app.py"]
assert capsule["workspace"]["scratch_only"] is False
assert capsule["last_mutation"] == {
"tool": "edit_source",
"operation": "edit_source",
"path": "src/app.py",
"classification": "source",
"changed": True,
"partial": False,
"workspace_epoch": 1,
}
def test_runtime_state_capsule_message_is_stable_json(tmp_path: Path) -> None:
workspace = tmp_path / "workspace"
workspace.mkdir()
_init_git_workspace(workspace)
_commit_file(workspace, "src/app.py", "print('base')\n")
ctx = ToolContext(workspace_dir=str(workspace), workspace_epoch=0)
message = runtime_state_capsule_message(
build_runtime_state_capsule(workspace=workspace, tool_context=ctx)
)
prefix = "Runtime state capsule:\n"
assert message.startswith(prefix)
payload = json.loads(message.removeprefix(prefix))
assert payload["schema"] == "runtime_state_capsule_v1"
assert payload["workspace"]["source_diff"] is False
def test_agent_runtime_state_capsule_injection_is_opt_in(tmp_path: Path) -> None:
workspace = tmp_path / "workspace"
workspace.mkdir()
_init_git_workspace(workspace)
source = _commit_file(workspace, "src/app.py", "print('base')\n")
ctx = ToolContext(workspace_dir=str(workspace), workspace_epoch=0)
before = fingerprint_file(source)
source.write_text("print('changed')\n", encoding="utf-8")
after = fingerprint_file(source)
record_semantic_mutation_receipt(
tool_name="edit_source",
path=source,
operation="edit_source",
before=before,
after=after,
partial=False,
ctx=ctx,
)
agent = Agent(
provider=None, # type: ignore[arg-type]
config=AgentConfig(
workspace_dir=str(workspace),
runtime_state_capsule_mode="inject",
),
tool_context=ctx,
)
request_messages, _sanitize = agent._provider_request_messages_with_sanitize(
[Message(role="user", content="fix this")],
request_context_message=None,
request_context_insert_index=1,
runtime_context_message=Agent._runtime_context_message("runtime"),
runtime_context_insert_index=1,
)
assert any(
isinstance(message.content, str)
and message.content.startswith("Runtime state capsule:\n")
for message in request_messages
)
off_agent = Agent(
provider=None, # type: ignore[arg-type]
config=AgentConfig(workspace_dir=str(workspace), runtime_state_capsule_mode="off"),
tool_context=ctx,
)
off_messages, _sanitize = off_agent._provider_request_messages_with_sanitize(
[Message(role="user", content="fix this")],
request_context_message=None,
request_context_insert_index=1,
runtime_context_message=Agent._runtime_context_message("runtime"),
runtime_context_insert_index=1,
)
assert not any(
isinstance(message.content, str)
and message.content.startswith("Runtime state capsule:\n")
for message in off_messages
)
def test_runtime_state_capsule_mode_env_parser(monkeypatch) -> None:
monkeypatch.setenv("OPENSQUILLA_RUNTIME_STATE_CAPSULE_MODE", "inject")
assert _runtime_state_capsule_mode_from_env("off") == "inject"
monkeypatch.setenv("OPENSQUILLA_RUNTIME_STATE_CAPSULE_MODE", "bad")
assert _runtime_state_capsule_mode_from_env("inject") == "off"
monkeypatch.delenv("OPENSQUILLA_RUNTIME_STATE_CAPSULE_MODE")
assert _runtime_state_capsule_mode_from_env("log") == "log"