feat(python-sdks): SDK-level cross-source memory deduplication - #1532
feat(python-sdks): SDK-level cross-source memory deduplication#1532Dhravya wants to merge 3 commits into
Conversation
|
Claude finished @ved015's task in 1m 7s —— View job Reviewing PR #1532
Overview: Ports SDK-level memory deduplication to Python SDKs (OpenAI, Agent Framework, Cartesia, Pipecat), adding normalized fact comparison and request-local context replacement. Issues found: None — this looks good to ship. The Cursor Bugbot issue regarding stale memory blocks has been addressed in commit Implementation highlights:
Score: 10/10 |
There was a problem hiding this comment.
Overview: Ports SDK-level memory deduplication to Python SDKs (OpenAI, Agent Framework, Cartesia, Pipecat), adding normalized fact comparison and request-local context replacement.
Issues found: None — this looks good to ship.
The implementation is consistent across all four Python SDKs:
-
Normalized deduplication (
normalize_fact/fact_key): Correctly strips date prefixes[YYYY-MM-DD], normalizes whitespace, and case-folds for comparison. This handles the"User likes Python"vs" user likes python "vs"[2026-08-10] USER LIKES PYTHON"variations correctly. -
Memory injection replacement: The regex pattern with
re.DOTALLand non-greedy.*?properly matches<supermemory>blocks across newlines. Thestrip_memory_injection→replace_memory_injectionflow correctly replaces prior SDK blocks while preserving caller instructions. -
Mode-aware filtering: In "query" mode, passing empty arrays for static/dynamic to
deduplicate_memoriesis intentional — search results shouldn't be deduplicated against profile data when the mode only wants search results. -
Multi-system-message handling: The injection logic correctly injects into the first system message and strips from subsequent ones, preventing accumulation.
-
Test coverage: Good coverage for normalized deduplication variants and mode-specific behavior.
Score: 10/10
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 42f308b. Configure here.
| different Agent Framework providers. | ||
| """ | ||
| messages = context.messages | ||
| memory_text = f"\n\n{wrap_memory_injection(memories)}" |
There was a problem hiding this comment.
Stale memory blocks not cleared
Medium Severity
_inject_memories now replaces owned <supermemory> blocks, but process only calls it when memories is truthy. On a later turn with an empty retrieval, prior SDK blocks stay in context.messages, so stale memory context keeps going to the model. The OpenAI path in this same PR still runs replace/strip when a system message exists even if new memories are empty.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 42f308b. Configure here.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
supermemory-app | cb557f4 | Commit Preview URL Branch Preview URL |
Aug 24 2026, 06:14 PM |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
supermemory-mcp | cb557f4 | Aug 24 2026, 06:13 PM |
Port the normalized, priority-ordered (static > dynamic > search) profile deduplication into the Python SDKs, injecting one owned memory block per request that replaces the prior block rather than accumulating. Dedup is request-local (no shared state), so it stays correct under concurrency. Covers OpenAI, Agent Framework (middleware + context provider), Cartesia, and Pipecat. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2fa2e0d to
be97748
Compare
42f308b to
8de27af
Compare
There was a problem hiding this comment.
Overview: Ports SDK-level memory deduplication to Python SDKs (OpenAI, Agent Framework, Cartesia, Pipecat), adding normalized fact comparison (casefold + whitespace normalization + date-prefix stripping) and request-local context replacement.
Issues found:
- Agent Framework stale block retention (inline comment): When
memoriesis empty,_inject_memoriesis never called, so stale<supermemory>blocks from prior turns persist in the context. The OpenAI SDK correctly handles this by running strip/replace logic regardless of whether new memories exist. Cartesia and Pipecat use different patterns that avoid this issue.
What looks good:
- Normalized deduplication is consistent across all SDKs: strips
[YYYY-MM-DD]prefixes, normalizes whitespace, and usescasefold()for case-insensitive comparison - Priority order (static → dynamic → search) is correctly preserved
- Mode-aware filtering in "query" mode correctly passes empty arrays for static/dynamic to avoid deduping search results against profile data
- OpenAI SDK's multi-system-message handling correctly injects into the first and strips from subsequent ones
- Test coverage is solid for the new normalized deduplication and mode-specific behavior
Score: 8/10
One real bug that should be addressed before merge, but the overall implementation is well-structured and consistent across the SDK ports.
There was a problem hiding this comment.
Overview: Ports SDK-level memory deduplication to Python SDKs (OpenAI, Agent Framework, Cartesia, Pipecat), adding normalized fact comparison and request-local context replacement.
Issues found: None — this looks good to ship.
The Cursor Bugbot issue regarding stale memory blocks has been addressed in commit 90babae. The fix at middleware.py:279 calls _inject_memories(context, "") at the start of process(), ensuring stale SDK-owned <supermemory> blocks are always stripped before any conditional path executes.
Implementation highlights:
- Normalized deduplication: Correctly strips
[Recent]and[YYYY-MM-DD]prefixes, normalizes whitespace, and usescasefold()for case-insensitive comparison across all SDKs - Mode-aware filtering: In "query" mode, static/dynamic arrays are correctly passed as empty to
deduplicate_memories, so search results aren't deduplicated against profile data - Context replacement: OpenAI SDK properly handles both string and structured
contentfields, and prioritizesdeveloperrole messages per the newer OpenAI API conventions - Tag escaping: Each SDK escapes its respective delimiter tags (
<supermemory>for OpenAI/Agent Framework,<user_memories>for Cartesia/Pipecat) to prevent injection attacks - Test coverage: Solid coverage for normalized fact variants, query-mode behavior, and stale block replacement
Score: 10/10



Stack Context
Part 2 of a 3-PR stack moving memory deduplication into the SDKs. See
sdk-dedup/tools-ts(parent) for the full context and the TypeScript implementation this mirrors.What?
Port the normalized, priority-ordered (
static > dynamic > search) profile deduplication into the Python SDKs.Covers OpenAI, Agent Framework (middleware + context provider), Cartesia, and Pipecat.
Why?
Keeps the Python SDKs at behavioral parity with the TypeScript SDK so all integrations deduplicate memory the same way.
Testing
🤖 Generated with Claude Code
Note
Medium Risk
Changes memory formatting and system-prompt injection across multiple SDK integrations; incorrect dedup or replacement could alter LLM context, but there is no auth or data-store risk.
Overview
Ports normalized cross-source memory deduplication and replace-not-append injection into the Python OpenAI, Agent Framework, Cartesia, and Pipecat packages so they match the TypeScript SDK behavior.
Deduplication uses request-local keys: strip optional
[YYYY-MM-DD]prefixes, normalize whitespace, and compare withcasefold, with priority static → dynamic → search. Inquerymode, profile static/dynamic are excluded from dedup input so facts that only appear in search (or overlap profile) are not dropped before formatting.Injection no longer appends memory text every turn. OpenAI and Agent Framework middleware strip prior owned
<supermemory context="user-memories" readonly>blocks and replace them once per request while keeping the caller’s system instructions; extra system messages lose stale blocks only. New helpers (strip/replace/wrap) live in each package’s utils.Tests cover normalized fact variants, query-mode search retention, and stale block replacement.
Reviewed by Cursor Bugbot for commit 42f308b. Bugbot is set up for automated code reviews on this repo. Configure here.