@xdarkicex/openclaw-memory-libravdb 1.3.13 → 1.3.18
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 +297 -43
- package/docs/README.md +1 -0
- package/docs/ast-v2.md +47 -5
- package/docs/continuity.md +220 -0
- package/docs/contributing.md +1 -0
- package/docs/elevated-guidance.md +258 -0
- package/docs/implementation.md +60 -2
- package/docs/install.md +7 -5
- package/docs/installation.md +13 -16
- package/docs/mathematics-v2.md +161 -1
- package/docs/uninstall.md +2 -2
- package/openclaw.plugin.json +5 -0
- package/package.json +8 -1
- package/packaging/README.md +36 -0
- package/packaging/homebrew/libravdbd.rb.tmpl +186 -2
- package/packaging/launchd/com.xdarkicex.libravdbd.plist +6 -0
- package/src/cli.ts +47 -0
- package/src/context-engine.ts +596 -157
- package/src/index.ts +6 -1
- package/src/lifecycle-hooks.ts +96 -0
- package/src/memory-provider.ts +80 -17
- package/src/memory-runtime.ts +150 -0
- package/src/openclaw-plugin-sdk.d.ts +1 -0
- package/src/plugin-runtime.ts +53 -4
- package/src/recall-utils.ts +20 -3
- package/src/scoring.ts +130 -0
- package/src/sidecar.ts +45 -1
- package/src/types.ts +28 -0
package/docs/installation.md
CHANGED
|
@@ -7,7 +7,7 @@ This document is the full installation reference for `@xdarkicex/openclaw-memory
|
|
|
7
7
|
| Requirement | Minimum | Recommended | Notes |
|
|
8
8
|
|---|---|---|---|
|
|
9
9
|
| Node.js | `22.0.0` | Latest LTS | Enforced in [`package.json`](../package.json) `engines.node` |
|
|
10
|
-
| OpenClaw | `2026.3.22` | Current stable | Pinned by [`package.json`](../package.json) `peerDependencies.openclaw`; this is the earliest local tag confirmed to expose `definePluginEntry`, `registerContextEngine`, `registerMemoryPromptSection`, and the plugin API shape this repo uses |
|
|
10
|
+
| OpenClaw | `2026.3.22` | Current stable | Pinned by [`package.json`](../package.json) `peerDependencies.openclaw`; this is the earliest local tag confirmed to expose `definePluginEntry`, `registerContextEngine`, `registerMemoryPromptSection`, and the base plugin API shape this repo uses. Newer hosts may also expose the optional `registerMemoryRuntime` seam, which this plugin now adopts when available |
|
|
11
11
|
| Go | `1.22` | Latest stable | Required only for local daemon development, not for normal plugin install |
|
|
12
12
|
| Disk | about `1 GB` free for default Nomic install | `2 GB+` if provisioning optional T5 and leaving room for DB growth | See Resource Requirements below |
|
|
13
13
|
| RAM | about `512 MB` for embed-only runtime | `1 GB+` if optional T5 summarizer is provisioned | Based on local RSS measurements below |
|
|
@@ -183,6 +183,8 @@ The release workflow generates a publish-ready `libravdbd.rb` formula asset from
|
|
|
183
183
|
- `libravdbd-linux-amd64`
|
|
184
184
|
- `libravdbd-linux-arm64`
|
|
185
185
|
|
|
186
|
+
The generated Homebrew formula also stages the bundled ONNX Runtime archive, the shipped embedding profile assets, and the T5 summarizer bundle into the install prefix so the daemon can start without a separate manual asset unpack step.
|
|
187
|
+
|
|
186
188
|
If your GitHub Actions configuration includes:
|
|
187
189
|
|
|
188
190
|
- repository variable `HOMEBREW_TAP_REPO`, for example `xDarkicex/homebrew-openclaw-libravdb-memory`
|
|
@@ -196,7 +198,8 @@ Example plugin config:
|
|
|
196
198
|
{
|
|
197
199
|
"plugins": {
|
|
198
200
|
"slots": {
|
|
199
|
-
"memory": "libravdb-memory"
|
|
201
|
+
"memory": "libravdb-memory",
|
|
202
|
+
"contextEngine": "libravdb-memory"
|
|
200
203
|
},
|
|
201
204
|
"configs": {
|
|
202
205
|
"libravdb-memory": {
|
|
@@ -217,7 +220,7 @@ Installed plugin: libravdb-memory
|
|
|
217
220
|
|
|
218
221
|
## Activation
|
|
219
222
|
|
|
220
|
-
The plugin declares `kind: ["memory", "context-engine"]` and
|
|
223
|
+
The plugin declares `kind: ["memory", "context-engine"]` and is intended to own both the `memory` and `contextEngine` slots together. Treat partial slot assignment as a misconfiguration.
|
|
221
224
|
|
|
222
225
|
Add this to `~/.openclaw/openclaw.json`:
|
|
223
226
|
|
|
@@ -225,18 +228,7 @@ Add this to `~/.openclaw/openclaw.json`:
|
|
|
225
228
|
{
|
|
226
229
|
"plugins": {
|
|
227
230
|
"slots": {
|
|
228
|
-
"memory": "libravdb-memory"
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
If your OpenClaw build uses the `contextEngine` slot instead, you can assign it there:
|
|
235
|
-
|
|
236
|
-
```json
|
|
237
|
-
{
|
|
238
|
-
"plugins": {
|
|
239
|
-
"slots": {
|
|
231
|
+
"memory": "libravdb-memory",
|
|
240
232
|
"contextEngine": "libravdb-memory"
|
|
241
233
|
}
|
|
242
234
|
}
|
|
@@ -245,8 +237,13 @@ If your OpenClaw build uses the `contextEngine` slot instead, you can assign it
|
|
|
245
237
|
|
|
246
238
|
Notes:
|
|
247
239
|
|
|
248
|
-
-
|
|
240
|
+
- This plugin should own both `memory` and `contextEngine`. Do not assign only one of them.
|
|
249
241
|
- The plugin id is `libravdb-memory`. The npm package name used at install time is `@xdarkicex/openclaw-memory-libravdb`.
|
|
242
|
+
- On newer OpenClaw versions, the plugin also registers a memory runtime bridge so the built-in `memory_search` tool can query libraVDB through the same sidecar-backed retrieval path.
|
|
243
|
+
- On newer OpenClaw versions, the plugin also listens for `before_reset` and `session_end` so it can send best-effort lifecycle hints into the sidecar.
|
|
244
|
+
- Those hints are journaled internally by the sidecar and can be inspected with `openclaw memory journal` without exposing them to normal memory export or recall.
|
|
245
|
+
- The journal keeps only a bounded number of newest entries. Override that cap with `plugins.configs.libravdb-memory.lifecycleJournalMaxEntries` if you need a different retention window.
|
|
246
|
+
- The plugin does not currently register `registerMemoryFlushPlan`; transcript ingest and compaction remain owned by the context-engine lifecycle and the sidecar.
|
|
250
247
|
|
|
251
248
|
Without a slot entry, OpenClaw's default memory can continue to run in parallel.
|
|
252
249
|
|
package/docs/mathematics-v2.md
CHANGED
|
@@ -5,7 +5,9 @@ by the plugin. The gating scalar is documented separately in
|
|
|
5
5
|
[gating.md](./gating.md). The continuity model and recent-tail preservation
|
|
6
6
|
layer are documented in [continuity.md](./continuity.md). The authored
|
|
7
7
|
invariant/variant partitioning rules are documented in
|
|
8
|
-
[ast-v2.md](./ast-v2.md).
|
|
8
|
+
[ast-v2.md](./ast-v2.md). The protected-shadow-rule Tier 1.5 model is
|
|
9
|
+
documented in [elevated-guidance.md](./elevated-guidance.md). Earlier
|
|
10
|
+
non-versioned math docs are preserved for
|
|
9
11
|
historical context, but the reviewed `*-v*` documents are authoritative when
|
|
10
12
|
both forms exist.
|
|
11
13
|
|
|
@@ -603,6 +605,69 @@ $$
|
|
|
603
605
|
|
|
604
606
|
This makes compaction load-bearing in retrieval rather than archival only.
|
|
605
607
|
|
|
608
|
+
### 5.6 Optional Lossless Compaction Extension
|
|
609
|
+
|
|
610
|
+
The current implementation replaces compacted session turns in the searchable
|
|
611
|
+
session collection after summary insertion succeeds. A stronger future variant
|
|
612
|
+
is to preserve compacted raw turns in an immutable session-history layer and
|
|
613
|
+
treat summary records as derived view nodes over that history. This extension is
|
|
614
|
+
inspired by the immutable-store and expandable-summary architecture in the LCM
|
|
615
|
+
paper ([Ehrlich and Blackman, 2026](https://papers.voltropy.com/LCM)), but the
|
|
616
|
+
formalization here is adapted to this repository's existing compaction and
|
|
617
|
+
continuity math.
|
|
618
|
+
|
|
619
|
+
Let:
|
|
620
|
+
|
|
621
|
+
$$
|
|
622
|
+
\mathcal{R}_{\mathrm{session}}=\langle r_1,\dots,r_n\rangle
|
|
623
|
+
$$
|
|
624
|
+
|
|
625
|
+
be the immutable raw session history, and let:
|
|
626
|
+
|
|
627
|
+
$$
|
|
628
|
+
\mathbf{S}=\{s_1,s_2,\dots\}
|
|
629
|
+
$$
|
|
630
|
+
|
|
631
|
+
be the set of compacted summary nodes. Define the summary-coverage DAG:
|
|
632
|
+
|
|
633
|
+
$$
|
|
634
|
+
\mathcal{G}_{\mathrm{cont}}=(\mathbf{S}\cup\mathcal{R}_{\mathrm{session}}, E_{\triangleleft})
|
|
635
|
+
$$
|
|
636
|
+
|
|
637
|
+
with:
|
|
638
|
+
|
|
639
|
+
$$
|
|
640
|
+
E_{\triangleleft}\subseteq (\mathbf{S}\times\mathbf{S})\cup(\mathbf{S}\times\mathcal{R}_{\mathrm{session}})
|
|
641
|
+
$$
|
|
642
|
+
|
|
643
|
+
Recursive raw expansion is:
|
|
644
|
+
|
|
645
|
+
$$
|
|
646
|
+
\mathrm{Expand}^{*}(x)=
|
|
647
|
+
\begin{cases}
|
|
648
|
+
\{x\} & \text{if } x\in\mathcal{R}_{\mathrm{session}} \\
|
|
649
|
+
\bigcup_{y:(x,y)\in E_{\triangleleft}} \mathrm{Expand}^{*}(y) & \text{if } x\in\mathbf{S}
|
|
650
|
+
\end{cases}
|
|
651
|
+
$$
|
|
652
|
+
|
|
653
|
+
The continuity contract for this extension is:
|
|
654
|
+
|
|
655
|
+
$$
|
|
656
|
+
\forall s\in\mathbf{S},\ \mathrm{Expand}^{*}(s)\neq\emptyset
|
|
657
|
+
$$
|
|
658
|
+
|
|
659
|
+
and:
|
|
660
|
+
|
|
661
|
+
$$
|
|
662
|
+
\forall r\in\mathcal{R}_{\mathrm{session}},\ \exists x\in \mathbf{S}\cup T_{\mathrm{recent}} \text{ such that } r\in\mathrm{Expand}^{*}(x)
|
|
663
|
+
$$
|
|
664
|
+
|
|
665
|
+
Under this extension, compaction changes the active retrievable view and the
|
|
666
|
+
assembly surface, but not the existence of raw historical evidence. This is
|
|
667
|
+
compatible with the section-1 through section-5 retrieval math because the
|
|
668
|
+
hybrid score still applies to the injected/searchable nodes; the extension only
|
|
669
|
+
strengthens the recoverability contract beneath those nodes.
|
|
670
|
+
|
|
606
671
|
## 6. Why These Pieces Compose
|
|
607
672
|
|
|
608
673
|
The full quality loop is:
|
|
@@ -1226,3 +1291,98 @@ Q(d)\in[1-\delta,\,1]\subseteq[0,1]
|
|
|
1226
1291
|
$$
|
|
1227
1292
|
|
|
1228
1293
|
for all valid inputs with $\delta\in[0,1]$.
|
|
1294
|
+
|
|
1295
|
+
## 8. Theory Boundary And Future Refinement
|
|
1296
|
+
|
|
1297
|
+
Cross-review of this document and [`continuity.md`](./continuity.md) surfaced a
|
|
1298
|
+
useful mathematical boundary that this reference should keep explicit:
|
|
1299
|
+
|
|
1300
|
+
1. storage and continuity axioms
|
|
1301
|
+
2. primary retrieval and assembly math
|
|
1302
|
+
3. optional recoverability policy
|
|
1303
|
+
|
|
1304
|
+
### 8.1 What Is Core Math
|
|
1305
|
+
|
|
1306
|
+
The core retrieval theorem in this document is the scored, budgeted selection
|
|
1307
|
+
of retrievable nodes from $\mathcal{V}_{\mathrm{rest}}$ together with authored
|
|
1308
|
+
invariants and the exact recent tail. In other words, the primary law remains:
|
|
1309
|
+
|
|
1310
|
+
$$
|
|
1311
|
+
C_{\mathrm{total}}(q)=\mathcal{I}_1\cup \mathcal{I}_2^{*}\cup T_{\mathrm{recent}}\cup \mathrm{Proj}(\mathcal{V}_{\mathrm{rest}}, q)
|
|
1312
|
+
$$
|
|
1313
|
+
|
|
1314
|
+
with the retrieval side governed by:
|
|
1315
|
+
|
|
1316
|
+
$$
|
|
1317
|
+
S_{\mathrm{final}}(d)=S_{\mathrm{base}}(d)\cdot Q(d)
|
|
1318
|
+
$$
|
|
1319
|
+
|
|
1320
|
+
and the budget side governed by the residual variant budget
|
|
1321
|
+
$\tau_{\mathcal{V}}(q)$ defined in Section 7.8.
|
|
1322
|
+
|
|
1323
|
+
### 8.2 What Is Not Core Math
|
|
1324
|
+
|
|
1325
|
+
The following should be treated as policy or heuristic unless they are derived
|
|
1326
|
+
from the governing score equations and budget laws:
|
|
1327
|
+
|
|
1328
|
+
- automatic query-time summary expansion
|
|
1329
|
+
- fixed expansion penalties
|
|
1330
|
+
- fixed expansion token sub-budgets
|
|
1331
|
+
- confidence thresholds for expansion eligibility
|
|
1332
|
+
- recursion-depth limits for summary expansion
|
|
1333
|
+
|
|
1334
|
+
These controls may be useful in runtime experiments, but they are not theorem
|
|
1335
|
+
terms by default. They should not be mistaken for new axioms of the scoring
|
|
1336
|
+
model.
|
|
1337
|
+
|
|
1338
|
+
### 8.3 Lossless Does Not Mean Always Expand
|
|
1339
|
+
|
|
1340
|
+
The lossless extension in Section 5.6 strengthens the storage and
|
|
1341
|
+
recoverability contract. It does not imply that every relevant summary should be
|
|
1342
|
+
expanded into raw turns during ordinary retrieval.
|
|
1343
|
+
|
|
1344
|
+
The mathematically safe reading is:
|
|
1345
|
+
|
|
1346
|
+
- raw immutability is an axiom
|
|
1347
|
+
- $\mathrm{Expand}^{*}$ is a recoverability theorem over the summary DAG
|
|
1348
|
+
- query-time expansion is **explicit recovery/audit only** — it was removed from
|
|
1349
|
+
the hot retrieval path and is not the default behavior; any expansion beyond
|
|
1350
|
+
the core $C_{\mathrm{total}}(q)$ assembly must be triggered deliberately, not
|
|
1351
|
+
applied silently to ranked candidates
|
|
1352
|
+
|
|
1353
|
+
This distinction preserves the design goal that continuity and recoverability
|
|
1354
|
+
support retrieval without silently replacing it.
|
|
1355
|
+
|
|
1356
|
+
### 8.4 Preferred Direction For Future Refinement
|
|
1357
|
+
|
|
1358
|
+
If a future version wants query-time expansion inside the main retrieval path,
|
|
1359
|
+
the preferred direction is to re-derive it from the existing two-pass and
|
|
1360
|
+
multi-hop framework rather than introduce standalone penalties and thresholds
|
|
1361
|
+
that float outside the score model.
|
|
1362
|
+
|
|
1363
|
+
In practical terms, future refinement should prefer one of two paths:
|
|
1364
|
+
|
|
1365
|
+
1. keep summary expansion as a separate recovery or audit layer
|
|
1366
|
+
2. formally unify summary expansion with the existing hop-expansion math
|
|
1367
|
+
|
|
1368
|
+
What this document should avoid is an in-between state where recoverability
|
|
1369
|
+
logic behaves like a second retrieval theorem without being derived as one.
|
|
1370
|
+
|
|
1371
|
+
### 8.5 Preserved Research Ideas
|
|
1372
|
+
|
|
1373
|
+
The review process also surfaced several strong theoretical ideas that are worth
|
|
1374
|
+
retaining for future work:
|
|
1375
|
+
|
|
1376
|
+
- rate-distortion views of compaction quality
|
|
1377
|
+
- information-adaptive clustering instead of equal-size chronological buckets
|
|
1378
|
+
- hot-spot preservation tiers driven by access concentration
|
|
1379
|
+
- causal-centrality-aware compaction penalties or vetoes
|
|
1380
|
+
- entropy-based tail selection
|
|
1381
|
+
- retrieval-failure-triggered raw-history recovery (the specific observable
|
|
1382
|
+
signals S1/S2/S3 are defined in the vNext spec slice; this entry refers to the
|
|
1383
|
+
general concept, not the current implementation)
|
|
1384
|
+
- closed-loop compaction tuning driven by observed retrieval quality
|
|
1385
|
+
|
|
1386
|
+
These ideas are intentionally preserved as future mathematics rather than
|
|
1387
|
+
current contract. The present document remains normative only for the formulas
|
|
1388
|
+
and invariants already defined above.
|
package/docs/uninstall.md
CHANGED
|
@@ -19,8 +19,8 @@ Remove the plugin from the active OpenClaw slot in `~/.openclaw/openclaw.json`:
|
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
Treat that JSON as a minimal example only. If you assigned `libravdb-memory`
|
|
22
|
-
under `memory`
|
|
23
|
-
other plugin slots intact.
|
|
22
|
+
under both `memory` and `contextEngine`, remove those two slot entries and
|
|
23
|
+
leave any other plugin slots intact.
|
|
24
24
|
|
|
25
25
|
If you installed the package through the OpenClaw.ai plugin UI, remove or
|
|
26
26
|
disable the same package there as well. If you use the CLI, remove it through
|
package/openclaw.plugin.json
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"properties": {
|
|
11
11
|
"dbPath": { "type": "string" },
|
|
12
12
|
"sidecarPath": { "type": "string" },
|
|
13
|
+
"useSessionSummarySearchExperiment": { "type": "boolean" },
|
|
13
14
|
"embeddingRuntimePath": { "type": "string" },
|
|
14
15
|
"embeddingBackend": { "type": "string", "enum": ["bundled", "onnx-local", "custom-local"] },
|
|
15
16
|
"embeddingProfile": {
|
|
@@ -64,6 +65,10 @@
|
|
|
64
65
|
"type": "number",
|
|
65
66
|
"default": 10
|
|
66
67
|
},
|
|
68
|
+
"lifecycleJournalMaxEntries": {
|
|
69
|
+
"type": "number",
|
|
70
|
+
"default": 500
|
|
71
|
+
},
|
|
67
72
|
"compactionQualityWeight": {
|
|
68
73
|
"type": "number",
|
|
69
74
|
"default": 0.5,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xdarkicex/openclaw-memory-libravdb",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.18",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -27,6 +27,13 @@
|
|
|
27
27
|
"check": "./.ts-toolchain/node_modules/.bin/tsc --noEmit && pnpm run test:ts",
|
|
28
28
|
"test:ts": "./.ts-toolchain/node_modules/.bin/tsc -p tsconfig.tests.json && node --test .ts-build/test/unit/*.test.js",
|
|
29
29
|
"test:integration": "./.ts-toolchain/node_modules/.bin/tsc -p tsconfig.tests.json && node --test .ts-build/test/integration/checklist-validation.test.js .ts-build/test/integration/host-flow.test.js .ts-build/test/integration/sidecar-lifecycle.test.js",
|
|
30
|
+
"benchmark:session_search_mid": "./.ts-toolchain/node_modules/.bin/tsc -p tsconfig.tests.json && OPENCLAW_PROFILE_ASSEMBLE=1 node --test --test-name-pattern=\"real sidecar mid-sized session search benchmark\" .ts-build/test/integration/host-flow.test.js",
|
|
31
|
+
"gate:assemble_optimization": "./.ts-toolchain/node_modules/.bin/tsc -p tsconfig.tests.json && OPENCLAW_PROFILE_ASSEMBLE=1 OPENCLAW_ENFORCE_ASSEMBLE_EVIDENCE_GATE=1 node --test --test-name-pattern=\"real sidecar mid-sized session search benchmark\" .ts-build/test/integration/host-flow.test.js",
|
|
32
|
+
"probe:session_recall": "./.ts-toolchain/node_modules/.bin/tsc -p tsconfig.tests.json && OPENCLAW_PROFILE_ASSEMBLE=1 node --test --test-name-pattern=\"real sidecar mid-sized session search benchmark\" .ts-build/test/integration/host-flow.test.js",
|
|
33
|
+
"probe:session_recall_threshold": "./.ts-toolchain/node_modules/.bin/tsc -p tsconfig.tests.json && OPENCLAW_PROFILE_ASSEMBLE=1 node --test --test-name-pattern=\"real sidecar session_recall index threshold probe\" .ts-build/test/integration/host-flow.test.js",
|
|
34
|
+
"benchmark:longmemeval": "./.ts-toolchain/node_modules/.bin/tsc -p tsconfig.tests.json && node --test .ts-build/test/integration/longmemeval-benchmark.test.js",
|
|
35
|
+
"benchmark:longmemeval:score": "node scripts/longmemeval-score.mjs",
|
|
36
|
+
"benchmark:longmemeval:diagnose": "node scripts/longmemeval-diagnose.mjs",
|
|
30
37
|
"build:daemon": "bash scripts/build-daemon.sh"
|
|
31
38
|
},
|
|
32
39
|
"dependencies": {
|
package/packaging/README.md
CHANGED
|
@@ -11,16 +11,51 @@ The templates assume the default daemon endpoint contract used by the plugin:
|
|
|
11
11
|
- macOS/Linux: `unix:$HOME/.clawdb/run/libravdb.sock`
|
|
12
12
|
- Windows: `tcp:127.0.0.1:37421`
|
|
13
13
|
|
|
14
|
+
## LaunchAgent plist
|
|
15
|
+
|
|
14
16
|
Before loading the macOS plist, replace:
|
|
15
17
|
|
|
16
18
|
- `__LIBRAVDBD_PATH__` with the absolute path to the `libravdbd` binary
|
|
17
19
|
- `__HOME__` with the current user's home directory
|
|
20
|
+
- `__ONNX_RUNTIME_LIB__` with the absolute path to the ONNX runtime shared library (e.g. `/path/to/onnxruntime/onnxruntime-osx-arm64-1.23.0/lib/libonnxruntime.dylib`)
|
|
21
|
+
|
|
22
|
+
## Provisioning models and runtime
|
|
23
|
+
|
|
24
|
+
**Primary install path:** The Homebrew formula (`brew install libravdbd`)
|
|
25
|
+
provisions all required assets — ONNX Runtime, nomic-embed-text-v1.5,
|
|
26
|
+
all-minilm-l6-v2, and t5-small — inline during `brew install`. No
|
|
27
|
+
additional steps are needed for a clean install.
|
|
28
|
+
|
|
29
|
+
**Repair / recovery:** If assets are deleted or corrupted after install,
|
|
30
|
+
`scripts/provision.sh` can rebuild them. This is an operator tool, not
|
|
31
|
+
the normal install path.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
bash scripts/provision.sh # provisions into .daemon-bin/
|
|
35
|
+
bash scripts/provision.sh --target /opt/libravdbd/assets # custom target
|
|
36
|
+
bash scripts/provision.sh --skip-summarizer # skip optional t5-small model
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The script downloads models from HuggingFace and the ONNX runtime from
|
|
40
|
+
GitHub Releases, verifies SHA-256 checksums, and writes the `embedding.json`
|
|
41
|
+
manifests that `libravdbd` needs at startup. It is idempotent — existing
|
|
42
|
+
verified assets are left in place.
|
|
43
|
+
|
|
44
|
+
The npm package does not include `provision.sh` or any install-time
|
|
45
|
+
provisioning hooks. The `scripts/` directory is excluded from the
|
|
46
|
+
published npm tarball via the `files` whitelist in `package.json`.
|
|
47
|
+
|
|
48
|
+
## Homebrew formula
|
|
18
49
|
|
|
19
50
|
The release workflow now generates `dist/libravdbd.rb` from this template using
|
|
20
51
|
the release version and SHA-256 files. If `HOMEBREW_TAP_REPO` and
|
|
21
52
|
`HOMEBREW_TAP_TOKEN` are configured in GitHub Actions, the workflow also updates
|
|
22
53
|
the tap automatically.
|
|
23
54
|
|
|
55
|
+
The Homebrew formula stages the bundled ONNX Runtime archive, the shipped
|
|
56
|
+
embedding profile assets, and the T5 summarizer bundle into the install prefix
|
|
57
|
+
so the daemon can boot without an extra asset-unpack step.
|
|
58
|
+
|
|
24
59
|
Expected GitHub configuration:
|
|
25
60
|
|
|
26
61
|
- repository variable `HOMEBREW_TAP_REPO`, for example `xDarkicex/homebrew-openclaw-libravdb-memory`
|
|
@@ -33,3 +68,4 @@ Template placeholders:
|
|
|
33
68
|
- `__SHA256_DARWIN_AMD64__`
|
|
34
69
|
- `__SHA256_LINUX_ARM64__`
|
|
35
70
|
- `__SHA256_LINUX_AMD64__`
|
|
71
|
+
- `__SHA256_PROVISION__`
|
|
@@ -23,15 +23,199 @@ class Libravdbd < Formula
|
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
if OS.mac?
|
|
27
|
+
resource "onnxruntime" do
|
|
28
|
+
url "https://github.com/microsoft/onnxruntime/releases/download/v1.23.0/onnxruntime-osx-universal2-1.23.0.tgz"
|
|
29
|
+
sha256 :no_check
|
|
30
|
+
end
|
|
31
|
+
elsif OS.linux?
|
|
32
|
+
if Hardware::CPU.arm?
|
|
33
|
+
resource "onnxruntime" do
|
|
34
|
+
url "https://github.com/microsoft/onnxruntime/releases/download/v1.23.0/onnxruntime-linux-aarch64-1.23.0.tgz"
|
|
35
|
+
sha256 :no_check # TODO: pin real checksum when Linux ARM64 CI is available
|
|
36
|
+
end
|
|
37
|
+
else
|
|
38
|
+
resource "onnxruntime" do
|
|
39
|
+
url "https://github.com/microsoft/onnxruntime/releases/download/v1.23.0/onnxruntime-linux-x64-1.23.0.tgz"
|
|
40
|
+
sha256 :no_check # TODO: pin real checksum when Linux AMD64 CI is available
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
resource "nomic-embed-text-v1.5-model" do
|
|
46
|
+
url "https://huggingface.co/nomic-ai/nomic-embed-text-v1.5/resolve/main/onnx/model.onnx"
|
|
47
|
+
sha256 "147d5aa88c2101237358e17796cf3a227cead1ec304ec34b465bb08e9d952965"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
resource "nomic-embed-text-v1.5-tokenizer" do
|
|
51
|
+
url "https://huggingface.co/nomic-ai/nomic-embed-text-v1.5/resolve/main/tokenizer.json"
|
|
52
|
+
sha256 "d241a60d5e8f04cc1b2b3e9ef7a4921b27bf526d9f6050ab90f9267a1f9e5c66"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
resource "all-minilm-l6-v2-model" do
|
|
56
|
+
url "https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2/resolve/main/onnx/model.onnx"
|
|
57
|
+
sha256 "6fd5d72fe4589f189f8ebc006442dbb529bb7ce38f8082112682524616046452"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
resource "all-minilm-l6-v2-tokenizer" do
|
|
61
|
+
url "https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2/resolve/main/tokenizer.json"
|
|
62
|
+
sha256 "be50c3628f2bf5bb5e3a7f17b1f74611b2561a3a27eeab05e5aa30f411572037"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
resource "t5-small-encoder" do
|
|
66
|
+
url "https://huggingface.co/optimum/t5-small/resolve/main/encoder_model.onnx"
|
|
67
|
+
sha256 "41d326633f1b85f526508cc0db78a5d40877c292c1b6dccae2eacd7d2a53480d"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
resource "t5-small-decoder" do
|
|
71
|
+
url "https://huggingface.co/optimum/t5-small/resolve/main/decoder_model.onnx"
|
|
72
|
+
sha256 "0a1451011d61bcc796a87b7306c503562e910f110f884d0cc08532972c2cc584"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
resource "t5-small-tokenizer" do
|
|
76
|
+
url "https://huggingface.co/optimum/t5-small/resolve/main/tokenizer.json"
|
|
77
|
+
sha256 "5f0ed8ab5b8cfa9812bb73752f1d80c292e52bcf5a87a144dc9ab2d251056cbb"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
resource "t5-small-tokenizer-config" do
|
|
81
|
+
url "https://huggingface.co/optimum/t5-small/resolve/main/tokenizer_config.json"
|
|
82
|
+
sha256 "4969f8d76ef05a16553bd2b07b3501673ae8d36972aea88a0f78ad31a3ff2de9"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
resource "t5-small-config" do
|
|
86
|
+
url "https://huggingface.co/optimum/t5-small/resolve/main/config.json"
|
|
87
|
+
sha256 "d112428e703aa7ea0d6b17a77e9739fcc15b87653779d9b7942d5ecbc61c00ed"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
resource "provision" do
|
|
91
|
+
url "https://github.com/xDarkicex/openclaw-memory-libravdb/releases/download/v__VERSION__/provision.sh"
|
|
92
|
+
sha256 "__SHA256_PROVISION__"
|
|
93
|
+
end
|
|
94
|
+
|
|
26
95
|
def install
|
|
27
96
|
bin.install Dir["libravdbd*"].first => "libravdbd"
|
|
97
|
+
|
|
98
|
+
models_dir = prefix/"models"
|
|
99
|
+
runtime_dir = models_dir/"onnxruntime"
|
|
100
|
+
nomic_dir = models_dir/"nomic-embed-text-v1.5"
|
|
101
|
+
minilm_dir = models_dir/"all-minilm-l6-v2"
|
|
102
|
+
t5_dir = models_dir/"t5-small"
|
|
103
|
+
|
|
104
|
+
runtime_dir.mkpath
|
|
105
|
+
nomic_dir.mkpath
|
|
106
|
+
minilm_dir.mkpath
|
|
107
|
+
t5_dir.mkpath
|
|
108
|
+
|
|
109
|
+
resource("onnxruntime").stage do
|
|
110
|
+
# Homebrew may auto-strip the top-level dir from the tgz
|
|
111
|
+
subdir = Dir["onnxruntime-*"].first
|
|
112
|
+
if subdir
|
|
113
|
+
cp_r "#{subdir}/.", runtime_dir
|
|
114
|
+
else
|
|
115
|
+
cp_r ".", runtime_dir
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
resource("nomic-embed-text-v1.5-model").stage do
|
|
120
|
+
cp "model.onnx", nomic_dir/"model.onnx"
|
|
121
|
+
end
|
|
122
|
+
resource("nomic-embed-text-v1.5-tokenizer").stage do
|
|
123
|
+
cp "tokenizer.json", nomic_dir/"tokenizer.json"
|
|
124
|
+
end
|
|
125
|
+
write_embedding_manifest(nomic_dir, "nomic-embed-text-v1.5", 768)
|
|
126
|
+
|
|
127
|
+
resource("all-minilm-l6-v2-model").stage do
|
|
128
|
+
cp "model.onnx", minilm_dir/"model.onnx"
|
|
129
|
+
end
|
|
130
|
+
resource("all-minilm-l6-v2-tokenizer").stage do
|
|
131
|
+
cp "tokenizer.json", minilm_dir/"tokenizer.json"
|
|
132
|
+
end
|
|
133
|
+
write_embedding_manifest(minilm_dir, "all-minilm-l6-v2", 384)
|
|
134
|
+
|
|
135
|
+
resource("t5-small-encoder").stage do
|
|
136
|
+
cp "encoder_model.onnx", t5_dir/"encoder_model.onnx"
|
|
137
|
+
end
|
|
138
|
+
resource("t5-small-decoder").stage do
|
|
139
|
+
cp "decoder_model.onnx", t5_dir/"decoder_model.onnx"
|
|
140
|
+
end
|
|
141
|
+
resource("t5-small-tokenizer").stage do
|
|
142
|
+
cp "tokenizer.json", t5_dir/"tokenizer.json"
|
|
143
|
+
end
|
|
144
|
+
resource("t5-small-tokenizer-config").stage do
|
|
145
|
+
cp "tokenizer_config.json", t5_dir/"tokenizer_config.json"
|
|
146
|
+
end
|
|
147
|
+
resource("t5-small-config").stage do
|
|
148
|
+
cp "config.json", t5_dir/"config.json"
|
|
149
|
+
end
|
|
150
|
+
write_summarizer_manifest(t5_dir, "t5-small")
|
|
151
|
+
|
|
152
|
+
resource("provision").stage do
|
|
153
|
+
libexec.install "provision.sh"
|
|
154
|
+
end
|
|
155
|
+
chmod 0755, libexec/"provision.sh"
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def post_install
|
|
159
|
+
(var/"clawdb").mkpath
|
|
160
|
+
(var/"clawdb/run").mkpath
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def caveats
|
|
164
|
+
<<~EOS
|
|
165
|
+
libravdbd requires ONNX embedding models to function. Models are
|
|
166
|
+
automatically provisioned during `brew install`. To re-provision
|
|
167
|
+
or repair assets manually:
|
|
168
|
+
|
|
169
|
+
#{libexec}/provision.sh --target #{prefix}/models
|
|
170
|
+
|
|
171
|
+
Data directory: #{var}/clawdb
|
|
172
|
+
Database file: #{var}/clawdb/data.libravdb
|
|
173
|
+
Socket directory: #{var}/clawdb/run
|
|
174
|
+
EOS
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
private
|
|
178
|
+
|
|
179
|
+
def write_embedding_manifest(dir, profile, dimensions)
|
|
180
|
+
File.write(dir/"embedding.json", <<~JSON)
|
|
181
|
+
{
|
|
182
|
+
"backend": "onnx-local",
|
|
183
|
+
"profile": "#{profile}",
|
|
184
|
+
"family": "#{profile}",
|
|
185
|
+
"model": "model.onnx",
|
|
186
|
+
"tokenizer": "tokenizer.json",
|
|
187
|
+
"dimensions": #{dimensions},
|
|
188
|
+
"normalize": true,
|
|
189
|
+
"inputNames": ["input_ids", "attention_mask", "token_type_ids"],
|
|
190
|
+
"outputName": "last_hidden_state",
|
|
191
|
+
"pooling": "mean",
|
|
192
|
+
"addSpecialTokens": true
|
|
193
|
+
}
|
|
194
|
+
JSON
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def write_summarizer_manifest(dir, profile)
|
|
198
|
+
File.write(dir/"summarizer.json", <<~JSON)
|
|
199
|
+
{
|
|
200
|
+
"backend": "onnx-local",
|
|
201
|
+
"profile": "#{profile}",
|
|
202
|
+
"family": "#{profile}",
|
|
203
|
+
"encoder": "encoder_model.onnx",
|
|
204
|
+
"decoder": "decoder_model.onnx",
|
|
205
|
+
"tokenizer": "tokenizer.json",
|
|
206
|
+
"maxContextTokens": 512
|
|
207
|
+
}
|
|
208
|
+
JSON
|
|
28
209
|
end
|
|
29
210
|
|
|
30
211
|
service do
|
|
31
212
|
run [opt_bin/"libravdbd", "serve"]
|
|
32
|
-
environment_variables LIBRAVDB_RPC_ENDPOINT: "unix:#{
|
|
213
|
+
environment_variables LIBRAVDB_RPC_ENDPOINT: "unix:#{var}/clawdb/run/libravdb.sock",
|
|
214
|
+
LIBRAVDB_DB_PATH: "#{var}/clawdb/data.libravdb",
|
|
215
|
+
LIBRAVDB_ONNX_RUNTIME: "#{opt_prefix}/models/onnxruntime/lib/libonnxruntime.dylib",
|
|
216
|
+
LIBRAVDB_SUMMARIZER_BACKEND: "bundled"
|
|
33
217
|
keep_alive true
|
|
34
|
-
working_dir
|
|
218
|
+
working_dir var/"clawdb"
|
|
35
219
|
end
|
|
36
220
|
|
|
37
221
|
test do
|
|
@@ -13,6 +13,12 @@
|
|
|
13
13
|
<dict>
|
|
14
14
|
<key>LIBRAVDB_RPC_ENDPOINT</key>
|
|
15
15
|
<string>unix:__HOME__/.clawdb/run/libravdb.sock</string>
|
|
16
|
+
<key>LIBRAVDB_DB_PATH</key>
|
|
17
|
+
<string>__HOME__/.clawdb/data</string>
|
|
18
|
+
<key>LIBRAVDB_ONNX_RUNTIME</key>
|
|
19
|
+
<string>__ONNX_RUNTIME_LIB__</string>
|
|
20
|
+
<key>LIBRAVDB_SUMMARIZER_BACKEND</key>
|
|
21
|
+
<string>bundled</string>
|
|
16
22
|
</dict>
|
|
17
23
|
<key>RunAtLoad</key>
|
|
18
24
|
<true/>
|
package/src/cli.ts
CHANGED
|
@@ -9,6 +9,7 @@ type StatusResult = {
|
|
|
9
9
|
message?: string;
|
|
10
10
|
turnCount?: number;
|
|
11
11
|
memoryCount?: number;
|
|
12
|
+
lifecycleHintCount?: number;
|
|
12
13
|
gatingThreshold?: number;
|
|
13
14
|
abstractiveReady?: boolean;
|
|
14
15
|
embeddingProfile?: string;
|
|
@@ -25,9 +26,18 @@ type ExportResult = {
|
|
|
25
26
|
|
|
26
27
|
type CliOptionBag = {
|
|
27
28
|
userId?: string;
|
|
29
|
+
sessionId?: string;
|
|
30
|
+
limit?: string | number;
|
|
28
31
|
yes?: boolean;
|
|
29
32
|
};
|
|
30
33
|
|
|
34
|
+
type JournalResult = {
|
|
35
|
+
results?: Array<{
|
|
36
|
+
id: string;
|
|
37
|
+
metadata: Record<string, unknown>;
|
|
38
|
+
}>;
|
|
39
|
+
};
|
|
40
|
+
|
|
31
41
|
type CliCommand = {
|
|
32
42
|
commands?: CliCommand[];
|
|
33
43
|
command(name: string): CliCommand;
|
|
@@ -74,6 +84,12 @@ export function registerMemoryCli(
|
|
|
74
84
|
.description("Stream stored memories as newline-delimited JSON");
|
|
75
85
|
exportCmd.option("--user-id <userId>", "Restrict export to a single user namespace");
|
|
76
86
|
exportCmd.action((opts) => void runExport(runtime, opts, logger));
|
|
87
|
+
|
|
88
|
+
const journal = ensureCommand(root, "journal")
|
|
89
|
+
.description("Inspect internal lifecycle journal hints");
|
|
90
|
+
journal.option("--session-id <sessionId>", "Restrict journal entries to one session id");
|
|
91
|
+
journal.option("--limit <limit>", "Maximum journal entries to show");
|
|
92
|
+
journal.action((opts) => void runJournal(runtime, opts, logger));
|
|
77
93
|
},
|
|
78
94
|
{
|
|
79
95
|
descriptors: [
|
|
@@ -108,6 +124,7 @@ async function runStatus(runtime: PluginRuntime, cfg: PluginConfig, logger: Logg
|
|
|
108
124
|
Sidecar: status.ok ? "running" : "down",
|
|
109
125
|
"Turns stored": status.turnCount ?? 0,
|
|
110
126
|
"Memories stored": status.memoryCount ?? 0,
|
|
127
|
+
"Lifecycle hints": status.lifecycleHintCount ?? 0,
|
|
111
128
|
"Gate threshold": status.gatingThreshold ?? cfg.ingestionGateThreshold ?? 0.35,
|
|
112
129
|
"Abstractive model": status.abstractiveReady ? "ready" : "not provisioned",
|
|
113
130
|
"Embedding profile": status.embeddingProfile ?? "unknown",
|
|
@@ -119,6 +136,7 @@ async function runStatus(runtime: PluginRuntime, cfg: PluginConfig, logger: Logg
|
|
|
119
136
|
Sidecar: "down",
|
|
120
137
|
"Turns stored": "n/a",
|
|
121
138
|
"Memories stored": "n/a",
|
|
139
|
+
"Lifecycle hints": "n/a",
|
|
122
140
|
"Gate threshold": cfg.ingestionGateThreshold ?? 0.35,
|
|
123
141
|
"Abstractive model": "unknown",
|
|
124
142
|
"Embedding profile": "unknown",
|
|
@@ -169,6 +187,22 @@ async function runExport(runtime: PluginRuntime, opts: CliOptionBag | undefined,
|
|
|
169
187
|
}
|
|
170
188
|
}
|
|
171
189
|
|
|
190
|
+
async function runJournal(runtime: PluginRuntime, opts: CliOptionBag | undefined, logger: LoggerLike): Promise<void> {
|
|
191
|
+
try {
|
|
192
|
+
const rpc = await runtime.getRpc();
|
|
193
|
+
const result = await rpc.call<JournalResult>("list_lifecycle_journal", {
|
|
194
|
+
sessionId: opts?.sessionId?.trim() || undefined,
|
|
195
|
+
limit: normalizeLimit(opts?.limit),
|
|
196
|
+
});
|
|
197
|
+
for (const record of result.results ?? []) {
|
|
198
|
+
stdout.write(`${JSON.stringify(record)}\n`);
|
|
199
|
+
}
|
|
200
|
+
} catch (error) {
|
|
201
|
+
logger.error(`LibraVDB journal lookup failed: ${formatError(error)}`);
|
|
202
|
+
process.exitCode = 1;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
172
206
|
async function confirm(prompt: string): Promise<boolean> {
|
|
173
207
|
const rl = createInterface({ input: stdin, output: stdout });
|
|
174
208
|
try {
|
|
@@ -186,6 +220,19 @@ function formatError(error: unknown): string {
|
|
|
186
220
|
return String(error);
|
|
187
221
|
}
|
|
188
222
|
|
|
223
|
+
function normalizeLimit(limit: string | number | undefined): number | undefined {
|
|
224
|
+
if (typeof limit === "number" && Number.isFinite(limit) && limit > 0) {
|
|
225
|
+
return Math.floor(limit);
|
|
226
|
+
}
|
|
227
|
+
if (typeof limit === "string") {
|
|
228
|
+
const parsed = Number.parseInt(limit, 10);
|
|
229
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
230
|
+
return parsed;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return undefined;
|
|
234
|
+
}
|
|
235
|
+
|
|
189
236
|
type CliRegistrar = {
|
|
190
237
|
registerCli?(
|
|
191
238
|
builder: (ctx: { program: CliProgram }) => void,
|