Skip to content

Commit 07875ad

Browse files
committed
update forget implementation in mcp (supermemoryai#773)
### TL;DR Enhanced the `forgetMemory` method to try exact content matching first, then fall back to semantic search with a high similarity threshold for more precise memory deletion. ### What changed? The `forgetMemory` method now uses a two-step approach: first attempting exact content matching via the API, and if that fails with a 404, falling back to semantic search with a similarity threshold of 0.85. The search method also accepts an optional threshold parameter. Error messages now distinguish between exact matches and semantic matches, including similarity scores in the response. ### How to test? 1. Call `forgetMemory` with the exact content of an existing memory to verify direct deletion 2. Call `forgetMemory` with similar but not identical content to test the semantic search fallback 3. Call `forgetMemory` with completely unrelated content to verify the "no matching memory found" response 4. Verify that success messages indicate whether deletion used exact matching or semantic matching with similarity scores ### Why make this change? This approach provides more precise memory deletion by prioritizing exact matches while still offering a fallback for similar content. The high similarity threshold (0.85) ensures that only very similar memories are deleted when exact matches aren't found, reducing the risk of accidentally deleting unrelated memories.
1 parent 9f7f415 commit 07875ad

1 file changed

Lines changed: 31 additions & 7 deletions

File tree

apps/mcp/src/client.ts

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -154,18 +154,39 @@ export class SupermemoryClient {
154154
}
155155
}
156156

157-
// Delete/forget memory by searching first
157+
// Delete/forget memory - try exact match first, then semantic search
158158
async forgetMemory(
159159
content: string,
160160
): Promise<{ success: boolean; message: string; containerTag: string }> {
161161
try {
162-
// First search for the memory
163-
const searchResult = await this.search(content, 5)
162+
// Try exact content matching first
163+
try {
164+
const result = await this.client.memories.forget({
165+
content: content,
166+
containerTag: this.containerTag,
167+
})
168+
169+
return {
170+
success: true,
171+
message: `Successfully forgot memory (exact match) with ID: ${result.id}`,
172+
containerTag: this.containerTag,
173+
}
174+
} catch (error: any) {
175+
// If not 404, it's a real error - re-throw it
176+
if (error?.status !== 404) {
177+
throw error
178+
}
179+
// Otherwise continue to semantic search fallback
180+
}
181+
182+
// Fallback to semantic search if exact match fails
183+
const SIMILARITY_THRESHOLD = 0.85 // High threshold - only very similar memories
184+
const searchResult = await this.search(content, 5, SIMILARITY_THRESHOLD)
164185

165186
if (searchResult.results.length === 0) {
166187
return {
167188
success: false,
168-
message: "No matching memory found to forget.",
189+
message: `No matching memory found to forget. Tried exact match and semantic search with similarity threshold ${SIMILARITY_THRESHOLD}.`,
169190
containerTag: this.containerTag,
170191
}
171192
}
@@ -176,10 +197,12 @@ export class SupermemoryClient {
176197
return {
177198
success: false,
178199
message:
179-
"No matching memory found to forget (only document chunks matched).",
200+
"No matching memory found to forget (only document chunks matched in semantic search).",
180201
containerTag: this.containerTag,
181202
}
182203
}
204+
205+
// Delete using the ID from semantic search
183206
await this.client.memories.forget({
184207
id: memoryToDelete.id,
185208
containerTag: this.containerTag,
@@ -189,7 +212,7 @@ export class SupermemoryClient {
189212
getMemoryText(memoryToDelete) || memoryToDelete.content || ""
190213
return {
191214
success: true,
192-
message: `Forgot: "${limitByChars(memoryText, 100)}"`,
215+
message: `Forgot similar memory (semantic match, similarity: ${memoryToDelete.similarity.toFixed(2)}): "${limitByChars(memoryText, 100)}"`,
193216
containerTag: this.containerTag,
194217
}
195218
} catch (error) {
@@ -198,13 +221,14 @@ export class SupermemoryClient {
198221
}
199222

200223
// Search memories using SDK
201-
async search(query: string, limit = 10): Promise<SearchResult> {
224+
async search(query: string, limit = 10, threshold?: number): Promise<SearchResult> {
202225
try {
203226
const result = await this.client.search.memories({
204227
q: query,
205228
limit,
206229
containerTag: this.containerTag,
207230
searchMode: "hybrid",
231+
threshold, // Optional threshold parameter
208232
})
209233

210234
// Normalize and limit response size — preserve memory vs chunk distinction

0 commit comments

Comments
 (0)