Memory API
The Memory package provides conversation memory, fact extraction, and knowledge management capabilities. It implements persistent memory across interactions and enables models to learn and recall information from previous conversations.
Overview
The Memory package provides:
- Memory Store: Persistent storage for conversation history and extracted facts
- Fact Extraction: Automatic extraction of key information from model responses
- Memory Runner: Enhanced model runner with memory capabilities
- Operation Determination: Intelligent analysis of what operations to perform
- Knowledge Management: Structured storage and retrieval of learned information
Core Classes
MemoryStore
Persistent storage for conversation memory and extracted facts.
import { MemoryStore } from '../src/memory/memory_store.js';
const memoryStore = new MemoryStore();
Methods
addFact(fact: ExtractedFact): Promise<void>
Add a new fact to the memory store.
import { ExtractedFact } from '../src/memory/types.js';
const fact: ExtractedFact = {
id: 'fact-001',
content: 'The user prefers detailed explanations',
category: 'preference',
confidence: 0.9,
timestamp: new Date(),
source: 'conversation-123'
};
await memoryStore.addFact(fact);
Parameters:
fact
: The extracted fact to store
getFacts(category?: string): Promise<ExtractedFact[]>
Retrieve facts from the memory store, optionally filtered by category.
// Get all facts
const allFacts = await memoryStore.getFacts();
// Get facts by category
const preferences = await memoryStore.getFacts('preference');
const knowledge = await memoryStore.getFacts('knowledge');
Parameters:
category
: Optional category filter
Returns: Promise resolving to array of extracted facts
searchFacts(query: string): Promise<ExtractedFact[]>
Search facts by content using semantic similarity.
const relevantFacts = await memoryStore.searchFacts('user preferences');
console.log('Found relevant facts:', relevantFacts.length);
Parameters:
query
: Search query string
Returns: Promise resolving to array of relevant facts
clearFacts(): Promise<void>
Clear all facts from the memory store.
await memoryStore.clearFacts();
console.log('Memory store cleared');
MemoryRunner
Enhanced model runner with memory capabilities and fact extraction.
import { MemoryRunner } from '../src/memory/memory_runner.js';
const memoryRunner = new MemoryRunner();
Methods
execute(interaction: Interaction): Promise<TextResponse>
Execute an interaction with memory capabilities.
import { Interaction } from '../src/interaction/interaction.js';
import { Stimulus } from '../src/interaction/stimulus.js';
const interaction = new Interaction(model, "You are a helpful assistant with memory.");
interaction.addStimulus(new Stimulus("Remember that I prefer detailed explanations."));
const response = await memoryRunner.execute(interaction);
console.log(response.content);
Parameters:
interaction
: The interaction to execute
Returns: Promise resolving to text response with memory integration
extractFacts(response: string): Promise<ExtractedFact[]>
Extract facts from a model response.
const response = "The user's name is John and they work as a software engineer.";
const facts = await memoryRunner.extractFacts(response);
facts.forEach(fact => {
console.log(`Extracted fact: ${fact.content} (${fact.category})`);
});
Parameters:
response
: The model response to analyze
Returns: Promise resolving to array of extracted facts
FactExtractor
Specialized class for extracting structured facts from text.
import { FactExtractor } from '../src/memory/extract_facts.js';
const extractor = new FactExtractor();
Methods
extract(text: string): Promise<ExtractedFact[]>
Extract facts from text using AI analysis.
const text = "Alice is a 30-year-old data scientist who lives in San Francisco. She enjoys hiking and reading science fiction.";
const facts = await extractor.extract(text);
facts.forEach(fact => {
console.log(`${fact.category}: ${fact.content}`);
});
Parameters:
text
: The text to analyze for facts
Returns: Promise resolving to array of extracted facts
extractFromResponse(response: TextResponse): Promise<ExtractedFact[]>
Extract facts from a model response.
const response = await modelRunner.generateText(interaction);
const facts = await extractor.extractFromResponse(response);
Parameters:
response
: The model response to analyze
Returns: Promise resolving to array of extracted facts
OperationDeterminer
Intelligent analysis of what operations to perform based on user input.
import { OperationDeterminer } from '../src/memory/determine_operations.js';
const determiner = new OperationDeterminer();
Methods
determine(text: string): Promise<Operation[]>
Determine what operations should be performed based on text analysis.
const text = "Remember that I prefer detailed explanations and I'm working on a React project.";
const operations = await determiner.determine(text);
operations.forEach(op => {
console.log(`Operation: ${op.type} - ${op.description}`);
});
Parameters:
text
: The text to analyze for operations
Returns: Promise resolving to array of operations to perform
Type Definitions
ExtractedFact
Represents a fact extracted from conversation or text.
interface ExtractedFact {
id: string; // Unique identifier
content: string; // The fact content
category: string; // Fact category (e.g., 'preference', 'knowledge', 'personal')
confidence: number; // Confidence score (0.0 to 1.0)
timestamp: Date; // When the fact was extracted
source: string; // Source of the fact (conversation ID, etc.)
metadata?: Record<string, any>; // Additional metadata
}
Operation
Represents an operation to be performed based on text analysis.
interface Operation {
type: 'store_fact' | 'retrieve_fact' | 'update_fact' | 'delete_fact' | 'search_fact';
description: string; // Human-readable description
parameters: Record<string, any>; // Operation parameters
priority: number; // Priority score (0.0 to 1.0)
confidence: number; // Confidence in the operation (0.0 to 1.0)
}
MemoryConfig
Configuration for memory operations.
interface MemoryConfig {
enableFactExtraction: boolean; // Whether to extract facts automatically
enableMemoryIntegration: boolean; // Whether to integrate memory in responses
factExtractionThreshold: number; // Minimum confidence for fact extraction
maxFactsPerResponse: number; // Maximum facts to extract per response
memoryContextLength: number; // How much memory context to include
}
Usage Examples
Basic Memory Integration
import { MemoryRunner } from '../src/memory/memory_runner.js';
import { Interaction } from '../src/interaction/interaction.js';
import { Stimulus } from '../src/interaction/stimulus.js';
const memoryRunner = new MemoryRunner();
// First interaction - establish preferences
const interaction1 = new Interaction(model, "You are a helpful assistant.");
interaction1.addStimulus(new Stimulus("I prefer detailed explanations with examples."));
const response1 = await memoryRunner.execute(interaction1);
console.log('Response with memory:', response1.content);
// Second interaction - memory should influence response
const interaction2 = new Interaction(model, "You are a helpful assistant.");
interaction2.addStimulus(new Stimulus("Explain quantum computing."));
const response2 = await memoryRunner.execute(interaction2);
// Response should be detailed with examples based on previous preference
console.log('Response with memory context:', response2.content);
Fact Extraction
import { FactExtractor } from '../src/memory/extract_facts.js';
const extractor = new FactExtractor();
const text = `
The user's name is Sarah Johnson. She is a 28-year-old software engineer
working at TechCorp. She specializes in React and TypeScript development.
Sarah prefers detailed technical explanations and enjoys learning about
new programming paradigms. She lives in Seattle and has a dog named Max.
`;
const facts = await extractor.extract(text);
console.log('Extracted facts:');
facts.forEach(fact => {
console.log(`[${fact.category}] ${fact.content} (confidence: ${fact.confidence})`);
});
Memory Store Operations
import { MemoryStore } from '../src/memory/memory_store.js';
import { ExtractedFact } from '../src/memory/types.js';
const memoryStore = new MemoryStore();
// Add facts
const facts: ExtractedFact[] = [
{
id: 'fact-001',
content: 'User prefers detailed explanations',
category: 'preference',
confidence: 0.9,
timestamp: new Date(),
source: 'conversation-1'
},
{
id: 'fact-002',
content: 'User is a software engineer',
category: 'personal',
confidence: 0.8,
timestamp: new Date(),
source: 'conversation-1'
},
{
id: 'fact-003',
content: 'User specializes in React development',
category: 'knowledge',
confidence: 0.7,
timestamp: new Date(),
source: 'conversation-1'
}
];
for (const fact of facts) {
await memoryStore.addFact(fact);
}
// Retrieve facts by category
const preferences = await memoryStore.getFacts('preference');
console.log('User preferences:', preferences.map(f => f.content));
// Search facts
const relevantFacts = await memoryStore.searchFacts('software development');
console.log('Relevant facts:', relevantFacts.map(f => f.content));
Operation Determination
import { OperationDeterminer } from '../src/memory/determine_operations.js';
const determiner = new OperationDeterminer();
const texts = [
"Remember that I prefer detailed explanations",
"What did I tell you about my preferences?",
"Forget what I said about my job",
"Search for information about React development"
];
for (const text of texts) {
const operations = await determiner.determine(text);
console.log(`\nText: "${text}"`);
operations.forEach(op => {
console.log(` Operation: ${op.type} - ${op.description} (priority: ${op.priority})`);
});
}
Advanced Memory Integration
import { MemoryRunner } from '../src/memory/memory_runner.js';
import { MemoryStore } from '../src/memory/memory_store.js';
import { Interaction } from '../src/interaction/interaction.js';
class AdvancedMemorySystem {
private memoryRunner: MemoryRunner;
private memoryStore: MemoryStore;
constructor() {
this.memoryRunner = new MemoryRunner();
this.memoryStore = new MemoryStore();
}
async processInteraction(interaction: Interaction) {
// Execute with memory
const response = await this.memoryRunner.execute(interaction);
// Extract facts from response
const facts = await this.memoryRunner.extractFacts(response.content);
// Store relevant facts
for (const fact of facts) {
if (fact.confidence > 0.7) {
await this.memoryStore.addFact(fact);
}
}
return response;
}
async getRelevantContext(query: string) {
const relevantFacts = await this.memoryStore.searchFacts(query);
return relevantFacts.map(f => f.content).join('; ');
}
}
// Usage
const memorySystem = new AdvancedMemorySystem();
const interaction = new Interaction(model, "You are a helpful assistant.");
interaction.addStimulus(new Stimulus("I'm working on a React project and need help with state management."));
const response = await memorySystem.processInteraction(interaction);
// Later, get relevant context
const context = await memorySystem.getRelevantContext('React state management');
console.log('Relevant context:', context);
Memory Configuration
import { MemoryRunner } from '../src/memory/memory_runner.js';
// Configure memory behavior
const memoryRunner = new MemoryRunner({
enableFactExtraction: true,
enableMemoryIntegration: true,
factExtractionThreshold: 0.8,
maxFactsPerResponse: 5,
memoryContextLength: 1000
});
const interaction = new Interaction(model, "You are a helpful assistant.");
interaction.addStimulus(new Stimulus("Remember my preferences and explain TypeScript generics."));
const response = await memoryRunner.execute(interaction);
Best Practices
1. Fact Quality Management
Ensure high-quality fact extraction:
async function extractHighQualityFacts(text: string, threshold: number = 0.8) {
const extractor = new FactExtractor();
const facts = await extractor.extract(text);
// Filter by confidence
const highQualityFacts = facts.filter(fact => fact.confidence >= threshold);
// Validate fact content
const validFacts = highQualityFacts.filter(fact =>
fact.content.length > 10 &&
fact.content.length < 500 &&
!fact.content.includes('I don\'t know') &&
!fact.content.includes('I cannot')
);
return validFacts;
}
2. Memory Context Management
Manage memory context size to avoid token limits:
async function getOptimizedMemoryContext(query: string, maxTokens: number = 500) {
const memoryStore = new MemoryStore();
const relevantFacts = await memoryStore.searchFacts(query);
// Sort by relevance and recency
const sortedFacts = relevantFacts.sort((a, b) => {
const recencyScore = b.timestamp.getTime() - a.timestamp.getTime();
const relevanceScore = b.confidence - a.confidence;
return relevanceScore * 0.7 + recencyScore * 0.3;
});
// Build context within token limit
let context = '';
for (const fact of sortedFacts) {
const factText = `${fact.category}: ${fact.content}. `;
if ((context + factText).length > maxTokens) break;
context += factText;
}
return context;
}
3. Fact Categorization
Use consistent fact categories for better organization:
const FACT_CATEGORIES = {
PREFERENCE: 'preference',
PERSONAL: 'personal',
KNOWLEDGE: 'knowledge',
SKILL: 'skill',
CONTEXT: 'context',
GOAL: 'goal',
CONSTRAINT: 'constraint'
} as const;
async function categorizeFact(fact: ExtractedFact): Promise<ExtractedFact> {
const content = fact.content.toLowerCase();
if (content.includes('prefer') || content.includes('like') || content.includes('want')) {
fact.category = FACT_CATEGORIES.PREFERENCE;
} else if (content.includes('work') || content.includes('job') || content.includes('company')) {
fact.category = FACT_CATEGORIES.PERSONAL;
} else if (content.includes('know') || content.includes('understand') || content.includes('learn')) {
fact.category = FACT_CATEGORIES.KNOWLEDGE;
} else if (content.includes('can') || content.includes('able') || content.includes('skill')) {
fact.category = FACT_CATEGORIES.SKILL;
}
return fact;
}
4. Memory Persistence
Implement proper memory persistence:
import { writeFileSync, readFileSync, existsSync } from 'fs';
class PersistentMemoryStore extends MemoryStore {
private filePath: string;
constructor(filePath: string = './memory.json') {
super();
this.filePath = filePath;
this.loadFromDisk();
}
private loadFromDisk() {
if (existsSync(this.filePath)) {
try {
const data = readFileSync(this.filePath, 'utf-8');
const facts = JSON.parse(data);
// Restore facts to memory
facts.forEach(fact => this.addFact(fact));
} catch (error) {
console.error('Failed to load memory from disk:', error);
}
}
}
async addFact(fact: ExtractedFact): Promise<void> {
await super.addFact(fact);
this.saveToDisk();
}
private saveToDisk() {
try {
const facts = this.getFacts();
writeFileSync(this.filePath, JSON.stringify(facts, null, 2));
} catch (error) {
console.error('Failed to save memory to disk:', error);
}
}
}
5. Memory Privacy
Implement privacy controls for sensitive information:
class PrivacyAwareMemoryStore extends MemoryStore {
private sensitivePatterns = [
/password/i,
/api.?key/i,
/token/i,
/secret/i,
/\b\d{3}-\d{2}-\d{4}\b/, // SSN pattern
/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/ // Credit card pattern
];
async addFact(fact: ExtractedFact): Promise<void> {
// Check for sensitive information
if (this.containsSensitiveInfo(fact.content)) {
console.warn('Skipping fact with potentially sensitive information');
return;
}
await super.addFact(fact);
}
private containsSensitiveInfo(content: string): boolean {
return this.sensitivePatterns.some(pattern => pattern.test(content));
}
}
Integration with Other Packages
With Cognition Package
import { MemoryRunner } from '../src/memory/memory_runner.js';
import { BaseModelRunner } from '../src/cognition/runner.js';
// MemoryRunner extends BaseModelRunner functionality
const memoryRunner = new MemoryRunner();
const baseRunner = new BaseModelRunner();
// MemoryRunner provides additional memory capabilities
const response = await memoryRunner.execute(interaction);
With Interaction Package
import { MemoryRunner } from '../src/memory/memory_runner.js';
import { Interaction } from '../src/interaction/interaction.js';
const memoryRunner = new MemoryRunner();
// Memory integrates with interactions
const interaction = new Interaction(model, "You are a helpful assistant with memory.");
interaction.addStimulus(new Stimulus("Remember my preferences and help me with this task."));
const response = await memoryRunner.execute(interaction);
With Evaluation Package
import { MemoryRunner } from '../src/memory/memory_runner.js';
import { EvaluationRunner } from '../src/evaluation/runner.js';
// Evaluate memory capabilities
const memoryRunner = new MemoryRunner();
const evaluator = new EvaluationRunner();
const interaction = new Interaction(model, "You are a helpful assistant.");
interaction.addStimulus(new Stimulus("Remember that I prefer detailed explanations."));
// Test memory retention
const evaluation = await evaluator.evaluate(interaction, {
memoryRunner,
testMemoryRetention: true
});