MemorySyncMemorySync
Node SDK

Bulk Operations

When you have a backlog to ingest — historical messages, exported docs, a one-off migration — call bulkAdd instead of looping over add. Each call carries up to 50 items and returns a per-item result so you know exactly what landed and what was rejected.

Why bulkAdd exists

  • One round-trip instead of fifty. Lower latency, fewer connections.
  • The server can deduplicate across the whole batch in one pass.
  • Per-item results: every input maps to created, skipped, or rejected.

The shape of a BulkAddItem

FieldTypeRequired
textstringYes
sourcestringNo
eventTypestringNo
tagsstring[]No
metadataRecord<string, unknown>No
importancenumber 0..1No
endUserIdstringNo (multi-tenant only)

A minimal call

TYPESCRIPT
const res = await client.bulkAdd(
[
{ text: "Picked the audit log schema we discussed.", tags: ["decision"] },
{ text: "Wrote the migration.", tags: ["work"] },
{ text: "Reviewed the migration with the team.", tags: ["review"] },
],
{ deduplicate: true },
);
console.log(res.total, res.created, res.skipped, res.rejected);
for (const r of res.results) {
console.log(r.index, r.status, r.memoryIds, r.reason);
}

BulkAddResponse, field by field

FieldTypeMeaning
totalnumberHow many items were submitted.
creatednumberHow many produced new memory rows.
skippednumberHow many the server intentionally did not store.
rejectednumberHow many were invalid (empty, oversized, etc.).
resultsBulkAddItemResult[]Per-item outcomes; index matches the input order.

The deduplicate flag

deduplicate defaults to true. With it on, items that are semantically identical to existing memories — or to earlier items in the same batch — are returned as status: "skipped" instead of being stored a second time. Set it to false only when you have a specific reason to keep duplicates.

Chunking a backlog over 50

TYPESCRIPT
async function ingestAll(items: { text: string }[]) {
const chunks: typeof items[] = [];
for (let i = 0; i < items.length; i += 50) {
chunks.push(items.slice(i, i + 50));
}
const results: number[] = [];
for (const c of chunks) {
const res = await client.bulkAdd(c);
results.push(res.created);
}
return results.reduce((a, b) => a + b, 0);
}

Running multiple chunks in parallel

Use a small concurrency cap (4\u20138) when you parallelise. The server will rate-limit you eventually; bound your own fan-out so you fail loud, not slow.

TYPESCRIPT
import pLimit from "p-limit"; // or any concurrency primitive
const limit = pLimit(4);
const counts = await Promise.all(
chunks.map((c) => limit(() => client.bulkAdd(c).then((r) => r.created))),
);

Errors specific to bulk calls

Validation fires before the network
bulkAdd([]) raises ValidationError client-side without making a request. So does an array of more than 50 items.
  • RateLimitError on a chunk — back off for the seconds the error reports, then retry the same chunk.
  • ServerError — safe to retry; ingestion is idempotent on the same text.
  • Per-item status: "rejected" entries inside a successful response are not exceptions; they describe why specific items did not store.