@digitalforgestudios/openclaw-sulcus 3.0.0 → 3.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 CHANGED
@@ -43,29 +43,29 @@ const FALLBACK_AWARENESS = `<sulcus_context token_budget="500">
43
43
  </sulcus_context>`;
44
44
 
45
45
  // ─── NATIVE LIB LOADER ──────────────────────────────────────────────────────
46
- // Loads libsulcus_store.dylib (embedded PG) and libsulcus_embed.dylib (embeddings)
46
+ // Loads libsulcus_store.dylib (embedded PG) and libsulcus_vectors.dylib (embeddings)
47
47
  // via koffi FFI. Provides queryFn and embedFn callbacks for SulcusMem.create().
48
48
 
49
49
  class NativeLibLoader {
50
50
  private koffi: any = null;
51
51
  private storeLib: any = null;
52
- private embedLib: any = null;
53
- private embedHandle: any = null;
52
+ private vectorsLib: any = null;
53
+ private vectorsHandle: any = null;
54
54
 
55
55
  // koffi function handles
56
56
  private fn_store_init: any = null;
57
57
  private fn_store_query: any = null;
58
58
  private fn_store_free: any = null;
59
- private fn_embed_create: any = null;
60
- private fn_embed_text: any = null;
61
- private fn_embed_free: any = null;
59
+ private fn_vectors_create: any = null;
60
+ private fn_vectors_text: any = null;
61
+ private fn_vectors_free: any = null;
62
62
 
63
63
  public loaded = false;
64
64
  public error: string | null = null;
65
65
 
66
66
  constructor(
67
67
  private storeLibPath: string,
68
- private embedLibPath: string
68
+ private vectorsLibPath: string
69
69
  ) {}
70
70
 
71
71
  init(logger: any): void {
@@ -84,8 +84,8 @@ class NativeLibLoader {
84
84
  logger.warn(`memory-sulcus: ${this.error}`);
85
85
  return;
86
86
  }
87
- if (!existsSync(this.embedLibPath)) {
88
- this.error = `libsulcus_embed not found at ${this.embedLibPath}`;
87
+ if (!existsSync(this.vectorsLibPath)) {
88
+ this.error = `libsulcus_vectors not found at ${this.vectorsLibPath}`;
89
89
  logger.warn(`memory-sulcus: ${this.error}`);
90
90
  return;
91
91
  }
@@ -102,12 +102,12 @@ class NativeLibLoader {
102
102
  }
103
103
 
104
104
  try {
105
- this.embedLib = this.koffi.load(this.embedLibPath);
106
- this.fn_embed_create = this.embedLib.func("sulcus_embed_create", "void*", []);
107
- this.fn_embed_text = this.embedLib.func("sulcus_embed_text", "char*", ["void*", "str"]);
108
- this.fn_embed_free = this.embedLib.func("sulcus_embed_free_string", "void", ["char*"]);
105
+ this.vectorsLib = this.koffi.load(this.vectorsLibPath);
106
+ this.fn_vectors_create = this.vectorsLib.func("sulcus_vectors_create", "void*", []);
107
+ this.fn_vectors_text = this.vectorsLib.func("sulcus_vectors_text", "char*", ["void*", "str"]);
108
+ this.fn_vectors_free = this.vectorsLib.func("sulcus_vectors_free_string", "void", ["char*"]);
109
109
  } catch (e: any) {
110
- this.error = `Failed to load libsulcus_embed: ${e.message}`;
110
+ this.error = `Failed to load libsulcus_vectors: ${e.message}`;
111
111
  logger.warn(`memory-sulcus: ${this.error}`);
112
112
  return;
113
113
  }
@@ -130,15 +130,15 @@ class NativeLibLoader {
130
130
 
131
131
  // ── Create embed handle ──
132
132
  try {
133
- this.embedHandle = this.fn_embed_create();
133
+ this.vectorsHandle = this.fn_vectors_create();
134
134
  } catch (e: any) {
135
- this.error = `sulcus_embed_create failed: ${e.message}`;
135
+ this.error = `sulcus_vectors_create failed: ${e.message}`;
136
136
  logger.warn(`memory-sulcus: ${this.error}`);
137
137
  return;
138
138
  }
139
139
 
140
140
  this.loaded = true;
141
- logger.info(`memory-sulcus: native libs loaded (store: ${this.storeLibPath}, embed: ${this.embedLibPath})`);
141
+ logger.info(`memory-sulcus: native libs loaded (store: ${this.storeLibPath}, vectors: ${this.vectorsLibPath})`);
142
142
  }
143
143
 
144
144
  // queryFn: async (sql: string, params: any[]) => any[]
@@ -163,12 +163,12 @@ class NativeLibLoader {
163
163
  }
164
164
 
165
165
  // embedFn: async (text: string) => Float32Array
166
- // Calls sulcus_embed_text which returns a JSON float array string.
166
+ // Calls sulcus_vectors_text which returns a JSON float array string.
167
167
  makeEmbedFn(): (text: string) => Promise<Float32Array> {
168
168
  return async (text: string): Promise<Float32Array> => {
169
- if (!this.loaded) throw new Error("Sulcus embed not available");
170
- const raw: string = this.fn_embed_text(this.embedHandle, text);
171
- if (!raw) throw new Error("sulcus_embed_text returned null");
169
+ if (!this.loaded) throw new Error("Sulcus vectors not available");
170
+ const raw: string = this.fn_vectors_text(this.vectorsHandle, text);
171
+ if (!raw) throw new Error("sulcus_vectors_text returned null");
172
172
  const arr: number[] = JSON.parse(raw);
173
173
  return new Float32Array(arr);
174
174
  };
@@ -220,9 +220,9 @@ const sulcusPlugin = {
220
220
  ? resolve(api.config.storeLibPath)
221
221
  : resolve(libDir, process.platform === "darwin" ? "libsulcus_store.dylib" : "libsulcus_store.so");
222
222
 
223
- const embedLibPath = api.config?.embedLibPath
224
- ? resolve(api.config.embedLibPath)
225
- : resolve(libDir, process.platform === "darwin" ? "libsulcus_embed.dylib" : "libsulcus_embed.so");
223
+ const vectorsLibPath = api.config?.vectorsLibPath
224
+ ? resolve(api.config.vectorsLibPath)
225
+ : resolve(libDir, process.platform === "darwin" ? "libsulcus_vectors.dylib" : "libsulcus_vectors.so");
226
226
 
227
227
  const wasmDir = api.config?.wasmDir
228
228
  ? resolve(api.config.wasmDir)
@@ -235,7 +235,7 @@ const sulcusPlugin = {
235
235
  : (api.config?.namespace || agentId || "default");
236
236
 
237
237
  // ── Load native dylibs ──
238
- const nativeLoader = new NativeLibLoader(storeLibPath, embedLibPath);
238
+ const nativeLoader = new NativeLibLoader(storeLibPath, vectorsLibPath);
239
239
  nativeLoader.init(api.logger);
240
240
 
241
241
  // ── Load WASM module ──
@@ -288,7 +288,7 @@ const sulcusPlugin = {
288
288
  throw new Error(`Sulcus unavailable: ${nativeLoader.error || "WASM not loaded"}`);
289
289
  }
290
290
  const res = await sulcusMem.search_memory(params.query, params.limit ?? 5);
291
- const results = res?.results ?? res;
291
+ const results = res?.results ?? res?.items ?? res?.nodes ?? res ?? [];
292
292
  return {
293
293
  content: [{ type: "text", text: JSON.stringify(results, null, 2) }],
294
294
  details: { results, backend: backendMode, namespace }
@@ -325,9 +325,11 @@ const sulcusPlugin = {
325
325
  }
326
326
 
327
327
  const res = await sulcusMem.add_memory(params.content, params.memory_type ?? null);
328
+ const nodeId = res?.id ?? "unknown";
329
+ const mtype = params.memory_type || "episodic";
328
330
  return {
329
- content: [{ type: "text", text: `Stored [${params.memory_type || "episodic"}] memory: "${(params.content || "").substring(0, 80)}..." [${backendMode}] namespace: ${namespace}` }],
330
- details: { ...res, backend: backendMode, namespace }
331
+ content: [{ type: "text", text: `Stored [${mtype}] memory (id: ${nodeId}) → backend: ${backendMode}, namespace: ${namespace}` }],
332
+ details: { id: nodeId, memory_type: mtype, backend: backendMode, namespace, ...res }
331
333
  };
332
334
  }
333
335
  }, { name: "memory_store" });
@@ -346,7 +348,7 @@ const sulcusPlugin = {
346
348
  namespace,
347
349
  error: nativeLoader.error || "WASM not loaded",
348
350
  storeLib: storeLibPath,
349
- embedLib: embedLibPath,
351
+ vectorsLib: vectorsLibPath,
350
352
  wasmDir,
351
353
  }, null, 2) }],
352
354
  };
