pipecat-memorysync 1.0.0__tar.gz → 1.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ All notable changes to `pipecat-memorysync` are documented here.
4
+
5
+ ## 1.0.1 — 2026-08-29
6
+
7
+ - Metadata only: the source repository moved to
8
+ `https://github.com/memorysyncio/memorysync-pipecat`; project URLs updated.
9
+ No code changes.
10
+
11
+ ## 1.0.0 — 2026-08-29
12
+
13
+ Initial release.
14
+
15
+ - `MemorySyncMemoryService`, a `FrameProcessor` for the position between the
16
+ user context aggregator and the LLM service.
17
+ - Budgeted memory recall (default 1.2 s hard timeout) injected into every
18
+ `LLMContextFrame` as a guarded system message — a slow or unreachable
19
+ backend degrades to an unenriched frame, never a stalled reply.
20
+ - Delta-only capture with deterministic idempotency seeds: only turns not
21
+ seen before are persisted, with role fidelity for user and assistant.
22
+ - Injection exclusion: the injected memory block is never re-captured.
23
+ - Graceful `EndFrame` flush (bounded 3 s window) and `CancelFrame` salvage.
24
+ - Tested with Pipecat v1.8.1 through `pipecat.tests.utils.run_test`
25
+ (14-test suite).
@@ -1,10 +1,11 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pipecat-memorysync
3
- Version: 1.0.0
3
+ Version: 1.0.1
4
4
  Summary: MemorySync for Pipecat: budgeted memory recall that never stalls a voice reply, delta-only conversation persistence with idempotency seeds, and a pipeline that cannot be broken by a memory outage.
5
5
  Project-URL: Homepage, https://docs.memorysync.io/guides/pipecat
6
6
  Project-URL: Documentation, https://docs.memorysync.io/guides/pipecat
7
- Project-URL: Repository, https://github.com/Rafay121/memorysync-plugins
7
+ Project-URL: Repository, https://github.com/memorysyncio/memorysync-pipecat
8
+ Project-URL: Changelog, https://github.com/memorysyncio/memorysync-pipecat/blob/main/CHANGELOG.md
8
9
  Author-email: MemorySync <support@memorysync.io>
9
10
  License-Expression: MIT
10
11
  Keywords: agents,long-term-memory,memory,memorysync,pipecat,voice
@@ -21,14 +22,22 @@ Requires-Dist: httpx<1,>=0.25
21
22
  Requires-Dist: pipecat-ai<2,>=1.0.0
22
23
  Description-Content-Type: text/markdown
23
24
 
24
- # pipecat-memorysync
25
+ # memorysync-pipecat
25
26
 
