MemoryOperations.js•9.53 kB
export class MemoryOperations {
constructor(factStore, qualityScorer) {
this.factStore = factStore;
this.qualityScorer = qualityScorer;
}
registerTools(server) {
this.registerStoreInsightTool(server);
this.registerUpdateFactTool(server);
this.registerDeleteFactTool(server);
this.registerGetStatsTool(server);
this.registerGetRelatedTool(server);
}
registerStoreInsightTool(server) {
server.registerTool(
'memory_store_insight',
'Store a new insight, pattern, or piece of knowledge in the memory system',
{
type: 'object',
properties: {
content: {
type: 'string',
description: 'The insight or knowledge content to store',
},
type: {
type: 'string',
description: 'The type of fact (verified_pattern, anti_pattern, optimization, etc.)',
enum: [
'verified_pattern',
'anti_pattern',
'optimization',
'discovery',
'constraint',
'debugging_solution',
'tool_configuration',
'decision_rationale',
'experimental_approach',
'workflow_improvement',
'security_concern',
],
},
domain: {
type: 'string',
description: 'The domain or area this applies to (e.g., web_development, data_science)',
},
tags: {
type: 'array',
items: { type: 'string' },
description: 'Tags to categorize this insight',
},
context: {
type: 'object',
description: 'Additional context about the technology, framework, or situation',
},
},
required: ['content'],
},
async (args) => {
return await this.handleStoreInsight(args);
}
);
}
registerUpdateFactTool(server) {
server.registerTool(
'memory_update_fact',
'Update an existing fact in the memory system',
{
type: 'object',
properties: {
factId: {
type: 'string',
description: 'The ID of the fact to update',
},
updates: {
type: 'object',
description: 'The updates to apply to the fact',
},
},
required: ['factId', 'updates'],
},
async (args) => {
return await this.handleUpdateFact(args);
}
);
}
registerDeleteFactTool(server) {
server.registerTool(
'memory_delete_fact',
'Delete a fact from the memory system',
{
type: 'object',
properties: {
factId: {
type: 'string',
description: 'The ID of the fact to delete',
},
},
required: ['factId'],
},
async (args) => {
return await this.handleDeleteFact(args);
}
);
}
registerGetStatsTool(server) {
server.registerTool(
'memory_get_stats',
'Get statistics about the memory system',
{
type: 'object',
properties: {},
},
async (args) => {
return await this.handleGetStats(args);
}
);
}
registerGetRelatedTool(server) {
server.registerTool(
'memory_get_related',
'Get facts related to a specific fact',
{
type: 'object',
properties: {
factId: {
type: 'string',
description: 'The ID of the fact to find related facts for',
},
maxDepth: {
type: 'number',
description: 'Maximum relationship depth to traverse',
default: 2,
},
},
required: ['factId'],
},
async (args) => {
return await this.handleGetRelated(args);
}
);
}
async handleStoreInsight(args) {
try {
const { content, type, domain, tags = [], context = {} } = args;
if (!content || content.trim().length === 0) {
throw new Error('Content is required and cannot be empty');
}
const fact = {
content: content.trim(),
type,
domain,
tags,
context,
metadata: {
source: 'manual_input',
addedAt: new Date().toISOString(),
},
};
const storedFact = await this.factStore.storeFact(fact);
const qualityResult = this.qualityScorer.calculateQualityScore(storedFact);
return {
content: [
{
type: 'text',
text: `✅ Insight stored successfully!\n\n**ID:** ${storedFact.id}\n**Type:** ${storedFact.type}\n**Quality Score:** ${qualityResult.totalScore}/100\n**Domain:** ${storedFact.domain || 'general'}\n\n**Content:** ${storedFact.content}`,
},
],
};
} catch (error) {
return {
content: [
{
type: 'text',
text: `Error storing insight: ${error.message}`,
},
],
isError: true,
};
}
}
async handleUpdateFact(args) {
try {
const { factId, updates } = args;
const updatedFact = await this.factStore.updateFact(factId, updates);
return {
content: [
{
type: 'text',
text: `✅ Fact updated successfully!\n\n**ID:** ${updatedFact.id}\n**Updated:** ${updatedFact.updatedAt}\n\n**Content:** ${updatedFact.content}`,
},
],
};
} catch (error) {
return {
content: [
{
type: 'text',
text: `Error updating fact: ${error.message}`,
},
],
isError: true,
};
}
}
async handleDeleteFact(args) {
try {
const { factId } = args;
await this.factStore.deleteFact(factId);
return {
content: [
{
type: 'text',
text: `✅ Fact ${factId} deleted successfully.`,
},
],
};
} catch (error) {
return {
content: [
{
type: 'text',
text: `Error deleting fact: ${error.message}`,
},
],
isError: true,
};
}
}
async handleGetStats(args) {
try {
const stats = await this.factStore.getStats();
let response = `📊 **Memory System Statistics**\n\n`;
response += `**Total Facts:** ${stats.totalFacts}\n`;
response += `**Average Quality:** ${stats.averageQualityScore}/100\n\n`;
if (Object.keys(stats.factsByType).length > 0) {
response += `**Facts by Type:**\n`;
for (const [type, count] of Object.entries(stats.factsByType)) {
response += `- ${type.replace('_', ' ')}: ${count}\n`;
}
response += `\n`;
}
if (Object.keys(stats.factsByDomain).length > 0) {
response += `**Facts by Domain:**\n`;
for (const [domain, count] of Object.entries(stats.factsByDomain)) {
response += `- ${domain}: ${count}\n`;
}
}
return {
content: [
{
type: 'text',
text: response.trim(),
},
],
};
} catch (error) {
return {
content: [
{
type: 'text',
text: `Error getting stats: ${error.message}`,
},
],
isError: true,
};
}
}
async handleGetRelated(args) {
try {
const { factId, maxDepth = 2 } = args;
const related = await this.factStore.getRelatedFacts(factId, maxDepth);
if (related.length === 0) {
return {
content: [
{
type: 'text',
text: `No related facts found for ${factId}`,
},
],
};
}
let response = `🔗 **Related Facts for ${factId}:**\n\n`;
for (const item of related) {
response += `**${item.relationship}** (depth ${item.depth})\n`;
response += `${item.fact.type}: ${item.fact.content.substring(0, 100)}...\n\n`;
}
return {
content: [
{
type: 'text',
text: response.trim(),
},
],
};
} catch (error) {
return {
content: [
{
type: 'text',
text: `Error getting related facts: ${error.message}`,
},
],
isError: true,
};
}
}
async storeInsight(insight) {
try {
const scoreResult = this.qualityScorer.calculateQualityScore(insight);
const qualityScore = scoreResult.totalScore;
const fact = {
id: `fact_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
content: insight.content,
type: insight.type || 'discovery',
domain: insight.domain || 'general',
tags: insight.tags || [],
context: insight.context || {},
qualityScore,
timestamp: new Date().toISOString(),
accessCount: 0,
lastAccessed: new Date().toISOString(),
};
await this.factStore.storeFact(fact);
return {
success: true,
factId: fact.id,
qualityScore: fact.qualityScore,
message: `Insight stored with quality score ${qualityScore}/100`,
...fact,
};
} catch (error) {
throw new Error(`Failed to store insight: ${error.message}`);
}
}
}