@xdarkicex/openclaw-memory-libravdb 1.6.25 → 1.6.27
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 +218 -37
- package/dist/context-engine.js +72 -8
- package/dist/identity.d.ts +10 -1
- package/dist/identity.js +20 -0
- package/dist/index.js +804 -135
- package/dist/libravdb-client.d.ts +3 -0
- package/dist/libravdb-client.js +12 -1
- package/dist/manifest.d.ts +46 -0
- package/dist/manifest.js +127 -0
- package/dist/memory-runtime.js +12 -7
- package/dist/plugin-runtime.d.ts +1 -1
- package/dist/plugin-runtime.js +10 -3
- package/dist/types.d.ts +5 -0
- package/docs/configuration.md +2 -2
- package/docs/embedding-profiles.md +5 -3
- package/docs/installation.md +14 -6
- package/openclaw.plugin.json +7 -2
- package/package.json +2 -2
|
@@ -10,6 +10,9 @@ export interface LibravDBClientOptions {
|
|
|
10
10
|
tlsMode?: "auto" | "tls" | "insecure";
|
|
11
11
|
tlsClientCertPath?: string;
|
|
12
12
|
tlsClientKeyPath?: string;
|
|
13
|
+
/** Stable tenant key for multi-agent DB routing. Attached as the
|
|
14
|
+
* `libravdb-tenant-key` gRPC metadata header on every call. */
|
|
15
|
+
tenantKey?: string;
|
|
13
16
|
}
|
|
14
17
|
export declare function resolveClientEndpoint(configuredEndpoint?: string): string;
|
|
15
18
|
export declare function isLegacyJsonRpcHealthResponse(payload: string): boolean;
|
package/dist/libravdb-client.js
CHANGED
|
@@ -19,6 +19,8 @@ export function resolveClientEndpoint(configuredEndpoint) {
|
|
|
19
19
|
path.join(os.homedir(), ".libravdbd", "run"),
|
|
20
20
|
"/opt/homebrew/var/libravdbd/run",
|
|
21
21
|
"/usr/local/var/libravdbd/run",
|
|
22
|
+
"/var/run/libravdbd",
|
|
23
|
+
"/run/libravdbd",
|
|
22
24
|
];
|
|
23
25
|
for (const dir of candidateDirs) {
|
|
24
26
|
const fullPath = path.join(dir, sockName);
|
|
@@ -178,6 +180,15 @@ export class LibravDBClient {
|
|
|
178
180
|
bootstrap: () => self.bootstrapHandshake(),
|
|
179
181
|
rpcMutex,
|
|
180
182
|
});
|
|
183
|
+
const interceptors = [];
|
|
184
|
+
if (options.tenantKey) {
|
|
185
|
+
const tenantKey = options.tenantKey;
|
|
186
|
+
interceptors.push((next) => async (req) => {
|
|
187
|
+
req.header.set("libravdb-tenant-key", tenantKey);
|
|
188
|
+
return next(req);
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
interceptors.push(authInterceptor);
|
|
181
192
|
const transport = createGrpcTransport({
|
|
182
193
|
baseUrl: targetUrl,
|
|
183
194
|
httpVersion: "2",
|
|
@@ -190,7 +201,7 @@ export class LibravDBClient {
|
|
|
190
201
|
...(isInsecure ? { rejectUnauthorized: false } : {}),
|
|
191
202
|
},
|
|
192
203
|
defaultTimeoutMs: options.timeoutMs ?? 30000,
|
|
193
|
-
interceptors
|
|
204
|
+
interceptors,
|
|
194
205
|
});
|
|
195
206
|
this.client = createPromiseClient(LibravDB, transport);
|
|
196
207
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export interface TurnEntry {
|
|
2
|
+
index: number;
|
|
3
|
+
role: string;
|
|
4
|
+
contentHash: string;
|
|
5
|
+
turnHash: string;
|
|
6
|
+
ingestedAt: number;
|
|
7
|
+
}
|
|
8
|
+
export interface TurnManifest {
|
|
9
|
+
sessionId: string;
|
|
10
|
+
version: number;
|
|
11
|
+
turns: TurnEntry[];
|
|
12
|
+
tailHash: string;
|
|
13
|
+
}
|
|
14
|
+
export interface KernelCompatibleMessage {
|
|
15
|
+
role: string;
|
|
16
|
+
content: string;
|
|
17
|
+
id?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare class TurnManifestStore {
|
|
20
|
+
private manifestDir;
|
|
21
|
+
constructor();
|
|
22
|
+
private getManifestPath;
|
|
23
|
+
hashString(data: string): string;
|
|
24
|
+
createEmpty(sessionId: string): TurnManifest;
|
|
25
|
+
load(sessionId: string, logger?: {
|
|
26
|
+
warn?: (msg: string) => void;
|
|
27
|
+
error?: (msg: string, e: unknown) => void;
|
|
28
|
+
}): TurnManifest;
|
|
29
|
+
save(manifest: TurnManifest): void;
|
|
30
|
+
verifyChain(manifest: TurnManifest): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Finds the overlap point between incoming messages and our stored history.
|
|
33
|
+
* Returns the index into incomingMessages where new (un-ACKed) messages begin.
|
|
34
|
+
* Returns 0 if no overlap (full re-sync).
|
|
35
|
+
*/
|
|
36
|
+
findOverlapIndex(manifest: TurnManifest, incomingMessages: KernelCompatibleMessage[]): number;
|
|
37
|
+
appendACKedMessages(manifest: TurnManifest, newMessages: KernelCompatibleMessage[], startingIndex: number): TurnManifest;
|
|
38
|
+
/**
|
|
39
|
+
* Determines the absolute starting index for a set of new messages.
|
|
40
|
+
* If we have stored turns, the next message's index is last_turn.index + 1.
|
|
41
|
+
* If the manifest is empty, we infer from OpenClaw's prePromptMessageCount signal
|
|
42
|
+
* (caller must provide this as a hint when available).
|
|
43
|
+
*/
|
|
44
|
+
deriveStartingIndex(manifest: TurnManifest, prePromptMessageCountHint?: number): number;
|
|
45
|
+
}
|
|
46
|
+
export declare const manifestStore: TurnManifestStore;
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import * as crypto from "crypto";
|
|
4
|
+
import * as os from "os";
|
|
5
|
+
export class TurnManifestStore {
|
|
6
|
+
manifestDir;
|
|
7
|
+
constructor() {
|
|
8
|
+
this.manifestDir = path.join(os.homedir(), ".openclaw", "libravdb-manifests");
|
|
9
|
+
if (!fs.existsSync(this.manifestDir)) {
|
|
10
|
+
fs.mkdirSync(this.manifestDir, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
getManifestPath(sessionId) {
|
|
14
|
+
const safe = sessionId.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
15
|
+
return path.join(this.manifestDir, `${safe}.manifest.json`);
|
|
16
|
+
}
|
|
17
|
+
hashString(data) {
|
|
18
|
+
return crypto.createHash("sha256").update(data).digest("hex");
|
|
19
|
+
}
|
|
20
|
+
createEmpty(sessionId) {
|
|
21
|
+
return {
|
|
22
|
+
sessionId,
|
|
23
|
+
version: 0,
|
|
24
|
+
turns: [],
|
|
25
|
+
tailHash: "0000000000000000000000000000000000000000000000000000000000000000",
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
load(sessionId, logger) {
|
|
29
|
+
const filePath = this.getManifestPath(sessionId);
|
|
30
|
+
if (!fs.existsSync(filePath)) {
|
|
31
|
+
return this.createEmpty(sessionId);
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const raw = fs.readFileSync(filePath, "utf8");
|
|
35
|
+
const manifest = JSON.parse(raw);
|
|
36
|
+
if (!this.verifyChain(manifest)) {
|
|
37
|
+
logger?.warn?.(`[LibraVDB] Manifest chain broken for session ${sessionId}. Forcing re-sync.`);
|
|
38
|
+
return this.createEmpty(sessionId);
|
|
39
|
+
}
|
|
40
|
+
return manifest;
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
logger?.error?.(`[LibraVDB] Failed to read manifest for ${sessionId}:`, e);
|
|
44
|
+
return this.createEmpty(sessionId);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
save(manifest) {
|
|
48
|
+
const filePath = this.getManifestPath(manifest.sessionId);
|
|
49
|
+
const tempPath = `${filePath}.${process.pid}.tmp`;
|
|
50
|
+
fs.writeFileSync(tempPath, JSON.stringify(manifest, null, 2), "utf8");
|
|
51
|
+
fs.renameSync(tempPath, filePath);
|
|
52
|
+
}
|
|
53
|
+
verifyChain(manifest) {
|
|
54
|
+
let currentHash = "0000000000000000000000000000000000000000000000000000000000000000";
|
|
55
|
+
for (const turn of manifest.turns) {
|
|
56
|
+
const expectedHash = this.hashString(`${turn.index}${turn.role}${turn.contentHash}${currentHash}`);
|
|
57
|
+
if (turn.turnHash !== expectedHash) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
currentHash = expectedHash;
|
|
61
|
+
}
|
|
62
|
+
return manifest.tailHash === currentHash;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Finds the overlap point between incoming messages and our stored history.
|
|
66
|
+
* Returns the index into incomingMessages where new (un-ACKed) messages begin.
|
|
67
|
+
* Returns 0 if no overlap (full re-sync).
|
|
68
|
+
*/
|
|
69
|
+
findOverlapIndex(manifest, incomingMessages) {
|
|
70
|
+
if (manifest.turns.length === 0) {
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
// Build a map of contentHash → index in our manifest
|
|
74
|
+
const known = new Map();
|
|
75
|
+
for (const turn of manifest.turns) {
|
|
76
|
+
known.set(turn.contentHash, turn.index);
|
|
77
|
+
}
|
|
78
|
+
// Scan incoming messages from newest to oldest to find the last match
|
|
79
|
+
for (let i = incomingMessages.length - 1; i >= 0; i--) {
|
|
80
|
+
const contentHash = this.hashString(incomingMessages[i].content);
|
|
81
|
+
if (known.has(contentHash)) {
|
|
82
|
+
return i + 1; // everything at and after this index is new
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// No overlap found — OpenClaw trimmed too much or session diverged
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
appendACKedMessages(manifest, newMessages, startingIndex) {
|
|
89
|
+
let currentHash = manifest.tailHash;
|
|
90
|
+
const newTurns = [];
|
|
91
|
+
for (let i = 0; i < newMessages.length; i++) {
|
|
92
|
+
const msg = newMessages[i];
|
|
93
|
+
const absoluteIndex = startingIndex + i;
|
|
94
|
+
const contentHash = this.hashString(msg.content);
|
|
95
|
+
currentHash = this.hashString(`${absoluteIndex}${msg.role}${contentHash}${currentHash}`);
|
|
96
|
+
newTurns.push({
|
|
97
|
+
index: absoluteIndex,
|
|
98
|
+
role: msg.role,
|
|
99
|
+
contentHash,
|
|
100
|
+
turnHash: currentHash,
|
|
101
|
+
ingestedAt: Date.now(),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
sessionId: manifest.sessionId,
|
|
106
|
+
version: manifest.version + 1,
|
|
107
|
+
turns: [...manifest.turns, ...newTurns],
|
|
108
|
+
tailHash: currentHash,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Determines the absolute starting index for a set of new messages.
|
|
113
|
+
* If we have stored turns, the next message's index is last_turn.index + 1.
|
|
114
|
+
* If the manifest is empty, we infer from OpenClaw's prePromptMessageCount signal
|
|
115
|
+
* (caller must provide this as a hint when available).
|
|
116
|
+
*/
|
|
117
|
+
deriveStartingIndex(manifest, prePromptMessageCountHint) {
|
|
118
|
+
if (manifest.turns.length > 0) {
|
|
119
|
+
return manifest.turns[manifest.turns.length - 1].index + 1;
|
|
120
|
+
}
|
|
121
|
+
// Empty manifest — use OpenClaw's signal if provided, else assume 0
|
|
122
|
+
return typeof prePromptMessageCountHint === "number" && prePromptMessageCountHint >= 0
|
|
123
|
+
? prePromptMessageCountHint
|
|
124
|
+
: 0;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
export const manifestStore = new TurnManifestStore();
|
package/dist/memory-runtime.js
CHANGED
|
@@ -74,18 +74,22 @@ function createMemorySearchManager(getClient, cfg, defaults, initialStatus) {
|
|
|
74
74
|
const filteredResults = minScore === undefined
|
|
75
75
|
? result.results
|
|
76
76
|
: result.results.filter((item) => item.score >= minScore);
|
|
77
|
-
const legacyResults = filteredResults.map((item) =>
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
const legacyResults = filteredResults.map((item) => {
|
|
78
|
+
const meta = parseMetadataJson(item);
|
|
79
|
+
return {
|
|
80
|
+
...item,
|
|
81
|
+
content: item.text || (typeof meta.text === "string" ? meta.text : ""),
|
|
82
|
+
};
|
|
83
|
+
});
|
|
81
84
|
if (legacyCall) {
|
|
82
85
|
return { results: legacyResults };
|
|
83
86
|
}
|
|
84
87
|
const memoryResults = filteredResults.map((item) => {
|
|
85
88
|
const meta = parseMetadataJson(item);
|
|
86
89
|
const collection = typeof meta.collection === "string" ? meta.collection : "memory";
|
|
90
|
+
const effectiveText = item.text || (typeof meta.text === "string" ? meta.text : "") || "";
|
|
87
91
|
const relPath = encodeSearchResultPath(collection, item.id);
|
|
88
|
-
returnedSearchPaths.set(relPath,
|
|
92
|
+
returnedSearchPaths.set(relPath, effectiveText);
|
|
89
93
|
return toMemorySearchResult(item);
|
|
90
94
|
});
|
|
91
95
|
return memoryResults;
|
|
@@ -194,12 +198,13 @@ function parseMetadataJson(item) {
|
|
|
194
198
|
function toMemorySearchResult(item) {
|
|
195
199
|
const meta = parseMetadataJson(item);
|
|
196
200
|
const collection = typeof meta.collection === "string" ? meta.collection : "memory";
|
|
201
|
+
const effectiveText = item.text || (typeof meta.text === "string" ? meta.text : "") || "";
|
|
197
202
|
return {
|
|
198
203
|
path: encodeSearchResultPath(collection, item.id),
|
|
199
204
|
startLine: 1,
|
|
200
|
-
endLine: Math.max(1,
|
|
205
|
+
endLine: Math.max(1, effectiveText.split("\n").length),
|
|
201
206
|
score: item.score,
|
|
202
|
-
snippet:
|
|
207
|
+
snippet: effectiveText,
|
|
203
208
|
source: collection.startsWith("session:") || collection.startsWith("session_") ? "sessions" : "memory",
|
|
204
209
|
citation: `${collection}:${item.id}`,
|
|
205
210
|
};
|
package/dist/plugin-runtime.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { LibravDBClient } from "./libravdb-client.js";
|
|
2
2
|
import type { LoggerLike, PluginConfig } from "./types.js";
|
|
3
3
|
export type ClientGetter = () => Promise<LibravDBClient>;
|
|
4
|
-
export declare const DEFAULT_RPC_TIMEOUT_MS =
|
|
4
|
+
export declare const DEFAULT_RPC_TIMEOUT_MS = 120000;
|
|
5
5
|
export declare const STARTUP_HEALTH_TIMEOUT_MS = 2000;
|
|
6
6
|
export declare const VALID_TLS_MODES: readonly ["auto", "tls", "insecure"];
|
|
7
7
|
export type ValidTlsMode = typeof VALID_TLS_MODES[number];
|
package/dist/plugin-runtime.js
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { LibravDBClient, resolveClientEndpoint } from "./libravdb-client.js";
|
|
2
2
|
import { formatError } from "./format-error.js";
|
|
3
|
+
import { resolveTenantKey } from "./identity.js";
|
|
3
4
|
import { existsSync, statSync } from "node:fs";
|
|
4
5
|
import path from "node:path";
|
|
5
|
-
export const DEFAULT_RPC_TIMEOUT_MS =
|
|
6
|
+
export const DEFAULT_RPC_TIMEOUT_MS = 120_000;
|
|
6
7
|
export const STARTUP_HEALTH_TIMEOUT_MS = 2000;
|
|
8
|
+
const ENV_RPC_TIMEOUT_MS = (() => {
|
|
9
|
+
const raw = Number(process.env.LIBRAVDB_RPC_TIMEOUT_MS);
|
|
10
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 0;
|
|
11
|
+
})();
|
|
7
12
|
export const VALID_TLS_MODES = ["auto", "tls", "insecure"];
|
|
8
13
|
const isTlsModeValid = (m) => VALID_TLS_MODES.includes(m);
|
|
9
14
|
export function resolveStartupHealthTimeoutMs(cfg) {
|
|
10
|
-
|
|
15
|
+
const timeout = cfg.rpcTimeoutMs ?? (ENV_RPC_TIMEOUT_MS || DEFAULT_RPC_TIMEOUT_MS);
|
|
16
|
+
return Math.max(STARTUP_HEALTH_TIMEOUT_MS, timeout);
|
|
11
17
|
}
|
|
12
18
|
export function daemonProvisioningHint() {
|
|
13
19
|
return "If you installed the npm package, install and start libravdbd separately; the package does not provision the daemon binary, ONNX Runtime, or model assets.";
|
|
@@ -48,11 +54,12 @@ export function createPluginRuntime(cfg, logger = console) {
|
|
|
48
54
|
validateTlsConfig(cfg, logger);
|
|
49
55
|
client = new LibravDBClient({
|
|
50
56
|
endpoint: cfg.grpcEndpoint || cfg.sidecarPath,
|
|
51
|
-
timeoutMs: cfg.rpcTimeoutMs ?? DEFAULT_RPC_TIMEOUT_MS,
|
|
57
|
+
timeoutMs: cfg.rpcTimeoutMs ?? (ENV_RPC_TIMEOUT_MS || DEFAULT_RPC_TIMEOUT_MS),
|
|
52
58
|
tlsCaPath: cfg.grpcEndpointTlsCa,
|
|
53
59
|
tlsMode: cfg.grpcEndpointTlsMode,
|
|
54
60
|
tlsClientCertPath: cfg.grpcEndpointTlsClientCert,
|
|
55
61
|
tlsClientKeyPath: cfg.grpcEndpointTlsClientKey,
|
|
62
|
+
tenantKey: resolveTenantKey(cfg),
|
|
56
63
|
});
|
|
57
64
|
await client.bootstrapHandshake();
|
|
58
65
|
return client;
|
package/dist/types.d.ts
CHANGED
|
@@ -2,6 +2,11 @@ export interface PluginConfig {
|
|
|
2
2
|
dbPath?: string;
|
|
3
3
|
/** Legacy fallback alias for grpcEndpoint. */
|
|
4
4
|
sidecarPath?: string;
|
|
5
|
+
/** Stable tenant identifier for multi-agent deployments. When set, the daemon
|
|
6
|
+
* routes this plugin instance to an isolated vector database. When unset,
|
|
7
|
+
* the plugin falls back to the auto-derived userId. Set different values per
|
|
8
|
+
* agent to isolate memory storage. */
|
|
9
|
+
tenantId?: string;
|
|
5
10
|
/** Stable identity for cross-session durable memory. When set, all sessions
|
|
6
11
|
* share memories under user:{userId}. When unset, the plugin auto-derives
|
|
7
12
|
* identity from the OS and persists it to the identity file. */
|
package/docs/configuration.md
CHANGED
|
@@ -87,8 +87,8 @@ address, explicitly set `grpcEndpointTlsMode: "tls"` to match:
|
|
|
87
87
|
|---|---|---|---|
|
|
88
88
|
| `embeddingProfile` | string | `nomic-embed-text-v1.5` | Primary embedding model |
|
|
89
89
|
| `fallbackProfile` | string | `bge-small-en-v1.5` | Fallback when primary model fails dimension checks |
|
|
90
|
-
| `embeddingBackend` | string | — | `bundled`, `onnx-local`, `custom-local`, or `remote` |
|
|
91
|
-
| `onnxDevice` | string | `
|
|
90
|
+
| `embeddingBackend` | string | — | `gguf` (recommended default), `bundled`, `onnx-local`, `custom-local`, or `remote` |
|
|
91
|
+
| `onnxDevice` | string | `cpu` | ONNX execution provider: `auto`, `cpu`, `coreml` (macOS), `cuda` (Linux/Windows), `directml` (Windows), `openvino` (Linux) |
|
|
92
92
|
| `embeddingRuntimePath` | string | — | Path to ONNX runtime library visible to the vector service (maps to `LIBRAVDB_ONNX_RUNTIME`; required with `embeddingBackend: "onnx-local"`) |
|
|
93
93
|
| `embeddingModelPath` | string | — | Path to the model directory containing `embedding.json`, `model.onnx`, and `tokenizer.json` (maps to `LIBRAVDB_EMBEDDING_MODEL`; required with `embeddingBackend: "onnx-local"`) |
|
|
94
94
|
| `embeddingTokenizerPath` | string | — | Path to custom tokenizer file |
|
|
@@ -9,7 +9,8 @@ Default selection baseline:
|
|
|
9
9
|
|
|
10
10
|
Why:
|
|
11
11
|
|
|
12
|
-
-
|
|
12
|
+
- GGUF is the recommended default and preferred backend for local embedding. It delivers Matryoshka-trained `nomic-embed-text-v1.5` embeddings with no ONNX Runtime dependency and hardware-native acceleration on Apple Silicon (Metal), NVIDIA (CUDA), and CPU.
|
|
13
|
+
- `bundled` uses the ONNX build of `nomic-embed-text-v1.5` and is the full-featured fallback when GGUF is unavailable.
|
|
13
14
|
- bge-small-en-v1.5 is the fallback for resource-constrained systems and is automatically selected when the primary model's dimensions do not match the active collection.
|
|
14
15
|
- Intel Macs without reliable Metal/MPS support should set `onnxDevice: "cpu"` to force CPU ONNX execution and bypass CoreML.
|
|
15
16
|
|
|
@@ -33,7 +34,7 @@ How it works:
|
|
|
33
34
|
- `onnx-local` still requires local model assets through `embeddingModelPath`, typically a directory containing `embedding.json`.
|
|
34
35
|
- The manifest may override or refine the profile, but explicit dimension mismatches fail closed.
|
|
35
36
|
- The vector service 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
|
-
- `onnxDevice` is passed through as `LIBRAVDB_ONNX_DEVICE` for vector service versions that support execution-provider selection (`auto`, `cpu
|
|
37
|
+
- `onnxDevice` is passed through as `LIBRAVDB_ONNX_DEVICE` for vector service versions that support execution-provider selection (`auto`, `cpu` (default), `cuda`, `coreml`, `directml`, `openvino`).
|
|
37
38
|
|
|
38
39
|
## Store Compatibility and Upgrades
|
|
39
40
|
|
|
@@ -65,6 +66,7 @@ Do not delete the old store until the replacement has been verified.
|
|
|
65
66
|
|
|
66
67
|
Recommended usage:
|
|
67
68
|
|
|
68
|
-
- `
|
|
69
|
+
- `gguf` for the recommended local embedding path, using `nomic-embed-text-v1.5` with hardware-native acceleration and no ONNX Runtime dependency.
|
|
70
|
+
- `bundled` for the ONNX build of `nomic-embed-text-v1.5` when GGUF is unavailable.
|
|
69
71
|
- `onnx-local` plus `embeddingProfile` when a power user wants a known model family with local assets.
|
|
70
72
|
- treat remote/Ollama providers as future separate backend types, not as overloads of `custom-local`.
|
package/docs/installation.md
CHANGED
|
@@ -231,12 +231,20 @@ libravdbd serve
|
|
|
231
231
|
|
|
232
232
|
### Deterministic fallback embeddings
|
|
233
233
|
|
|
234
|
-
If vector service
|
|
235
|
-
configured ONNX runtime or model
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
234
|
+
If the vector service falls back to deterministic embeddings, it could not locate
|
|
235
|
+
the configured ONNX runtime or model assets. The service will still run but all
|
|
236
|
+
embedding operations will fail until resolved.
|
|
237
|
+
|
|
238
|
+
To resolve: stop the vector service, then set `LIBRAVDB_ONNX_RUNTIME` to the
|
|
239
|
+
full path of the ONNX runtime library (e.g. `libonnxruntime.so` or
|
|
240
|
+
`libonnxruntime.dylib`) and `LIBRAVDB_EMBEDDING_MODEL` to the model directory
|
|
241
|
+
containing `embedding.json`. Verify the model directory also contains the
|
|
242
|
+
corresponding `.onnx` model file and `tokenizer.json`.
|
|
243
|
+
|
|
244
|
+
If a database was created while the service was in fallback mode, move that
|
|
245
|
+
`.libravdb` file and its adjacent `.embedding.json` aside before restarting —
|
|
246
|
+
a store initialized with deterministic embeddings is incompatible with ONNX-backed
|
|
247
|
+
operation.
|
|
240
248
|
|
|
241
249
|
### Incompatible database or embedding profile
|
|
242
250
|
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "libravdb-memory",
|
|
3
3
|
"name": "LibraVDB Memory",
|
|
4
4
|
"description": "Persistent vector memory with three-tier hybrid scoring",
|
|
5
|
-
"version": "1.6.
|
|
5
|
+
"version": "1.6.27",
|
|
6
6
|
"kind": [
|
|
7
7
|
"memory",
|
|
8
8
|
"context-engine"
|
|
@@ -63,6 +63,10 @@
|
|
|
63
63
|
"sidecarPath": {
|
|
64
64
|
"type": "string"
|
|
65
65
|
},
|
|
66
|
+
"tenantId": {
|
|
67
|
+
"type": "string",
|
|
68
|
+
"description": "Stable tenant identifier for multi-agent deployments. When set, the daemon routes this plugin instance to an isolated vector database. When unset, the plugin falls back to the auto-derived userId. Set different values per agent to isolate memory storage."
|
|
69
|
+
},
|
|
66
70
|
"userId": {
|
|
67
71
|
"type": "string",
|
|
68
72
|
"description": "Stable identity for cross-session durable memory. When set, sessions share memories under user:{userId}."
|
|
@@ -440,7 +444,8 @@
|
|
|
440
444
|
},
|
|
441
445
|
"rpcTimeoutMs": {
|
|
442
446
|
"type": "number",
|
|
443
|
-
"default":
|
|
447
|
+
"default": 120000,
|
|
448
|
+
"description": "gRPC timeout in milliseconds for daemon calls. Default: 120000 (2 min). Can also be set via LIBRAVDB_RPC_TIMEOUT_MS env var."
|
|
444
449
|
},
|
|
445
450
|
"maxRetries": {
|
|
446
451
|
"type": "number"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xdarkicex/openclaw-memory-libravdb",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.27",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -79,6 +79,6 @@
|
|
|
79
79
|
"dependencies": {
|
|
80
80
|
"@connectrpc/connect": "^1.7.0",
|
|
81
81
|
"@connectrpc/connect-node": "^1.7.0",
|
|
82
|
-
"@xdarkicex/libravdb-contracts": "^2.0.
|
|
82
|
+
"@xdarkicex/libravdb-contracts": "^2.0.12"
|
|
83
83
|
}
|
|
84
84
|
}
|