memory-provider-mem0.mjs
120 lines 3.3 KB
Raw
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor ⚠ breaking 20 hours ago
1 /**
2 * Mem0 API-backed memory provider.
3 * Delegates storage and search to an external Mem0 instance at config.memory.url.
4 * Falls back to file provider for listEvents/getStats when the API is unavailable.
5 * Phase 8 Memory Augmentation.
6 *
7 * Mem0 API assumed endpoints (https://docs.mem0.ai/):
8 * POST /v1/memories/ — add memory
9 * GET /v1/memories/ — list memories
10 * POST /v1/memories/search — search memories
11 * DELETE /v1/memories/:id — delete memory
12 */
13
14 import { FileMemoryProvider } from './memory-provider-file.mjs';
15
16 export class Mem0MemoryProvider {
17 #fileProvider;
18 #baseUrl;
19 #apiKey;
20
21 /**
22 * @param {string} baseDir — local memory directory (for file fallback)
23 * @param {{ url: string, apiKey?: string }} opts
24 */
25 constructor(baseDir, opts) {
26 this.#fileProvider = new FileMemoryProvider(baseDir);
27 this.#baseUrl = (opts.url || '').replace(/\/$/, '');
28 this.#apiKey = opts.apiKey || process.env.MEM0_API_KEY || '';
29 }
30
31 get baseDir() {
32 return this.#fileProvider.baseDir;
33 }
34
35 #headers() {
36 const h = { 'Content-Type': 'application/json' };
37 if (this.#apiKey) h['Authorization'] = `Bearer ${this.#apiKey}`;
38 return h;
39 }
40
41 /**
42 * Store event in both file log and Mem0 API.
43 * @param {object} event
44 * @returns {{ id: string, ts: string }}
45 */
46 storeEvent(event) {
47 const result = this.#fileProvider.storeEvent(event);
48 this.#storeToMem0Async(event).catch(() => {});
49 return result;
50 }
51
52 async #storeToMem0Async(event) {
53 if (!this.#baseUrl) return;
54 try {
55 const text = `[${event.type}] ${JSON.stringify(event.data)}`;
56 await fetch(`${this.#baseUrl}/v1/memories/`, {
57 method: 'POST',
58 headers: this.#headers(),
59 body: JSON.stringify({
60 messages: [{ role: 'user', content: text }],
61 metadata: { knowtation_id: event.id, type: event.type, ts: event.ts, vault_id: event.vault_id },
62 }),
63 });
64 } catch (_) {}
65 }
66
67 getLatest(type) {
68 return this.#fileProvider.getLatest(type);
69 }
70
71 listEvents(opts) {
72 return this.#fileProvider.listEvents(opts);
73 }
74
75 /**
76 * Semantic search via Mem0 API.
77 * @param {string} query
78 * @param {{ limit?: number }} [opts]
79 * @returns {Promise<object[]>}
80 */
81 async searchEvents(query, opts = {}) {
82 if (!this.#baseUrl) return [];
83 try {
84 const res = await fetch(`${this.#baseUrl}/v1/memories/search`, {
85 method: 'POST',
86 headers: this.#headers(),
87 body: JSON.stringify({ query, limit: opts.limit ?? 10 }),
88 });
89 if (!res.ok) return [];
90 const data = await res.json();
91 const memories = data.results || data.memories || data || [];
92 if (!Array.isArray(memories)) return [];
93 return memories.map((m) => ({
94 id: m.metadata?.knowtation_id || m.id,
95 type: m.metadata?.type || 'unknown',
96 ts: m.metadata?.ts || m.created_at || '',
97 data: { text: m.memory || m.content || '' },
98 score: m.score ?? null,
99 }));
100 } catch (_) {
101 return [];
102 }
103 }
104
105 supportsSearch() {
106 return Boolean(this.#baseUrl);
107 }
108
109 clearEvents(opts) {
110 return this.#fileProvider.clearEvents(opts);
111 }
112
113 pruneExpired(retentionDays) {
114 return this.#fileProvider.pruneExpired(retentionDays);
115 }
116
117 getStats() {
118 return this.#fileProvider.getStats();
119 }
120 }
File History 2 commits
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor 20 hours ago
sha256:9103f98c89257ed2b01c237cea895dabb3e85ea337dccb1161c175e4422355b6 docs: accept Calendar Events v0 spec with Phase 0 security … Human 1 day ago