@contextableai/openclaw-memory-rebac 0.3.7 → 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/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,9 +590,8 @@ const rebacMemoryPlugin = {
566
590
  }
567
591
  text = textParts.join("\n");
568
592
  }
569
- // Strip injected memory/tool blocks — keep the user's actual content
570
- text = text.replace(/<relevant-memories>[\s\S]*?<\/relevant-memories>/g, "").trim();
571
- text = text.replace(/<memory-tools>[\s\S]*?<\/memory-tools>/g, "").trim();
593
+ // Strip envelope metadata and injected blocks — keep the user's actual content
594
+ text = stripEnvelopeMetadata(text);
572
595
  if (!text || text.length < 5)
573
596
  continue;
574
597
  const roleLabel = role === "user" ? "User" : "Assistant";
@@ -660,7 +683,7 @@ const rebacMemoryPlugin = {
660
683
  }
661
684
  return "";
662
685
  };
663
- const userMsg = extractText(lastUserMsg);
686
+ const userMsg = stripEnvelopeMetadata(extractText(lastUserMsg));
664
687
  const assistantMsg = extractText(lastAssistMsg);
665
688
  if (userMsg && assistantMsg) {
666
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-21):
10
- # Overlay patches in startup.py — 5 of 6 still needed:
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contextableai/openclaw-memory-rebac",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
4
4
  "description": "OpenClaw two-layer memory plugin: SpiceDB ReBAC authorization + Graphiti knowledge graph",
5
5
  "type": "module",
6
6
  "license": "MIT",