mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-09-05 08:06:19 +00:00
## Stack Context
This stack moves memory deduplication **out of the playground UI and into the SDKs themselves**, so every integration injects a single, deduplicated, self-replacing memory block. Three PRs:
1. **`sdk-dedup/tools-ts`** (this PR) — TypeScript SDK core + integrations
2. `sdk-dedup/python` — Python SDKs
3. `sdk-dedup/playground` — playground debug view reflects the SDK-owned block
## What?
Move profile deduplication into the SDK middleware for the TypeScript tools package.
- Facts are normalized (strip leading `[YYYY-MM-DD]`, trim, collapse whitespace, casefold) and deduplicated in **`static > dynamic > search`** priority within a single request.
- The result is injected as one **owned `<supermemory>` block** that *replaces* the previous block instead of accumulating a new one each turn.
- Dedup is **mode-aware**: in query mode, search results are not dropped against a profile that isn't being injected.
- Deduplication is **request-local** — no global/browser `Set`. Safe for multiple users, concurrent requests, and Cloudflare Worker isolates.
Covers AI SDK, OpenAI (Chat + Responses), Mastra, and VoltAgent. New `shared/memory-context.ts` owns the block-replacement logic.
## Why?
The earlier "conversation-scoped deduplication" was only a playground browser `Set` — a UI debug affordance that did not change what the SDK sent to the model, and would have been unsafe as server-side global state. Real cross-source dedup belongs in the SDK, applied fresh per stateless model request.
## Testing
- `bun run test` in `packages/tools`: 145 passed (the one failing suite, `claude-memory.test.ts`, is a pre-existing broken import unrelated to this change).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Changes how system prompts and instructions are built across all TypeScript integrations; behavior is well-covered by unit tests but incorrect strip/replace logic could drop or duplicate context in production prompts.
>
> **Overview**
> Moves **cross-source memory deduplication** and **owned prompt injection** into `@supermemory/tools` so every integration sends one deduplicated memory block per request instead of growing context each turn.
>
> **Deduplication:** Facts are normalized via `normalizeMemoryFact` (strip `[YYYY-MM-DD]`, trim, collapse whitespace, lowercase) and deduplicated with **static → dynamic → search** priority. `deduplicateMemoriesForMode` keeps search hits in **query** mode when the profile is not injected.
>
> **Owned `<supermemory>` block:** New `shared/memory-context.ts` wraps memories in `<supermemory context="user-memories" readonly>`, strips stale blocks, and **replaces** prior SDK context while preserving caller system instructions. Applied in AI SDK (`injectMemoriesIntoParams`), OpenAI Chat/Responses middleware, Mastra input processor (`wrapMemoryContext`), and VoltAgent hooks.
>
> **Tests:** Unit coverage for block replacement (with-supermemory, OpenAI, VoltAgent), Mastra wrapper tag assertion, normalized dedup variants, and concurrent `containerTag` isolation.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 2fa2e0d85c. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
74 lines
2.1 KiB
JSON
74 lines
2.1 KiB
JSON
{
|
|
"name": "@supermemory/tools",
|
|
"type": "module",
|
|
"version": "2.3.0",
|
|
"description": "Memory tools for AI SDK, OpenAI, Voltagent and Mastra with supermemory",
|
|
"scripts": {
|
|
"build": "tsdown",
|
|
"dev": "tsdown --watch --ignore-watch .turbo",
|
|
"check-types": "tsc --noEmit",
|
|
"test": "vitest --testTimeout 100000",
|
|
"test:unit": "vitest run --testTimeout 100000 src/tools-shared.test.ts src/tool-operations.test.ts src/claude-memory.test.ts test/with-supermemory/unit.test.ts test/with-supermemory/conversation-conversion.test.ts test/openai-middleware.unit.test.ts test/mastra/unit.test.ts test/voltagent.unit.test.ts",
|
|
"test:watch": "vitest --watch --testTimeout 100000"
|
|
},
|
|
"dependencies": {
|
|
"@ai-sdk/anthropic": "^2.0.25",
|
|
"@ai-sdk/openai": "^2.0.23",
|
|
"ai": "^5.0.29",
|
|
"lru-cache": "^11.2.6",
|
|
"openai": "^4.104.0",
|
|
"supermemory": "^4.25.4",
|
|
"zod": "^4.1.5"
|
|
},
|
|
"devDependencies": {
|
|
"@ai-sdk/provider": "^3.0.0",
|
|
"@anthropic-ai/sdk": "^0.65.0",
|
|
"@voltagent/core": "^2.6.12",
|
|
"@mastra/core": "^1.0.0",
|
|
"@total-typescript/tsconfig": "^1.0.4",
|
|
"@types/bun": "^1.2.21",
|
|
"dotenv": "^16.6.1",
|
|
"tsdown": "^0.14.2",
|
|
"typescript": "^5.9.2",
|
|
"vitest": "^3.2.4"
|
|
},
|
|
"peerDependencies": {
|
|
"@ai-sdk/provider": "^2.0.0 || ^3.0.0",
|
|
"@voltagent/core": "^2.6.12"
|
|
},
|
|
"peerDependenciesMeta": {
|
|
"@voltagent/core": {
|
|
"optional": true
|
|
}
|
|
},
|
|
"main": "./dist/index.js",
|
|
"module": "./dist/index.js",
|
|
"types": "./dist/index.d.ts",
|
|
"files": [
|
|
"dist"
|
|
],
|
|
"exports": {
|
|
".": "./dist/index.js",
|
|
"./ai-sdk": "./dist/ai-sdk.js",
|
|
"./claude-memory": "./dist/claude-memory.js",
|
|
"./mastra": "./dist/mastra.js",
|
|
"./openai": "./dist/openai/index.js",
|
|
"./voltagent": "./dist/voltagent/index.js",
|
|
"./package.json": "./package.json"
|
|
},
|
|
"repository": {
|
|
"url": "https://github.com/supermemoryai/supermemory",
|
|
"directory": "packages/tools"
|
|
},
|
|
"keywords": [
|
|
"ai",
|
|
"sdk",
|
|
"openai",
|
|
"typescript",
|
|
"supermemory",
|
|
"memory",
|
|
"context",
|
|
"tools"
|
|
],
|
|
"license": "MIT"
|
|
}
|