openclaw-plugin-memory-engine 4.2.2 → 4.4.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/README.md CHANGED
@@ -40,7 +40,7 @@ Enable the plugin UI page once via **Control UI → Settings → Labs → Custom
40
40
 
41
41
  ## Privacy & Data
42
42
 
43
- - **What is stored**: with session ingest enabled (default), OpenClaw chat messages are stored as session_msg atoms in the configured SQLite database, and a per-session digest is refreshed periodically.
43
+ - **What is stored**: with session ingest enabled, OpenClaw chat messages are stored as session_msg atoms in the configured SQLite database, and a per-session digest is refreshed periodically.
44
44
  - **Opt out**: set ingest.enabled false in the plugin config to stop capturing chats entirely; existing captured data stays until cleaned.
45
45
  - **Automatic cleanup**: session_msg and session_digest atoms carry a TTL (default 7 days, configurable via ingest.retention_days) and are expired automatically by the periodic flush.
46
46
  - **Manual cleanup**: use memory_cleanup_sessions, memory_delete_atom, memory_export_all to review or purge stored contents.
@@ -42,12 +42,19 @@ export async function semanticSearch(db, query, limit = 10, domain) {
42
42
  "WHERE a.status = 'active'")
43
43
  .all();
44
44
  const scored = [];
45
+ let skippedCorrupt = 0;
45
46
  for (const r of rows) {
46
47
  if (domain && r.domain !== domain)
47
48
  continue;
48
- const v = new Float32Array(r.embedding.buffer, r.embedding.byteOffset, r.embedding.byteLength / 4);
49
+ const buf = Buffer.isBuffer(r.embedding) ? r.embedding : Buffer.from(r.embedding?.buffer ?? r.embedding);
50
+ if (!buf || !buf.length || buf.length % 4 !== 0 || buf.length / 4 !== qv.length) {
51
+ skippedCorrupt++;
52
+ continue;
53
+ } // riga anomala: dimensione incoerente, scartata e conteggiata
54
+ const v = new Float32Array(buf.buffer, buf.byteOffset, buf.length / 4);
49
55
  scored.push({ id: r.id, title: r.title, domain: r.domain, type: r.type, semantic_score: Math.round(cosine(qv, v) * 10000) / 10000 });
50
56
  }
57
+ semanticSearch._lastSkippedCorrupt = skippedCorrupt;
51
58
  scored.sort((a, b) => b.semantic_score - a.semantic_score);
52
59
  return scored.slice(0, limit);
53
60
  }
package/dist/entry.js CHANGED
@@ -46,7 +46,7 @@ export default definePluginEntry({
46
46
  const me = createTools(dbPath);
47
47
  const curator = new Curator(me.__db, me.__engine, (api.config ?? {}).curator ?? {});
48
48
  const ingestCfg = ((api.config ?? {}).ingest ?? {});
49
- const ingestEnabled = ingestCfg.enabled !== false;
49
+ const ingestEnabled = ingestCfg.enabled === true;
50
50
  const retentionDays = Number(ingestCfg.retention_days ?? 7);
51
51
  const logger = api.logger ?? console;
52
52
  // ── Tools ─────────────────────────────────────────────
@@ -166,6 +166,6 @@ export default definePluginEntry({
166
166
  }
167
167
  }, FLUSH_MS);
168
168
  timer.unref?.();
169
- logger.info?.("[memory-engine] v" + VERSION + " registered: " + defs.length + " tools + ingest " + (ingestEnabled ? "on (retention " + retentionDays + "d)" : "OFF") + " (" + (FLUSH_MS / 1000) + "s)");
169
+ logger.info?.("[memory-engine] v" + VERSION + " registered: " + defs.length + " tools + ingest " + (ingestEnabled ? "on (retention " + retentionDays + "d)" : "off (enable via config ingest.enabled=true)") + " (" + (FLUSH_MS / 1000) + "s)");
170
170
  },
171
171
  });
package/dist/semantic.js CHANGED
@@ -28,16 +28,24 @@ export function buildSemanticDefs(db, curator) {
28
28
  if (!probe)
29
29
  return { ok: false, reason: "ollama non raggiungibile (OLLAMA_HOST / ME_EMBED_MODEL)" };
30
30
  const rows = q("SELECT id, title, COALESCE(body_compact, body, '') body FROM atoms a WHERE a.status='active' AND a.type IN ('fact','decision','procedure','preference','project','note') AND NOT EXISTS (SELECT 1 FROM atom_embeddings e WHERE e.atom_id = a.id) LIMIT ?", a.max_atoms ?? 100);
31
- let indexed = 0, failed = 0;
31
+ let indexed = 0;
32
+ const failed = [];
32
33
  for (const r of rows) {
33
- const ok = await embedAtom(db, r.id, r.title + ". " + String(r.body || "").slice(0, 1500));
34
- if (ok)
35
- indexed++;
36
- else
37
- failed++;
34
+ const text = r.title + ". " + String(r.body || "").slice(0, 1500);
35
+ try {
36
+ const ok = await embedAtom(db, r.id, text);
37
+ if (ok)
38
+ indexed++;
39
+ else
40
+ failed.push({ id: r.id, reason: "embed returned null (ollama/model)" });
41
+ }
42
+ catch (err) {
43
+ failed.push({ id: r.id, reason: String(err?.message || err).slice(0, 200) });
44
+ }
38
45
  }
39
46
  const total = q1("SELECT COUNT(*) n FROM atom_embeddings").n;
40
- return { ok: true, indexed, failed, scanned: rows.length, embeddings_total: total };
47
+ const pending = q1("SELECT COUNT(*) n FROM atoms a WHERE a.status='active' AND a.type IN ('fact','decision','procedure','preference','project','note') AND NOT EXISTS (SELECT 1 FROM atom_embeddings e WHERE e.atom_id = a.id)").n;
48
+ return { ok: true, indexed, failed: failed.length, failed_detail: failed.slice(0, 50), scanned: rows.length, still_pending: pending, embeddings_total: total };
41
49
  },
