npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sheriax/simplemem

v0.3.2

Published

Efficient lifelong memory for LLM agents - TypeScript implementation

Readme

SimpleMem

Efficient Lifelong Memory for LLM Agents - TypeScript Implementation

npm version CI License: MIT

A TypeScript implementation of the SimpleMem paper, achieving:

  • 43.24% F1 score (26.4% better than Mem0)
  • ~550 token cost (30x fewer than full-context methods)
  • Cross-runtime support: Bun, Node.js, and Deno

Installation

# Bun (recommended)
bun add @sheriax/simplemem

# npm
npm install @sheriax/simplemem

# pnpm
pnpm add @sheriax/simplemem

Quick Start

import { SimpleMem, OpenAIProvider, OpenAIEmbeddings } from "@sheriax/simplemem";

const memory = new SimpleMem({
  llm: new OpenAIProvider({
    apiKey: process.env.OPENAI_API_KEY!,
  }),
  embeddings: new OpenAIEmbeddings({
    apiKey: process.env.OPENAI_API_KEY!,
  }),
});

// Add dialogue
await memory.addDialogue("Alice", "Let's meet at Starbucks tomorrow at 2pm", "2025-11-15T14:30:00");
await memory.addDialogue("Bob", "Sure, I'll bring the report", "2025-11-15T14:31:00");
await memory.finalize();

// Query
const answer = await memory.ask("When and where will Alice and Bob meet?");
// => "16 November 2025 at 2:00 PM at Starbucks"

Features

Three-Stage Pipeline

  1. Semantic Structured Compression (Stage 1)

    • Sliding window dialogue segmentation
    • Entropy-aware filtering
    • Coreference resolution (pronouns -> names)
    • Temporal anchoring (relative -> absolute timestamps)
  2. Structured Multi-View Indexing (Stage 2)

    • Semantic Layer: Dense vector embeddings
    • Lexical Layer: BM25 keyword matching
    • Symbolic Layer: Metadata filtering (time, location, entities)
  3. Adaptive Query-Aware Retrieval (Stage 3)

    • Query complexity estimation (LOW/HIGH)
    • Dynamic retrieval depth
    • Hybrid scoring across all layers
    • Optional reflection for complex queries

Abstract Memory (Paper Section 3.2)

Automatically clusters similar memory units and generates higher-level patterns:

// After adding many memories, trigger consolidation
const abstracts = await memory.consolidate();
// => [{ pattern: "Alice and Bob meet weekly at cafes to discuss project status", ... }]

// Abstracts are automatically included in retrieval context
const answer = await memory.ask("What are Alice's regular habits?");

Consolidation also runs automatically based on a configurable interval (default: every 50 new units).

Flexible Input

Beyond dialogue, you can add raw text, documents, and direct facts:

// Raw text (extracted via LLM)
await memory.addText("The quarterly review showed 15% revenue growth in Q3.");

// Long documents (automatically chunked)
await memory.addDocument(longArticle, {
  chunkSize: 2000,
  chunkOverlap: 200,
  source: "quarterly-report.pdf",
});

// Direct facts (no LLM extraction, stored immediately)
await memory.addFact("User prefers dark mode", {
  topic: "preferences",
  salience: "high",
});

Event System

Subscribe to lifecycle events for observability, debugging, and custom workflows:

memory.events.on("memory:units_created", ({ units, count }) => {
  console.log(`Created ${count} memory units`);
});

memory.events.on("retrieval:answer_generated", ({ query, answer }) => {
  telemetry.record({ query, answer });
});

memory.events.on("memory:abstract_created", ({ abstract }) => {
  console.log(`New pattern: ${abstract.pattern}`);
});

memory.events.on("error", ({ stage, error }) => {
  logger.error(`Error in ${stage}:`, error);
});

Available events: memory:units_created, memory:units_indexed, memory:abstract_created, memory:consolidation_completed, retrieval:query_analyzed, retrieval:context_retrieved, retrieval:answer_generated, storage:cleared, error

Provider Flexibility

LLM Providers

Use any OpenAI-compatible API:

// OpenAI directly
new OpenAIProvider({ apiKey: "sk-..." });

// OpenRouter
new OpenAIProvider({
  apiKey: "sk-or-...",
  baseURL: "https://openrouter.ai/api/v1",
  model: "anthropic/claude-3-haiku",
});

