@xdarkicex/openclaw-memory-libravdb 1.6.10 → 1.6.12
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/dist/dream-promotion.d.ts +1 -0
- package/dist/dream-promotion.js +9 -4
- package/dist/index.js +7 -5
- package/dist/libravdb-client.d.ts +2 -1
- package/dist/libravdb-client.js +4 -2
- package/docs/configuration.md +53 -0
- package/docs/embedding-profiles.md +28 -0
- package/docs/installation.md +24 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
|
@@ -42,4 +42,5 @@ export declare function promoteDreamDiaryFile(client: LibravDBClient, opts: {
|
|
|
42
42
|
sourceMtimeMs?: number;
|
|
43
43
|
}): Promise<DreamPromotionResult>;
|
|
44
44
|
export declare function parseDreamPromotionCandidates(text: string): DreamPromotionCandidate[];
|
|
45
|
+
export declare function normalizeDiaryPath(value?: string): string;
|
|
45
46
|
export {};
|
package/dist/dream-promotion.js
CHANGED
|
@@ -279,7 +279,7 @@ function parseHeading(value) {
|
|
|
279
279
|
return normalizeSectionName(match[2] ?? "");
|
|
280
280
|
}
|
|
281
281
|
function isPromotionSection(section) {
|
|
282
|
-
return
|
|
282
|
+
return /^(?:deep sleep|dream promotion(?: candidates?)?|promotion candidates?|promote candidates?)$/.test(section);
|
|
283
283
|
}
|
|
284
284
|
function parseBulletCandidate(line) {
|
|
285
285
|
const match = /^\s*[-*+]\s+(.+)$/.exec(line);
|
|
@@ -357,18 +357,23 @@ function parseInteger(value) {
|
|
|
357
357
|
function normalizeSectionName(value) {
|
|
358
358
|
return value.trim().toLowerCase().replace(/\s+/g, " ");
|
|
359
359
|
}
|
|
360
|
-
function normalizeDiaryPath(value) {
|
|
360
|
+
export function normalizeDiaryPath(value) {
|
|
361
361
|
const trimmed = value?.trim();
|
|
362
362
|
if (!trimmed) {
|
|
363
363
|
return "";
|
|
364
364
|
}
|
|
365
|
+
// Expand ~ to home directory before resolving. path.resolve does not
|
|
366
|
+
// expand tilde, so "~/dreams.md" would resolve to "<cwd>/~/dreams.md".
|
|
367
|
+
const expanded = trimmed.startsWith("~")
|
|
368
|
+
? path.join(os.homedir(), trimmed.slice(1))
|
|
369
|
+
: trimmed;
|
|
365
370
|
// Reject traversal components — even though path.resolve collapses them,
|
|
366
371
|
// their presence signals an attempt to escape intended boundaries.
|
|
367
|
-
const segments =
|
|
372
|
+
const segments = expanded.split(/[/\\]+/);
|
|
368
373
|
if (segments.some((s) => s === "..")) {
|
|
369
374
|
throw new Error(`dream diary path must not contain ".." traversal: ${trimmed}`);
|
|
370
375
|
}
|
|
371
|
-
const resolved = path.resolve(
|
|
376
|
+
const resolved = path.resolve(expanded);
|
|
372
377
|
// Restrict to known-safe locations to prevent arbitrary file reads.
|
|
373
378
|
// Allowed roots: home directory and the configured OpenClaw state dir.
|
|
374
379
|
const allowedRoots = [
|
package/dist/index.js
CHANGED
|
@@ -25601,7 +25601,7 @@ function parseHeading(value) {
|
|
|
25601
25601
|
return normalizeSectionName(match[2] ?? "");
|
|
25602
25602
|
}
|
|
25603
25603
|
function isPromotionSection(section) {
|
|
25604
|
-
return
|
|
25604
|
+
return /^(?:deep sleep|dream promotion(?: candidates?)?|promotion candidates?|promote candidates?)$/.test(section);
|
|
25605
25605
|
}
|
|
25606
25606
|
function parseBulletCandidate(line) {
|
|
25607
25607
|
const match = /^\s*[-*+]\s+(.+)$/.exec(line);
|
|
@@ -25684,13 +25684,14 @@ function normalizeDiaryPath(value) {
|
|
|
25684
25684
|
if (!trimmed) {
|
|
25685
25685
|
return "";
|
|
25686
25686
|
}
|
|
25687
|
-
const
|
|
25687
|
+
const expanded = trimmed.startsWith("~") ? path.join(os.homedir(), trimmed.slice(1)) : trimmed;
|
|
25688
|
+
const segments = expanded.split(/[/\\]+/);
|
|
25688
25689
|
if (segments.some((s) => s === "..")) {
|
|
25689
25690
|
throw new Error(
|
|
25690
25691
|
`dream diary path must not contain ".." traversal: ${trimmed}`
|
|
25691
25692
|
);
|
|
25692
25693
|
}
|
|
25693
|
-
const resolved = path.resolve(
|
|
25694
|
+
const resolved = path.resolve(expanded);
|
|
25694
25695
|
const allowedRoots = [
|
|
25695
25696
|
os.homedir(),
|
|
25696
25697
|
process.env.OPENCLAW_STATE_DIR
|
|
@@ -36796,14 +36797,15 @@ function extractHost(target) {
|
|
|
36796
36797
|
const sep = withoutDns.lastIndexOf(":");
|
|
36797
36798
|
return sep > 0 ? withoutDns.slice(0, sep) : withoutDns;
|
|
36798
36799
|
}
|
|
36799
|
-
function loadSecretFromEnv() {
|
|
36800
|
+
function loadSecretFromEnv(logger) {
|
|
36800
36801
|
const secret = process.env.LIBRAVDB_AUTH_SECRET?.trim();
|
|
36801
36802
|
if (secret) return secret;
|
|
36802
36803
|
const secretPath = process.env.LIBRAVDB_AUTH_SECRET_FILE;
|
|
36803
36804
|
if (secretPath) {
|
|
36804
36805
|
try {
|
|
36805
36806
|
return fs3.readFileSync(secretPath, "utf8").trim() || void 0;
|
|
36806
|
-
} catch {
|
|
36807
|
+
} catch (error2) {
|
|
36808
|
+
logger?.warn?.(`LibraVDB: failed to read auth secret file "${secretPath}": ${formatError(error2)}`);
|
|
36807
36809
|
return void 0;
|
|
36808
36810
|
}
|
|
36809
36811
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Interceptor } from "@connectrpc/connect";
|
|
2
2
|
import type { PartialMessage } from "@bufbuild/protobuf";
|
|
3
|
+
import type { LoggerLike } from "./types.js";
|
|
3
4
|
import type { AfterTurnKernelRequest, AfterTurnKernelResponse, AssembleContextInternalRequest, AssembleContextInternalResponse, BootstrapSessionKernelRequest, BootstrapSessionKernelResponse, CompactSessionRequest, CompactSessionResponse, DeleteAuthoredDocumentRequest, DeleteAuthoredDocumentResponse, DreamPromotionResponse, ExportMemoryRequest, ExportMemoryResponse, FlushNamespaceRequest, FlushNamespaceResponse, FlushRequest, FlushResponse, HealthRequest, HealthResponse, IngestMarkdownDocumentRequest, IngestMarkdownDocumentResponse, IngestMessageKernelRequest, IngestMessageKernelResponse, ListCollectionRequest, ListCollectionResponse, ListLifecycleJournalRequest, ListLifecycleJournalResponse, MarkMemorySupersededRequest, MarkMemorySupersededResponse, MemoryStatusRequest, MemoryStatusResponse, PromoteDreamEntriesRequest, RankCandidatesRequest, RankCandidatesResponse, RebuildIndexRequest, RebuildIndexResponse, ReindexAuthoredDocumentRequest, ReindexAuthoredDocumentResponse, SearchTextCollectionsRequest, SearchTextRequest, SearchTextResponse, SessionLifecycleHintRequest, SessionLifecycleHintResponse } from "@xdarkicex/libravdb-contracts";
|
|
4
5
|
export interface LibravDBClientOptions {
|
|
5
6
|
endpoint?: string;
|
|
@@ -56,5 +57,5 @@ export declare class LibravDBClient {
|
|
|
56
57
|
rankCandidates(req: PartialMessage<RankCandidatesRequest>): Promise<RankCandidatesResponse>;
|
|
57
58
|
close(): void;
|
|
58
59
|
}
|
|
59
|
-
export declare function loadSecretFromEnv(): string | undefined;
|
|
60
|
+
export declare function loadSecretFromEnv(logger?: LoggerLike): string | undefined;
|
|
60
61
|
export {};
|
package/dist/libravdb-client.js
CHANGED
|
@@ -3,6 +3,7 @@ import { createGrpcTransport } from "@connectrpc/connect-node";
|
|
|
3
3
|
import { LibravDB } from "@xdarkicex/libravdb-contracts/client";
|
|
4
4
|
import { createHmac } from "node:crypto";
|
|
5
5
|
import fs from "node:fs";
|
|
6
|
+
import { formatError } from "./format-error.js";
|
|
6
7
|
import net from "node:net";
|
|
7
8
|
import os from "node:os";
|
|
8
9
|
import path from "node:path";
|
|
@@ -279,7 +280,7 @@ function extractHost(target) {
|
|
|
279
280
|
const sep = withoutDns.lastIndexOf(":");
|
|
280
281
|
return sep > 0 ? withoutDns.slice(0, sep) : withoutDns;
|
|
281
282
|
}
|
|
282
|
-
export function loadSecretFromEnv() {
|
|
283
|
+
export function loadSecretFromEnv(logger) {
|
|
283
284
|
const secret = process.env.LIBRAVDB_AUTH_SECRET?.trim();
|
|
284
285
|
if (secret)
|
|
285
286
|
return secret;
|
|
@@ -288,7 +289,8 @@ export function loadSecretFromEnv() {
|
|
|
288
289
|
try {
|
|
289
290
|
return fs.readFileSync(secretPath, "utf8").trim() || undefined;
|
|
290
291
|
}
|
|
291
|
-
catch {
|
|
292
|
+
catch (error) {
|
|
293
|
+
logger?.warn?.(`LibraVDB: failed to read auth secret file "${secretPath}": ${formatError(error)}`);
|
|
292
294
|
return undefined;
|
|
293
295
|
}
|
|
294
296
|
}
|
package/docs/configuration.md
CHANGED
|
@@ -15,6 +15,8 @@ CPU when a provider is unavailable.
|
|
|
15
15
|
| `grpcEndpoint` | string | — | gRPC kernel endpoint. See `grpcEndpointTlsMode` for credential control. |
|
|
16
16
|
| `grpcEndpointTlsCa` | string | — | Path to CA certificate PEM file. Only needed for self-signed or private CA certs. Omit when using Let's Encrypt or cert-manager. |
|
|
17
17
|
| `grpcEndpointTlsMode` | string | `"auto"` | gRPC credential mode. `"auto"`: loopback/unix → plaintext, remote → TLS. `"tls"`: always TLS. `"insecure"`: always plaintext. |
|
|
18
|
+
| `grpcEndpointTlsClientCert` | string | — | Path to client certificate PEM for mTLS. Must be paired with `grpcEndpointTlsClientKey`. |
|
|
19
|
+
| `grpcEndpointTlsClientKey` | string | — | Path to client private key PEM for mTLS. Must be paired with `grpcEndpointTlsClientCert`. |
|
|
18
20
|
| `rpcTimeoutMs` | number | `30000` | Per-call timeout for service RPC (ms) |
|
|
19
21
|
| `dbPath` | string | auto-named | Explicit DB path; when set bypasses model-specific naming |
|
|
20
22
|
|
|
@@ -56,6 +58,19 @@ Set `grpcEndpointTlsCa` to the path of the CA certificate PEM file:
|
|
|
56
58
|
The daemon must be configured with matching TLS cert and key via
|
|
57
59
|
`LIBRAVDB_GRPC_TLS_CERT` and `LIBRAVDB_GRPC_TLS_KEY`.
|
|
58
60
|
|
|
61
|
+
**Remote daemon with mTLS (mutual TLS):**
|
|
62
|
+
When the daemon requires client certificate authentication, set both
|
|
63
|
+
`grpcEndpointTlsClientCert` and `grpcEndpointTlsClientKey` (they must both
|
|
64
|
+
be present or both be omitted):
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"grpcEndpoint": "tcp:yourdaemon.internal:50051",
|
|
68
|
+
"grpcEndpointTlsCa": "/etc/certs/ca.pem",
|
|
69
|
+
"grpcEndpointTlsClientCert": "/etc/certs/client-cert.pem",
|
|
70
|
+
"grpcEndpointTlsClientKey": "/etc/certs/client-key.pem"
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
59
74
|
**Local daemon with TLS enabled:**
|
|
60
75
|
If the daemon has `LIBRAVDB_GRPC_TLS_CERT`/`LIBRAVDB_GRPC_TLS_KEY` set on a loopback
|
|
61
76
|
address, explicitly set `grpcEndpointTlsMode: "tls"` to match:
|
|
@@ -147,11 +162,49 @@ The plugin exposes `ingestionGateThreshold` for host-side gating decisions:
|
|
|
147
162
|
| `markdownIngestionObsidianInclude` | string[] | — | Obsidian glob include patterns |
|
|
148
163
|
| `markdownIngestionObsidianExclude` | string[] | same defaults as above | Obsidian glob exclude patterns; defaults to the same set as generic markdown ingestion |
|
|
149
164
|
| `markdownIngestionObsidianDebounceMs` | number | `150` | Obsidian debounce window |
|
|
165
|
+
| `markdownIngestionSnapshotPath` | string | — | Path to snapshot file for generic markdown ingestion state |
|
|
166
|
+
| `markdownIngestionObsidianSnapshotPath` | string | — | Path to snapshot file for Obsidian ingestion state |
|
|
150
167
|
|
|
151
168
|
Configured markdown roots are ignored unless the matching enable flag is set to
|
|
152
169
|
`true`. Set `markdownIngestionEnabled: true` for generic roots and
|
|
153
170
|
`markdownIngestionObsidianEnabled: true` for Obsidian vault roots.
|
|
154
171
|
|
|
172
|
+
## Continuity
|
|
173
|
+
|
|
174
|
+
| Key | Type | Default | Notes |
|
|
175
|
+
|---|---|---|---|
|
|
176
|
+
| `continuityMinTurns` | number | — | Minimum conversation turns before continuity retrieval activates |
|
|
177
|
+
| `continuityPriorContextTokens` | number | — | Token budget allocated to prior context in continuity retrieval |
|
|
178
|
+
| `continuityTailBudgetTokens` | number | — | Token budget for tail-end context in continuity retrieval |
|
|
179
|
+
|
|
180
|
+
## Recovery
|
|
181
|
+
|
|
182
|
+
| Key | Type | Default | Notes |
|
|
183
|
+
|---|---|---|---|
|
|
184
|
+
| `recoveryFloorScore` | number | — | Minimum score floor for recovery-phase retrieval |
|
|
185
|
+
| `recoveryMinConfidenceMean` | number | — | Minimum mean confidence threshold for recovery candidates |
|
|
186
|
+
| `recoveryMinTopK` | number | — | Minimum number of top-K results required for recovery |
|
|
187
|
+
|
|
188
|
+
## Section 7 scoring
|
|
189
|
+
|
|
190
|
+
Two-pass retrieval scoring subsystem. These keys control the authority-weighted
|
|
191
|
+
and recency-adjusted scoring pass that runs after the initial vector search.
|
|
192
|
+
|
|
193
|
+
| Key | Type | Default | Notes |
|
|
194
|
+
|---|---|---|---|
|
|
195
|
+
| `section7Theta1` | number | — | Primary theta parameter for first-pass scoring |
|
|
196
|
+
| `section7Kappa` | number | — | Kappa scaling factor for authority scoring |
|
|
197
|
+
| `section7HopEta` | number | — | Eta decay for hop-distance scoring |
|
|
198
|
+
| `section7HopThreshold` | number | — | Hop distance threshold for second-pass eligibility |
|
|
199
|
+
| `section7CoarseTopK` | number | — | Top-K for coarse (first-pass) retrieval |
|
|
200
|
+
| `section7SecondPassTopK` | number | — | Top-K for second-pass refined retrieval |
|
|
201
|
+
| `section7AuthorityRecencyLambda` | number | — | Lambda for recency decay in authority scoring (commented out in code) |
|
|
202
|
+
| `section7AuthorityRecencyWeight` | number | — | Weight for authority recency in combined score |
|
|
203
|
+
| `section7AuthorityFrequencyWeight` | number | — | Weight for authority frequency in combined score |
|
|
204
|
+
| `section7AuthorityAuthoredWeight` | number | — | Weight for authority authored signal in combined score |
|
|
205
|
+
| `section7AuthoritySalienceWeight` | number | — | Weight for authority salience in combined score |
|
|
206
|
+
| `section7RecencyAccessLambda` | number | — | Lambda for access-based recency decay |
|
|
207
|
+
|
|
155
208
|
## Dream promotion
|
|
156
209
|
|
|
157
210
|
| Key | Type | Default | Notes |
|
|
@@ -35,6 +35,34 @@ How it works:
|
|
|
35
35
|
- The sidecar store persists an embedding fingerprint, so reopening an existing store with a different effective model profile will fail instead of silently mixing vector spaces.
|
|
36
36
|
- `onnxDevice` is passed through as `LIBRAVDB_ONNX_DEVICE` for daemon versions that support execution-provider selection (`auto`, `cpu`, `cuda`, `coreml`, `directml`, `openvino`).
|
|
37
37
|
|
|
38
|
+
## Store Compatibility and Upgrades
|
|
39
|
+
|
|
40
|
+
The persisted embedding fingerprint is part of the database compatibility check.
|
|
41
|
+
That is intentional: if a daemon opens a store with a different effective model
|
|
42
|
+
profile, the safest outcome is to stop before mixing vector spaces.
|
|
43
|
+
|
|
44
|
+
When updating `libravdbd`, keep the same effective embedding profile unless you
|
|
45
|
+
intend to rebuild the store. The effective profile includes the profile family,
|
|
46
|
+
dimensions, normalization setting, and any metadata supplied by the model
|
|
47
|
+
manifest or daemon defaults.
|
|
48
|
+
|
|
49
|
+
Legacy local setups can be more fragile than the current packaged profiles. For
|
|
50
|
+
example, older `all-minilm-l6-v2` stores may fail to reopen after a daemon update
|
|
51
|
+
if the daemon now computes different metadata for that local profile. This does
|
|
52
|
+
not imply that current packaged `nomic-embed-text-v1.5` or
|
|
53
|
+
`bge-small-en-v1.5` stores are incompatible; it means the old local profile must
|
|
54
|
+
be treated as a separate vector space unless a migration path is provided.
|
|
55
|
+
|
|
56
|
+
If a daemon update reports that the database format or embedding profile is
|
|
57
|
+
incompatible:
|
|
58
|
+
|
|
59
|
+
1. back up both the `.libravdb` file and its `.embedding.json` metadata file;
|
|
60
|
+
2. either downgrade to the previous daemon that created the store, or move the
|
|
61
|
+
old store aside and let the new daemon initialize a fresh database;
|
|
62
|
+
3. rebuild/reingest memories with the new effective embedding profile.
|
|
63
|
+
|
|
64
|
+
Do not delete the old store until the replacement has been verified.
|
|
65
|
+
|
|
38
66
|
Recommended usage:
|
|
39
67
|
|
|
40
68
|
- `bundled` for the shipped default path, which uses `nomic-embed-text-v1.5`.
|
package/docs/installation.md
CHANGED
|
@@ -171,6 +171,30 @@ For foreground debugging:
|
|
|
171
171
|
libravdbd serve
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
+
### Incompatible database or embedding profile
|
|
175
|
+
|
|
176
|
+
If the daemon exits with `database format is incompatible` or `database
|
|
177
|
+
embedding profile is incompatible`, it is refusing to open a store whose saved
|
|
178
|
+
format or embedding fingerprint differs from the current daemon settings. This
|
|
179
|
+
fail-closed behavior protects the store from mixing incompatible vector spaces.
|
|
180
|
+
|
|
181
|
+
Before changing anything, back up both files for the affected store:
|
|
182
|
+
|
|
183
|
+
- the database file, such as `$HOME/.libravdbd/data_nomic-embed-text-v1_5.libravdb`
|
|
184
|
+
- the adjacent `.embedding.json` metadata file
|
|
185
|
+
|
|
186
|
+
Then choose one recovery path:
|
|
187
|
+
|
|
188
|
+
- downgrade to the daemon version that created the store; or
|
|
189
|
+
- move the old store aside, start the new daemon so it creates a fresh store,
|
|
190
|
+
and rebuild/reingest memories with the current embedding profile.
|
|
191
|
+
|
|
192
|
+
This can affect legacy local profiles such as older `all-minilm-l6-v2` setups
|
|
193
|
+
when daemon defaults or model metadata change across releases. It is not
|
|
194
|
+
expected for stores that stay on the current packaged profiles and assets. See
|
|
195
|
+
[Embedding Profiles](./embedding-profiles.md#store-compatibility-and-upgrades)
|
|
196
|
+
for more detail.
|
|
197
|
+
|
|
174
198
|
### Hash mismatch
|
|
175
199
|
|
|
176
200
|
Do not bypass a checksum mismatch. Delete the corrupt or stale asset and rerun
|
package/openclaw.plugin.json
CHANGED