generated from coulomb/repo-seed
Add guided reflection capture with preview, cya memory reflections CLI, near-duplicate compaction, budget-capped surfacing, and expanded tests. Profile 1 is now documented as production-ready in README and MemoryVision.
86 lines
2.9 KiB
Python
86 lines
2.9 KiB
Python
"""Orchestrator tests — Profile 1 surfacing and explain-context roundtrip."""
|
|
|
|
from io import StringIO
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from rich.console import Console
|
|
|
|
from cya.memory import KIND_REFLECTION, remember_reflection
|
|
from cya.memory.reflections import format_reflection_surfacing
|
|
from cya.orchestrator import handle_request
|
|
|
|
|
|
@pytest.fixture
|
|
def isolated_memory(monkeypatch, tmp_path):
|
|
mem_dir = tmp_path / "memory"
|
|
mem_dir.mkdir()
|
|
|
|
def _fake_mem_path(scope: str = "cwd") -> Path:
|
|
return mem_dir / f"{scope}.json"
|
|
|
|
monkeypatch.setattr("cya.memory._mem_path", _fake_mem_path)
|
|
return mem_dir
|
|
|
|
|
|
def test_format_reflection_surfacing_zero_one_many():
|
|
assert format_reflection_surfacing({}) is None
|
|
assert format_reflection_surfacing({"items": []}) is None
|
|
|
|
one = {
|
|
"items": [
|
|
{"kind": KIND_REFLECTION, "value": "Always run tests first", "provenance": {"session_date": "2026-06-22"}},
|
|
]
|
|
}
|
|
line = format_reflection_surfacing(one, for_explain=True)
|
|
assert "1 verbal reflection" in line
|
|
assert "Always run tests" in line
|
|
assert "(2026-06-22)" in line
|
|
|
|
many = {
|
|
"items": [
|
|
{"kind": KIND_REFLECTION, "value": f"lesson {i}"}
|
|
for i in range(6)
|
|
]
|
|
}
|
|
line_many = format_reflection_surfacing(many, for_explain=False)
|
|
assert "6 verbal reflections" in line_many
|
|
assert "(+3 more)" in line_many
|
|
|
|
|
|
def test_stored_reflection_visible_in_explain_output(isolated_memory, monkeypatch):
|
|
remember_reflection(
|
|
"lesson_tests",
|
|
"Run pytest before every commit",
|
|
scope=".",
|
|
provenance={"session_date": "2026-06-22", "scope": ".", "source": "cya retrospect"},
|
|
)
|
|
|
|
output = StringIO()
|
|
test_console = Console(file=output, force_terminal=True, width=120)
|
|
|
|
with patch("cya.orchestrator.console", test_console):
|
|
with patch("cya.orchestrator.collect") as mock_collect:
|
|
mock_collect.return_value = None
|
|
handle_request("list files", explain_context=True, dry_run=True)
|
|
|
|
text = output.getvalue()
|
|
assert "Reflections:" in text or "verbal reflection" in text.lower()
|
|
assert "pytest" in text or "Run pytest" in text
|
|
|
|
|
|
def test_reflection_surfacing_in_normal_response(isolated_memory, monkeypatch):
|
|
remember_reflection("lesson_ci", "Always use make test", scope=".")
|
|
|
|
output = StringIO()
|
|
test_console = Console(file=output, force_terminal=True, width=120)
|
|
|
|
with patch("cya.orchestrator.console", test_console):
|
|
with patch("cya.orchestrator.collect") as mock_collect:
|
|
with patch("cya.orchestrator.get_user_confirmation", return_value=True):
|
|
mock_collect.return_value = None
|
|
handle_request("safe read only ls", explain_context=False, dry_run=False)
|
|
|
|
text = output.getvalue()
|
|
assert "verbal reflection" in text.lower() or "influenced this" in text |