pipecat-memorysync 1.1.0__tar.gz → 1.2.0__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.
@@ -1,5 +1,5 @@
1
- venv/
2
- __pycache__/
3
- .pytest_cache/
4
- dist/
5
- *.egg-info/
1
+ venv/
2
+ __pycache__/
3
+ .pytest_cache/
4
+ dist/
5
+ *.egg-info/
@@ -1,38 +1,51 @@
1
- # Changelog
2
-
3
- All notable changes to `pipecat-memorysync` are documented here.
4
-
5
- ## 1.1.0 — 2026-08-29
6
-
7
- - **Turn-complete capture.** Voice aggregators split one utterance across
8
- several context messages at speech pauses; those fragments previously
9
- stored as separate rows ("and", "dinner", …). Consecutive new user
10
- fragments now merge into ONE verbatim turn, stored when the assistant
11
- reply completes the turn; an in-progress utterance is flushed as one
12
- merged turn at end of call. Assistant turns still store immediately,
13
- and a failed store releases its fragments for retry on the next frame.
14
- - Delta-only and idempotency guarantees unchanged; suite grows to 17
15
- checks on Pipecat v1.8.1 (fragment merging, end-of-call tail flush,
16
- failed-store retry).
17
-
18
- ## 1.0.1 — 2026-08-29
19
-
20
- - Metadata only: the source repository moved to
21
- `https://github.com/memorysyncio/memorysync-pipecat`; project URLs updated.
22
- No code changes.
23
-
24
- ## 1.0.0 — 2026-08-29
25
-
26
- Initial release.
27
-
28
- - `MemorySyncMemoryService`, a `FrameProcessor` for the position between the
29
- user context aggregator and the LLM service.
30
- - Budgeted memory recall (default 1.2 s hard timeout) injected into every
31
- `LLMContextFrame` as a guarded system message — a slow or unreachable
32
- backend degrades to an unenriched frame, never a stalled reply.
33
- - Delta-only capture with deterministic idempotency seeds: only turns not
34
- seen before are persisted, with role fidelity for user and assistant.
35
- - Injection exclusion: the injected memory block is never re-captured.
36
- - Graceful `EndFrame` flush (bounded 3 s window) and `CancelFrame` salvage.
37
- - Tested with Pipecat v1.8.1 through `pipecat.tests.utils.run_test`
38
- (14-test suite).
1
+ # Changelog
2
+
3
+ All notable changes to `pipecat-memorysync` are documented here.
4
+
5
+ ## 1.1.1 — 2026-08-29
6
+
7
+ - **Immediate, loss-proof capture.** 1.1.0's turn-complete merging
8
+ deferred the current utterance until the turn completed — on a browser
9
+ disconnect that deferral raced the brief cancel salvage window and
10
+ could lose the newest (usually most important) turn over slow
11
+ networks. Capture is immediate again: every new user/assistant message
12
+ is in flight the moment its frame passes, BEFORE the LLM replies.
13
+ Junk filtering and fact extraction now happen server-side (the
14
+ platform's low-value gate + conversational ingestion), so client-side
15
+ merging is unnecessary. Suite: 17 checks on Pipecat v1.8.1, including
16
+ the exact disconnect sequence that previously lost data.
17
+
18
+ ## 1.1.0 — 2026-08-29
19
+
20
+ - **Turn-complete capture.** Voice aggregators split one utterance across
21
+ several context messages at speech pauses; those fragments previously
22
+ stored as separate rows ("and", "dinner", …). Consecutive new user
23
+ fragments now merge into ONE verbatim turn, stored when the assistant
24
+ reply completes the turn; an in-progress utterance is flushed as one
25
+ merged turn at end of call. Assistant turns still store immediately,
26
+ and a failed store releases its fragments for retry on the next frame.
27
+ - Delta-only and idempotency guarantees unchanged; suite grows to 17
28
+ checks on Pipecat v1.8.1 (fragment merging, end-of-call tail flush,
29
+ failed-store retry).
30
+
31
+ ## 1.0.1 — 2026-08-29
32
+
33
+ - Metadata only: the source repository moved to
34
+ `https://github.com/memorysyncio/memorysync-pipecat`; project URLs updated.
35
+ No code changes.
36
+
37
+ ## 1.0.0 — 2026-08-29
38
+
39
+ Initial release.
40
+
41
+ - `MemorySyncMemoryService`, a `FrameProcessor` for the position between the
42
+ user context aggregator and the LLM service.
43
+ - Budgeted memory recall (default 1.2 s hard timeout) injected into every
44
+ `LLMContextFrame` as a guarded system message — a slow or unreachable
45
+ backend degrades to an unenriched frame, never a stalled reply.
46
+ - Delta-only capture with deterministic idempotency seeds: only turns not
47
+ seen before are persisted, with role fidelity for user and assistant.
48
+ - Injection exclusion: the injected memory block is never re-captured.
49
+ - Graceful `EndFrame` flush (bounded 3 s window) and `CancelFrame` salvage.
50
+ - Tested with Pipecat v1.8.1 through `pipecat.tests.utils.run_test`
51
+ (14-test suite).
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pipecat-memorysync
3
- Version: 1.1.0
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.
3
+ Version: 1.2.0
4
+ Summary: MemorySync for Pipecat: budgeted memory recall that never stalls a voice reply, delta-only fact capture from the caller's turns 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
7
  Project-URL: Repository, https://github.com/memorysyncio/memorysync-pipecat
@@ -26,7 +26,7 @@ Description-Content-Type: text/markdown
26
26
 
27
27
  [MemorySync](https://memorysync.io) for [Pipecat](https://github.com/pipecat-ai/pipecat) —
28
28
  long-term memory for voice pipelines that never stalls a reply and never
29
- re-stores what it already knows. PyPI package: **`pipecat-memorysync`**.
29
+ re-sends a turn it already sent. PyPI package: **`pipecat-memorysync`**.
30
30
 
31
31
  Built and maintained by the [MemorySync](https://memorysync.io) team —
32
32
  MemorySync is our product, and this integration is actively maintained
@@ -73,26 +73,28 @@ pipeline = Pipeline([
73
73
  ```
74
74
 
75
75
  Every `LLMContextFrame` that flows through is enriched with relevant memories
76
- (as a system message) and mined for **new** turns to persist — then pushed on,
77
- enriched or not, on time.
76
+ (as a system message) and its **new** user turns are sent to fact extraction —
77
+ then pushed on, enriched or not, on time.
78
78
 
79
79
  ## Design guarantees
80
80
 
81
81
  - **Budgeted recall.** Enrichment runs under a hard timeout (default
82
82
  **1.2 s**). A slow or dead memory backend means an unenriched frame, never a
83
83
  stalled voice reply.
84
- - **Turn-complete capture.** Voice aggregators split one utterance across
85
- several context messages at speech pauses; consecutive fragments merge
86
- into ONE stored turn when the assistant's reply completes it (the
87
- in-progress tail flushes at end of call) — no per-fragment junk rows.
88
- - **Delta-only capture.** Only messages *not seen before* are stored, tracked
89
- by deterministic idempotency seeds. Growing a 50-message context does not
90
- re-store 50 messages per turn.
91
- - **Injection exclusion.** The memory block this service adds is never captured
92
- back as a new memory.
93
- - **Graceful end, salvaged abort.** On `EndFrame`, queued writes get a bounded
94
- window (3 s) to land before the pipeline stops — the call's final exchange is
95
- not lost. On `CancelFrame`, the frame is pushed first and writes get a brief
84
+ - **Immediate, loss-proof capture.** Every new user message is sent the
85
+ moment its frame passes — the current utterance is in flight BEFORE the
86
+ LLM replies, so a disconnect can never lose it. Filler filtering and fact
87
+ extraction happen server-side: only the durable facts in what the caller
88
+ said are stored as memories, not the turn text.
89
+ - **Delta-only capture.** Only user messages *not seen before* are sent,
90
+ tracked by deterministic idempotency seeds; a retried turn is recognised
91
+ server-side and not extracted twice. Growing a 50-message context does not
92
+ re-send 50 messages per turn.
93
+ - **Injection exclusion.** The memory block this service adds is never sent
94
+ back as a new turn.
95
+ - **Graceful end, salvaged abort.** On `EndFrame`, queued sends get a bounded
96
+ window (3 s) to land before the pipeline stops — the caller's last words are
97
+ not lost. On `CancelFrame`, the frame is pushed first and sends get a brief
96
98
  salvage window.
97
99
  - **Failure-proof.** HTTP errors, quota limits, and timeouts all degrade to
98
100
  "no memories this turn". Nothing propagates into the pipeline.
@@ -145,10 +147,15 @@ memory = MemorySyncMemoryService(
145
147
 
146
148
  ## Semantics worth knowing
147
149
 
148
- - Both **user and assistant** turns are persisted, with role fidelity.
149
- - Idempotency seeds make retries/reconnects duplicate-free server-side.
150
+ - Only the caller's (**user**) turns are sent, as plain text with
151
+ `role: "user"`. The server extracts the durable facts they contain and
152
+ stores only those, tagged with `session_id: "pipecat::<session>"`.
153
+ Assistant replies are not sent — they are not stored as memories — and
154
+ filler such as "ok" or "thanks" stores nothing.
155
+ - Idempotency seeds let the server recognise retries and reconnects: the same
156
+ turn is not extracted twice.
150
157
  - Free-tier quota exhaustion is silent by design (empty recall, accepted-but-
151
- dropped writes); evaluation keys surface strict `429`s instead.
158
+ skipped sends); evaluation keys surface strict `429`s instead.
152
159
  - The service is reusable across pipeline runs; call `await memory.aclose()`
153
160
  from application shutdown if you want an explicit flush + client close.
154
161
 
@@ -156,7 +163,7 @@ memory = MemorySyncMemoryService(
156
163
 
157
164
  ```bash
158
165
  python -m venv venv && venv/Scripts/pip install -e . pipecat-ai pytest pytest-asyncio
159
- venv/Scripts/python -m pytest tests -q # 14 tests, run via pipecat's official test harness
166
+ venv/Scripts/python -m pytest tests -q # 19 tests, run via pipecat's official test harness
160
167
  ```
161
168
 
162
169
  ## Docs
@@ -1,144 +1,151 @@
1
- # memorysync-pipecat
2
-
3
- [MemorySync](https://memorysync.io) for [Pipecat](https://github.com/pipecat-ai/pipecat) —
4
- long-term memory for voice pipelines that never stalls a reply and never
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`).
12
-
13
- ```bash
14
- pip install pipecat-memorysync
15
- # or
16
- uv add pipecat-memorysync
17
- ```
18
-
19
- ## Where it sits
20
-
21
- `MemorySyncMemoryService` is a `FrameProcessor`. Place it **between your
22
- context aggregator and your LLM service**:
23
-
24
- ```
25
- transport.input() → stt → context_aggregator.user()
26
- → MemorySyncMemoryService ← enriches + captures here
27
- → llm → tts → transport.output() → context_aggregator.assistant()
28
- ```
29
-
30
- ```python
31
- from pipecat_memorysync import MemorySyncMemoryService
32
-
33
- memory = MemorySyncMemoryService(
34
- api_key="ms_...", # or MEMORYSYNC_API_KEY env var
35
- user_id="caller-42", # stable end-user id
36
- session_id="call-123", # optional: scope to this call
37
- )
38
-
39
- pipeline = Pipeline([
40
- transport.input(),
41
- stt,
42
- context_aggregator.user(),
43
- memory,
44
- llm,
45
- tts,
46
- transport.output(),
47
- context_aggregator.assistant(),
48
- ])
49
- ```
50
-
51
- Every `LLMContextFrame` that flows through is enriched with relevant memories
52
- (as a system message) and mined for **new** turns to persist — then pushed on,
53
- enriched or not, on time.
54
-
55
- ## Design guarantees
56
-
57
- - **Budgeted recall.** Enrichment runs under a hard timeout (default
58
- **1.2 s**). A slow or dead memory backend means an unenriched frame, never a
59
- stalled voice reply.
60
- - **Turn-complete capture.** Voice aggregators split one utterance across
61
- several context messages at speech pauses; consecutive fragments merge
62
- into ONE stored turn when the assistant's reply completes it (the
63
- in-progress tail flushes at end of call) — no per-fragment junk rows.
64
- - **Delta-only capture.** Only messages *not seen before* are stored, tracked
65
- by deterministic idempotency seeds. Growing a 50-message context does not
66
- re-store 50 messages per turn.
67
- - **Injection exclusion.** The memory block this service adds is never captured
68
- back as a new memory.
69
- - **Graceful end, salvaged abort.** On `EndFrame`, queued writes get a bounded
70
- window (3 s) to land before the pipeline stops — the call's final exchange is
71
- not lost. On `CancelFrame`, the frame is pushed first and writes get a brief
72
- salvage window.
73
- - **Failure-proof.** HTTP errors, quota limits, and timeouts all degrade to
74
- "no memories this turn". Nothing propagates into the pipeline.
75
-
76
- ## Running the example
77
-
78
- A single-file voice agent that remembers callers across calls lives in
79
- [`examples/foundational.py`](examples/foundational.py):
80
-
81
- ```bash
82
- uv add pipecat-memorysync "pipecat-ai[deepgram,cartesia,openai,silero,runner,webrtc]"
83
-
84
- export MEMORYSYNC_API_KEY=ms_... # https://app.memorysync.io
85
- export DEEPGRAM_API_KEY=...
86
- export CARTESIA_API_KEY=...
87
- export OPENAI_API_KEY=...
88
-
89
- python examples/foundational.py
90
- ```
91
-
92
- Open `http://localhost:7860/client`, tell the bot your name and a preference,
93
- hang up, and connect again — it remembers.
94
-
95
- ## Configuration (`InputParams`)
96
-
97
- ```python
98
- from pipecat_memorysync import MemorySyncMemoryService
99
-
100
- memory = MemorySyncMemoryService(
101
- api_key="ms_...",
102
- user_id="caller-42",
103
- params=MemorySyncMemoryService.InputParams(
104
- top_k=5, # memories injected per turn
105
- recall_timeout=1.2, # hard budget, seconds
106
- add_as_system_message=True,
107
- position="end", # where the memory block lands in the context
108
- min_prompt_chars=8, # skip enrichment for shorter user prompts
109
- ),
110
- )
111
- ```
112
-
113
- | Param | Default | Meaning |
114
- | --- | --- | --- |
115
- | `top_k` | `5` | Memories injected per turn |
116
- | `recall_timeout` | `1.2` | Hard recall budget in seconds |
117
- | `system_prompt` | (guarded header) | Prefix line for the injected block; also the capture-exclusion marker |
118
- | `add_as_system_message` | `True` | Inject as `system` (else appended to the latest user message) |
119
- | `position` | `"end"` | `"start"` or `"end"` of the message list |
120
- | `min_prompt_chars` | `8` | Skip recall for trivial prompts |
121
-
122
- ## Semantics worth knowing
123
-
124
- - Both **user and assistant** turns are persisted, with role fidelity.
125
- - Idempotency seeds make retries/reconnects duplicate-free server-side.
126
- - Free-tier quota exhaustion is silent by design (empty recall, accepted-but-
127
- dropped writes); evaluation keys surface strict `429`s instead.
128
- - The service is reusable across pipeline runs; call `await memory.aclose()`
129
- from application shutdown if you want an explicit flush + client close.
130
-
131
- ## Development
132
-
133
- ```bash
134
- python -m venv venv && venv/Scripts/pip install -e . pipecat-ai pytest pytest-asyncio
135
- venv/Scripts/python -m pytest tests -q # 14 tests, run via pipecat's official test harness
136
- ```
137
-
138
- ## Docs
139
-
140
- Full guide: [docs.memorysync.io/guides/pipecat](https://docs.memorysync.io/guides/pipecat)
141
-
142
- ## License
143
-
144
- MIT
1
+ # memorysync-pipecat
2
+
3
+ [MemorySync](https://memorysync.io) for [Pipecat](https://github.com/pipecat-ai/pipecat) —
4
+ long-term memory for voice pipelines that never stalls a reply and never
5
+ re-sends a turn it already sent. 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`).
12
+
13
+ ```bash
14
+ pip install pipecat-memorysync
15
+ # or
16
+ uv add pipecat-memorysync
17
+ ```
18
+
19
+ ## Where it sits
20
+
21
+ `MemorySyncMemoryService` is a `FrameProcessor`. Place it **between your
22
+ context aggregator and your LLM service**:
23
+
24
+ ```
25
+ transport.input() → stt → context_aggregator.user()
26
+ → MemorySyncMemoryService ← enriches + captures here
27
+ → llm → tts → transport.output() → context_aggregator.assistant()
28
+ ```
29
+
30
+ ```python
31
+ from pipecat_memorysync import MemorySyncMemoryService
32
+
33
+ memory = MemorySyncMemoryService(
34
+ api_key="ms_...", # or MEMORYSYNC_API_KEY env var
35
+ user_id="caller-42", # stable end-user id
36
+ session_id="call-123", # optional: scope to this call
37
+ )
38
+
39
+ pipeline = Pipeline([
40
+ transport.input(),
41
+ stt,
42
+ context_aggregator.user(),
43
+ memory,
44
+ llm,
45
+ tts,
46
+ transport.output(),
47
+ context_aggregator.assistant(),
48
+ ])
49
+ ```
50
+
51
+ Every `LLMContextFrame` that flows through is enriched with relevant memories
52
+ (as a system message) and its **new** user turns are sent to fact extraction —
53
+ then pushed on, enriched or not, on time.
54
+
55
+ ## Design guarantees
56
+
57
+ - **Budgeted recall.** Enrichment runs under a hard timeout (default
58
+ **1.2 s**). A slow or dead memory backend means an unenriched frame, never a
59
+ stalled voice reply.
60
+ - **Immediate, loss-proof capture.** Every new user message is sent the
61
+ moment its frame passes — the current utterance is in flight BEFORE the
62
+ LLM replies, so a disconnect can never lose it. Filler filtering and fact
63
+ extraction happen server-side: only the durable facts in what the caller
64
+ said are stored as memories, not the turn text.
65
+ - **Delta-only capture.** Only user messages *not seen before* are sent,
66
+ tracked by deterministic idempotency seeds; a retried turn is recognised
67
+ server-side and not extracted twice. Growing a 50-message context does not
68
+ re-send 50 messages per turn.
69
+ - **Injection exclusion.** The memory block this service adds is never sent
70
+ back as a new turn.
71
+ - **Graceful end, salvaged abort.** On `EndFrame`, queued sends get a bounded
72
+ window (3 s) to land before the pipeline stops — the caller's last words are
73
+ not lost. On `CancelFrame`, the frame is pushed first and sends get a brief
74
+ salvage window.
75
+ - **Failure-proof.** HTTP errors, quota limits, and timeouts all degrade to
76
+ "no memories this turn". Nothing propagates into the pipeline.
77
+
78
+ ## Running the example
79
+
80
+ A single-file voice agent that remembers callers across calls lives in
81
+ [`examples/foundational.py`](examples/foundational.py):
82
+
83
+ ```bash
84
+ uv add pipecat-memorysync "pipecat-ai[deepgram,cartesia,openai,silero,runner,webrtc]"
85
+
86
+ export MEMORYSYNC_API_KEY=ms_... # https://app.memorysync.io
87
+ export DEEPGRAM_API_KEY=...
88
+ export CARTESIA_API_KEY=...
89
+ export OPENAI_API_KEY=...
90
+
91
+ python examples/foundational.py
92
+ ```
93
+
94
+ Open `http://localhost:7860/client`, tell the bot your name and a preference,
95
+ hang up, and connect again — it remembers.
96
+
97
+ ## Configuration (`InputParams`)
98
+
99
+ ```python
100
+ from pipecat_memorysync import MemorySyncMemoryService
101
+
102
+ memory = MemorySyncMemoryService(
103
+ api_key="ms_...",
104
+ user_id="caller-42",
105
+ params=MemorySyncMemoryService.InputParams(
106
+ top_k=5, # memories injected per turn
107
+ recall_timeout=1.2, # hard budget, seconds
108
+ add_as_system_message=True,
109
+ position="end", # where the memory block lands in the context
110
+ min_prompt_chars=8, # skip enrichment for shorter user prompts
111
+ ),
112
+ )
113
+ ```
114
+
115
+ | Param | Default | Meaning |
116
+ | --- | --- | --- |
117
+ | `top_k` | `5` | Memories injected per turn |
118
+ | `recall_timeout` | `1.2` | Hard recall budget in seconds |
119
+ | `system_prompt` | (guarded header) | Prefix line for the injected block; also the capture-exclusion marker |
120
+ | `add_as_system_message` | `True` | Inject as `system` (else appended to the latest user message) |
121
+ | `position` | `"end"` | `"start"` or `"end"` of the message list |
122
+ | `min_prompt_chars` | `8` | Skip recall for trivial prompts |
123
+
124
+ ## Semantics worth knowing
125
+
126
+ - Only the caller's (**user**) turns are sent, as plain text with
127
+ `role: "user"`. The server extracts the durable facts they contain and
128
+ stores only those, tagged with `session_id: "pipecat::<session>"`.
129
+ Assistant replies are not sent — they are not stored as memories — and
130
+ filler such as "ok" or "thanks" stores nothing.
131
+ - Idempotency seeds let the server recognise retries and reconnects: the same
132
+ turn is not extracted twice.
133
+ - Free-tier quota exhaustion is silent by design (empty recall, accepted-but-
134
+ skipped sends); evaluation keys surface strict `429`s instead.
135
+ - The service is reusable across pipeline runs; call `await memory.aclose()`
136
+ from application shutdown if you want an explicit flush + client close.
137
+
138
+ ## Development
139
+
140
+ ```bash
141
+ python -m venv venv && venv/Scripts/pip install -e . pipecat-ai pytest pytest-asyncio
142
+ venv/Scripts/python -m pytest tests -q # 19 tests, run via pipecat's official test harness
143
+ ```
144
+
145
+ ## Docs
146
+
147
+ Full guide: [docs.memorysync.io/guides/pipecat](https://docs.memorysync.io/guides/pipecat)
148
+
149
+ ## License
150
+
151
+ MIT