Framework-agnostic hierarchical memory system for AI agents
Based on xMemory and Memory Taxonomy research papers.
| Feature | Description |
|---|---|
| Framework-Agnostic | Works with OpenClaw, LangChain, or standalone |
| Hierarchical Storage | 4-level memory hierarchy (Original → Episode → Semantic → Theme) |
| 3D Taxonomy | Form × Function × Dynamics classification |
| Knowledge Graph | Entity-relationship management with path finding |
| Multi-Hop Reasoning | Complex inference across memory hierarchy |
| Forgetting Mechanism | Ebbinghaus curve-based memory lifecycle |
| Conflict Detection | Automatic detection and resolution of memory conflicts |
| Zero Config | Works out of the box, no setup required |
| Cross-Platform | Pure JavaScript, no native dependencies |
| Type-Safe | Full TypeScript support |
# Create .npmrc file (one-time setup)
echo "@kakezh:registry=https://npm.pkg.github.com" > ~/.npmrc
# Install
npm install @kakezh/memory-xgit clone https://github.com/Kakezh/openclaw-memoryplus.git
cd openclaw-memoryplus/extensions/memory-x
pnpm install && pnpm buildimport { MemoryEngine } from '@kakezh/memory-x';
// Create engine (zero config)
const memory = new MemoryEngine();
await memory.init();
// Store a memory
await memory.remember("User prefers dark mode", {
type: "preference",
confidence: 0.9,
entities: ["User"]
});
// Recall memories
const result = await memory.recall("user preferences");
console.log(result.evidence);
// Get statistics
const stats = memory.stats();
console.log(stats);import { createMemoryX } from '@kakezh/memory-x';
const adapter = await createMemoryX();
// Get all tools
const tools = adapter.getTools();
// Execute a tool
const result = await adapter.execute('memory_remember', {
content: "User likes TypeScript",
type: "preference"
});import { createOpenClawPlugin } from '@kakezh/memory-x/adapters/openclaw';
export default createOpenClawPlugin({
workspacePath: "./data"
});┌─────────────────────────────────────────────────────────────────────────────┐
│ Memory-X System Architecture │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Framework-Agnostic Core │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Memory │ │ Vector │ │ Dynamics │ │ │
│ │ │ Engine │ │ Index │ │ (Forget) │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Knowledge │ │ Multi-Hop │ │ Conflict │ │ │
│ │ │ Graph │ │ Reasoning │ │ Detector │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────┼───────────────────────────────────┐ │
│ │ Adapters Layer │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Generic │ │ OpenClaw │ │ LangChain │ │ │
│ │ │ Adapter │ │ Adapter │ │ Adapter │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────┼───────────────────────────────────┐ │
│ │ Storage Layer │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ SQLite (sql.js / better-sqlite3) - Auto-select backend │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
memory-x/
├── core/ # Framework-agnostic core
│ ├── engine.ts # MemoryEngine class
│ ├── types.ts # Type definitions
│ └── index.ts # Core exports
│
├── adapters/ # Framework adapters
│ ├── generic.ts # Generic adapter (any project)
│ ├── openclaw.ts # OpenClaw adapter
│ └── index.ts # Adapter exports
│
├── store/ # Storage implementations
│ ├── sqlite-store.ts # Native SQLite (better-sqlite3)
│ ├── sqljs-store.ts # Pure JS SQLite (sql.js)
│ └── vector-index.ts # Vector similarity search
│
├── dynamics/ # Memory lifecycle
│ ├── forgetting.ts # Ebbinghaus forgetting curve
│ └── conflict.ts # Conflict detection & resolution
│
└── reasoning/ # Advanced reasoning
├── knowledge-graph.ts # Entity-relationship graph
└── multi-hop.ts # Multi-hop inference engine
Memory-X implements a hierarchical memory structure inspired by human cognition:
┌─────────────────────────────────────────────────────────────────────────────┐
│ Level 4: Theme (主题) │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ High-level concepts: User preferences, projects, domain knowledge │ │
│ │ Example: { name: "编程偏好", semanticIds: ["sem-1", "sem-2"] } │ │
│ │ Auto-created from entity references in semantic memories │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ ▲ │
│ │ contains │
│ Level 3: Semantic (语义) │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ Reusable facts: preferences, goals, constraints, events │ │
│ │ Example: { content: "User prefers TypeScript", type: "preference" } │ │
│ │ Extracted from episodes, can be searched semantically │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ ▲ │
│ │ extracted from │
│ Level 2: Episode (片段) │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ Contiguous message blocks: conversation segments, task context │ │
│ │ Example: { summary: "讨论项目架构...", originalIds: ["orig-1"] } │ │
│ │ Grouped by topic or time boundaries │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ ▲ │
│ │ contains │
│ Level 1: Original (原始) │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ Raw messages: User input, Agent responses │ │
│ │ Example: { content: "请帮我写一个函数", speaker: "user" } │ │
│ │ Immutable record of all interactions │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
Data Flow:
User Input → Original → Episode → Semantic → Theme
↓ ↓ ↓ ↓
Raw Log Summarize Extract Organize
Memory-X classifies memories across three dimensions:
Form
│
┌───────────┼───────────┐
│ │ │
token parametric latent
(context) (weights) (hidden)
│ │ │
└───────────┼───────────┘
│
┌────────────────┼────────────────┐
│ │ │
Function Function Function
│ │ │
factual experiential working
(objective) (personal) (temporal)
│ │ │
└────────────────┼────────────────┘
│
┌───────────┼───────────┐
│ │ │
Forgetting Conflict Reconstruction
Curve Resolution (future)
│ │ │
└───────────┼───────────┘
│
Dynamics
| Dimension | Values | Description |
|---|---|---|
| Form | token, parametric, latent | Where memory exists |
| Function | factual, experiential, working | What memory is used for |
| Dynamics | forgetting, conflict, reconstruction | How memory evolves |
type MemoryType =
| 'fact' // Objective truth: "Paris is the capital of France"
| 'preference' // User preferences: "User prefers dark mode"
| 'goal' // Goals and objectives: "Complete the project by Friday"
| 'constraint' // Rules and limits: "API rate limit is 1000/hour"
| 'event'; // Time-based events: "Meeting scheduled for 3pm"Memory-X automatically builds a knowledge graph from entity references:
// Entity Types
type EntityType =
| 'person' // People
| 'organization' // Companies, teams
| 'location' // Places
| 'concept' // Abstract concepts
| 'event' // Events
| 'object' // Physical objects
| 'topic'; // Topics/subjects
// Relation Types
type RelationType =
| 'related_to' // Generic relation
| 'part_of' // Composition
| 'has_property' // Property
| 'prefers' // Preference
| 'dislikes' // Dislike
| 'works_at' // Employment
| 'located_in' // Location
| 'occurred_at' // Event location
| 'caused_by' // Causation
| 'follows' // Sequence
| 'contradicts'; // ConflictExample Graph:
┌─────────┐ prefers ┌─────────┐
│ User │──────────────▶│Dark Mode│
└─────────┘ └─────────┘
│
│ works_at
▼
┌─────────┐ located_in ┌─────────┐
│Acme Corp│──────────────▶│New York │
└─────────┘ └─────────┘
Based on the Ebbinghaus forgetting curve:
Retention
│
1.0 ┤●
│ ╲
0.8 ┤ ●
│ ╲
0.6 ┤ ●
│ ╲
0.4 ┤ ●
│ ╲
0.2 ┤ ●●●
│
0.0 ┤──────────────────────▶ Time (days)
0 1 2 5 10 30
Formula: R = e^(-t/S) where:
R= Retention scoret= Time elapsed (days)S= Stability (increases with access count)
Importance Score considers:
- Confidence level
- Memory type weight
- Entity connections
- Theme membership
Automatically detects and resolves conflicts:
| Conflict Type | Example | Resolution |
|---|---|---|
| Factual | "User is 25" vs "User is 30" | Keep highest confidence |
| Preference | "User likes X" vs "User dislikes X" | Ask user or keep newest |
| Temporal | Overlapping validity periods | Merge or split |
class MemoryEngine {
constructor(config?: MemoryConfig);
// Lifecycle
init(): Promise<void>;
close(): void;
// Core methods
remember(content: string, options?: RememberOptions): Promise<RememberResult>;
recall(query: string, options?: RecallOptions): Promise<RecallResult>;
reflect(): Promise<ReflectResult>;
stats(): MemoryStats;
// Tool interface
getTools(): MemoryTool[];
executeTool(name: string, params: any): Promise<MemoryToolResult>;
// Events
on(event: string, handler: MemoryEventHandler): void;
}Store a memory with automatic hierarchy classification:
await memory.remember("User prefers dark mode", {
type: "preference", // Memory type
confidence: 0.9, // Confidence score (0-1)
entities: ["User"] // Entity references for knowledge graph
});
// Returns:
// {
// success: true,
// ids: {
// original: "orig-...",
// episode: "ep-...",
// semantic: "sem-...",
// theme: "theme-..."
// }
// }Retrieve memories using semantic search:
const result = await memory.recall("user preferences", {
maxTokens: 4000 // Maximum tokens to return
});
// Returns:
// {
// evidence: {
// themes: [{ id, name }],
// semantics: [{ id, content, score }],
// episodes: [{ id, summary }]
// },
// metrics: {
// totalTokens: 1234,
// evidenceDensity: 0.85
// }
// }Discover patterns from memory themes:
const patterns = await memory.reflect();
// Returns:
// {
// patterns: [{
// themeId: "theme-...",
// themeName: "编程偏好",
// occurrenceCount: 5,
// suggestedSkill: "SOP for 编程偏好"
// }],
// evolutionSuggestions: [...]
// }| Tool | Parameters | Description |
|---|---|---|
memory_remember |
content, type?, confidence?, entities? |
Store memory |
memory_recall |
query, maxTokens? |
Retrieve memories |
memory_reflect |
- | Discover patterns |
memory_status |
- | Get statistics |
interface MemoryConfig {
workspacePath?: string; // Storage path (default: "./memory-data")
storage?: "sqlite" | "memory"; // Storage backend (default: "sqlite")
hierarchy?: {
maxThemeSize?: number; // Max memories per theme (default: 50)
minThemeCoherence?: number; // Min coherence score (default: 0.7)
autoReorganize?: boolean; // Auto-reorganize themes (default: true)
};
retrieval?: {
themeTopK?: number; // Top themes to retrieve (default: 3)
semanticTopK?: number; // Top semantics to retrieve (default: 5)
maxTokens?: number; // Max tokens in response (default: 4000)
};
}
interface RememberOptions {
type?: "fact" | "preference" | "goal" | "constraint" | "event";
confidence?: number; // 0-1, default: 0.5
entities?: string[]; // Entity references
}
interface RecallOptions {
maxTokens?: number; // Default: 4000
}const memory = new MemoryEngine({
workspacePath: "./my-memory-data"
});
await memory.init();const memory = new MemoryEngine({
workspacePath: "./data",
storage: "sqlite",
hierarchy: {
maxThemeSize: 50,
minThemeCoherence: 0.7,
autoReorganize: true
},
retrieval: {
themeTopK: 3,
semanticTopK: 5,
maxTokens: 4000
}
});
await memory.init();Memory-X automatically selects the best available storage backend:
| Backend | Performance | Portability | Dependencies |
|---|---|---|---|
| better-sqlite3 | ⚡ Fastest | Platform-specific | Native compilation |
| sql.js | 🔄 Good | Cross-platform | Pure JavaScript |
No configuration needed - the system auto-detects and uses the best available option.
The following metrics are based on the xMemory research paper:
| Metric | Value | Description |
|---|---|---|
| Token Efficiency | -30% | Reduction vs flat retrieval through hierarchical filtering |
| QA Accuracy | +10% | Improvement vs RAG baseline with evidence density scoring |
| Evidence Density | 2× | Higher relevance vs simple top-k retrieval |
The following metrics are from actual benchmark tests run on:
| Environment | Value |
|---|---|
| Platform | Linux x64 |
| Node.js | v22.22.0 |
| CPU Cores | 16 |
| Total RAM | 6.70 GB |
| Operation | Mean | P50 | P95 | P99 |
|---|---|---|---|---|
| Single Write | 49.02 µs | 14.55 µs | 103.38 µs | 1.50 ms |
| Batch Write (100) | 1.14 ms | 635.42 µs | 3.24 ms | 3.24 ms |
| Search (100 memories) | 6.25 µs | 2.64 µs | 9.99 µs | 131.48 µs |
| Search (500 memories) | 3.86 µs | 3.09 µs | 8.14 µs | 10.87 µs |
| Search (1000 memories) | 9.46 µs | 7.61 µs | 13.82 µs | 49.75 µs |
| Search (5000 memories) | 57.19 µs | 38.83 µs | 79.34 µs | 803.95 µs |
| Operation | Mean | P50 | P95 | Grade |
|---|---|---|---|---|
| Remember (4-level) | 7.13 µs | 6.58 µs | 11.41 µs | 🟢 Excellent |
| Recall (500 memories) | 5.26 µs | 4.63 µs | 8.46 µs | 🟢 Excellent |
| Reflect (100 memories) | 30.60 µs | 1.98 µs | 341.47 µs | 🟢 Excellent |
| Stats (1000 memories) | 3.14 µs | 3.02 µs | 3.42 µs | 🟢 Excellent |
| Metric | Value |
|---|---|
| Per Memory Overhead | ~882 B |
| 1000 Memories | ~861 KB |
| Aspect | Description |
|---|---|
| Storage | SQLite with auto-select backend (sql.js / better-sqlite3) |
| Search | Keyword-based with vector similarity (when embedding provider configured) |
| Memory Model | 4-level hierarchy with automatic classification |
cd extensions/memory-x
pnpm benchResults are saved to bench/results.json.
memory.on('memory:created', (event) => {
console.log('New memory:', event.payload);
});
memory.on('memory:conflict', (event) => {
console.log('Conflict detected:', event.payload);
});import { IEmbeddingProvider } from '@kakezh/memory-x';
class MyEmbeddingProvider implements IEmbeddingProvider {
async embed(text: string): Promise<number[]> {
// Your embedding logic
return [/* vector */];
}
async embedBatch(texts: string[]): Promise<number[][]> {
return Promise.all(texts.map(t => this.embed(t)));
}
}
memory.setEmbeddingProvider(new MyEmbeddingProvider());// 1. Use appropriate memory types
await memory.remember("Paris is the capital of France", { type: "fact" });
await memory.remember("User prefers dark mode", { type: "preference" });
await memory.remember("Complete project by Friday", { type: "goal" });
await memory.remember("API rate limit is 1000/hour", { type: "constraint" });
await memory.remember("Meeting at 3pm", { type: "event" });
// 2. Provide entity references for knowledge graph
await memory.remember("John works at Acme Corp", {
type: "fact",
entities: ["John", "Acme Corp"]
});
// 3. Set confidence for uncertain information
await memory.remember("User might be interested in Python", {
type: "preference",
confidence: 0.6
});
// 4. Always close the engine when done
process.on('SIGTERM', () => memory.close());- xMemory: Beyond RAG for Agent Memory - Four-level hierarchy concept
- Memory Taxonomy: Memory in the Age of AI Agents - 3D classification system
- AMemGym: Interactive Memory Benchmarking - Evaluation framework
- ✅ Framework-agnostic architecture (Core + Adapters)
- ✅ Published to GitHub Packages
- ✅ Zero configuration setup
- ✅ Cross-platform support (sql.js)
- ✅ Full TypeScript support
- ✅ Knowledge graph with path finding
- ✅ Multi-hop reasoning engine
- ✅ Ebbinghaus forgetting mechanism
- ✅ Conflict detection & resolution
MIT © Kakezh
Author: Kakezh
Repository: github.com/Kakezh/openclaw-memoryplus
Package: @kakezh/memory-x
Documentation: INTEGRATION.md | ARCHITECTURE.md