26
27
  [MemorySync](https://memorysync.io) for [Pipecat](https://github.com/pipecat-ai/pipecat) —
27
28
  long-term memory for voice pipelines that never stalls a reply and never
28
- re-stores what it already knows.
29
+ re-stores what it already knows. PyPI package: **`pipecat-memorysync`**.
30
+
31
+ Built and maintained by the [MemorySync](https://memorysync.io) team —
32
+ MemorySync is our product, and this integration is actively maintained
33
+ alongside it.
34
+
35
+ **Tested with Pipecat v1.8.1** (`pipecat-ai>=1.0.0,<2`).
29
36
 
30
37
  ```bash
31
38
  pip install pipecat-memorysync
39
+ # or
40
+ uv add pipecat-memorysync
32
41
  ```
33
42
 
34
43
  ## Where it sits
@@ -74,8 +83,7 @@ enriched or not, on time.
74
83
  stalled voice reply.
75
84
  - **Delta-only capture.** Only messages *not seen before* are stored, tracked
76
85
  by deterministic idempotency seeds. Growing a 50-message context does not
77
- re-store 50 messages per turn (a real flaw in some in-tree memory services,
78
- which re-send the entire context every frame — O(n²) writes per call).
86
+ re-store 50 messages per turn.
79
87
  - **Injection exclusion.** The memory block this service adds is never captured
80
88
  back as a new memory.
81
89
  - **Graceful end, salvaged abort.** On `EndFrame`, queued writes get a bounded
@@ -85,6 +93,25 @@ enriched or not, on time.
85
93
  - **Failure-proof.** HTTP errors, quota limits, and timeouts all degrade to
86
94
  "no memories this turn". Nothing propagates into the pipeline.
87
95
 
96
+ ## Running the example
97
+
98
+ A single-file voice agent that remembers callers across calls lives in
99
+ [`examples/foundational.py`](examples/foundational.py):
100
+
101
+ ```bash
102
+ uv add pipecat-memorysync "pipecat-ai[deepgram,cartesia,openai,silero,runner,webrtc]"
103
+
104
+ export MEMORYSYNC_API_KEY=ms_... # https://app.memorysync.io
105
+ export DEEPGRAM_API_KEY=...
106
+ export CARTESIA_API_KEY=...
107
+ export OPENAI_API_KEY=...
108
+
109
+ python examples/foundational.py
110
+ ```
111
+
112
+ Open `http://localhost:7860/client`, tell the bot your name and a preference,
113
+ hang up, and connect again — it remembers.
114
+
88
115
  ## Configuration (`InputParams`)
89
116
 
90
117
  ```python
@@ -128,6 +155,10 @@ python -m venv venv && venv/Scripts/pip install -e . pipecat-ai pytest pytest-as
128
155
  venv/Scripts/python -m pytest tests -q # 14 tests, run via pipecat's official test harness
129
156
  ```
130
157
 
158
+ ## Docs
159
+
160
+ Full guide: [docs.memorysync.io/guides/pipecat](https://docs.memorysync.io/guides/pipecat)
161
+
131
162
  ## License
132
163
 
133
164
  MIT
@@ -1,11 +1,19 @@
1
- # pipecat-memorysync
1
+ # memorysync-pipecat
2
2
 
3
3
  [MemorySync](https://memorysync.io) for [Pipecat](https://github.com/pipecat-ai/pipecat) —
4
4
  long-term memory for voice pipelines that never stalls a reply and never
5
- re-stores what it already knows.
5
+ re-stores what it already knows. PyPI package: **`pipecat-memorysync`**.
6
+
7
+ Built and maintained by the [MemorySync](https://memorysync.io) team —
8
+ MemorySync is our product, and this integration is actively maintained
9
+ alongside it.
10
+
11
+ **Tested with Pipecat v1.8.1** (`pipecat-ai>=1.0.0,<2`).
6
12
 
7
13
  ```bash
8
14
  pip install pipecat-memorysync
15
+ # or
16
+ uv add pipecat-memorysync
9
17
  ```
10
18
 
11
19
  ## Where it sits
@@ -51,8 +59,7 @@ enriched or not, on time.
51
59
  stalled voice reply.
52
60
  - **Delta-only capture.** Only messages *not seen before* are stored, tracked
53
61
  by deterministic idempotency seeds. Growing a 50-message context does not
54
- re-store 50 messages per turn (a real flaw in some in-tree memory services,
55
- which re-send the entire context every frame — O(n²) writes per call).
62
+ re-store 50 messages per turn.
56
63
  - **Injection exclusion.** The memory block this service adds is never captured
57
64
  back as a new memory.
58
65
  - **Graceful end, salvaged abort.** On `EndFrame`, queued writes get a bounded
@@ -62,6 +69,25 @@ enriched or not, on time.
62
69
  - **Failure-proof.** HTTP errors, quota limits, and timeouts all degrade to
63
70
  "no memories this turn". Nothing propagates into the pipeline.
64
71
 
72
+ ## Running the example
73
+
74
+ A single-file voice agent that remembers callers across calls lives in
75
+ [`examples/foundational.py`](examples/foundational.py):
76
+
77
+ ```bash
78
+ uv add pipecat-memorysync "pipecat-ai[deepgram,cartesia,openai,silero,runner,webrtc]"
79
+
80
+ export MEMORYSYNC_API_KEY=ms_... # https://app.memorysync.io
81
+ export DEEPGRAM_API_KEY=...
82
+ export CARTESIA_API_KEY=...
83
+ export OPENAI_API_KEY=...
84
+
85
+ python examples/foundational.py
86
+ ```
87
+
88
+ Open `http://localhost:7860/client`, tell the bot your name and a preference,
89
+ hang up, and connect again — it remembers.
90
+
65
91
  ## Configuration (`InputParams`)
66
92
 
67
93
  ```python
@@ -105,6 +131,10 @@ python -m venv venv && venv/Scripts/pip install -e . pipecat-ai pytest pytest-as
105
131
  venv/Scripts/python -m pytest tests -q # 14 tests, run via pipecat's official test harness
106
132
  ```
107
133
 
134
+ ## Docs
135
+
136
+ Full guide: [docs.memorysync.io/guides/pipecat](https://docs.memorysync.io/guides/pipecat)
137
+
108
138
  ## License
109
139
 
110
140
  MIT
@@ -0,0 +1,128 @@
1
+ #
2
+ # Foundational example: a voice agent that remembers callers across calls.
3
+ #
4
+ # MemorySyncMemoryService sits between the user context aggregator and the
5
+ # LLM: every LLMContextFrame is enriched with relevant long-term memories
6
+ # under a hard time budget, and new turns are persisted in the background.
7
+ # A slow or unreachable memory backend can never stall the voice reply.
8
+ #
9
+ # Run (choose any transport supported by the Pipecat runner):
10
+ #
11
+ # uv add pipecat-memorysync "pipecat-ai[deepgram,cartesia,openai,silero,runner,webrtc]"
12
+ # export MEMORYSYNC_API_KEY=ms_... # https://app.memorysync.io
13
+ # export DEEPGRAM_API_KEY=...
14
+ # export CARTESIA_API_KEY=...
15
+ # export OPENAI_API_KEY=...
16
+ # python foundational.py
17
+ #
18
+ # Then open http://localhost:7860/client, talk to the bot, tell it your
19
+ # name and a preference, hang up, and call again: it remembers.
20
+ #
21
+
22
+ import os
23
+
24
+ from dotenv import load_dotenv
25
+ from loguru import logger
26
+
27
+ from pipecat.audio.vad.silero import SileroVADAnalyzer
28
+ from pipecat.frames.frames import LLMRunFrame
29
+ from pipecat.pipeline.pipeline import Pipeline
30
+ from pipecat.pipeline.runner import PipelineRunner
31
+ from pipecat.pipeline.task import PipelineParams, PipelineTask
32
+ from pipecat.processors.aggregators.llm_context import LLMContext
33
+ from pipecat.processors.aggregators.llm_response_universal import (
34
+ LLMContextAggregatorPair,
35
+ LLMUserAggregatorParams,
36
+ )
37
+ from pipecat.runner.types import RunnerArguments
38
+ from pipecat.runner.utils import create_transport
39
+ from pipecat.services.cartesia.tts import CartesiaTTSService
40
+ from pipecat.services.deepgram.stt import DeepgramSTTService
41
+ from pipecat.services.openai.llm import OpenAILLMService
42
+ from pipecat.transports.base_transport import BaseTransport, TransportParams
43
+
44
+ from pipecat_memorysync import MemorySyncMemoryService
45
+
46
+ load_dotenv(override=True)
47
+
48
+ SYSTEM_INSTRUCTION = (
49
+ "You are a friendly voice assistant with long-term memory. "
50
+ "Relevant facts about the caller may appear as background memory context. "
51
+ "Use them naturally; never read them out verbatim. "
52
+ "Your answers are spoken aloud, so keep them short and conversational."
53
+ )
54
+
55
+ transport_params = {
56
+ "webrtc": lambda: TransportParams(audio_in_enabled=True, audio_out_enabled=True),
57
+ }
58
+
59
+
60
+ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
61
+ logger.info("Starting bot")
62
+
63
+ stt = DeepgramSTTService(api_key=os.environ["DEEPGRAM_API_KEY"])
64
+
65
+ tts = CartesiaTTSService(
66
+ api_key=os.environ["CARTESIA_API_KEY"],
67
+ voice_id="71a7ad14-091c-4e8e-a314-022ece01c121",
68
+ )
69
+
70
+ llm = OpenAILLMService(api_key=os.environ["OPENAI_API_KEY"])
71
+
72
+ # Long-term memory. In a real deployment, derive user_id from the
73
+ # caller's identity (phone number, account id, ...) so each caller
74
+ # gets their own memories.
75
+ memory = MemorySyncMemoryService(
76
+ api_key=os.environ["MEMORYSYNC_API_KEY"],
77
+ user_id=os.environ.get("MEMORYSYNC_USER_ID", "demo-caller"),
78
+ )
79
+
80
+ context = LLMContext([{"role": "system", "content": SYSTEM_INSTRUCTION}])
81
+ context_aggregator = LLMContextAggregatorPair(
82
+ context,
83
+ user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()),
84
+ )
85
+
86
+ pipeline = Pipeline(
87
+ [
88
+ transport.input(),
89
+ stt,
90
+ context_aggregator.user(),
91
+ memory, # enrich with memories + capture new turns, on budget
92
+ llm,
93
+ tts,
94
+ transport.output(),
95
+ context_aggregator.assistant(),
96
+ ]
97
+ )
98
+
99
+ task = PipelineTask(
100
+ pipeline,
101
+ params=PipelineParams(enable_metrics=True, enable_usage_metrics=True),
102
+ idle_timeout_secs=runner_args.pipeline_idle_timeout_secs,
103
+ )
104
+
105
+ @transport.event_handler("on_client_connected")
106
+ async def on_client_connected(transport, client):
107
+ logger.info("Client connected")
108
+ await task.queue_frames([LLMRunFrame()])
109
+
110
+ @transport.event_handler("on_client_disconnected")
111
+ async def on_client_disconnected(transport, client):
112
+ logger.info("Client disconnected")
113
+ await task.cancel()
114
+
115
+ runner = PipelineRunner(handle_sigint=runner_args.handle_sigint)
116
+ await runner.run(task)
117
+
118
+
119
+ async def bot(runner_args: RunnerArguments):
120
+ """Main bot entry point compatible with the Pipecat runner."""
121
+ transport = await create_transport(runner_args, transport_params)
122
+ await run_bot(transport, runner_args)
123
+
124
+
125
+ if __name__ == "__main__":
126
+ from pipecat.runner.run import main
127
+
128
+ main()
@@ -29,7 +29,8 @@ dependencies = [
29
29
  [project.urls]
30
30
  Homepage = "https://docs.memorysync.io/guides/pipecat"
31
31
  Documentation = "https://docs.memorysync.io/guides/pipecat"
32
- Repository = "https://github.com/Rafay121/memorysync-plugins"
32
+ Repository = "https://github.com/memorysyncio/memorysync-pipecat"
33
+ Changelog = "https://github.com/memorysyncio/memorysync-pipecat/blob/main/CHANGELOG.md"
33
34
 
34
35
  [tool.hatch.version]
35
36
  path = "src/pipecat_memorysync/_version.py"
@@ -1,3 +1,3 @@
1
1
  """Version for pipecat-memorysync. Single source of truth."""
2
2
 
3
- __version__ = "1.0.0"
3
+ __version__ = "1.0.1"
@@ -28,12 +28,20 @@ def context_of(messages: List[dict]) -> LLMContext:
28
28
 
29
29
 
30
30
  async def drive(service: Any, *contexts: LLMContext) -> None:
31
- """Send one LLMContextFrame per context through the real harness."""
31
+ """Send one LLMContextFrame per context through the real harness.
32
+
33
+ ``start_timeout`` defaults to 1s inside pipecat's harness, which the
34
+ FIRST test in the session routinely blows on a cold shared CI runner
35
+ (import machinery + task spin-up), failing it with a TimeoutError
36
+ before any frame flows. A generous ceiling costs nothing when the
37
+ pipeline starts fast — it is not a sleep — and removes the flake.
38
+ """
32
39
  frames = [LLMContextFrame(context=ctx) for ctx in contexts]
33
40
  await run_test(
34
41
  service,
35
42
  frames_to_send=frames,
36
43
  expected_down_frames=[LLMContextFrame] * len(frames),
44
+ start_timeout=30.0,
37
45
  )
38
46
 
39
47