Minimal, Pluggable LLM Memory SDK
npm install @mhbdev/mem-kitbash
npm install @mhbdev/mem-kit
`
Or with yarn:
`bash
yarn add @mhbdev/mem-kit
`
Requirements:
- Node >=18 (uses global fetch)
- For generation/embeddings, set OPENAI_API_KEY.
- SQLite adapter is optional and uses a native dependency (better-sqlite3). If you donโt need SQLite, you can skip installing native modules; the package marks it as optional.
---
๐ Quickstart
`typescript
import {
MemoryManager,
InMemoryStorageAdapter,
KeywordRetrievalStrategy
} from "@mhbdev/mem-kit";
// Initialize memory system
const memory = new MemoryManager({
storage: new InMemoryStorageAdapter(),
retrieval: new KeywordRetrievalStrategy()
});
// Store memories
await memory.remember({
type: "preference",
content: "User loves sci-fi movies, especially Blade Runner"
});
await memory.remember({
type: "fact",
content: "User is learning TypeScript and React"
});
// Recall relevant memories
const results = await memory.recall("What does the user like?");
console.log(results);
// Inspect specific memory
const details = await memory.inspect(results[0].id);
console.log(details);
`
---
๐๏ธ Architecture
MemKit follows clean architecture principles with clear layer separation:
`
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ SDK Layer โ
โ Public API: MemoryManager + Adapter Exports โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Application Layer โ
โ Business Logic: MemoryManager, Use Cases โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Domain Layer โ
โ Core Models & Interfaces (Ports) โ
โ โข MemoryItem, MemoryType โ
โ โข IStorageAdapter, IEmbeddingAdapter โ
โ โข ILLMAdapter, IRetrievalStrategy โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Infrastructure Layer โ
โ Concrete Implementations (Adapters) โ
โ โข Storage: InMemory, SQLite โ
โ โข Embeddings: OpenAI โ
โ โข LLM: OpenAI โ
โ โข Retrieval: Keyword, Embedding โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
`
---
๐ง Core Concepts
$3
MemKit supports five core memory types:
- fact: Factual information about the user or context
- preference: User preferences and likes/dislikes
- event: Time-based events or interactions
- summary: Condensed summaries of multiple memories
- todo: Tasks or action items
$3
`typescript
interface MemoryItem {
id: string; // Unique identifier
type: MemoryType; // Memory classification
content: string; // The actual memory content
embedding?: number[]; // Vector embedding (optional)
metadata?: Record; // Additional context
createdAt: string; // ISO timestamp
updatedAt?: string; // Last modification time
relevance?: number; // Decay score (0-1)
source?: string; // Origin of memory
}
`
---
๐ฎ Usage Guide
$3
#### Storing Memories
`typescript
// Simple memory
await memory.remember({
type: "fact",
content: "User's favorite color is blue"
});
// With metadata
await memory.remember({
type: "event",
content: "User attended NodeConf 2024",
metadata: {
location: "Austin, TX",
attendees: 500
}
});
// With source tracking
await memory.remember({
type: "preference",
content: "User prefers dark mode",
source: "settings_page"
});
`
#### Retrieving Memories
`typescript
// Basic recall
const memories = await memory.recall("user preferences");
// With limit
const top5 = await memory.recall("JavaScript", 5);
// Inspect specific memory
const item = await memory.inspect("memory-id-here");
`
#### Managing Memories
`typescript
// Forget a specific memory
await memory.forget("memory-id");
// Clear all memories
await memory.clear();
`
#### Generating Summaries
`typescript
// Requires LLM adapter
const summary = await memory.summarize();
// Filter by type
const factSummary = await memory.summarize({ type: "fact" });
// Limit items
const recentSummary = await memory.summarize({ limit: 10 });
`
---
๐ Built-in Adapters
$3
#### InMemoryStorageAdapter
Perfect for development, testing, or ephemeral sessions.
`typescript
import { InMemoryStorageAdapter } from "@mhbdev/mem-kit";
const storage = new InMemoryStorageAdapter();
`
#### SQLiteStorageAdapter
Production-ready persistent storage.
`typescript
import { SQLiteStorageAdapter } from "@mhbdev/mem-kit";
// In-memory database
const storage = new SQLiteStorageAdapter(":memory:");
// Persistent file
const storage = new SQLiteStorageAdapter("./memories.db");
`
#### PostgresStorageAdapter (pgvector + drizzle)
Production-grade Postgres storage using the pgvector extension for embeddings.
Requirements:
- PostgreSQL with pgvector installed: CREATE EXTENSION IF NOT EXISTS vector;
- Install optional dependencies:
- npm install pg drizzle-orm
`typescript
import { PostgresStorageAdapter, MemoryManager, EmbeddingRetrievalStrategy, OpenAIEmbeddingAdapter } from "@mhbdev/mem-kit";
const storage = new PostgresStorageAdapter({
connectionString: process.env.DATABASE_URL!,
embeddingDimensions: 1536 // match your embedding model
});
const embedder = new OpenAIEmbeddingAdapter({ apiKey: process.env.OPENAI_API_KEY });
const memory = new MemoryManager({
storage,
embedder,
retrieval: new EmbeddingRetrievalStrategy(embedder)
});
await memory.remember({ type: "fact", content: "User enjoys hiking" });
const results = await memory.recall("outdoor activities");
`
$3
#### OpenAIEmbeddingAdapter
Real semantic search with OpenAI embeddings.
`typescript
import { OpenAIEmbeddingAdapter } from "@mhbdev/mem-kit";
const embedder = new OpenAIEmbeddingAdapter({
apiKey: process.env.OPENAI_API_KEY,
model: "text-embedding-3-small" // Default
});
`
#### MockEmbeddingAdapter
Deterministic embeddings for testing.
`typescript
import { MockEmbeddingAdapter } from "@mhbdev/mem-kit";
const embedder = new MockEmbeddingAdapter(1536); // Dimension
`
$3
#### OpenAIAdapter
Text generation and summarization.
`typescript
import { OpenAIAdapter } from "@mhbdev/mem-kit";
const llm = new OpenAIAdapter({
apiKey: process.env.OPENAI_API_KEY,
model: "gpt-4o-mini"
});
`
$3
#### KeywordRetrievalStrategy
Fast, simple keyword matching.
`typescript
import { KeywordRetrievalStrategy } from "@mhbdev/mem-kit";
const retrieval = new KeywordRetrievalStrategy();
`
#### EmbeddingRetrievalStrategy
Semantic similarity search using embeddings.
`typescript
import { EmbeddingRetrievalStrategy } from "@mhbdev/mem-kit";
const retrieval = new EmbeddingRetrievalStrategy(embedder);
`
#### PgVectorRetrievalStrategy (server-side similarity)
Use Postgres pgvector to perform similarity search directly in the database for efficient large-scale retrieval.
Requirements:
- PostgreSQL with pgvector installed
- Optional deps installed: pg, drizzle-orm
`typescript
import { PgVectorRetrievalStrategy, PostgresStorageAdapter, MemoryManager, OpenAIEmbeddingAdapter } from "@mhbdev/mem-kit";
import { Pool } from "pg";
const storage = new PostgresStorageAdapter({
connectionString: process.env.DATABASE_URL!,
embeddingDimensions: 1536
});
const embedder = new OpenAIEmbeddingAdapter({ apiKey: process.env.OPENAI_API_KEY });
const pool = new Pool({ connectionString: process.env.DATABASE_URL! });
const memory = new MemoryManager({
storage,
embedder,
retrieval: new PgVectorRetrievalStrategy({ pool, embedder }),
});
const results = await memory.recall("recommend outdoor activities", 10);
`
---
๐ ๏ธ Advanced Usage
$3
`typescript
import {
MemoryManager,
SQLiteStorageAdapter,
OpenAIEmbeddingAdapter,
OpenAIAdapter,
EmbeddingRetrievalStrategy,
ConsoleLogger
} from "@mhbdev/mem-kit";
const embedder = new OpenAIEmbeddingAdapter({
apiKey: process.env.OPENAI_API_KEY
});
const memory = new MemoryManager({
storage: new SQLiteStorageAdapter("./prod-memories.db"),
embedder: embedder,
llm: new OpenAIAdapter({
apiKey: process.env.OPENAI_API_KEY
}),
retrieval: new EmbeddingRetrievalStrategy(embedder),
logger: new ConsoleLogger(),
options: {
autoEmbed: true,
defaultRetrievalLimit: 10,
enableDecay: true,
decayFactor: 0.95
}
});
`
Note: A lightweight MockEmbeddingAdapter exists for internal tests. It is not exported in the public API and should not be used in production.
$3
Enable time-based relevance decay:
`typescript
const memory = new MemoryManager({
storage: new InMemoryStorageAdapter(),
options: {
enableDecay: true,
decayFactor: 0.95 // Daily decay rate
}
});
`
Older memories will have lower relevance scores over time.
---
๐จ Writing Custom Adapters
MemKit is designed for extensibility. Here's how to create custom adapters:
$3
`typescript
import { IStorageAdapter, MemoryItem } from "MemKit";
class RedisStorageAdapter implements IStorageAdapter {
private client: RedisClient;
constructor(redisUrl: string) {
this.client = createClient({ url: redisUrl });
}
async save(item: MemoryItem): Promise {
await this.client.set(
memory:${item.id},
JSON.stringify(item)
);
}
async get(id: string): Promise {
const data = await this.client.get( memory:${id});
return data ? JSON.parse(data) : null;
}
async getAll(): Promise {
const keys = await this.client.keys("memory:*");
const items = await Promise.all(
keys.map(key => this.client.get(key))
);
return items
.filter(Boolean)
.map(data => JSON.parse(data!));
}
async delete(id: string): Promise {
const result = await this.client.del( memory:${id});
return result > 0;
}
async clear(): Promise {
const keys = await this.client.keys("memory:*");
if (keys.length > 0) {
await this.client.del(...keys);
}
}
}
`
$3
`typescript
import { IRetrievalStrategy, MemoryItem } from "MemKit";
class HybridRetrievalStrategy implements IRetrievalStrategy {
constructor(
private keywordWeight: number = 0.3,
private semanticWeight: number = 0.7
) {}
async retrieve(
query: string,
items: MemoryItem[],
limit: number = 10
): Promise {
// Combine keyword and semantic scores
const scored = items.map(item => {
const keywordScore = this.getKeywordScore(query, item);
const semanticScore = this.getSemanticScore(query, item);
return {
item,
score: (keywordScore * this.keywordWeight) +
(semanticScore * this.semanticWeight)
};
});
return scored
.sort((a, b) => b.score - a.score)
.slice(0, limit)
.map(s => s.item);
}
private getKeywordScore(query: string, item: MemoryItem): number {
// Implementation...
}
private getSemanticScore(query: string, item: MemoryItem): number {
// Implementation...
}
}
`
---
๐งช Testing
Run the test suite:
`bash
npm test
`
With coverage:
`bash
npm run test:coverage
`
MemKit includes comprehensive tests for:
- MemoryManager core logic
- All built-in adapters
- Retrieval strategies
- Edge cases and error handling
---
๐ Performance Considerations
$3
- InMemory: Fastest, but lost on restart. Great for sessions.
- SQLite: Good balance of speed and persistence. Suitable for most apps.
- Custom (Redis, Postgres): Best for distributed systems and high scale.
$3
- Mock: Instant, but not semantically meaningful. Use for testing.
- OpenAI: High quality, ~100ms per embedding. Batch when possible.
$3
- Keyword: ~1ms for 1000 items. Fast but limited accuracy.
- Embedding: ~10ms for 1000 items. Slower but semantically accurate.
---
๐บ๏ธ Roadmap
- [ ] Pinecone/Weaviate vector DB adapters
- [ ] Conversation threading/context management
- [ ] Memory importance scoring
- [ ] Automatic memory consolidation
- [ ] Multi-user memory isolation
- [ ] Memory export/import utilities
- [ ] React hooks for client-side usage
---
๐ค Contributing
Contributions are welcome! Please follow these guidelines:
1. Fork the repository
2. Create a feature branch: git checkout -b feature/amazing-feature
3. Commit changes: git commit -m 'Add amazing feature'
4. Push to branch: git push origin feature/amazing-feature
5. Open a Pull Request
Ensure all tests pass and coverage remains above 85%.
---
๐ License
MIT License - see LICENSE file for details.
---
๐ Acknowledgments
Built with inspiration from:
- LangChain Memory
- Zep
- Clean Architecture principles by Robert C. Martin
---
๐ฌ Support
- ๐ Documentation
- ๐ Issue Tracker
- ๐ฌ Discussions
---
๐ Benchmarks: Reducing LLM Memory Costs
The benchmarks/CostBenchmarks.ts script estimates token and dollar savings when using MemKitโs retrieval to construct prompts versus a naive LLM approach that includes the entire memory log.
- What it measures:
- Approximate tokens for a full-history prompt vs a retrieval-limited prompt.
- Estimated input cost using configurable per-token pricing.
- Savings in tokens, percent, and cost.
- How to run:
- Build: npx tsc -p tsconfig.json
- Run: node dist/benchmarks/CostBenchmarks.js
This benchmark uses InMemoryStorageAdapter and KeywordRetrievalStrategy for deterministic retrieval and does not call any external APIs.
๐ฏ Examples
Check out the /examples` directory for: