JavaScript / TypeScript SDK

Zero runtime dependencies — uses the global fetch. Works in Node ≥ 18, Bun, Deno, browsers, and edge runtimes. Ships ESM + CJS + full types.

Install#

# npm publish pending — install from source:
npm install "github:11data/longmem#workspace=sdk/js"

Constructor#

import { Longmem } from "longmem";

const mem = new Longmem({
  apiKey: undefined,    // default: LONGMEM_API_KEY env var
  baseUrl: undefined,   // default: LONGMEM_BASE_URL or https://rememberos.ai
  timeout: 30000,       // ms per request (AbortController)
  maxRetries: 2,        // retry transient failures (429/5xx/network); 0 disables
  backoffBase: 500,     // ms, doubles each retry (Retry-After header wins)
  backoffCap: 8000,
});

Throws LongmemError if no key is available.

Automatic retries#

Transient failures — network errors and 429/500/502/ 503/504 — are retried with exponential backoff, honoring a Retry-After header when present. 4xx responses are returned immediately (never retried). Tune with maxRetries / backoffBase / backoffCap, or set maxRetries: 0 to disable.

Methods (all async)#

MethodReturns
add(text, { collection, importance, category, metadata, source, containerTag })Memory
addMany(items, { collection, containerTag, importance, category, source }){ created, ids }; bulk import, items are strings or objects, chunked to 100/call
remember(content, { collection, sync = true })facts (sync) or {job_id}
update(memoryId, { collection, text, importance, category, metadata })Memory; only set fields change
search(query, { collection, limit, minScore, mode, category, containerTag })SearchHit[]; omit collection for tenant-wide
get(memoryId, { collection })Memory
listMemories({ collection, limit, offset, includeArchived })Memory[], newest first (pinned first)
move(memoryId, { collection, toCollection }){ moved }; move a memory to another collection
delete(memoryId, { collection })deletes the memory (+ its files)
deleteCollection(collection)deletes the collection and all its memories
forget(query, { collection, minScore, limit }){ deleted }; semantic delete — destructive
collections()Collection[]
profile(collection){ profile, based_on }
related(memoryId, { collection, limit, minScore })SearchHit[]; nearest neighbours, excludes self/archived
dedup({ collection, threshold, dryRun }){ clusters, deleted, dry_run }
contradictions({ collection, limit })list of { current, superseded } pairs
pin(memoryId, { collection, pinned })Memory; pin/unpin
archive(memoryId, { collection, archived })Memory; archive/restore
archiveStale({ collection, olderThanDays, dryRun }){ would_archive } or { archived }
health({ collection, staleDays })collection health snapshot — total, stale, expired, supersessions, needs_attention, categories
summary({ collection, limit })board-report briefing — { summary, themes, based_on, generated_at }
createConnection(provider, { name, collection, containerTag, config, credentials })the connection; managed connector (creds encrypted, never returned)
listConnections() / getConnection(id)connection objects (no credentials)
syncConnection(id){ synced, cursor, status } or { status: "error", error }
connectionRuns(id, { limit })recent sync runs: { status, synced_count, error, created_at }
deleteConnection(id)removes the connection (synced memories kept)
connectorHealth({ hours })admin: cross-tenant sync health [{ provider, runs, errors, last_run }]
connectorStatus()admin: connection counts by status [{ status, n }] — surfaces paused/erroring connectors
adminMemoryHealth()admin: fleet-wide memory hygiene { total, current, archived, stale, expired, supersessions, needs_attention }
exportAccount()full knowledge-base dump { tenant, collections, memories, … } — text-only, re-imports anywhere
importMemories(memories, { collections, intoCollection })re-ingest a dump (re-embeds text); { imported, skipped, collections }

Bulk import#

// strings, or objects for per-item fields; chunked to 100/call, retries per chunk
await mem.addMany([
  "Alex prefers dark mode",
  { text: "Bianca is on the design team", containerTag: "user-42", metadata: { src: "crm" } },
], { collection: "memories" });   // -> { created: 2, ids: [...] }

Errors#

import { Longmem, LongmemError, LongmemAPIError } from "longmem";

try {
  await mem.add("…");
} catch (e) {
  if (e instanceof LongmemAPIError) console.error(e.status, e.message);
  else if (e instanceof LongmemError) console.error("config/network:", e.message);
}

In a chat handler#

const hits = await mem.search(userMessage, {
  collection: "assistant", containerTag: `user-${userId}`, limit: 5 });

const context = hits.map(h => h.text).join("\n");
// …call your model with context, then:
await mem.remember(userMessage, { collection: "assistant", sync: false });