mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-11-05 07:12:02 +08:00
fix(LongTermMemory): enforce stored context budgets before publication
This commit is contained in:
@@ -652,4 +652,4 @@ Existing historical summary records without lineage cannot be retroactively trac
|
||||
Document deletion invalidates dependent summaries and pending drafts for every affected memory scope before removing imported records. Deleting a knowledge base clears only that collection's pending drafts. Preview generation and collection deletion share the same collection lock, so an in-flight model preview cannot save source text after deletion completes; a preview for a removed KB is rejected before calling the model. Each model call holding that lock is capped at 30 seconds; queued callers and storage operations still follow their normal API lifecycle.
|
||||
|
||||
|
||||
A reviewed summary must also fit the bounded recall record budget before publication; oversized summaries are rejected without writing an episode or hiding source facts. Reduce the consolidation candidate count and preview again. This is a character/serialization bound, not an exact token estimate.
|
||||
A reviewed summary must also fit the bounded recall record budget before publication; oversized summaries are rejected before activation, with source facts retained. If Host-added metadata takes a staged summary over budget, the staged record is removed. Reduce the consolidation candidate count and preview again. This is a character/serialization bound, not an exact token estimate.
|
||||
|
||||
@@ -220,6 +220,10 @@ async def apply_summary(store, collection_id: str, embedding_model_uuid: str, us
|
||||
written = await store.get_episode_by_id(collection_id, episode_id, user_key)
|
||||
if written is None or any(written["metadata"].get(key) != value for key, value in meta.items()):
|
||||
raise RuntimeError("Consolidation draft could not be verified; source memories were retained")
|
||||
stored_record = {"id": episode_id, "metadata": written["metadata"], "document": written["content"], "score": None, "distance": 0.0}
|
||||
if not select_memories([stored_record], "", top_k=1):
|
||||
await store.delete_episode_by_id(collection_id, episode_id, user_key)
|
||||
raise ValueError("Stored summary exceeds the recall budget; source memories were retained")
|
||||
await store._write_json(proposal_key(collection_id, user_key), {}, collection_id)
|
||||
summary = await store.update_episode_status(
|
||||
collection_id, embedding_model_uuid, episode_id, user_key, store.EPISODE_STATUS_ACTIVE
|
||||
|
||||
@@ -362,3 +362,20 @@ async def test_summary_too_large_for_recall_is_not_published():
|
||||
await store.apply_consolidation("kb", "emb", "scope", proposal_id=draft["proposal_id"])
|
||||
assert set(plugin.records) == {"one", "two"}
|
||||
assert all(item["metadata"]["status"] == "active" for item in plugin.records.values())
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_host_metadata_cannot_make_published_summary_exceed_budget():
|
||||
class VerboseHostPlugin(SemanticPlugin):
|
||||
async def vector_upsert(self, *args, **kwargs):
|
||||
kwargs["metadata"] = [{**metadata, "_backend_annotation": "x" * 8000} for metadata in kwargs["metadata"]]
|
||||
await super().vector_upsert(*args, **kwargs)
|
||||
|
||||
plugin = VerboseHostPlugin()
|
||||
add_source(plugin, "source", "A fact that must remain searchable")
|
||||
store = MemoryStore(plugin)
|
||||
draft = await preview(store)
|
||||
with pytest.raises(ValueError, match="Stored summary exceeds"):
|
||||
await store.apply_consolidation("kb", "emb", "scope", proposal_id=draft["proposal_id"])
|
||||
assert set(plugin.records) == {"source"}
|
||||
assert plugin.records["source"]["metadata"]["status"] == "active"
|
||||
|
||||
Reference in New Issue
Block a user