diff --git a/src/index.ts b/src/index.ts index 03ed953..cb090e5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -524,9 +524,16 @@ export const SupermemoryPlugin: Plugin = async (ctx: PluginInput) => { } const scope = args.scope || "project"; + const readTags = + scope === "user" + ? tags.personalReads + : scope === "project" + ? tags.projectReads + : tags.allReads; const result = await supermemoryClient.deleteMemory( - args.memoryId + args.memoryId, + [tags.canonical, ...readTags], ); if (!result.success) { @@ -593,10 +600,15 @@ function formatSearchResults( query, scope, count: memoryResults.length, - results: memoryResults.slice(0, limit || 10).map((r) => ({ - id: r.id, - content: r.memory || r.chunk, - similarity: Math.round((r.similarity ?? 0) * 100), - })), + results: memoryResults.slice(0, limit || 10).map((r) => { + const result = { + content: r.memory ?? r.chunk, + similarity: Math.round((r.similarity ?? 0) * 100), + }; + + return r.memory === undefined + ? { ...result, forgettable: false } + : { id: r.id, ...result, forgettable: true }; + }), }); } diff --git a/src/services/client.ts b/src/services/client.ts index bb73f69..d9454fc 100644 --- a/src/services/client.ts +++ b/src/services/client.ts @@ -89,6 +89,24 @@ function supportsScopedCanonicalTag(containerTag: string): boolean { return /^repo_.+__[0-9a-f]{16}$/i.test(containerTag); } +function isNotFoundError(error: unknown): boolean { + return ( + typeof error === "object" && + error !== null && + "status" in error && + error.status === 404 + ); +} + +function isAuthorizationError(error: unknown): boolean { + return ( + typeof error === "object" && + error !== null && + "status" in error && + (error.status === 401 || error.status === 403) + ); +} + function withTimeout(promise: Promise, ms: number): Promise { let id: ReturnType; const timeout = new Promise((_, reject) => { @@ -378,18 +396,49 @@ export class SupermemoryClient { } } - async deleteMemory(memoryId: string) { + async deleteMemory(memoryId: string, containerTags: string[] = []) { log("deleteMemory: start", { memoryId }); + const uniqueTags = [...new Set(containerTags.filter(Boolean))]; + let retainedAuthorizationError: unknown; + + for (const [index, containerTag] of uniqueTags.entries()) { + try { + await withTimeout( + this.getClient().memories.forget({ id: memoryId, containerTag }), + TIMEOUT_MS, + ); + log("deleteMemory: forgotten", { memoryId }); + return { success: true as const }; + } catch (error) { + if (isNotFoundError(error)) continue; + if (index > 0 && isAuthorizationError(error)) { + retainedAuthorizationError ??= error; + continue; + } + + const errorMessage = + error instanceof Error ? error.message : String(error); + log("deleteMemory: forget error", { memoryId, error: errorMessage }); + return { success: false as const, error: errorMessage }; + } + } + try { await withTimeout( this.getClient().memories.delete(memoryId), TIMEOUT_MS, ); - log("deleteMemory: success", { memoryId }); + log("deleteMemory: deleted document", { memoryId }); return { success: true as const }; } catch (error) { + const errorToReturn = + isNotFoundError(error) && retainedAuthorizationError !== undefined + ? retainedAuthorizationError + : error; const errorMessage = - error instanceof Error ? error.message : String(error); + errorToReturn instanceof Error + ? errorToReturn.message + : String(errorToReturn); log("deleteMemory: error", { memoryId, error: errorMessage }); return { success: false as const, error: errorMessage }; }