Files
opensquilla--opensquilla/tests/test_memory_dream_runner.py
2026-07-13 13:12:33 +08:00

247 lines
8.2 KiB
Python

from __future__ import annotations
import json
from types import SimpleNamespace
import pytest
from opensquilla.memory.dream import Dream
from opensquilla.memory.dream.evidence import load_evidence_store
class _Response:
def __init__(self, content: str) -> None:
self.content = content
class _PatchProvider:
def __init__(self, text: str | None = None, *, delete_path=None) -> None:
self.calls = 0
self.delete_path = delete_path
self.text = text or json.dumps(
{
"operations": [
{
"op": "upsert",
"candidate_ids": ["auto"],
"section": "User Preferences",
"memory_id": "mem_provider_benchmarks",
"text": "- User prefers provider-backed benchmarks over toy simulations.",
}
]
}
)
async def complete(self, *, messages, max_tokens):
self.calls += 1
if self.delete_path is not None and self.delete_path.exists():
self.delete_path.unlink()
return _Response(self.text)
class _FailIfCalledProvider:
def __init__(self) -> None:
self.calls = 0
async def complete(self, *, messages, max_tokens): # noqa: ARG002
self.calls += 1
raise AssertionError("provider should not be called")
def _dream(workspace, *, provider=None, preview=False):
config = SimpleNamespace(
max_batch_size=10,
min_batch_size=1,
input_slimming="off",
preview_mode=preview,
dry_run=preview,
evidence_min_score=0.0,
evidence_negative_recurrence_threshold=2,
evidence_quarantine_enabled=True,
evidence_curated_writes_enabled=True,
)
return Dream(
workspace=workspace,
provider=provider or _PatchProvider(),
session_lock=None,
config=config,
)
@pytest.mark.asyncio
async def test_dream_records_evidence_and_writes_curated_memory(tmp_path):
memory_dir = tmp_path / "memory"
memory_dir.mkdir()
(memory_dir / "note.md").write_text(
"User prefers provider-backed benchmarks over toy simulations.",
encoding="utf-8",
)
result = await _dream(tmp_path).run()
assert result.evidence_status == "ok"
assert result.apply_status == "ok"
assert "User Preferences" in (tmp_path / "MEMORY.md").read_text(encoding="utf-8")
assert (memory_dir / ".dream_state" / "promotion_evidence.json").exists()
assert (memory_dir / "note.md").exists()
@pytest.mark.asyncio
async def test_dream_result_and_log_use_single_path_names(tmp_path):
memory_dir = tmp_path / "memory"
memory_dir.mkdir()
(memory_dir / "note.md").write_text(
"User prefers provider-backed benchmarks over toy simulations.",
encoding="utf-8",
)
result = await _dream(tmp_path).run()
log_path = next((tmp_path / "logs").glob("dream-main-*.jsonl"))
log_row = json.loads(log_path.read_text(encoding="utf-8").splitlines()[-1])
assert result.evidence_status == "ok"
assert result.apply_status == "ok"
assert result.provider_calls == 1
assert not hasattr(result, "phase" + "1_status")
assert not hasattr(result, "phase" + "2_status")
assert not hasattr(result, "files_deleted")
assert "evidence_status" in log_row
assert "apply_status" in log_row
assert "provider_calls" in log_row
assert "files_deleted" not in log_row
assert all("phase" not in key for key in log_row)
@pytest.mark.asyncio
async def test_dream_preview_mutates_nothing(tmp_path):
memory_dir = tmp_path / "memory"
memory_dir.mkdir()
note = memory_dir / "note.md"
note.write_text("User prefers concise implementation notes.", encoding="utf-8")
result = await _dream(tmp_path, preview=True).run()
assert result.evidence_status == "ok"
assert result.apply_status == "ok"
assert note.exists()
assert not (tmp_path / "MEMORY.md").exists()
assert not (memory_dir / ".dream_state" / "promotion_evidence.json").exists()
assert result.cursor_after == result.cursor_before
@pytest.mark.asyncio
async def test_dream_externally_missing_candidate_after_evidence_does_not_raise(tmp_path):
memory_dir = tmp_path / "memory"
memory_dir.mkdir()
note = memory_dir / "note.md"
note.write_text("User prefers concise implementation notes.", encoding="utf-8")
provider = _PatchProvider(delete_path=note)
result = await _dream(tmp_path, provider=provider).run()
assert result.apply_status == "ok"
assert "FileNotFoundError" not in (result.error or "")
@pytest.mark.asyncio
async def test_dream_writes_evidence_receipt(tmp_path):
memory_dir = tmp_path / "memory"
memory_dir.mkdir()
(memory_dir / "note.md").write_text(
"User prefers provider-backed benchmarks over toy simulations.",
encoding="utf-8",
)
result = await _dream(tmp_path).run()
assert result.edit_receipt_path is not None
receipt = json.loads((tmp_path / result.edit_receipt_path).read_text(encoding="utf-8"))
assert receipt["schema_version"] == 1
assert "version" not in receipt
assert "ranked_candidates" in receipt
assert "applied_promotions" in receipt
@pytest.mark.asyncio
async def test_dream_skips_provider_when_no_candidates_rank(tmp_path):
memory_dir = tmp_path / "memory"
memory_dir.mkdir()
note = memory_dir / "note.md"
note.write_text("Do not use this one-off label.", encoding="utf-8")
provider = _FailIfCalledProvider()
result = await _dream(tmp_path, provider=provider).run()
assert provider.calls == 0
assert result.provider_calls == 0
assert result.evidence_status == "ok"
assert result.apply_status == "skipped"
assert note.exists()
assert not (tmp_path / "MEMORY.md").exists()
@pytest.mark.asyncio
async def test_dream_does_not_promote_stale_candidate_from_mixed_operation(tmp_path):
memory_dir = tmp_path / "memory"
memory_dir.mkdir()
stale = memory_dir / "stale.md"
live = memory_dir / "live.md"
stale.write_text("User prefers stale source.", encoding="utf-8")
live.write_text("User prefers live source.", encoding="utf-8")
provider = _PatchProvider(
text=json.dumps(
{
"operations": [
{
"op": "upsert",
"candidate_ids": ["auto"],
"section": "User Preferences",
"memory_id": "mem_mixed",
"text": "- User prefers live source.",
}
]
}
),
delete_path=stale,
)
result = await _dream(tmp_path, provider=provider).run()
store = load_evidence_store(tmp_path)
stale_entries = [
entry for entry in store.entries.values() if entry.source_path == "memory/stale.md"
]
live_entries = [
entry for entry in store.entries.values() if entry.source_path == "memory/live.md"
]
assert result.apply_status == "ok"
assert stale_entries and stale_entries[0].status == "candidate"
assert stale_entries[0].last_skip_reason == "source_missing"
assert live_entries and live_entries[0].status == "promoted"
@pytest.mark.asyncio
async def test_dream_marks_noop_curated_write_as_represented_not_promoted(tmp_path):
memory_dir = tmp_path / "memory"
memory_dir.mkdir()
existing = "- User prefers provider-backed benchmarks over toy simulations."
(tmp_path / "MEMORY.md").write_text(
f"# Long-Term Memory\n\n## User Preferences\n\n{existing}\n",
encoding="utf-8",
)
(memory_dir / "note.md").write_text(
"User prefers provider-backed benchmarks over toy simulations.",
encoding="utf-8",
)
result = await _dream(tmp_path).run()
store = load_evidence_store(tmp_path)
entry = next(iter(store.entries.values()))
receipt = json.loads((tmp_path / result.edit_receipt_path).read_text(encoding="utf-8"))
assert result.apply_status == "ok"
assert entry.status == "represented"
assert entry.promoted_at is None
assert entry.last_skip_reason == "no_curated_change"
assert receipt["applied_promotions"][0]["changed"] is False