@contextableai/openclaw-memory-rebac 0.3.6 → 0.3.8
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/dist/cli.js +3 -3
- package/dist/index.d.ts +6 -0
- package/dist/index.js +27 -3
- package/docker/graphiti/Dockerfile +4 -2
- package/docker/graphiti/startup.py +25 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -347,9 +347,9 @@ export function registerCommands(cmd, ctx) {
|
|
|
347
347
|
.map((b) => b.text)
|
|
348
348
|
.join("\n");
|
|
349
349
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
350
|
+
text = text.replace(/<relevant-memories>[\s\S]*?<\/relevant-memories>/g, "").trim();
|
|
351
|
+
text = text.replace(/<memory-tools>[\s\S]*?<\/memory-tools>/g, "").trim();
|
|
352
|
+
if (text && text.length >= 5) {
|
|
353
353
|
const roleLabel = role === "user" ? "User" : "Assistant";
|
|
354
354
|
conversationLines.push(`${roleLabel}: ${text}`);
|
|
355
355
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,12 @@
|
|
|
16
16
|
* falling back to config-level subjectType/subjectId when agentId is absent.
|
|
17
17
|
*/
|
|
18
18
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
19
|
+
/**
|
|
20
|
+
* Strip OpenClaw envelope metadata from message text before Graphiti ingestion.
|
|
21
|
+
* Removes channel headers, sender/message-id meta lines, and memory injection
|
|
22
|
+
* blocks that would pollute entity extraction.
|
|
23
|
+
*/
|
|
24
|
+
export declare function stripEnvelopeMetadata(text: string): string;
|
|
19
25
|
declare const rebacMemoryPlugin: {
|
|
20
26
|
id: string;
|
|
21
27
|
name: string;
|
package/dist/index.js
CHANGED
|
@@ -55,6 +55,30 @@ function isSessionAllowed(sessionKey, filter) {
|
|
|
55
55
|
return true;
|
|
56
56
|
}
|
|
57
57
|
// ============================================================================
|
|
58
|
+
// Content sanitization
|
|
59
|
+
// ============================================================================
|
|
60
|
+
/**
|
|
61
|
+
* Strip OpenClaw envelope metadata from message text before Graphiti ingestion.
|
|
62
|
+
* Removes channel headers, sender/message-id meta lines, and memory injection
|
|
63
|
+
* blocks that would pollute entity extraction.
|
|
64
|
+
*/
|
|
65
|
+
export function stripEnvelopeMetadata(text) {
|
|
66
|
+
let result = text;
|
|
67
|
+
// Strip envelope header: [ChannelName ...metadata...] at start of line
|
|
68
|
+
// Matches: [Telegram Dev Chat +5m 2025-01-02T03:04Z] body
|
|
69
|
+
result = result.replace(/^\[[A-Z][^\]\n]*\]\s*/gm, "");
|
|
70
|
+
// Strip [from: SenderLabel] trailer lines
|
|
71
|
+
result = result.replace(/^\[from:\s*[^\]]*\]\s*$/gm, "");
|
|
72
|
+
// Strip [message_id: ...] hint lines
|
|
73
|
+
result = result.replace(/^\[message_id:\s*[^\]]*\]\s*$/gm, "");
|
|
74
|
+
// Strip memory injection blocks
|
|
75
|
+
result = result.replace(/<relevant-memories>[\s\S]*?<\/relevant-memories>/g, "");
|
|
76
|
+
result = result.replace(/<memory-tools>[\s\S]*?<\/memory-tools>/g, "");
|
|
77
|
+
// Collapse excess blank lines and trim
|
|
78
|
+
result = result.replace(/\n{3,}/g, "\n\n").trim();
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
// ============================================================================
|
|
58
82
|
// Plugin Definition
|
|
59
83
|
// ============================================================================
|
|
60
84
|
const rebacMemoryPlugin = {
|
|
@@ -566,10 +590,10 @@ const rebacMemoryPlugin = {
|
|
|
566
590
|
}
|
|
567
591
|
text = textParts.join("\n");
|
|
568
592
|
}
|
|
593
|
+
// Strip envelope metadata and injected blocks — keep the user's actual content
|
|
594
|
+
text = stripEnvelopeMetadata(text);
|
|
569
595
|
if (!text || text.length < 5)
|
|
570
596
|
continue;
|
|
571
|
-
if (text.includes("<relevant-memories>"))
|
|
572
|
-
continue;
|
|
573
597
|
const roleLabel = role === "user" ? "User" : "Assistant";
|
|
574
598
|
conversationLines.unshift(`${roleLabel}: ${text}`);
|
|
575
599
|
messageCount++;
|
|
@@ -659,7 +683,7 @@ const rebacMemoryPlugin = {
|
|
|
659
683
|
}
|
|
660
684
|
return "";
|
|
661
685
|
};
|
|
662
|
-
const userMsg = extractText(lastUserMsg);
|
|
686
|
+
const userMsg = stripEnvelopeMetadata(extractText(lastUserMsg));
|
|
663
687
|
const assistantMsg = extractText(lastAssistMsg);
|
|
664
688
|
if (userMsg && assistantMsg) {
|
|
665
689
|
backend.enrichSession({
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
# 1. Install sentence-transformers for BGE reranker
|
|
7
7
|
# 2. Overlay per-component config + startup to wire separate clients
|
|
8
8
|
#
|
|
9
|
-
# UPGRADE AUDIT (vs upstream getzep/graphiti v0.28.2, audited 2026-03-
|
|
10
|
-
# Overlay patches in startup.py —
|
|
9
|
+
# UPGRADE AUDIT (vs upstream getzep/graphiti v0.28.2, audited 2026-03-24):
|
|
10
|
+
# Overlay patches in startup.py — 6 of 7 still needed:
|
|
11
11
|
# [NEEDED] AsyncWorker crash-on-error recovery (startup.py:109-126)
|
|
12
12
|
# [NEEDED] Neo4j nested attribute sanitization (startup.py:128-250)
|
|
13
13
|
# [SAFE] None-index extract_edges fix (startup.py:252-298)
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
# [NEEDED] IS_DUPLICATE_OF edge filtering (startup.py:152-169,216-227,310-318)
|
|
16
16
|
# [NEEDED] Self-referential edge filtering (startup.py:228-239)
|
|
17
17
|
# [NEEDED] Singleton client / per-request fix (startup.py:38-87)
|
|
18
|
+
# [NEEDED] resolve_extracted_edge IndexError guard (startup.py:325-349)
|
|
19
|
+
# — fixed upstream v0.28.2+; no Docker image published beyond 0.22.0
|
|
18
20
|
###############################################################################
|
|
19
21
|
|
|
20
22
|
FROM zepai/graphiti:0.22.0
|
|
@@ -322,6 +322,31 @@ def patch():
|
|
|
322
322
|
# Patch the local binding in graphiti.py
|
|
323
323
|
graphiti_mod.extract_edges = safe_extract_edges
|
|
324
324
|
|
|
325
|
+
# -- Guard resolve_extracted_edge against IndexError from out-of-bounds
|
|
326
|
+
# contradicted_facts indices (issue #22) --
|
|
327
|
+
# The LLM sometimes returns fact indices that exceed the existing_edges list
|
|
328
|
+
# length, crashing the list comprehension. Upstream v0.28.2+ adds bounds
|
|
329
|
+
# checking; this patch provides equivalent safety for pinned v0.22.0.
|
|
330
|
+
original_resolve_extracted_edge = edge_ops_mod.resolve_extracted_edge
|
|
331
|
+
|
|
332
|
+
async def safe_resolve_extracted_edge(*args, **kwargs):
|
|
333
|
+
try:
|
|
334
|
+
return await original_resolve_extracted_edge(*args, **kwargs)
|
|
335
|
+
except IndexError as e:
|
|
336
|
+
logger.warning(
|
|
337
|
+
"resolve_extracted_edge: IndexError caught (out-of-bounds "
|
|
338
|
+
"contradicted_facts index): %s — returning edge as-is with "
|
|
339
|
+
"no invalidations",
|
|
340
|
+
e,
|
|
341
|
+
)
|
|
342
|
+
# args[1] is extracted_edge per the function signature
|
|
343
|
+
extracted_edge = args[1] if len(args) > 1 else kwargs.get("extracted_edge")
|
|
344
|
+
if extracted_edge is None:
|
|
345
|
+
raise
|
|
346
|
+
return (extracted_edge, [], [])
|
|
347
|
+
|
|
348
|
+
edge_ops_mod.resolve_extracted_edge = safe_resolve_extracted_edge
|
|
349
|
+
|
|
325
350
|
return app
|
|
326
351
|
|
|
327
352
|
|
package/package.json
CHANGED