synap-pipecat
Synap integration for Pipecat — preload long-term memory into voice pipelines and record every turn back to Synap.
Install
pip install synap-pipecat
Requires pipecat-ai>=0.0.80, maximem-synap>=0.7.1.
Quickstart
from pipecat.pipeline.pipeline import Pipeline
from pipecat.processors.aggregators.llm_context import LLMContext
from pipecat.processors.aggregators.llm_response_universal import (
LLMContextAggregatorPair,
LLMUserAggregator,
LLMAssistantAggregator,
)
from maximem_synap import MaximemSynapSDK
from synap_pipecat import SynapMemoryProcessor, SynapRecorder
sdk = MaximemSynapSDK(api_key="sk-...")
context = LLMContext(messages=[{"role": "system", "content": "You are a helpful assistant."}])
user_agg = LLMUserAggregator(context=context)
asst_agg = LLMAssistantAggregator(context=context)
pipeline = Pipeline([
transport.input(),
stt,
SynapMemoryProcessor(sdk, user_id="alice", customer_id="acme", context=context),
user_agg,
llm,
tts,
transport.output(),
asst_agg,
SynapRecorder(sdk, user_id="alice", customer_id="acme", context=context),
])
Pass
context=to both processors.SynapMemoryProcessorwithout a context is a read-only tap; it fetches nothing into the prompt. On Pipecat ≥1.x the universal aggregators consumeTranscriptionFrame, so aSynapRecorderat the end of the pipeline recovers the user turn from the shared context, and it is also the context Synap's compaction is spliced into. Withoutcontext=it records only the assistant half.
Scope
SynapMemoryProcessor— sits BEFORE the user context aggregator. On eachTranscriptionFrame, fetches relevant context from Synap viasdk.fetch()and appends it as a system message to the sharedLLMContext. The transcription frame itself flows through unchanged so the user aggregator can record it as the user turn.SynapRecorder: sits AFTER the assistant context aggregator. Records both turns of each exchange. The user turn comes from the latestTranscriptionFrameto reach the processor, or (on universal-aggregator pipelines where that frame never arrives) from the sharedcontext. The assistant turn comes from streamedLLMTextFrames or theTTSTextFramestream, or, behind the universalLLMAssistantAggregator, fromLLMContextAssistantTurnFrame(see below).SynapShortTermProcessor: sits BEFORE the user aggregator, with theconversation_idof the recorder. Keeps one tagged system block at the head of the context, and never repeats a turn the context already holds.
What the recorder sees depends on where it sits
Pipecat 1.x's LLMAssistantAggregator consumes LLMFullResponseStartFrame/EndFrame, every TextFrame (so TTSTextFrame too), LLMThoughtTextFrame and the function-call frames, and pushes none of them on (llm_response_universal.py, LLMAssistantAggregator.process_frame). Behind it, as in the quickstart, the recorder gets one end-of-turn frame, LLMContextAssistantTurnFrame (pipecat-ai 1.7+), and records the turn from that. Tool calls and results are read back out of the shared context after the turn, since no frame carries them; reasoning is not recoverable there.
To get tool calls at the moment they are dispatched, and reasoning, put the recorder BEFORE the assistant aggregator (for example llm, SynapRecorder(...), tts, ..., asst_agg). It then ends the turn on LLMFullResponseEndFrame, and the aggregator's LLMContextAssistantTurnFrame is ignored so a turn is never recorded twice.
The gRPC stream is the default; REST only as a fallback, never both
The first turn, tool call or tool result opens the stream (sdk.instance.listen()) if you did not, and everything after rides it. The server persists streamed turns itself, so sdk.conversation.record_message is called only when the stream cannot carry the turn. Set SYNAP_AUTO_LISTEN=false (or set_auto_listen(sdk, False) from synap_integrations_common) to stay on REST.
Synap's compaction replaces the earlier turns
With context= given, after each turn it records the recorder checks whether Synap has compacted the conversation. If so, the shared LLMContext is rewritten in place (set_messages, the same call pipecat's own LLMContextSummarizer ends in): the earlier turns become one <synap_conversation_history> system message plus the turns after the compaction, and the current exchange is untouched. Before the first compaction, or if Synap does not answer within 1.5s, the context is left alone and enable_auto_context_summarization (if you turned it on) stays the fallback. SynapShortTermProcessor does the same before each user turn.
Error policy
- Reads (
SynapMemoryProcessor) degrade gracefully — SDK failures log atERRORand the frame continues downstream with no Synap context injected. A Synap blip must never break a live voice call. - Writes (
SynapRecorder) that fail on both the stream and REST are logged and pushed upstream as anErrorFramecarrying aSynapIntegrationError; the pipeline itself stays alive (errors propagate as frames, not exceptions). - Non-matching frames pass through untouched in both processors — standard Pipecat
push_framecontract.
Deeper scope ladders
If your account's scope ladder has levels beyond customer and user, pass the level to read and write at as scope_path (key order does not matter; the server orders by ladder position). It is forwarded to sdk.fetch and to the user and assistant turns, only when set; nothing changes for callers who do not pass it, and no extra network call is made per turn.
path = {"customer": "acme", "team": "payments", "user": "dana"} # e.g. from ScopeAddress.scope_path
memory = SynapMemoryProcessor(sdk, user_id="dana", customer_id="acme", context=ctx, scope_path=path)
recorder = SynapRecorder(sdk, user_id="dana", customer_id="acme", context=ctx, scope_path=path)
The server lets a path's user and customer levels win over flat ids, so user_id / customer_id that disagree with the path raise SynapIntegrationError at construction, before anything is sent. If you reassign processor.user_id or .customer_id later, the processor skips that read or turn and logs an ERROR (it never raises inside the pipeline).
SynapShortTermProcessor reads through the conversation, which remembers its own level, so it takes no scope_path. Needs a maximem-synap release whose sdk.fetch accepts scope_path.
Constructor args (both processors)
sdk: a configuredMaximemSynapSDKuser_id: required — Synap memory is user-scopedcustomer_id: B2B instances only, where it is required. Not accepted on a B2C instance, which rejects it with HTTP 400.scope_path(memory processor, recorder): optional{level_key: value}for a deeper scope ladder; see aboveconversation_id(recorder, short-term processor): optional explicit id for the recorder (auto-generated when absent), required for the short-term processor: pass the same value to both
Metadata
Release files for maximem-synap-pipecat 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| maximem_synap_pipecat-0.3.0.tar.gz | 30.2 kB | Without provenance | Details for maximem_synap_pipecat-0.3.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| maximem_synap_pipecat-0.3.0-py3-none-any.whl | Python 3 | none | any | Details for maximem_synap_pipecat-0.3.0-py3-none-any.whl |
Total release size: 48.3 kB
Release files / maximem_synap_pipecat-0.3.0.tar.gz
| Download URL | maximem_synap_pipecat-0.3.0.tar.gz |
|---|---|
| Size | 30.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1b0eb717ae09f8afc6747726a4249492e6b24d9ac8667e7662f1dc3339e00ff6
|
|
BLAKE2b-256 checksum How to use checksums |
0d0602b659e0818e00fbb8325c12a167803f63ab1710655c1be5c2b13efa715f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.4
|
Release files / maximem_synap_pipecat-0.3.0-py3-none-any.whl
| Download URL | maximem_synap_pipecat-0.3.0-py3-none-any.whl |
|---|---|
| Size | 18.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7c3b519842f2d1efaa18e858899d059ce42d32b68a0fbb80f68551aff7ed88c9
|
|
BLAKE2b-256 checksum How to use checksums |
f303b2a3514d7a663a7ad4c6a3301d22ae7e61a4d71ff4b2e4589d72b9a484b5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.4
|
Security for maximem-synap-pipecat 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.