Files
nexus-mcp/src/server/memory.ts

107 lines
2.7 KiB
TypeScript

import crypto from 'node:crypto';
import { MemoryItem } from '../types.js';
class MemoryStore {
private items: Map<string, MemoryItem> = new Map();
constructor() {
// Seed with initial self-hosting memory
this.set({
key: 'system_welcome',
value: {
server: 'Do Everything API & MCP Server',
mcpVersion: '2024-11-05',
status: 'Online and ready for Agent connection.',
},
tags: ['system', 'welcome', 'mcp'],
agentId: 'system',
});
}
public set(params: {
key: string;
value: any;
tags?: string[];
agentId?: string;
ttlSeconds?: number;
}): MemoryItem {
const existing = this.items.get(params.key);
const now = new Date().toISOString();
const item: MemoryItem = {
id: existing ? existing.id : crypto.randomUUID(),
key: params.key,
value: params.value,
tags: params.tags || (existing ? existing.tags : []),
agentId: params.agentId || (existing ? existing.agentId : 'agent'),
createdAt: existing ? existing.createdAt : now,
updatedAt: now,
ttlSeconds: params.ttlSeconds,
};
this.items.set(params.key, item);
return item;
}
public get(key: string): MemoryItem | null {
const item = this.items.get(key);
if (!item) return null;
// Check TTL expiration
if (item.ttlSeconds) {
const created = new Date(item.updatedAt).getTime();
if (Date.now() - created > item.ttlSeconds * 1000) {
this.items.delete(key);
return null;
}
}
return item;
}
public delete(key: string): boolean {
return this.items.delete(key);
}
public list(tagFilter?: string, limit = 50): MemoryItem[] {
let result = Array.from(this.items.values());
if (tagFilter) {
result = result.filter(item => item.tags.some(t => t.toLowerCase() === tagFilter.toLowerCase()));
}
result.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
return result.slice(0, limit);
}
public search(query?: string, tag?: string): MemoryItem[] {
let result = Array.from(this.items.values());
if (tag) {
result = result.filter(item => item.tags.includes(tag));
}
if (query && query.trim().length > 0) {
const q = query.toLowerCase();
result = result.filter(item => {
const keyMatch = item.key.toLowerCase().includes(q);
const valMatch = JSON.stringify(item.value).toLowerCase().includes(q);
const tagMatch = item.tags.some(t => t.toLowerCase().includes(q));
return keyMatch || valMatch || tagMatch;
});
}
return result;
}
public count(): number {
return this.items.size;
}
public clear(): void {
this.items.clear();
}
}
export const memoryStore = new MemoryStore();