Skip to content

fix: harden search/forget behavior and skip capture for memory-management turns#25

Open
pascalkienast wants to merge 1 commit intosupermemoryai:mainfrom
pascalkienast:fix/search-forget-reliability
Open

fix: harden search/forget behavior and skip capture for memory-management turns#25
pascalkienast wants to merge 1 commit intosupermemoryai:mainfrom
pascalkienast:fix/search-forget-reliability

Conversation

@pascalkienast
Copy link

@pascalkienast pascalkienast commented Mar 14, 2026

Summary

  • stop auto-capturing Supermemory management turns (search / forget / store) back into memory
  • make forgetByQuery() safer by avoiding blind deletion of the first semantic hit
  • locally rerank search results so exact/literal matches are preferred when they are already present in the candidate set
  • only report forget success when the backend explicitly confirms forgotten === true
  • add focused regression tests for safer forget behavior and capture skipping

Why this PR exists

This plugin currently has a few failure modes around search / forget that make memory management feel less trustworthy than it should:

  1. forgetByQuery() can delete the wrong memory because it trusts the first semantic search hit too much.
  2. Exact/literal matches are not preferred locally, even when they are already present in the returned result set.
  3. Memory-management turns themselves can get auto-captured again, which reintroduces deletion/search text as fresh memory-like context and creates meta-memory pollution.

Scope of this fix

This PR is intentionally a plugin-layer hardening pass, not a claim that all search/delete ambiguity is fully solved end-to-end.

In particular, this change improves behavior when:

  • the correct target is already present in the returned candidate set
  • the plugin would otherwise delete the first fuzzy match too eagerly
  • management-turn text would otherwise be captured back into memory

It does not try to redesign or over-assume the backend’s broader memory extraction semantics.

What changed

client.ts

  • add local normalization helpers
  • rerank returned search candidates to prefer exact/literal matches before fuzzier semantic neighbors
  • make forgetByQuery() search a wider candidate set and prefer an exact textual match when available
  • require explicit backend confirmation (forgotten === true) before reporting forget success

hooks/capture.ts

  • detect Supermemory management turns
  • skip auto-capture for these turns so search/forget/store operations do not feed their own management text back into memory

Tests

Added focused regression coverage for:

  • exact-match preference within returned search candidates
  • safer forgetByQuery() target selection
  • forget success acknowledgement handling
  • skipping capture for memory-management turns

Root cause addressed here

This patch addresses three concrete plugin-level issues:

  1. Blind first-result deletion

    • forgetByQuery() effectively searched and deleted results[0]
    • that is too optimistic for a semantically ranked system
  2. No exact-match preference

    • exact/literal matches in the result set were not locally boosted
  3. Management-turn recapture

    • search/forget/store interactions could be auto-captured back into memory, creating ghost/meta-memory artifacts

Why the fix is intentionally conservative

I deliberately kept this patch small and local to the plugin.

There may still be broader API-/backend-level behaviors (for example asynchronous extraction or memory text normalization/canonicalization) that affect how quickly or how literally a newly added memory can be searched or forgotten.

This PR does not attempt to solve those larger semantics in the plugin layer.
Instead, it makes the plugin safer and less misleading under the assumptions it can control today.

Testing

bun test
bun run check-types
bun run lint

All passed locally.

Comment on lines 261 to +266
const preview = limitText(target.content || target.memory || "", 100)
if (!deleted.forgotten) {
return {
success: false,
message: `Unable to confirm forgetting: "${preview}"`,
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The function forgetByQuery unconditionally fails if the deleteMemory SDK call does not return the expected forgotten field, which is an unverified assumption.
Severity: MEDIUM

Suggested Fix

To prevent incorrect failure messages, add a check to verify that the forgotten field exists and is a boolean before evaluating it. For example, check typeof deleted.forgotten === 'boolean' and handle the case where the field is missing, perhaps by assuming success for backward compatibility or logging a warning.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: client.ts#L261-L266

Potential issue: The `forgetByQuery` function relies on the `deleteMemory` method
returning an object with a `forgotten` boolean field. The `deleteMemory` function
directly returns the response from the Supermemory v4 SDK's `memories.forget()` method.
If the SDK's response does not include this `forgotten` field, the check
`!deleted.forgotten` will always evaluate to true. This would cause `forgetByQuery` to
incorrectly report a failure to the user (e.g., `Unable to confirm forgetting: ...`),
even though the underlying memory deletion was successful. This behavior is a regression
and relies on an unverified assumption about the external SDK's API contract.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks — I checked this against the currently shipped supermemory SDK contract (supermemory@4.15.0), and client.memories.forget() does in fact return a typed MemoryForgetResponse with:

{
  id: string;
  forgotten: boolean;
}

This is defined in the generated SDK types (src/resources/memories.ts and resources/memories.d.ts), where forgotten is explicitly documented as:

Indicates the memory was successfully forgotten

So the deleted.forgotten check here is intentional and aligned with the current SDK/API contract.

The goal of this branch is specifically to avoid false-positive success after fuzzy mis-targeting, not to loosen delete confirmation semantics. If the backend does not confirm forgotten === true, I would prefer to surface that as a failed forget operation rather than reporting success optimistically.

@pascalkienast pascalkienast changed the title fix: improve exact-match search and forget reliability fix: harden search/forget behavior and skip capture for memory-management turns Mar 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant