feat(api)!: memory single chain — async MemoryService, strict eval closure
Route all memory ingest/retrieve/enrichment/compaction through async MemoryService. Remove legacy sync memory implementations (ingest/retrieve/compaction); Celery and memoir Phase2 call asyncio.run into MemoryService-backed helpers. Memoir Phase1 batch ingest uses MemoryService.ingest_transcripts_batch; drop chapters. evidence_bundle_json mirror (Alembic 0015). Evaluation uses snapshot/link-only bundles; raise EvidenceClosureMissing instead of partial/fallback lineage tiers. Split memoir state into NarrativeCoverageState and InterviewControlState; delete the _interview_meta_store adapter layer. Remove rolling-query and recent-fact fallback settings from config and evidence assembly. Update judges, docs, tests, and PlaygroundPage alignment. Made-with: Cursor
This commit is contained in:
@@ -1,41 +1,46 @@
|
||||
"""ingest_transcript_sync 将 lineage_json 传入 create_source。"""
|
||||
"""MemoryIngestService 将 lineage_json 传入 create_source。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from types import SimpleNamespace
|
||||
|
||||
from app.features.memory.service import ingest_transcript_sync
|
||||
import pytest
|
||||
|
||||
from app.features.memory.ingest_service import MemoryIngestService
|
||||
|
||||
|
||||
def test_ingest_transcript_sync_passes_lineage(monkeypatch) -> None:
|
||||
@pytest.mark.asyncio
|
||||
async def test_memory_ingest_passes_lineage(monkeypatch) -> None:
|
||||
captured: dict = {}
|
||||
|
||||
class FakeSession:
|
||||
commit_calls = 0
|
||||
|
||||
def commit(self) -> None:
|
||||
async def commit(self) -> None:
|
||||
self.commit_calls += 1
|
||||
|
||||
def flush(self) -> None:
|
||||
async def flush(self) -> None:
|
||||
pass
|
||||
|
||||
def begin_nested(self):
|
||||
from contextlib import nullcontext
|
||||
class FakeScheduler:
|
||||
def schedule(self, request):
|
||||
captured["scheduled"] = request
|
||||
return "task-1"
|
||||
|
||||
return nullcontext()
|
||||
|
||||
def fake_create_source(session, **kwargs):
|
||||
async def fake_create_source(session, **kwargs):
|
||||
captured.update(kwargs)
|
||||
return SimpleNamespace(id="src-1")
|
||||
|
||||
monkeypatch.setattr("app.core.dependencies.get_embedding_provider", lambda: None)
|
||||
async def fake_create_chunk(*_args, **kwargs):
|
||||
return SimpleNamespace(id=f"ch-{kwargs.get('chunk_index')}")
|
||||
|
||||
monkeypatch.setattr(
|
||||
"app.features.memory.repo.create_source_sync",
|
||||
"app.features.memory.ingest_service.create_source",
|
||||
fake_create_source,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"app.features.memory.repo.create_chunk_sync",
|
||||
lambda *a, **k: SimpleNamespace(id=f"ch-{k.get('chunk_index')}"),
|
||||
"app.features.memory.ingest_service.create_chunk",
|
||||
fake_create_chunk,
|
||||
)
|
||||
monkeypatch.setattr("app.core.config.settings.memory_enrichment_enabled", False)
|
||||
|
||||
@@ -49,8 +54,12 @@ def test_ingest_transcript_sync_passes_lineage(monkeypatch) -> None:
|
||||
}
|
||||
|
||||
fake_session = FakeSession()
|
||||
sid = ingest_transcript_sync(
|
||||
fake_session,
|
||||
service = MemoryIngestService(
|
||||
fake_session, # type: ignore[arg-type]
|
||||
embedding_provider=None,
|
||||
enrichment_scheduler=FakeScheduler(), # type: ignore[arg-type]
|
||||
)
|
||||
sid = await service.ingest_transcript(
|
||||
"u1",
|
||||
"c9",
|
||||
"hello there",
|
||||
@@ -59,3 +68,4 @@ def test_ingest_transcript_sync_passes_lineage(monkeypatch) -> None:
|
||||
assert sid == "src-1"
|
||||
assert captured.get("lineage_json") == lineage
|
||||
assert captured.get("primary_user_message_id") == "um-1"
|
||||
assert captured["scheduled"].source_id == "src-1"
|
||||
|
||||
Reference in New Issue
Block a user