refactor(memory): extract F2 recall path (#23)

This commit is contained in:
2026-08-24 01:08:15 +02:00
parent beac2e80f4
commit 93fe0d733b
8 changed files with 585 additions and 236 deletions
+42
View File
@@ -137,6 +137,48 @@ REUSABLE_TYPES = frozenset({"concept_clarified"})
MAX_PROMOTION_CANDIDATES = 5
def recall_memories(
question: str,
*,
records: list[MemoryRecord],
decisions: list[DecisionRecord],
searcher,
embedder,
top: int = 5,
) -> list[dict]:
"""Return reviewer-visible F2 candidates in semantic-search rank order.
Memory owns filtering against the canonical registry, reusable decision types,
and decisions already persisted in the current (including resumed) session.
The CLI remains a thin adapter that supplies the vector ports and renders output.
"""
excluded = decided_memory_ids(decisions)
hits = searcher.search(
embedder.embed_query(question),
top_n=top,
kinds=["memory"],
)
by_id = {record.id: record for record in records}
results = []
for hit in hits:
record = by_id.get(hit.ref)
if record is None or record.type not in REUSABLE_TYPES or record.id in excluded:
continue
results.append({
"id": record.id,
"type": record.type,
"subject": record.subject,
"detail": record.detail,
"rationale": record.rationale,
"question_context": record.question_context,
"tables": record.tables,
"concepts": record.concepts,
"session_id": record.session_id,
"score": round(hit.similarity, 4),
})
return results
def _compute_promotions(
session_dir: Path, manifest: SessionManifest, *,
seqs: list[int] | None, existing: list[MemoryRecord],