// Local LLM (Ollama, LM Studio, etc.)
new OpenAIProvider({
  apiKey: "ollama",
  baseURL: "http://localhost:11434/v1",
  model: "llama3.2",
});

Embedding Providers

import { OpenAIEmbeddings, LocalEmbeddings, VoyageEmbeddings } from "@sheriax/simplemem";

// OpenAI (default)
new OpenAIEmbeddings({ apiKey: "sk-..." });

// Local embeddings (offline, free - requires @xenova/transformers)
new LocalEmbeddings({ model: "Xenova/all-MiniLM-L6-v2" });

// Multimodal embeddings (text + images)
new VoyageEmbeddings({ apiKey: "voyage-..." });

Storage Options

import { MemoryStorage, FileStorage, SQLiteStorage } from "@sheriax/simplemem";

// In-memory (default, ephemeral)
new SimpleMem({ storage: new MemoryStorage(), ... });

// File-based (JSON persistence)
new SimpleMem({ storage: new FileStorage({ path: "./memory.json" }), ... });

// SQLite (production-grade, ACID transactions, indexed queries)
new SimpleMem({ storage: new SQLiteStorage({ path: "./memory.db" }), ... });

SQLite uses bun:sqlite on Bun and better-sqlite3 on Node.js (install as optional peer dep).

Structured Logging

import { silentLogger } from "@sheriax/simplemem";

// Default: logs warnings to console with [SimpleMem] prefix
new SimpleMem({ llm, embeddings });

// Silent: suppress all output
new SimpleMem({ llm, embeddings, logger: silentLogger });

// Custom logger
new SimpleMem({
  llm,
  embeddings,
  logger: {
    debug: (msg, ...args) => myLogger.debug(msg, ...args),
    info: (msg, ...args) => myLogger.info(msg, ...args),
    warn: (msg, ...args) => myLogger.warn(msg, ...args),
    error: (msg, ...args) => myLogger.error(msg, ...args),
  },
});

API Reference

SimpleMem

class SimpleMem {
  // Lifecycle events
  readonly events: SimpleMemEventEmitter;

  constructor(options: SimpleMemOptions);

  // Dialogue input
  addDialogue(speaker: string, content: string, timestamp?: string | Date): Promise<void>;
  addDialogues(dialogues: Array<{ speaker; content; timestamp? }>): Promise<void>;
  finalize(): Promise<void>;

  // Flexible input
  addText(text: string, metadata?: TextMetadata): Promise<MemoryUnit[]>;
  addDocument(content: string, options?: DocumentOptions): Promise<MemoryUnit[]>;
  addFact(content: string, metadata?: FactMetadata): Promise<MemoryUnit>;

  // Query
  ask(question: string): Promise<string>;
  search(query: string, options?: SearchOptions): Promise<MemoryUnit[]>;
  getContext(query: string): Promise<RetrievalContext>;

  // Abstract memory
  consolidate(): Promise<AbstractMemory[]>;

  // Management
  getAllMemories(): Promise<MemoryUnit[]>;
  getMemoryCount(): Promise<number>;
  getStats(): { indexedUnits; bufferedDialogues; processedDialogues };
  export(): Promise<ExportData>;
  import(data: ExportData): Promise<void>;
  clear(): Promise<void>;
}

Configuration

const memory = new SimpleMem({
  llm: provider,
  embeddings: embeddings,
  storage: new MemoryStorage(),

  // Stage 1: Compression
  compression: {
    windowSize: 40,
    overlapSize: 2,
    redundancyThreshold: 0.3,
  },

  // Stage 2: Indexing
  indexing: {
    semanticTopK: 25,
    keywordTopK: 5,
    semanticWeight: 0.6,
    lexicalWeight: 0.3,
  },

  // Stage 3: Retrieval
  retrieval: {
    baseK: 3,
    complexityDelta: 2.0,
    enableReflection: true,
  },

  // Abstract memory consolidation
  abstraction: {
    clusterThreshold: 0.75,
    minClusterSize: 2,
    maxClusterSize: 20,
    consolidationInterval: 50,
  },

  // Logging
  logger: silentLogger,
});

Setup for Contributors

After cloning, configure the pre-commit hook:

git config core.hooksPath .githooks

This enforces CHANGELOG.md updates and version bumps on every commit.

References

License

MIT