@@ -2,10 +2,10 @@
2
2
  "id": "openclaw-sulcus",
3
3
  "kind": "memory",
4
4
  "name": "Sulcus",
5
- "description": "Reactive, thermodynamic memory for AI agents. Runs entirely local via WASM + native dylibs (embedded PostgreSQL, fastembed). No network calls. Optional cloud sync via sulcus-sync dylib when serverUrl/apiKey are configured.",
5
+ "description": "Reactive, thermodynamic memory for AI agents. Runs entirely local via WASM + native dylibs (embedded PostgreSQL, sulcus-vectors). No network calls. Optional cloud sync via sulcus-sync dylib when serverUrl/apiKey are configured.",
6
6
  "privacy": {
7
7
  "consentModel": "local-first",
8
- "consentNote": "Plugin runs entirely in-process. No network calls. All data stays local in ~/.sulcus/. Cloud sync is opt-in via serverUrl/apiKey config, handled by sulcus-sync dylib loaded by sulcus-local.",
8
+ "consentNote": "Plugin runs entirely in-process. No network calls. All data stays local in ~/.sulcus/. Cloud sync is opt-in via serverUrl/apiKey config, handled by sulcus-sync dylib loaded by sulcus.",
9
9
  "crossNamespaceAccess": "local-only",
10
10
  "crossNamespaceNote": "All memory operations are local. Cross-namespace access only applies if cloud sync is configured separately.",
11
11
  "dataFlows": [
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "libDir": {
36
36
  "type": "string",
37
- "description": "Directory containing native dylibs (libsulcus_store, libsulcus_embed)",
37
+ "description": "Directory containing native dylibs (libsulcus_store, libsulcus_vectors)",
38
38
  "default": "~/.sulcus/lib"
39
39
  },
40
40
  "wasmDir": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitalforgestudios/openclaw-sulcus",
3
- "version": "3.0.0",
3
+ "version": "3.1.1",
4
4
  "description": "Sulcus — reactive, thermodynamic memory plugin for OpenClaw. Opt-in persistent memory with heat-based decay, semantic search, and cross-agent sync. Auto-recall and auto-capture disabled by default.",
5
5
  "keywords": [
6
6
  "openclaw",