42
50
  },
43
51
  {
package/dist/tools.d.ts CHANGED
@@ -4,7 +4,7 @@
4
4
  * Python server and are exposed as explicit pointers.
5
5
  */
6
6
  import { DatabaseSync } from "node:sqlite";
7
- export declare const VERSION = "4.2.2";
7
+ export declare const VERSION = "4.4.0";
8
8
  export declare function createTools(dbPath: string): {
9
9
  __db: DatabaseSync;
10
10
  version: () => {
package/dist/tools.js CHANGED
@@ -6,7 +6,7 @@
6
6
  import { DatabaseSync } from "node:sqlite";
7
7
  import { Engine } from "./engine.js";
8
8
  import { buildSessionDigest } from "./digest.js";
9
- export const VERSION = "4.2.2";
9
+ export const VERSION = "4.4.0";
10
10
  export function createTools(dbPath) {
11
11
  const db = new DatabaseSync(dbPath);
12
12
  const engine = new Engine(db, {});
@@ -16,7 +16,7 @@ export function createTools(dbPath) {
16
16
  const tokens = (a) => Math.max(16, Math.floor((String(a.title || "").length + String(a.snippet || "").length) / 4));
17
17
  return {
18
18
  __db: db,
19
- version: () => ({ version: VERSION, note: "Native Memory Engine plugin: 19 tools + session ingest/digest + curator." }),
19
+ version: () => ({ version: VERSION, note: "Native Memory Engine plugin: 45 tools + session ingest/digest + curator." }),
20
20
  recall: async (query, limit = 5, domain, semantic = false) => {
21
21
  const base = engine.recall(query, limit, { domain: domain ?? undefined, semantic: false });
22
22
  if (!semantic)
@@ -13,9 +13,9 @@ export declare function createFeatureHandlers(): {
13
13
  results: any[];
14
14
  };
15
15
  atom: ({ id }: any) => {
16
+ error: string;
16
17
  atom?: undefined;
17
18
  bonds?: undefined;
18
- error: string;
19
19
  } | {
20
20
  error?: undefined;
21
21
  atom: any;
@@ -50,10 +50,10 @@ export declare function createFeatureHandlers(): {
50
50
  }[];
51
51
  };
52
52
  backup_now: () => {
53
- reason?: undefined;
54
53
  ok: boolean;
55
54
  path: string;
56
55
  size_bytes: number;
56
+ reason?: undefined;
57
57
  } | {
58
58
  path?: undefined;
59
59
  size_bytes?: undefined;
@@ -2,29 +2,11 @@
2
2
  "id": "memory-engine",
3
3
  "name": "Memory Engine",
4
4
  "description": "Native Memory Engine: 45 memory tools, session ingest/digest, curator and Control UI.",
5
- "version": "4.2.2",
5
+ "version": "4.4.0",
6
6
  "configSchema": {
7
7
  "type": "object",
8
- "properties": {
9
- "ingest": {
10
- "type": "object",
11
- "description": "Session ingest (chat memory capture) controls.",
12
- "properties": {
13
- "enabled": {
14
- "type": "boolean",
15
- "default": true,
16
- "description": "Capture OpenClaw chat contents into the memory database. Set false to opt out completely."
17
- },
18
- "retention_days": {
19
- "type": "number",
20
- "default": 7,
21
- "description": "Days before session_msg/session_digest atoms expire automatically."
22
- }
23
- },
24
- "additionalProperties": false
25
- }
26
- },
27
- "additionalProperties": false
8
+ "additionalProperties": false,
9
+ "properties": {}
28
10
  },
29
11
  "activation": {
30
12
  "onStartup": true
@@ -81,4 +63,4 @@
81
63
  "memory_answer_human"
82
64
  ]
83
65
  }
84
- }
66
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-plugin-memory-engine",
3
- "version": "4.2.2",
3
+ "version": "4.4.0",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "build": "tsc -p tsconfig.json && openclaw plugins build",