mr-memory 2.11.8 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.ts +20 -13
- package/package.json +1 -1
- package/upload.ts +70 -0
package/index.ts
CHANGED
|
@@ -276,11 +276,17 @@ const memoryRouterPlugin = {
|
|
|
276
276
|
.map(b => b.text!)
|
|
277
277
|
.join("\n");
|
|
278
278
|
}
|
|
279
|
-
|
|
280
|
-
|
|
279
|
+
if (!text) continue;
|
|
280
|
+
// Sanitize ALL roles: strip memory injections, envelope metadata, system noise
|
|
281
|
+
const cleaned = sanitizeForIngest(text);
|
|
282
|
+
if (!cleaned || isSystemNoise(cleaned)) continue;
|
|
283
|
+
contextPayload.push({ role: m.role, content: cleaned });
|
|
281
284
|
}
|
|
282
285
|
}
|
|
283
|
-
|
|
286
|
+
const cleanedPrompt = sanitizeForIngest(prompt);
|
|
287
|
+
if (cleanedPrompt && !isSystemNoise(cleanedPrompt)) {
|
|
288
|
+
contextPayload.push({ role: "user", content: cleanedPrompt });
|
|
289
|
+
}
|
|
284
290
|
|
|
285
291
|
|
|
286
292
|
const res = await fetch(`${endpoint}/v1/memory/prepare`, {
|
|
@@ -359,9 +365,8 @@ const memoryRouterPlugin = {
|
|
|
359
365
|
contextPayload.push({ role: "system", content: fullContext });
|
|
360
366
|
}
|
|
361
367
|
|
|
362
|
-
// Add conversation history
|
|
368
|
+
// Add conversation history (sanitized — strip noise, metadata, old memory injections)
|
|
363
369
|
if (event.messages && Array.isArray(event.messages)) {
|
|
364
|
-
let skipped = 0;
|
|
365
370
|
for (const msg of event.messages) {
|
|
366
371
|
const m = msg as { role?: string; content?: unknown };
|
|
367
372
|
if (!m.role) continue;
|
|
@@ -377,17 +382,19 @@ const memoryRouterPlugin = {
|
|
|
377
382
|
.join("\n");
|
|
378
383
|
}
|
|
379
384
|
|
|
380
|
-
if (text)
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
}
|
|
385
|
+
if (!text) continue;
|
|
386
|
+
// Sanitize ALL roles: strip memory injections, envelope metadata, system noise
|
|
387
|
+
const cleaned = sanitizeForIngest(text);
|
|
388
|
+
if (!cleaned || isSystemNoise(cleaned)) continue;
|
|
389
|
+
contextPayload.push({ role: m.role, content: cleaned });
|
|
386
390
|
}
|
|
387
391
|
}
|
|
388
392
|
|
|
389
|
-
// Add current user prompt (
|
|
390
|
-
|
|
393
|
+
// Add current user prompt (sanitized)
|
|
394
|
+
const cleanedPrompt = sanitizeForIngest(prompt);
|
|
395
|
+
if (cleanedPrompt && !isSystemNoise(cleanedPrompt)) {
|
|
396
|
+
contextPayload.push({ role: "user", content: cleanedPrompt });
|
|
397
|
+
}
|
|
391
398
|
|
|
392
399
|
// 4. Call /v1/memory/prepare
|
|
393
400
|
|
package/package.json
CHANGED
package/upload.ts
CHANGED
|
@@ -5,6 +5,71 @@
|
|
|
5
5
|
import fs from "node:fs/promises";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
|
|
8
|
+
// ── Sanitization utilities (shared with index.ts ingest logic)
|
|
9
|
+
// These MUST stay in sync with the patterns in index.ts
|
|
10
|
+
|
|
11
|
+
const MEMORY_TAG_RE = /<mr-memory>[\s\S]*?<\/mr-memory>\s*/g;
|
|
12
|
+
const LEGACY_TAG_RE = /<memory_context>[\s\S]*?<\/memory_context>\s*(?:The above are retrieved memories|IMPORTANT: The above block contains retrieved memories)[^\n]*\n*/g;
|
|
13
|
+
function stripOldMemory(text: string): string {
|
|
14
|
+
return text.replace(MEMORY_TAG_RE, "").replace(LEGACY_TAG_RE, "").trim();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const ENVELOPE_METADATA_RE = /Conversation info \(untrusted metadata\):\s*```json\s*\{[^}]*\}\s*```\s*/g;
|
|
18
|
+
const SENDER_METADATA_RE = /Sender \(untrusted metadata\):\s*```json\s*\{[^}]*\}\s*```\s*/g;
|
|
19
|
+
const REPLY_CONTEXT_RE = /Replied message \(untrusted, for context\):\s*```json\s*\{[^}]*\}\s*```\s*/g;
|
|
20
|
+
const MEMORY_INSTRUCTION_RE = /The above are retrieved memories from past conversations[^\n]*\n*/g;
|
|
21
|
+
const IMPORTANT_MEMORY_RE = /IMPORTANT: The above (?:are retrieved memories|block contains retrieved memories)[^\n]*\n*/g;
|
|
22
|
+
|
|
23
|
+
const MEDIA_ATTACHED_RE = /\[media attached[^\]]*\]/gi;
|
|
24
|
+
const MEDIA_TAGS_RE = /<media:(?:audio|image|video|document)>/gi;
|
|
25
|
+
const MEDIA_INSTRUCTION_RE = /To send an image back,[\s\S]*?Keep caption in the text body\./gi;
|
|
26
|
+
const MEDIA_INBOUND_PATH_RE = /\/Users\/[^\s]*\/media\/inbound\/[^\s)\]"]*/gi;
|
|
27
|
+
const IMAGE_DATA_RE = /\[image data removed[^\]]*\]/gi;
|
|
28
|
+
function stripMediaReferences(text: string): string {
|
|
29
|
+
return text
|
|
30
|
+
.replace(MEDIA_INSTRUCTION_RE, "")
|
|
31
|
+
.replace(MEDIA_ATTACHED_RE, "[media reference removed]")
|
|
32
|
+
.replace(MEDIA_TAGS_RE, "")
|
|
33
|
+
.replace(MEDIA_INBOUND_PATH_RE, "[media reference removed]")
|
|
34
|
+
.replace(IMAGE_DATA_RE, "")
|
|
35
|
+
.replace(/\n{3,}/g, "\n\n");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function sanitizeForUpload(text: string): string {
|
|
39
|
+
let cleaned = stripOldMemory(text);
|
|
40
|
+
cleaned = stripMediaReferences(cleaned);
|
|
41
|
+
cleaned = cleaned
|
|
42
|
+
.replace(ENVELOPE_METADATA_RE, "")
|
|
43
|
+
.replace(SENDER_METADATA_RE, "")
|
|
44
|
+
.replace(REPLY_CONTEXT_RE, "")
|
|
45
|
+
.replace(MEMORY_INSTRUCTION_RE, "")
|
|
46
|
+
.replace(IMPORTANT_MEMORY_RE, "");
|
|
47
|
+
cleaned = cleaned.replace(/\n{3,}/g, "\n\n").trim();
|
|
48
|
+
return cleaned;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const SYSTEM_NOISE_PATTERNS = [
|
|
52
|
+
/^Read HEARTBEAT\.md if it exists/,
|
|
53
|
+
/^HEARTBEAT_OK\s*$/,
|
|
54
|
+
/^Pre-compaction memory flush\./,
|
|
55
|
+
/⚠️ Post-Compaction Audit:/,
|
|
56
|
+
/^NO_REPLY\s*$/,
|
|
57
|
+
/^Note: The previous agent run was aborted/,
|
|
58
|
+
/^\[Queued messages while agent was busy\]/,
|
|
59
|
+
/^\[media reference removed\]\s*$/,
|
|
60
|
+
/^System: \[\d{4}-\d{2}-\d{2}/,
|
|
61
|
+
/^\[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [A-Z]{2,4}\] ⚠️/,
|
|
62
|
+
/^Store durable memories now/,
|
|
63
|
+
/^Current time: .+\(America\//,
|
|
64
|
+
/^A new session was started via \/new or \/reset/,
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
function isSystemNoise(text: string): boolean {
|
|
68
|
+
const trimmed = text.trim();
|
|
69
|
+
if (!trimmed) return true;
|
|
70
|
+
return SYSTEM_NOISE_PATTERNS.some(pattern => pattern.test(trimmed));
|
|
71
|
+
}
|
|
72
|
+
|
|
8
73
|
type MemoryLine = {
|
|
9
74
|
content: string;
|
|
10
75
|
role: "user" | "assistant";
|
|
@@ -114,6 +179,11 @@ async function sessionToJsonl(filePath: string): Promise<MemoryLine[]> {
|
|
|
114
179
|
|
|
115
180
|
if (!text || text.trim().length < 20) continue;
|
|
116
181
|
|
|
182
|
+
// Sanitize: strip memory injections, envelope metadata, media refs, system noise
|
|
183
|
+
text = sanitizeForUpload(text);
|
|
184
|
+
if (!text || text.trim().length < 20) continue;
|
|
185
|
+
if (isSystemNoise(text)) continue;
|
|
186
|
+
|
|
117
187
|
let timestamp: number;
|
|
118
188
|
if (typeof parsed.timestamp === "string") {
|
|
119
189
|
timestamp = new Date(parsed.timestamp).getTime();
|