@xdarkicex/openclaw-memory-libravdb 1.4.9 → 1.4.10
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/context-engine.d.ts +41 -4
- package/dist/context-engine.js +106 -9
- package/dist/index.js +1 -1
- package/dist/plugin-runtime.d.ts +1 -0
- package/dist/plugin-runtime.js +4 -1
- package/dist/rpc-protobuf-codecs.js +8 -1
- package/dist/rpc.d.ts +1 -0
- package/dist/rpc.js +88 -9
- package/dist/sidecar.d.ts +2 -1
- package/dist/sidecar.js +20 -4
- package/dist/types.d.ts +2 -0
- package/docs/install.md +10 -1
- package/docs/installation.md +14 -1
- package/openclaw.plugin.json +158 -47
- package/package.json +1 -1
package/dist/context-engine.d.ts
CHANGED
|
@@ -1,6 +1,42 @@
|
|
|
1
1
|
import type { PluginRuntime } from "./plugin-runtime.js";
|
|
2
2
|
import type { LoggerLike, PluginConfig, RecallCache, SearchResult } from "./types.js";
|
|
3
3
|
import { AssembleContextInternalResponse } from "./generated/libravdb/ipc/v1/rpc_pb.js";
|
|
4
|
+
type KernelCompatibleMessage = {
|
|
5
|
+
role: string;
|
|
6
|
+
content: string;
|
|
7
|
+
id?: string;
|
|
8
|
+
};
|
|
9
|
+
type OpenClawCompatibleMessage = {
|
|
10
|
+
role: string;
|
|
11
|
+
content: string;
|
|
12
|
+
id?: string;
|
|
13
|
+
};
|
|
14
|
+
type OpenClawCompatibleAssembleResult = {
|
|
15
|
+
messages: OpenClawCompatibleMessage[];
|
|
16
|
+
estimatedTokens: number;
|
|
17
|
+
systemPromptAddition: string;
|
|
18
|
+
debug?: AssembleContextInternalResponse["debug"];
|
|
19
|
+
};
|
|
20
|
+
export declare function normalizeKernelMessage(message: {
|
|
21
|
+
role: string;
|
|
22
|
+
content: unknown;
|
|
23
|
+
id?: string;
|
|
24
|
+
}): KernelCompatibleMessage;
|
|
25
|
+
export declare function normalizeKernelMessages(messages: Array<{
|
|
26
|
+
role: string;
|
|
27
|
+
content: unknown;
|
|
28
|
+
id?: string;
|
|
29
|
+
}>): KernelCompatibleMessage[];
|
|
30
|
+
export declare function normalizeAssembleResult(result: {
|
|
31
|
+
messages?: Array<{
|
|
32
|
+
role: string;
|
|
33
|
+
content?: unknown;
|
|
34
|
+
id?: string;
|
|
35
|
+
}>;
|
|
36
|
+
estimatedTokens?: number;
|
|
37
|
+
systemPromptAddition?: string;
|
|
38
|
+
debug?: AssembleContextInternalResponse["debug"];
|
|
39
|
+
}): OpenClawCompatibleAssembleResult;
|
|
4
40
|
export declare function buildContextEngineFactory(runtime: PluginRuntime, cfg: PluginConfig, recallCache: RecallCache<SearchResult>, logger?: LoggerLike): {
|
|
5
41
|
info: {
|
|
6
42
|
id: string;
|
|
@@ -19,7 +55,7 @@ export declare function buildContextEngineFactory(runtime: PluginRuntime, cfg: P
|
|
|
19
55
|
userId?: string;
|
|
20
56
|
message: {
|
|
21
57
|
role: string;
|
|
22
|
-
content:
|
|
58
|
+
content: unknown;
|
|
23
59
|
id?: string;
|
|
24
60
|
};
|
|
25
61
|
isHeartbeat?: boolean;
|
|
@@ -30,12 +66,12 @@ export declare function buildContextEngineFactory(runtime: PluginRuntime, cfg: P
|
|
|
30
66
|
userId?: string;
|
|
31
67
|
messages: Array<{
|
|
32
68
|
role: string;
|
|
33
|
-
content:
|
|
69
|
+
content: unknown;
|
|
34
70
|
id?: string;
|
|
35
71
|
}>;
|
|
36
72
|
tokenBudget: number;
|
|
37
73
|
prompt?: string;
|
|
38
|
-
}): Promise<
|
|
74
|
+
}): Promise<OpenClawCompatibleAssembleResult>;
|
|
39
75
|
compact(args: {
|
|
40
76
|
sessionId: string;
|
|
41
77
|
force?: boolean;
|
|
@@ -47,10 +83,11 @@ export declare function buildContextEngineFactory(runtime: PluginRuntime, cfg: P
|
|
|
47
83
|
userId?: string;
|
|
48
84
|
messages: Array<{
|
|
49
85
|
role: string;
|
|
50
|
-
content:
|
|
86
|
+
content: unknown;
|
|
51
87
|
id?: string;
|
|
52
88
|
}>;
|
|
53
89
|
prePromptMessageCount?: number;
|
|
54
90
|
isHeartbeat?: boolean;
|
|
55
91
|
}): Promise<any>;
|
|
56
92
|
};
|
|
93
|
+
export {};
|
package/dist/context-engine.js
CHANGED
|
@@ -1,3 +1,91 @@
|
|
|
1
|
+
function describeUnexpectedContent(value) {
|
|
2
|
+
try {
|
|
3
|
+
const serialized = JSON.stringify(value);
|
|
4
|
+
return serialized === undefined ? String(value) : serialized;
|
|
5
|
+
}
|
|
6
|
+
catch {
|
|
7
|
+
return String(value);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function stringifyKernelBlock(block) {
|
|
11
|
+
if (!block || typeof block !== "object") {
|
|
12
|
+
return "";
|
|
13
|
+
}
|
|
14
|
+
const record = block;
|
|
15
|
+
switch (record.type) {
|
|
16
|
+
case "text":
|
|
17
|
+
return typeof record.text === "string" ? record.text : "";
|
|
18
|
+
case "thinking":
|
|
19
|
+
return typeof record.thinking === "string" ? record.thinking : "";
|
|
20
|
+
case "toolCall": {
|
|
21
|
+
const name = typeof record.name === "string" ? record.name : "tool";
|
|
22
|
+
const args = record.arguments;
|
|
23
|
+
let renderedArgs = "";
|
|
24
|
+
if (typeof args === "string") {
|
|
25
|
+
renderedArgs = args;
|
|
26
|
+
}
|
|
27
|
+
else if (args !== undefined) {
|
|
28
|
+
try {
|
|
29
|
+
renderedArgs = JSON.stringify(args);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
renderedArgs = String(args);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return renderedArgs ? `[tool:${name}] ${renderedArgs}` : `[tool:${name}]`;
|
|
36
|
+
}
|
|
37
|
+
case "image":
|
|
38
|
+
return "[image omitted]";
|
|
39
|
+
default:
|
|
40
|
+
console.warn("[libravdb] unsupported kernel content block", {
|
|
41
|
+
type: record.type,
|
|
42
|
+
block: describeUnexpectedContent(record),
|
|
43
|
+
});
|
|
44
|
+
return typeof record.text === "string" ? record.text : "";
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function normalizeKernelContent(content) {
|
|
48
|
+
if (typeof content === "string") {
|
|
49
|
+
return content;
|
|
50
|
+
}
|
|
51
|
+
if (!Array.isArray(content)) {
|
|
52
|
+
console.warn("[libravdb] unexpected kernel content shape", {
|
|
53
|
+
kind: typeof content,
|
|
54
|
+
value: describeUnexpectedContent(content),
|
|
55
|
+
});
|
|
56
|
+
return "";
|
|
57
|
+
}
|
|
58
|
+
return content.map(stringifyKernelBlock).filter((part) => part.length > 0).join("\n");
|
|
59
|
+
}
|
|
60
|
+
export function normalizeKernelMessage(message) {
|
|
61
|
+
return {
|
|
62
|
+
role: message.role,
|
|
63
|
+
content: normalizeKernelContent(message.content),
|
|
64
|
+
...(typeof message.id === "string" ? { id: message.id } : {}),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export function normalizeKernelMessages(messages) {
|
|
68
|
+
return messages.map((message) => normalizeKernelMessage(message));
|
|
69
|
+
}
|
|
70
|
+
export function normalizeAssembleResult(result) {
|
|
71
|
+
const messages = Array.isArray(result.messages)
|
|
72
|
+
? result.messages.map((message) => ({
|
|
73
|
+
// OpenClaw replay only expects conversational turns here, so assemble output
|
|
74
|
+
// is collapsed to user/assistant even though normalizeKernelMessage preserves
|
|
75
|
+
// richer inbound roles. If kernel.assembleContext starts emitting other roles,
|
|
76
|
+
// this coercion point is where that contract needs to be revisited.
|
|
77
|
+
role: message.role === "user" ? "user" : "assistant",
|
|
78
|
+
content: normalizeKernelContent(message.content),
|
|
79
|
+
...(typeof message.id === "string" ? { id: message.id } : {}),
|
|
80
|
+
}))
|
|
81
|
+
: [];
|
|
82
|
+
return {
|
|
83
|
+
messages,
|
|
84
|
+
estimatedTokens: typeof result.estimatedTokens === "number" ? result.estimatedTokens : 0,
|
|
85
|
+
systemPromptAddition: typeof result.systemPromptAddition === "string" ? result.systemPromptAddition : "",
|
|
86
|
+
...(result.debug != null ? { debug: result.debug } : {}),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
1
89
|
export function buildContextEngineFactory(runtime, cfg, recallCache, logger = console) {
|
|
2
90
|
return {
|
|
3
91
|
info: { id: "libravdb-memory", name: "LibraVDB Memory", ownsCompaction: true },
|
|
@@ -24,39 +112,44 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
|
|
|
24
112
|
return await rpc.call("bootstrap_session_kernel", args);
|
|
25
113
|
},
|
|
26
114
|
async ingest(args) {
|
|
115
|
+
const message = normalizeKernelMessage(args.message);
|
|
27
116
|
const kernel = runtime.getKernel();
|
|
28
117
|
if (kernel) {
|
|
29
118
|
return await kernel.ingestMessage({
|
|
30
119
|
sessionId: args.sessionId,
|
|
31
120
|
sessionKey: args.sessionKey,
|
|
32
121
|
userId: args.userId,
|
|
33
|
-
message
|
|
122
|
+
message,
|
|
34
123
|
isHeartbeat: args.isHeartbeat,
|
|
35
124
|
});
|
|
36
125
|
}
|
|
37
126
|
const rpc = await runtime.getRpc();
|
|
38
|
-
return await rpc.call("ingest_message_kernel",
|
|
127
|
+
return await rpc.call("ingest_message_kernel", {
|
|
128
|
+
...args,
|
|
129
|
+
message,
|
|
130
|
+
});
|
|
39
131
|
},
|
|
40
132
|
async assemble(args) {
|
|
133
|
+
const messages = normalizeKernelMessages(args.messages);
|
|
41
134
|
const kernel = runtime.getKernel();
|
|
42
135
|
if (kernel) {
|
|
43
|
-
return await kernel.assembleContext({
|
|
136
|
+
return normalizeAssembleResult(await kernel.assembleContext({
|
|
44
137
|
sessionId: args.sessionId,
|
|
45
138
|
sessionKey: args.sessionKey,
|
|
46
139
|
userId: args.userId,
|
|
47
140
|
queryText: args.prompt ?? "",
|
|
48
|
-
visibleMessages:
|
|
141
|
+
visibleMessages: messages,
|
|
49
142
|
tokenBudget: args.tokenBudget,
|
|
50
143
|
config: {},
|
|
51
144
|
emitDebug: true
|
|
52
|
-
});
|
|
145
|
+
}));
|
|
53
146
|
}
|
|
54
147
|
const rpc = await runtime.getRpc();
|
|
55
148
|
const resp = await rpc.call("assemble_context_internal", {
|
|
56
149
|
sessionId: args.sessionId,
|
|
57
150
|
sessionKey: args.sessionKey,
|
|
58
151
|
userId: args.userId,
|
|
59
|
-
messages
|
|
152
|
+
messages,
|
|
60
153
|
tokenBudget: args.tokenBudget,
|
|
61
154
|
prompt: args.prompt,
|
|
62
155
|
emitDebug: true,
|
|
@@ -92,7 +185,7 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
|
|
|
92
185
|
ingestionGateThreshold: cfg.ingestionGateThreshold,
|
|
93
186
|
},
|
|
94
187
|
});
|
|
95
|
-
return resp;
|
|
188
|
+
return normalizeAssembleResult(resp);
|
|
96
189
|
},
|
|
97
190
|
async compact(args) {
|
|
98
191
|
const kernel = runtime.getKernel();
|
|
@@ -107,19 +200,23 @@ export function buildContextEngineFactory(runtime, cfg, recallCache, logger = co
|
|
|
107
200
|
return await rpc.call("compact_session", args);
|
|
108
201
|
},
|
|
109
202
|
async afterTurn(args) {
|
|
203
|
+
const messages = normalizeKernelMessages(args.messages);
|
|
110
204
|
const kernel = runtime.getKernel();
|
|
111
205
|
if (kernel) {
|
|
112
206
|
return await kernel.afterTurn({
|
|
113
207
|
sessionId: args.sessionId,
|
|
114
208
|
sessionKey: args.sessionKey,
|
|
115
209
|
userId: args.userId,
|
|
116
|
-
messages
|
|
210
|
+
messages,
|
|
117
211
|
prePromptMessageCount: args.prePromptMessageCount,
|
|
118
212
|
isHeartbeat: args.isHeartbeat,
|
|
119
213
|
});
|
|
120
214
|
}
|
|
121
215
|
const rpc = await runtime.getRpc();
|
|
122
|
-
return await rpc.call("after_turn_kernel",
|
|
216
|
+
return await rpc.call("after_turn_kernel", {
|
|
217
|
+
...args,
|
|
218
|
+
messages,
|
|
219
|
+
});
|
|
123
220
|
}
|
|
124
221
|
};
|
|
125
222
|
}
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ export default definePluginEntry({
|
|
|
12
12
|
id: "libravdb-memory",
|
|
13
13
|
name: "LibraVDB Memory",
|
|
14
14
|
description: "Persistent vector memory with three-tier hybrid scoring",
|
|
15
|
-
kind: "context-engine",
|
|
15
|
+
kind: ["memory", "context-engine"],
|
|
16
16
|
register(api) {
|
|
17
17
|
const cfg = api.pluginConfig;
|
|
18
18
|
const recallCache = createRecallCache();
|
package/dist/plugin-runtime.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { LoggerLike, PluginConfig } from "./types.js";
|
|
|
4
4
|
export type RpcGetter = () => Promise<RpcClient>;
|
|
5
5
|
export declare const DEFAULT_RPC_TIMEOUT_MS = 30000;
|
|
6
6
|
export declare const STARTUP_HEALTH_TIMEOUT_MS = 2000;
|
|
7
|
+
export declare function resolveStartupHealthTimeoutMs(cfg: PluginConfig): number;
|
|
7
8
|
export interface LifecycleHint {
|
|
8
9
|
hook: "before_reset" | "session_end";
|
|
9
10
|
reason?: string;
|
package/dist/plugin-runtime.js
CHANGED
|
@@ -4,6 +4,9 @@ import { daemonProvisioningHint, startSidecar } from "./sidecar.js";
|
|
|
4
4
|
import { readFileSync } from "node:fs";
|
|
5
5
|
export const DEFAULT_RPC_TIMEOUT_MS = 30000;
|
|
6
6
|
export const STARTUP_HEALTH_TIMEOUT_MS = 2000;
|
|
7
|
+
export function resolveStartupHealthTimeoutMs(cfg) {
|
|
8
|
+
return Math.max(STARTUP_HEALTH_TIMEOUT_MS, cfg.rpcTimeoutMs ?? DEFAULT_RPC_TIMEOUT_MS);
|
|
9
|
+
}
|
|
7
10
|
export function createPluginRuntime(cfg, logger = console) {
|
|
8
11
|
let started = null;
|
|
9
12
|
let stopped = false;
|
|
@@ -19,7 +22,7 @@ export function createPluginRuntime(cfg, logger = console) {
|
|
|
19
22
|
timeoutMs: cfg.rpcTimeoutMs ?? DEFAULT_RPC_TIMEOUT_MS,
|
|
20
23
|
});
|
|
21
24
|
const health = await rpc.call("health", {}, {
|
|
22
|
-
timeoutMs:
|
|
25
|
+
timeoutMs: resolveStartupHealthTimeoutMs(cfg),
|
|
23
26
|
});
|
|
24
27
|
if (!health.ok) {
|
|
25
28
|
try {
|
|
@@ -23,6 +23,13 @@ function normalizeSearchTextResponse(bytes) {
|
|
|
23
23
|
}
|
|
24
24
|
return response;
|
|
25
25
|
}
|
|
26
|
+
function normalizeAssembleContextInternalResponse(bytes) {
|
|
27
|
+
const response = decodeProtobufResult(AssembleContextInternalResponse, bytes);
|
|
28
|
+
if (!Array.isArray(response.messages)) {
|
|
29
|
+
response.messages = [];
|
|
30
|
+
}
|
|
31
|
+
return response;
|
|
32
|
+
}
|
|
26
33
|
function normalizeExcludeByCollection(value) {
|
|
27
34
|
const normalized = {};
|
|
28
35
|
if (!value) {
|
|
@@ -68,7 +75,7 @@ export const rpcProtobufCodecs = {
|
|
|
68
75
|
bootstrap_session_kernel: codec((params) => encodeMessage(BootstrapSessionKernelRequest, params), (bytes) => decodeProtobufResult(BootstrapSessionKernelResponse, bytes)),
|
|
69
76
|
ingest_message_kernel: codec((params) => encodeMessage(IngestMessageKernelRequest, params), (bytes) => decodeProtobufResult(IngestMessageKernelResponse, bytes)),
|
|
70
77
|
after_turn_kernel: codec((params) => encodeMessage(AfterTurnKernelRequest, params), (bytes) => decodeProtobufResult(AfterTurnKernelResponse, bytes)),
|
|
71
|
-
assemble_context_internal: codec((params) => encodeMessage(AssembleContextInternalRequest, params),
|
|
78
|
+
assemble_context_internal: codec((params) => encodeMessage(AssembleContextInternalRequest, params), normalizeAssembleContextInternalResponse),
|
|
72
79
|
compact_session: codec((params) => encodeMessage(CompactSessionRequest, params), (bytes) => decodeProtobufResult(CompactSessionResponse, bytes)),
|
|
73
80
|
rank_candidates: codec((params) => encodeMessage(RankCandidatesRequest, params), (bytes) => decodeProtobufResult(RankCandidatesResponse, bytes)),
|
|
74
81
|
};
|
package/dist/rpc.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export declare class RpcClient {
|
|
|
8
8
|
private sentMagic;
|
|
9
9
|
constructor(socket: SidecarSocket, options: RpcCallOptions);
|
|
10
10
|
call<T>(method: string, params: unknown, callOptions?: Partial<RpcCallOptions>): Promise<T>;
|
|
11
|
+
private waitForReconnect;
|
|
11
12
|
private handleData;
|
|
12
13
|
private dispatchMessage;
|
|
13
14
|
private rejectAll;
|
package/dist/rpc.js
CHANGED
|
@@ -26,12 +26,13 @@ export class RpcClient {
|
|
|
26
26
|
return await new Promise((resolve, reject) => {
|
|
27
27
|
const id = ++this.seq;
|
|
28
28
|
const timeoutMs = callOptions.timeoutMs ?? this.options.timeoutMs;
|
|
29
|
+
const deadline = Date.now() + timeoutMs;
|
|
29
30
|
const timer = setTimeout(() => {
|
|
30
31
|
this.pending.delete(id);
|
|
31
32
|
reject(new Error(`RPC timeout: ${method} (${timeoutMs}ms)`));
|
|
32
33
|
}, timeoutMs);
|
|
33
34
|
this.pending.set(id, { resolve, reject, timer, decodeResult: codec.decodeResult });
|
|
34
|
-
|
|
35
|
+
const buildFrame = () => {
|
|
35
36
|
const envelope = new RpcRequest({
|
|
36
37
|
id,
|
|
37
38
|
method,
|
|
@@ -41,18 +42,93 @@ export class RpcClient {
|
|
|
41
42
|
const header = Buffer.alloc(4);
|
|
42
43
|
header.writeUInt32BE(payload.byteLength, 0);
|
|
43
44
|
const chunks = [];
|
|
44
|
-
|
|
45
|
+
const includesMagic = !this.sentMagic;
|
|
46
|
+
if (includesMagic) {
|
|
45
47
|
chunks.push(Buffer.from([0x02]));
|
|
46
|
-
this.sentMagic = true;
|
|
47
48
|
}
|
|
48
49
|
chunks.push(header, payload);
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
50
|
+
return { frame: Buffer.concat(chunks), includesMagic };
|
|
51
|
+
};
|
|
52
|
+
const send = (allowReconnectRetry) => {
|
|
53
|
+
if (!this.pending.has(id)) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const { frame, includesMagic } = buildFrame();
|
|
57
|
+
try {
|
|
58
|
+
this.socket.write(frame);
|
|
59
|
+
if (includesMagic) {
|
|
60
|
+
this.sentMagic = true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (allowReconnectRetry && isReconnectableSocketGap(error)) {
|
|
65
|
+
this.sentMagic = false;
|
|
66
|
+
const remainingMs = Math.max(0, deadline - Date.now());
|
|
67
|
+
if (remainingMs <= 0) {
|
|
68
|
+
if (!this.pending.has(id)) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
clearTimeout(timer);
|
|
72
|
+
this.pending.delete(id);
|
|
73
|
+
reject(new Error(`RPC timeout: ${method} (${timeoutMs}ms)`));
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
void this.waitForReconnect(remainingMs)
|
|
77
|
+
.then(() => {
|
|
78
|
+
if (!this.pending.has(id)) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
send(false);
|
|
82
|
+
})
|
|
83
|
+
.catch((reconnectError) => {
|
|
84
|
+
if (!this.pending.has(id)) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
clearTimeout(timer);
|
|
88
|
+
this.pending.delete(id);
|
|
89
|
+
reject(reconnectError instanceof Error
|
|
90
|
+
? reconnectError
|
|
91
|
+
: new Error(String(reconnectError)));
|
|
92
|
+
});
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
clearTimeout(timer);
|
|
96
|
+
this.pending.delete(id);
|
|
97
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
send(true);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
async waitForReconnect(timeoutMs) {
|
|
104
|
+
await new Promise((resolve, reject) => {
|
|
105
|
+
let settled = false;
|
|
106
|
+
const onConnect = () => {
|
|
107
|
+
if (settled)
|
|
108
|
+
return;
|
|
109
|
+
settled = true;
|
|
52
110
|
clearTimeout(timer);
|
|
53
|
-
this.
|
|
54
|
-
|
|
55
|
-
}
|
|
111
|
+
this.socket.off("error", onError);
|
|
112
|
+
resolve();
|
|
113
|
+
};
|
|
114
|
+
const onError = (error) => {
|
|
115
|
+
if (settled)
|
|
116
|
+
return;
|
|
117
|
+
settled = true;
|
|
118
|
+
clearTimeout(timer);
|
|
119
|
+
this.socket.off("connect", onConnect);
|
|
120
|
+
reject(error);
|
|
121
|
+
};
|
|
122
|
+
const timer = setTimeout(() => {
|
|
123
|
+
if (settled)
|
|
124
|
+
return;
|
|
125
|
+
settled = true;
|
|
126
|
+
this.socket.off("connect", onConnect);
|
|
127
|
+
this.socket.off("error", onError);
|
|
128
|
+
reject(new Error(`Sidecar reconnect timed out (${timeoutMs}ms)`));
|
|
129
|
+
}, timeoutMs);
|
|
130
|
+
this.socket.once("connect", onConnect);
|
|
131
|
+
this.socket.once("error", onError);
|
|
56
132
|
});
|
|
57
133
|
}
|
|
58
134
|
handleData(chunk) {
|
|
@@ -119,3 +195,6 @@ export class RpcClient {
|
|
|
119
195
|
}
|
|
120
196
|
}
|
|
121
197
|
}
|
|
198
|
+
function isReconnectableSocketGap(error) {
|
|
199
|
+
return error instanceof Error && /Sidecar socket unavailable/i.test(error.message);
|
|
200
|
+
}
|
package/dist/sidecar.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ declare class PlaceholderSocket implements SidecarSocket {
|
|
|
17
17
|
setEncoding(_encoding: string): void;
|
|
18
18
|
on(event: "data" | "close" | "error", handler: DataHandler | CloseHandler | ErrorHandler): void;
|
|
19
19
|
once(event: "connect" | "error", handler: CloseHandler | ErrorHandler): void;
|
|
20
|
+
off(event: "connect" | "error", handler: CloseHandler | ErrorHandler): void;
|
|
20
21
|
write(chunk: Buffer | string): void;
|
|
21
22
|
destroy(): void;
|
|
22
23
|
private emitError;
|
|
@@ -28,7 +29,7 @@ export declare function isTcpEndpoint(endpoint: string): boolean;
|
|
|
28
29
|
export declare function resolveEndpoint(cfg: PluginConfig): string;
|
|
29
30
|
export declare function resolveConfiguredEndpoint(cfg: PluginConfig): string;
|
|
30
31
|
export declare function daemonProvisioningHint(): string;
|
|
31
|
-
export declare function defaultEndpoint(platform?: NodeJS.Platform, homeDir?: string): string;
|
|
32
|
+
export declare function defaultEndpoint(platform?: NodeJS.Platform, homeDir?: string, pathExists?: (path: string) => boolean): string;
|
|
32
33
|
export declare function buildSidecarEnv(cfg: PluginConfig): Record<string, string>;
|
|
33
34
|
export { PlaceholderSocket };
|
|
34
35
|
export declare function probeSidecarEndpoint(cfg: PluginConfig): Promise<string | null>;
|
package/dist/sidecar.js
CHANGED
|
@@ -38,6 +38,13 @@ class PlaceholderSocket {
|
|
|
38
38
|
}
|
|
39
39
|
this.errorOnce.add(handler);
|
|
40
40
|
}
|
|
41
|
+
off(event, handler) {
|
|
42
|
+
if (event === "connect") {
|
|
43
|
+
this.connectOnce.delete(handler);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
this.errorOnce.delete(handler);
|
|
47
|
+
}
|
|
41
48
|
write(chunk) {
|
|
42
49
|
try {
|
|
43
50
|
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8");
|
|
@@ -95,13 +102,15 @@ class SupervisorSocket {
|
|
|
95
102
|
connectOnce = new Set();
|
|
96
103
|
errorOnce = new Set();
|
|
97
104
|
current;
|
|
98
|
-
encoding
|
|
105
|
+
encoding;
|
|
99
106
|
generation = 0;
|
|
100
107
|
bind(socket) {
|
|
101
108
|
this.current = socket;
|
|
102
109
|
this.generation += 1;
|
|
103
110
|
const generation = this.generation;
|
|
104
|
-
|
|
111
|
+
if (this.encoding) {
|
|
112
|
+
socket.setEncoding(this.encoding);
|
|
113
|
+
}
|
|
105
114
|
socket.on("data", (chunk) => {
|
|
106
115
|
if (generation !== this.generation) {
|
|
107
116
|
return;
|
|
@@ -163,6 +172,13 @@ class SupervisorSocket {
|
|
|
163
172
|
}
|
|
164
173
|
this.errorOnce.add(handler);
|
|
165
174
|
}
|
|
175
|
+
off(event, handler) {
|
|
176
|
+
if (event === "connect") {
|
|
177
|
+
this.connectOnce.delete(handler);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
this.errorOnce.delete(handler);
|
|
181
|
+
}
|
|
166
182
|
write(chunk) {
|
|
167
183
|
if (!this.current) {
|
|
168
184
|
throw new Error("Sidecar socket unavailable");
|
|
@@ -314,7 +330,7 @@ export function resolveConfiguredEndpoint(cfg) {
|
|
|
314
330
|
export function daemonProvisioningHint() {
|
|
315
331
|
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.";
|
|
316
332
|
}
|
|
317
|
-
export function defaultEndpoint(platform = process.platform, homeDir = os.homedir()) {
|
|
333
|
+
export function defaultEndpoint(platform = process.platform, homeDir = os.homedir(), pathExists = fs.existsSync) {
|
|
318
334
|
// Honour the daemon's own env var first (set by Homebrew LaunchAgent / systemd unit).
|
|
319
335
|
const envEndpoint = process.env.LIBRAVDB_RPC_ENDPOINT?.trim();
|
|
320
336
|
if (envEndpoint && isConfiguredEndpoint(envEndpoint)) {
|
|
@@ -335,7 +351,7 @@ export function defaultEndpoint(platform = process.platform, homeDir = os.homedi
|
|
|
335
351
|
for (const dir of candidateDirs) {
|
|
336
352
|
const sockPath = path.join(dir, sockName);
|
|
337
353
|
try {
|
|
338
|
-
if (
|
|
354
|
+
if (pathExists(sockPath)) {
|
|
339
355
|
return `unix:${sockPath}`;
|
|
340
356
|
}
|
|
341
357
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -131,6 +131,8 @@ export interface SidecarSocket {
|
|
|
131
131
|
on(event: "error", handler: (error: Error) => void): void;
|
|
132
132
|
once(event: "connect", handler: () => void): void;
|
|
133
133
|
once(event: "error", handler: (error: Error) => void): void;
|
|
134
|
+
off(event: "connect", handler: () => void): void;
|
|
135
|
+
off(event: "error", handler: (error: Error) => void): void;
|
|
134
136
|
write(chunk: Buffer | string): void;
|
|
135
137
|
destroy(err?: Error): void;
|
|
136
138
|
}
|
package/docs/install.md
CHANGED
|
@@ -67,13 +67,22 @@ If you run the daemon on a non-default endpoint, add a plugin config:
|
|
|
67
67
|
}
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
+
When `sidecarPath` is set to `"auto"`, the plugin resolves endpoints in this order on macOS/Linux:
|
|
71
|
+
|
|
72
|
+
1. `LIBRAVDB_RPC_ENDPOINT` if it is set to a valid daemon endpoint
|
|
73
|
+
2. `$HOME/.clawdb/run/libravdb.sock` if it exists
|
|
74
|
+
3. `/opt/homebrew/var/clawdb/run/libravdb.sock` if it exists
|
|
75
|
+
4. `/usr/local/var/clawdb/run/libravdb.sock` if it exists
|
|
76
|
+
5. fallback to `$HOME/.clawdb/run/libravdb.sock`
|
|
77
|
+
|
|
70
78
|
## Sidecar Daemon Install
|
|
71
79
|
|
|
72
80
|
The daemon owns the local database, embeddings, and JSON-RPC endpoint.
|
|
73
81
|
|
|
74
82
|
Default endpoints:
|
|
75
83
|
|
|
76
|
-
- macOS
|
|
84
|
+
- Homebrew on macOS: `unix:/opt/homebrew/var/clawdb/run/libravdb.sock`
|
|
85
|
+
- macOS/Linux user-local installs: `unix:$HOME/.clawdb/run/libravdb.sock`
|
|
77
86
|
- Windows: `tcp:127.0.0.1:37421`
|
|
78
87
|
|
|
79
88
|
Default data path:
|
package/docs/installation.md
CHANGED
|
@@ -142,7 +142,8 @@ Install and start `libravdbd` separately for the same user account that runs Ope
|
|
|
142
142
|
|
|
143
143
|
Default endpoints:
|
|
144
144
|
|
|
145
|
-
- macOS
|
|
145
|
+
- Homebrew on macOS: `unix:/opt/homebrew/var/clawdb/run/libravdb.sock`
|
|
146
|
+
- macOS/Linux user-local installs: `unix:$HOME/.clawdb/run/libravdb.sock`
|
|
146
147
|
- Windows: `tcp:127.0.0.1:37421`
|
|
147
148
|
|
|
148
149
|
If you run the daemon on a different endpoint, set `plugins.configs.libravdb-memory.sidecarPath` in `~/.openclaw/openclaw.json`.
|
|
@@ -176,6 +177,18 @@ brew install libravdbd
|
|
|
176
177
|
brew services start libravdbd
|
|
177
178
|
```
|
|
178
179
|
|
|
180
|
+
With `sidecarPath: "auto"`, Homebrew installs on Apple Silicon should resolve to:
|
|
181
|
+
|
|
182
|
+
```text
|
|
183
|
+
unix:/opt/homebrew/var/clawdb/run/libravdb.sock
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
User-local installs still default to:
|
|
187
|
+
|
|
188
|
+
```text
|
|
189
|
+
unix:$HOME/.clawdb/run/libravdb.sock
|
|
190
|
+
```
|
|
191
|
+
|
|
179
192
|
The daemon release pipeline generates a publish-ready `libravdbd.rb` formula asset for release assets named:
|
|
180
193
|
|
|
181
194
|
- `libravdbd-darwin-arm64`
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,17 +2,35 @@
|
|
|
2
2
|
"id": "libravdb-memory",
|
|
3
3
|
"name": "LibraVDB Memory",
|
|
4
4
|
"description": "Persistent vector memory with three-tier hybrid scoring",
|
|
5
|
-
"version": "1.4.
|
|
6
|
-
"kind":
|
|
5
|
+
"version": "1.4.10",
|
|
6
|
+
"kind": [
|
|
7
|
+
"memory",
|
|
8
|
+
"context-engine"
|
|
9
|
+
],
|
|
7
10
|
"configSchema": {
|
|
8
11
|
"type": "object",
|
|
9
12
|
"additionalProperties": false,
|
|
10
13
|
"properties": {
|
|
11
|
-
"dbPath": {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
|
|
14
|
+
"dbPath": {
|
|
15
|
+
"type": "string"
|
|
16
|
+
},
|
|
17
|
+
"sidecarPath": {
|
|
18
|
+
"type": "string"
|
|
19
|
+
},
|
|
20
|
+
"useSessionSummarySearchExperiment": {
|
|
21
|
+
"type": "boolean"
|
|
22
|
+
},
|
|
23
|
+
"embeddingRuntimePath": {
|
|
24
|
+
"type": "string"
|
|
25
|
+
},
|
|
26
|
+
"embeddingBackend": {
|
|
27
|
+
"type": "string",
|
|
28
|
+
"enum": [
|
|
29
|
+
"bundled",
|
|
30
|
+
"onnx-local",
|
|
31
|
+
"custom-local"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
16
34
|
"embeddingProfile": {
|
|
17
35
|
"type": "string",
|
|
18
36
|
"default": "all-minilm-l6-v2"
|
|
@@ -21,22 +39,60 @@
|
|
|
21
39
|
"type": "string",
|
|
22
40
|
"default": "all-minilm-l6-v2"
|
|
23
41
|
},
|
|
24
|
-
"embeddingModelPath": {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
"embeddingModelPath": {
|
|
43
|
+
"type": "string"
|
|
44
|
+
},
|
|
45
|
+
"embeddingTokenizerPath": {
|
|
46
|
+
"type": "string"
|
|
47
|
+
},
|
|
48
|
+
"embeddingDimensions": {
|
|
49
|
+
"type": "number"
|
|
50
|
+
},
|
|
51
|
+
"embeddingNormalize": {
|
|
52
|
+
"type": "boolean"
|
|
53
|
+
},
|
|
54
|
+
"summarizerBackend": {
|
|
55
|
+
"type": "string",
|
|
56
|
+
"enum": [
|
|
57
|
+
"bundled",
|
|
58
|
+
"onnx-local",
|
|
59
|
+
"ollama-local",
|
|
60
|
+
"custom-local"
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
"summarizerProfile": {
|
|
64
|
+
"type": "string"
|
|
65
|
+
},
|
|
66
|
+
"summarizerRuntimePath": {
|
|
67
|
+
"type": "string"
|
|
68
|
+
},
|
|
69
|
+
"summarizerModelPath": {
|
|
70
|
+
"type": "string"
|
|
71
|
+
},
|
|
72
|
+
"summarizerTokenizerPath": {
|
|
73
|
+
"type": "string"
|
|
74
|
+
},
|
|
75
|
+
"summarizerModel": {
|
|
76
|
+
"type": "string"
|
|
77
|
+
},
|
|
78
|
+
"summarizerEndpoint": {
|
|
79
|
+
"type": "string"
|
|
80
|
+
},
|
|
81
|
+
"sessionTTL": {
|
|
82
|
+
"type": "number"
|
|
83
|
+
},
|
|
84
|
+
"topK": {
|
|
85
|
+
"type": "number"
|
|
86
|
+
},
|
|
87
|
+
"alpha": {
|
|
88
|
+
"type": "number"
|
|
89
|
+
},
|
|
90
|
+
"beta": {
|
|
91
|
+
"type": "number"
|
|
92
|
+
},
|
|
93
|
+
"gamma": {
|
|
94
|
+
"type": "number"
|
|
95
|
+
},
|
|
40
96
|
"ingestionGateThreshold": {
|
|
41
97
|
"type": "number",
|
|
42
98
|
"default": 0.35
|
|
@@ -47,7 +103,9 @@
|
|
|
47
103
|
},
|
|
48
104
|
"markdownIngestionRoots": {
|
|
49
105
|
"type": "array",
|
|
50
|
-
"items": {
|
|
106
|
+
"items": {
|
|
107
|
+
"type": "string"
|
|
108
|
+
}
|
|
51
109
|
},
|
|
52
110
|
"markdownIngestionObsidianEnabled": {
|
|
53
111
|
"type": "boolean",
|
|
@@ -55,15 +113,21 @@
|
|
|
55
113
|
},
|
|
56
114
|
"markdownIngestionObsidianRoots": {
|
|
57
115
|
"type": "array",
|
|
58
|
-
"items": {
|
|
116
|
+
"items": {
|
|
117
|
+
"type": "string"
|
|
118
|
+
}
|
|
59
119
|
},
|
|
60
120
|
"markdownIngestionObsidianInclude": {
|
|
61
121
|
"type": "array",
|
|
62
|
-
"items": {
|
|
122
|
+
"items": {
|
|
123
|
+
"type": "string"
|
|
124
|
+
}
|
|
63
125
|
},
|
|
64
126
|
"markdownIngestionObsidianExclude": {
|
|
65
127
|
"type": "array",
|
|
66
|
-
"items": {
|
|
128
|
+
"items": {
|
|
129
|
+
"type": "string"
|
|
130
|
+
}
|
|
67
131
|
},
|
|
68
132
|
"markdownIngestionObsidianDebounceMs": {
|
|
69
133
|
"type": "number",
|
|
@@ -71,11 +135,15 @@
|
|
|
71
135
|
},
|
|
72
136
|
"markdownIngestionInclude": {
|
|
73
137
|
"type": "array",
|
|
74
|
-
"items": {
|
|
138
|
+
"items": {
|
|
139
|
+
"type": "string"
|
|
140
|
+
}
|
|
75
141
|
},
|
|
76
142
|
"markdownIngestionExclude": {
|
|
77
143
|
"type": "array",
|
|
78
|
-
"items": {
|
|
144
|
+
"items": {
|
|
145
|
+
"type": "string"
|
|
146
|
+
}
|
|
79
147
|
},
|
|
80
148
|
"markdownIngestionCollection": {
|
|
81
149
|
"type": "string",
|
|
@@ -103,16 +171,38 @@
|
|
|
103
171
|
"type": "object",
|
|
104
172
|
"additionalProperties": false,
|
|
105
173
|
"default": {
|
|
106
|
-
"w1c": 0.35,
|
|
107
|
-
"
|
|
174
|
+
"w1c": 0.35,
|
|
175
|
+
"w2c": 0.4,
|
|
176
|
+
"w3c": 0.25,
|
|
177
|
+
"w1t": 0.4,
|
|
178
|
+
"w2t": 0.35,
|
|
179
|
+
"w3t": 0.25
|
|
108
180
|
},
|
|
109
181
|
"properties": {
|
|
110
|
-
"w1c": {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
"
|
|
115
|
-
|
|
182
|
+
"w1c": {
|
|
183
|
+
"type": "number",
|
|
184
|
+
"default": 0.35
|
|
185
|
+
},
|
|
186
|
+
"w2c": {
|
|
187
|
+
"type": "number",
|
|
188
|
+
"default": 0.4
|
|
189
|
+
},
|
|
190
|
+
"w3c": {
|
|
191
|
+
"type": "number",
|
|
192
|
+
"default": 0.25
|
|
193
|
+
},
|
|
194
|
+
"w1t": {
|
|
195
|
+
"type": "number",
|
|
196
|
+
"default": 0.4
|
|
197
|
+
},
|
|
198
|
+
"w2t": {
|
|
199
|
+
"type": "number",
|
|
200
|
+
"default": 0.35
|
|
201
|
+
},
|
|
202
|
+
"w3t": {
|
|
203
|
+
"type": "number",
|
|
204
|
+
"default": 0.25
|
|
205
|
+
}
|
|
116
206
|
}
|
|
117
207
|
},
|
|
118
208
|
"gatingTechNorm": {
|
|
@@ -132,21 +222,42 @@
|
|
|
132
222
|
"default": 0.5,
|
|
133
223
|
"description": "Controls how much summary confidence affects retrieval score. 0 ignores summary quality and 1 fully suppresses zero-confidence summaries."
|
|
134
224
|
},
|
|
135
|
-
"recencyLambdaSession": {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
"
|
|
139
|
-
|
|
225
|
+
"recencyLambdaSession": {
|
|
226
|
+
"type": "number"
|
|
227
|
+
},
|
|
228
|
+
"recencyLambdaUser": {
|
|
229
|
+
"type": "number"
|
|
230
|
+
},
|
|
231
|
+
"recencyLambdaGlobal": {
|
|
232
|
+
"type": "number"
|
|
233
|
+
},
|
|
234
|
+
"tokenBudgetFraction": {
|
|
235
|
+
"type": "number"
|
|
236
|
+
},
|
|
237
|
+
"compactThreshold": {
|
|
238
|
+
"type": "number"
|
|
239
|
+
},
|
|
140
240
|
"compactSessionTokenBudget": {
|
|
141
241
|
"type": "number",
|
|
142
242
|
"default": 2000,
|
|
143
243
|
"description": "Auto-trigger compaction when the session accumulates this many tokens since the last compaction. Set to 0 to disable auto-compaction."
|
|
144
244
|
},
|
|
145
|
-
"ollamaUrl": {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
"
|
|
149
|
-
|
|
245
|
+
"ollamaUrl": {
|
|
246
|
+
"type": "string"
|
|
247
|
+
},
|
|
248
|
+
"compactModel": {
|
|
249
|
+
"type": "string"
|
|
250
|
+
},
|
|
251
|
+
"rpcTimeoutMs": {
|
|
252
|
+
"type": "number",
|
|
253
|
+
"default": 30000
|
|
254
|
+
},
|
|
255
|
+
"maxRetries": {
|
|
256
|
+
"type": "number"
|
|
257
|
+
},
|
|
258
|
+
"logLevel": {
|
|
259
|
+
"type": "string"
|
|
260
|
+
}
|
|
150
261
|
}
|
|
151
262
|
}
|
|
152
263
|
}
|