107 lines
2.7 KiB
TypeScript
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();
|