Getting Started
Pipecat Voice Memory
Long-term memory for Pipecat voice pipelines — one FrameProcessor between your context aggregator and LLM enriches every context frame under a hard latency budget and persists only what is new. Built on the current frame API and tested through Pipecat’s own harness.
What the package provides
| Piece | What it does |
|---|---|
MemorySyncMemoryService | A FrameProcessor you place before your LLM service. Each LLMContextFrame is enriched with relevant memories (as a system message) and mined for new turns to persist — then pushed on, enriched or not, on time. |
| Budgeted enrichment | Recall runs under a hard timeout (default 1.2s). A slow or dead memory backend means an unenriched frame, never a stalled voice reply. |
| Delta-only capture | Only messages not seen before are stored, tracked by deterministic idempotency seeds — O(new), not O(entire context) per frame. |
| Lifecycle safety | On EndFrame, queued writes get a bounded window to land so the call’s final exchange is never lost; CancelFrame pushes first, then briefly salvages. |
| Mem0 | Supermemory | Zep | MemorySync | |
|---|---|---|---|---|
| Pipecat integration | ✓ in-tree service | △ exists but imports a removed frame API — cannot load on Pipecat 1.x | ✗ none | ✓ pipecat-memorysync package |
| Recall latency budget | ✗ unbounded await before every LLM push | — | — | ✓ hard timeout, default 1.2s, tested against a 5s-slow backend |
| Write amplification | ✗ re-stores the ENTIRE context every frame — O(n²) writes per call | — | — | ✓ delta-only with idempotency seeds, proven by test (3 stores for 3 new messages) |
| Injected context re-stored | unguarded | — | — | ✓ the injected block is capture-excluded, tested |
| End-of-call data loss | pending stores can be torn down | — | — | ✓ graceful EndFrame flush, tested |
| Tested via the official harness | △ partial | ✗ | — | ✓ every test runs through pipecat.tests.utils.run_test |
Install and place it
pip install pipecat-memorysync
Placement matters: after context_aggregator.user() so the frame carries the full context, before llm so enrichment reaches the model. The service is reusable across pipeline runs; call await memory.aclose() at application shutdown for an explicit flush.
What runs when
| Moment | What happens |
|---|---|
LLMContextFrame arrives | Recall runs under the budget; relevant memories land as a system message (position configurable). The frame is pushed on time either way. |
| Same frame, after push | New user and assistant messages — and only new ones — persist in the background with role fidelity. The injected memory block is excluded. |
EndFrame (graceful end) | Queued stores get a bounded 3s window to land before the pipeline stops — the final exchange is not lost. |
CancelFrame (abort) | The frame is pushed first; writes get a brief salvage window. |
| Backend slow / dead / over quota | Unenriched frame, silent skip — the pipeline is never affected. Free-tier quota exhaustion is silent by design; evaluation keys surface strict 429s instead. |
Configuration
| Parameter | Default | Meaning |
|---|---|---|
top_k | 5 | Memories injected per turn |
recall_timeout | 1.2 | Hard recall budget in seconds |
system_prompt | guarded header | Prefix line for the injected block; doubles as the capture-exclusion marker |
add_as_system_message | True | Inject as a system message (else appended to the latest user message) |
position | "end" | "start" or "end" of the message list |
min_prompt_chars | 8 | Skip recall for trivial prompts |
Supported versions
| Surface | Requires | Verified on |
|---|---|---|
pipecat-memorysync 1.0.0 | pipecat-ai 1.x, Python 3.10+ | 14 CI checks driven through pipecat.tests.utils.run_test — the framework’s official harness — on the latest pipecat-ai: budget enforcement, delta-only proof, injection exclusion, role fidelity, EndFrame flush, quota modes |
Where to go next
Was this page helpful?