@digitalforgestudios/openclaw-sulcus 1.0.2 → 1.1.1
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 +69 -2
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -97,6 +97,10 @@ class SulcusClient {
|
|
|
97
97
|
body: JSON.stringify(body),
|
|
98
98
|
});
|
|
99
99
|
|
|
100
|
+
if (res.status === 409) {
|
|
101
|
+
// Duplicate memory — silently skip, not an error
|
|
102
|
+
return { id: "", label, memory_type: memoryType, namespace: namespace ?? this.config.namespace ?? "default" } as SulcusNode;
|
|
103
|
+
}
|
|
100
104
|
if (!res.ok) {
|
|
101
105
|
const errText = await res.text().catch(() => "");
|
|
102
106
|
throw new Error(`Sulcus store failed: ${res.status} ${errText}`);
|
|
@@ -210,6 +214,23 @@ function shouldCapture(text: string): boolean {
|
|
|
210
214
|
// Reject if stripping removed >60% of the content (mostly metadata)
|
|
211
215
|
if (cleaned.length < text.length * 0.4) return false;
|
|
212
216
|
|
|
217
|
+
// Reject system prompts and OpenClaw operational messages that caused 1,000+ dupes
|
|
218
|
+
const rejectPatterns = [
|
|
219
|
+
/^Pre-compaction memory flush/i,
|
|
220
|
+
/^A new session was started via/i,
|
|
221
|
+
/^\[cron:[0-9a-f-]+/i,
|
|
222
|
+
/^To send an image back, prefer the message tool/i,
|
|
223
|
+
/^Heartbeat prompt:/i,
|
|
224
|
+
/^Read HEARTBEAT\.md/i,
|
|
225
|
+
/^Run your Session Startup sequence/i,
|
|
226
|
+
/^You are \w+\. T/i, // cron job identity preambles
|
|
227
|
+
/^Gateway restart/i,
|
|
228
|
+
/^System: \[/,
|
|
229
|
+
/^HEARTBEAT_OK$/i,
|
|
230
|
+
/^NO_REPLY$/i,
|
|
231
|
+
];
|
|
232
|
+
if (rejectPatterns.some((r) => r.test(cleaned))) return false;
|
|
233
|
+
|
|
213
234
|
const triggers = [
|
|
214
235
|
/remember|zapamatuj/i,
|
|
215
236
|
/prefer|like|love|hate|want/i,
|
|
@@ -529,7 +550,7 @@ const sulcusMemoryPlugin = {
|
|
|
529
550
|
// ========================================================================
|
|
530
551
|
|
|
531
552
|
if (config.autoRecall) {
|
|
532
|
-
api.on("
|
|
553
|
+
api.on("before_model_resolve", async (event) => {
|
|
533
554
|
if (!event.prompt || event.prompt.length < 5) return;
|
|
534
555
|
|
|
535
556
|
try {
|
|
@@ -539,7 +560,8 @@ const sulcusMemoryPlugin = {
|
|
|
539
560
|
const memoryLines = results.map((node, i) => {
|
|
540
561
|
const label = node.pointer_summary ?? node.label ?? "";
|
|
541
562
|
const heat = node.current_heat ?? node.heat ?? 0;
|
|
542
|
-
|
|
563
|
+
const id = node.id ?? "";
|
|
564
|
+
return `${i + 1}. [${node.memory_type}] (heat: ${heat.toFixed(2)}) [id: ${id}] ${escapeForPrompt(label.slice(0, 400))}`;
|
|
543
565
|
});
|
|
544
566
|
|
|
545
567
|
api.logger.info?.(`openclaw-sulcus: injecting ${results.length} memories into context`);
|
|
@@ -553,6 +575,51 @@ const sulcusMemoryPlugin = {
|
|
|
553
575
|
});
|
|
554
576
|
}
|
|
555
577
|
|
|
578
|
+
// ========================================================================
|
|
579
|
+
// Lifecycle — Preserve memories before compaction
|
|
580
|
+
// ========================================================================
|
|
581
|
+
|
|
582
|
+
api.on("before_compaction", async (event) => {
|
|
583
|
+
if (!event.messages || event.messages.length === 0) return;
|
|
584
|
+
|
|
585
|
+
try {
|
|
586
|
+
// Scan messages being compacted for important content worth preserving
|
|
587
|
+
const toPreserve: string[] = [];
|
|
588
|
+
for (const msg of event.messages) {
|
|
589
|
+
if (!msg || typeof msg !== "object") continue;
|
|
590
|
+
const msgObj = msg as Record<string, unknown>;
|
|
591
|
+
const content = typeof msgObj.content === "string" ? msgObj.content : "";
|
|
592
|
+
if (!content || content.length < 30) continue;
|
|
593
|
+
|
|
594
|
+
const cleaned = stripMetadataEnvelope(content);
|
|
595
|
+
if (cleaned.length < 30) continue;
|
|
596
|
+
if (!shouldCapture(cleaned)) continue;
|
|
597
|
+
|
|
598
|
+
toPreserve.push(cleaned);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
if (toPreserve.length === 0) return;
|
|
602
|
+
|
|
603
|
+
// Store up to 5 important memories before compaction discards them
|
|
604
|
+
let stored = 0;
|
|
605
|
+
for (const text of toPreserve.slice(0, 5)) {
|
|
606
|
+
const type = detectMemoryType(text);
|
|
607
|
+
try {
|
|
608
|
+
await client.store(text.slice(0, 2000), type);
|
|
609
|
+
stored++;
|
|
610
|
+
} catch {
|
|
611
|
+
// 409 (dedup) or other — continue
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if (stored > 0) {
|
|
616
|
+
api.logger.info(`openclaw-sulcus: preserved ${stored} memories before compaction`);
|
|
617
|
+
}
|
|
618
|
+
} catch (err) {
|
|
619
|
+
api.logger.warn(`openclaw-sulcus: before_compaction failed: ${String(err)}`);
|
|
620
|
+
}
|
|
621
|
+
});
|
|
622
|
+
|
|
556
623
|
// ========================================================================
|
|
557
624
|
// Lifecycle — Auto-capture
|
|
558
625
|
// ========================================================================
|
package/package.json
CHANGED