Proposal: Add SDK idempotency keys for safe memory write retries

Author: SravanjangamCreated Aug 30, 2026Updated Aug 30, 2026

Proposal: Add SDK idempotency keys for safe memory write retries

Problem

packages/tools/src/ai-sdk.ts:addMemoryTool and documentAddTool (and the same in packages/tools/src/openai/tools.ts, claude-memory.ts) call client.add({ content, containerTags }) with no idempotency signal. If the network retries (the supermemory client retries 2× on 5XX/network), or the caller retries, the backend creates:

  • duplicate memories,
  • duplicate embeddings,
  • duplicate writes.

There is no Idempotency-Key header and no client helper to keep the same key across retries. Offline sync and batching also need a stable per-content key.

Impact

  • Duplicate memories on retry (common on mobile/flaky networks)
  • No safe retry primitive for SDK consumers
  • Blocks offline queue (no stable key to dedupe)

Proposal — Phase A (SDK-only, mergeable now)

Generate the key in the SDK and attach it as Idempotency-Key header. No backend change required in this phase — the header is optional and ignored until the backend honors it. The SDK is already correct for safe retries.

Idempotency-Key = SHA256(
  content +
  '|' + containerTags.sort().join(',') +
  '|' + minuteBucket   // Math.floor(Date.now()/60000)
)
  • minuteBucket makes the key stable within the same minute (retries share it) but rotates soon after, preventing indefinite dedupe.
  • SHA-256 is available via Web Crypto (and Node 20+ crypto.subtle) — already a repo dependency for other hashing.

SDK flow:

typescript
const key = await generateIdempotencyKey(content, containerTags)
await client.add({ content, containerTags }, { headers: { "Idempotency-Key": key } })

Phase A files:

  • New packages/tools/src/shared/idempotency.tsgenerateIdempotencyKey(content, containerTags, now?), buildIdempotencyHeaders(...)
  • Wire addMemoryTool + documentAddTool in packages/tools/src/ai-sdk.ts (and openai/tools.ts for parity) to attach the header via the second RequestOptions arg
  • Unit tests in packages/tools (vitest already exists)

Out of scope for this PR:

  • Backend honoring the key (Phase B — server-side dedupe store)
  • Custom userId in the hash (Phase B — if backend needs it, it can hash apiKey server-side)
  • Batch idempotency

Questions for maintainers

Is the backend already capable of accepting Idempotency-Key, or would this require backend support? This PR keeps the header optional so it is useful even before the backend honors it (stable key for caller-side retry dedupe, foundation for Phase B).

Verification

Vitest in packages/tools — 10 scenarios: same content+tags+minute → same key, different content → different key, different tags → different key, minute rollover → different key, custom now injection, header builder, retry helper reuses same key, empty content edge, containerTags order independence, concurrent callers share key.

Non-goals (Phase A)

  • No backend change
  • No persistent storage of keys
  • No cross-process coordination
  • No batch/bulk idempotency

Source: supermemoryai/supermemory