memory-braid 0.3.4 → 0.3.6
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 +10 -1
- package/package.json +1 -1
- package/src/mem0-client.ts +123 -1
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ On the target machine:
|
|
|
20
20
|
1. Install from npm:
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
openclaw plugins install memory-braid@0.3.
|
|
23
|
+
openclaw plugins install memory-braid@0.3.5
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
2. Rebuild native dependencies inside the installed extension:
|
|
@@ -71,6 +71,7 @@ openclaw gateway restart
|
|
|
71
71
|
If you install from npm and see native module errors like:
|
|
72
72
|
|
|
73
73
|
- `Could not locate the bindings file` (sqlite3)
|
|
74
|
+
- `.../node_modules/jiti/.../node_sqlite3.node` in the stack/error text
|
|
74
75
|
- `Cannot find module ... sharp-*.node`
|
|
75
76
|
|
|
76
77
|
run:
|
|
@@ -81,6 +82,14 @@ npm rebuild sqlite3 sharp
|
|
|
81
82
|
openclaw gateway restart
|
|
82
83
|
```
|
|
83
84
|
|
|
85
|
+
Note:
|
|
86
|
+
- The `jiti/.../node_sqlite3.node` error is still a sqlite native artifact/runtime loading issue.
|
|
87
|
+
- `memory-braid` now preloads sqlite via native `require` to avoid that path, but you still need `npm rebuild sqlite3 sharp` after `--ignore-scripts` installs.
|
|
88
|
+
- When this happens, startup logs now include `memory_braid.mem0.error` with:
|
|
89
|
+
- `sqliteBindingsError: true`
|
|
90
|
+
- `fixCommand` (copy/paste command for that machine)
|
|
91
|
+
- `pluginDir` (resolved extension directory when available)
|
|
92
|
+
|
|
84
93
|
## Quick start: hybrid capture + multilingual NER
|
|
85
94
|
|
|
86
95
|
Add this under `plugins.entries["memory-braid"].config` in your OpenClaw config:
|
package/package.json
CHANGED
package/src/mem0-client.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
2
3
|
import os from "node:os";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { normalizeForHash } from "./chunking.js";
|
|
@@ -46,6 +47,13 @@ type OssClientLike = {
|
|
|
46
47
|
|
|
47
48
|
type OssMemoryCtor = new (config?: Record<string, unknown>) => OssClientLike;
|
|
48
49
|
|
|
50
|
+
type LoadedOssModule = {
|
|
51
|
+
moduleValue: unknown;
|
|
52
|
+
loader: "require" | "import";
|
|
53
|
+
mem0Path?: string;
|
|
54
|
+
sqlite3Path?: string;
|
|
55
|
+
};
|
|
56
|
+
|
|
49
57
|
function extractCloudText(memory: CloudRecord): string {
|
|
50
58
|
const byData = memory.data?.memory;
|
|
51
59
|
if (typeof byData === "string" && byData.trim()) {
|
|
@@ -137,6 +145,34 @@ function resolveCtorFromCandidate(candidate: unknown, depth = 0): OssMemoryCtor
|
|
|
137
145
|
);
|
|
138
146
|
}
|
|
139
147
|
|
|
148
|
+
function asErrorMessage(error: unknown): string {
|
|
149
|
+
if (error instanceof Error) {
|
|
150
|
+
return error.message;
|
|
151
|
+
}
|
|
152
|
+
return String(error);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function isSqliteBindingsError(error: unknown): boolean {
|
|
156
|
+
const message = asErrorMessage(error);
|
|
157
|
+
return /Could not locate the bindings file/i.test(message) || /node_sqlite3\.node/i.test(message);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function createLocalRequire(): NodeJS.Require {
|
|
161
|
+
return createRequire(import.meta.url);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function tryResolve(requireFn: NodeJS.Require, id: string): string | undefined {
|
|
165
|
+
try {
|
|
166
|
+
return requireFn.resolve(id);
|
|
167
|
+
} catch {
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function tryRequire(requireFn: NodeJS.Require, id: string): unknown {
|
|
173
|
+
return requireFn(id);
|
|
174
|
+
}
|
|
175
|
+
|
|
140
176
|
export function resolveOssMemoryCtor(moduleValue: unknown): OssMemoryCtor | undefined {
|
|
141
177
|
return (
|
|
142
178
|
resolveCtorFromCandidate(moduleValue) ??
|
|
@@ -300,11 +336,13 @@ export class Mem0Adapter {
|
|
|
300
336
|
private ossClient: OssClientLike | null = null;
|
|
301
337
|
private readonly cfg: MemoryBraidConfig;
|
|
302
338
|
private readonly log: MemoryBraidLogger;
|
|
339
|
+
private readonly pluginDir?: string;
|
|
303
340
|
private stateDir?: string;
|
|
304
341
|
|
|
305
342
|
constructor(cfg: MemoryBraidConfig, log: MemoryBraidLogger, options?: Mem0AdapterOptions) {
|
|
306
343
|
this.cfg = cfg;
|
|
307
344
|
this.log = log;
|
|
345
|
+
this.pluginDir = this.resolvePluginDir();
|
|
308
346
|
this.stateDir = options?.stateDir;
|
|
309
347
|
}
|
|
310
348
|
|
|
@@ -362,7 +400,7 @@ export class Mem0Adapter {
|
|
|
362
400
|
}
|
|
363
401
|
|
|
364
402
|
try {
|
|
365
|
-
const mod = await
|
|
403
|
+
const { moduleValue: mod, loader, mem0Path, sqlite3Path } = await this.loadOssModule();
|
|
366
404
|
const Memory = resolveOssMemoryCtor(mod);
|
|
367
405
|
if (!Memory) {
|
|
368
406
|
const exportKeys = Object.keys(asRecord(mod));
|
|
@@ -384,20 +422,104 @@ export class Mem0Adapter {
|
|
|
384
422
|
this.log.debug("memory_braid.mem0.response", {
|
|
385
423
|
action: "init",
|
|
386
424
|
mode: "oss",
|
|
425
|
+
loader,
|
|
426
|
+
mem0Path,
|
|
427
|
+
sqlite3Path,
|
|
387
428
|
hasCustomConfig,
|
|
388
429
|
sqliteDbPaths: collectSqliteDbPaths(configToUse),
|
|
389
430
|
}, true);
|
|
390
431
|
return this.ossClient;
|
|
391
432
|
} catch (err) {
|
|
433
|
+
const sqliteBindingsError = isSqliteBindingsError(err);
|
|
392
434
|
this.log.error("memory_braid.mem0.error", {
|
|
393
435
|
reason: "init_failed",
|
|
394
436
|
mode: "oss",
|
|
437
|
+
sqliteBindingsError,
|
|
438
|
+
...(sqliteBindingsError ? this.nativeRebuildHint() : {}),
|
|
395
439
|
error: err instanceof Error ? err.message : String(err),
|
|
396
440
|
});
|
|
397
441
|
return null;
|
|
398
442
|
}
|
|
399
443
|
}
|
|
400
444
|
|
|
445
|
+
private async loadOssModule(): Promise<LoadedOssModule> {
|
|
446
|
+
const requireFromHere = createLocalRequire();
|
|
447
|
+
const sqlite3Path = tryResolve(requireFromHere, "sqlite3");
|
|
448
|
+
if (sqlite3Path) {
|
|
449
|
+
try {
|
|
450
|
+
tryRequire(requireFromHere, sqlite3Path);
|
|
451
|
+
} catch (error) {
|
|
452
|
+
this.log.warn("memory_braid.mem0.error", {
|
|
453
|
+
reason: "sqlite3_preload_failed",
|
|
454
|
+
mode: "oss",
|
|
455
|
+
...this.nativeRebuildHint(),
|
|
456
|
+
sqlite3Path,
|
|
457
|
+
error: asErrorMessage(error),
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const mem0Path = tryResolve(requireFromHere, "mem0ai/oss");
|
|
463
|
+
if (mem0Path) {
|
|
464
|
+
try {
|
|
465
|
+
const required = tryRequire(requireFromHere, mem0Path);
|
|
466
|
+
return {
|
|
467
|
+
moduleValue: required,
|
|
468
|
+
loader: "require",
|
|
469
|
+
mem0Path,
|
|
470
|
+
sqlite3Path,
|
|
471
|
+
};
|
|
472
|
+
} catch (error) {
|
|
473
|
+
const sqliteBindingsError = isSqliteBindingsError(error);
|
|
474
|
+
this.log.warn("memory_braid.mem0.error", {
|
|
475
|
+
reason: "oss_require_failed",
|
|
476
|
+
mode: "oss",
|
|
477
|
+
mem0Path,
|
|
478
|
+
sqlite3Path,
|
|
479
|
+
sqliteBindingsError,
|
|
480
|
+
...(sqliteBindingsError ? this.nativeRebuildHint() : {}),
|
|
481
|
+
error: asErrorMessage(error),
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
const imported = await import("mem0ai/oss");
|
|
487
|
+
return {
|
|
488
|
+
moduleValue: imported,
|
|
489
|
+
loader: "import",
|
|
490
|
+
mem0Path,
|
|
491
|
+
sqlite3Path,
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
private resolvePluginDir(): string | undefined {
|
|
496
|
+
const requireFromHere = createLocalRequire();
|
|
497
|
+
const packageJsonPath = tryResolve(requireFromHere, "../package.json");
|
|
498
|
+
if (!packageJsonPath) {
|
|
499
|
+
return undefined;
|
|
500
|
+
}
|
|
501
|
+
return path.dirname(packageJsonPath);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
private nativeRebuildHint(): {
|
|
505
|
+
pluginDir?: string;
|
|
506
|
+
fixCommand: string;
|
|
507
|
+
why: string;
|
|
508
|
+
} {
|
|
509
|
+
if (this.pluginDir) {
|
|
510
|
+
return {
|
|
511
|
+
pluginDir: this.pluginDir,
|
|
512
|
+
fixCommand: `cd "${this.pluginDir}" && npm rebuild sqlite3 sharp && openclaw gateway restart`,
|
|
513
|
+
why: "OpenClaw plugin installs use --ignore-scripts, so sqlite3/sharp native artifacts may be missing after install/update.",
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
return {
|
|
518
|
+
fixCommand: "cd ~/.openclaw/extensions/memory-braid && npm rebuild sqlite3 sharp && openclaw gateway restart",
|
|
519
|
+
why: "OpenClaw plugin installs use --ignore-scripts, so sqlite3/sharp native artifacts may be missing after install/update.",
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
|
|
401
523
|
async ensureClient(): Promise<{ mode: "cloud" | "oss"; client: CloudClientLike | OssClientLike } | null> {
|
|
402
524
|
if (this.cfg.mem0.mode === "oss") {
|
|
403
525
|
const client = await this.ensureOssClient();
|