fix(pipecat): stop re-storing injected memory blocks as new memories#1279
Open
abhay-codes07 wants to merge 1 commit into
Open
fix(pipecat): stop re-storing injected memory blocks as new memories#1279abhay-codes07 wants to merge 1 commit into
abhay-codes07 wants to merge 1 commit into
Conversation
LLMContext.get_messages() returns the context's live message list — the enhancement code depends on that, mutating it in place to inject the <user_memories> block. But the frame handler snapshotted that same reference *before* enhancement, so by the time it sliced out storable_messages the list already contained this turn's injected user-message, and _store_messages wrote the recalled memories back to Supermemory as a brand-new memory. Next turn recalls the stored block and re-stores it again, compounding every turn. (Previously masked by the dedup crash fixed in supermemoryai#1268 — with search results empty and profile facts present, the loop is live.) Two defenses: - copy the message list before enhancement mutates it, so the current turn's injection never enters the storage slice - filter any message carrying the memory tag out of storable_messages, which also covers the previous turn's injected block still sitting in the context (it is only replaced during the next enhancement, after the snapshot is taken) Regression tests drive process_frame with a live-list fake context and a mocked client: the injected block lands in the context but never in the storage payload, across both the same-turn and next-turn shapes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The pipecat service was writing its own injected memories back to Supermemory as brand-new memories.
LLMContext.get_messages()returns the context's live message list — the enhancement code depends on that, mutating the returned list in place to inject the<user_memories>block. Butprocess_framecaptured that same reference before enhancement:By the time
storable_messageswas sliced, the list already contained this turn's injected user-message, so_store_messagespersisted the recalled memories as a new memory. The next turn recalls the stored block and re-stores it again — a self-referential loop that compounds every turn. (It was previously masked by the dedup crash fixed in #1268; with profile facts present and search results empty, the loop is live.)Fix
Two defenses, both needed:
list(context.get_messages())before enhancement, so the current turn's injection never enters the storage slice_is_memory_injectionhelper excludes any message carrying the memory tag fromstorable_messages, which covers the previous turn's injected block still sitting in the context (it's only replaced during the next enhancement, after the snapshot is taken)The helper is tolerant of non-string content (multimodal parts,
None).Testing
tests/test_no_memory_restorage.pydrivesprocess_frameend-to-end with a live-list fake context (same semantics the enhancement code relies on) and a mocked Supermemory client: the memory block lands in the context but never in the storage payload, for both the same-turn and next-turn shapes; plus non-string-content tolerance for the helperpython -m pytest testsin the package — 4 passedutils.py; this touchesservice.py)cc @MaheshtheDev