@xdarkicex/openclaw-memory-libravdb 1.5.5 → 1.6.1

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.
@@ -41,13 +41,20 @@ interface IngestFeedback {
41
41
  walDepth?: number;
42
42
  walCapacity?: number;
43
43
  }
44
+ interface IngestMarkdownDocumentResponse {
45
+ ok: boolean;
46
+ feedback?: IngestFeedback;
47
+ }
44
48
  export declare class IngestQueue {
45
49
  private readonly queue;
46
- private readonly rpcCall;
50
+ private readonly ingestDocument;
51
+ private readonly deleteDocument;
47
52
  private readonly logger;
48
53
  private readonly options;
49
54
  private running;
50
- constructor(rpcCall: <T>(method: string, params: unknown) => Promise<T>, logger: LoggerLike, options?: Partial<IngestQueueOptions>);
55
+ constructor(ingestDocument: (params: IngestMarkdownDocumentParams) => Promise<IngestMarkdownDocumentResponse>, deleteDocument: (params: {
56
+ sourceDoc: string;
57
+ }) => Promise<unknown>, logger: LoggerLike, options?: Partial<IngestQueueOptions>);
51
58
  enqueueIngest(sourceDoc: string, text: string, baseParams: Omit<IngestMarkdownDocumentParams, "sourceDoc" | "text" | "mode">, maxChunkTokens?: number): Promise<IngestFeedback | undefined>;
52
59
  private ingestWithRetry;
53
60
  enqueueDelete(sourceDoc: string): Promise<void>;
@@ -6,12 +6,14 @@ const DEFAULT_OPTIONS = {
6
6
  };
7
7
  export class IngestQueue {
8
8
  queue = [];
9
- rpcCall;
9
+ ingestDocument;
10
+ deleteDocument;
10
11
  logger;
11
12
  options;
12
13
  running = false;
13
- constructor(rpcCall, logger, options = {}) {
14
- this.rpcCall = rpcCall;
14
+ constructor(ingestDocument, deleteDocument, logger, options = {}) {
15
+ this.ingestDocument = ingestDocument;
16
+ this.deleteDocument = deleteDocument;
15
17
  this.logger = logger;
16
18
  this.options = { ...DEFAULT_OPTIONS, ...options };
17
19
  if (!(this.options.chunkTokens > 0)) {
@@ -71,10 +73,16 @@ export class IngestQueue {
71
73
  return lastFeedback;
72
74
  }
73
75
  async ingestWithRetry(params) {
74
- return withRetry(() => this.rpcCall("ingest_markdown_document", params), this.options.maxRetries, this.options.retryBaseDelayMs, this.logger, `ingest_markdown_document(${params.sourceDoc})`);
76
+ return withRetry(async () => {
77
+ const resp = await this.ingestDocument(params);
78
+ if (!resp.ok) {
79
+ throw new Error(`ingest_markdown_document(${params.sourceDoc}) mode=${params.mode} returned ok=false`);
80
+ }
81
+ return resp;
82
+ }, this.options.maxRetries, this.options.retryBaseDelayMs, this.logger, `ingest_markdown_document(${params.sourceDoc})`);
75
83
  }
76
84
  async enqueueDelete(sourceDoc) {
77
- await withRetry(() => this.rpcCall("delete_authored_document", { sourceDoc }), this.options.maxRetries, this.options.retryBaseDelayMs, this.logger, `delete_authored_document(${sourceDoc})`);
85
+ await withRetry(() => this.deleteDocument({ sourceDoc }), this.options.maxRetries, this.options.retryBaseDelayMs, this.logger, `delete_authored_document(${sourceDoc})`);
78
86
  }
79
87
  }
80
88
  function splitIntoChunks(text, maxTokens) {
@@ -0,0 +1,59 @@
1
+ import type { Interceptor } from "@connectrpc/connect";
2
+ import type { PartialMessage } from "@bufbuild/protobuf";
3
+ 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
+ export interface LibravDBClientOptions {
5
+ endpoint?: string;
6
+ secret?: string;
7
+ timeoutMs?: number;
8
+ tlsCaPath?: string;
9
+ tlsMode?: "auto" | "tls" | "insecure";
10
+ tlsClientCertPath?: string;
11
+ tlsClientKeyPath?: string;
12
+ }
13
+ export declare function resolveClientEndpoint(configuredEndpoint?: string): string;
14
+ interface RpcMutex {
15
+ current: Promise<void>;
16
+ lock(): Promise<() => void>;
17
+ }
18
+ export interface AuthInterceptorState {
19
+ readonly secret: string | undefined;
20
+ nonceHex: string | undefined;
21
+ bootstrap(): Promise<void>;
22
+ readonly rpcMutex: RpcMutex;
23
+ }
24
+ export declare function createAuthInterceptor(state: AuthInterceptorState): Interceptor;
25
+ export declare class LibravDBClient {
26
+ private client;
27
+ private readonly secret;
28
+ private nonceHex;
29
+ private closed;
30
+ constructor(options?: LibravDBClientOptions);
31
+ bootstrapHandshake(): Promise<void>;
32
+ private guardOpen;
33
+ health(req?: PartialMessage<HealthRequest>): Promise<HealthResponse>;
34
+ status(req?: PartialMessage<MemoryStatusRequest>): Promise<MemoryStatusResponse>;
35
+ flush(req?: PartialMessage<FlushRequest>): Promise<FlushResponse>;
36
+ sessionLifecycleHint(req: PartialMessage<SessionLifecycleHintRequest>): Promise<SessionLifecycleHintResponse>;
37
+ listLifecycleJournal(req: PartialMessage<ListLifecycleJournalRequest>): Promise<ListLifecycleJournalResponse>;
38
+ ingestMarkdownDocument(req: PartialMessage<IngestMarkdownDocumentRequest>): Promise<IngestMarkdownDocumentResponse>;
39
+ promoteDreamEntries(req: PartialMessage<PromoteDreamEntriesRequest>): Promise<DreamPromotionResponse>;
40
+ reindexAuthoredDocument(req: PartialMessage<ReindexAuthoredDocumentRequest>): Promise<ReindexAuthoredDocumentResponse>;
41
+ deleteAuthoredDocument(req: PartialMessage<DeleteAuthoredDocumentRequest>): Promise<DeleteAuthoredDocumentResponse>;
42
+ markMemorySuperseded(req: PartialMessage<MarkMemorySupersededRequest>): Promise<MarkMemorySupersededResponse>;
43
+ searchText(req: PartialMessage<SearchTextRequest>): Promise<SearchTextResponse>;
44
+ searchTextCollections(req: PartialMessage<SearchTextCollectionsRequest>): Promise<SearchTextResponse>;
45
+ listCollection(req: PartialMessage<ListCollectionRequest>): Promise<ListCollectionResponse>;
46
+ exportMemory(req: PartialMessage<ExportMemoryRequest>): Promise<ExportMemoryResponse>;
47
+ flushNamespace(req: PartialMessage<FlushNamespaceRequest>): Promise<FlushNamespaceResponse>;
48
+ rebuildIndex(req: PartialMessage<RebuildIndexRequest>, opts?: {
49
+ timeoutMs?: number;
50
+ }): Promise<RebuildIndexResponse>;
51
+ bootstrapSessionKernel(req: PartialMessage<BootstrapSessionKernelRequest>): Promise<BootstrapSessionKernelResponse>;
52
+ ingestMessageKernel(req: PartialMessage<IngestMessageKernelRequest>): Promise<IngestMessageKernelResponse>;
53
+ afterTurnKernel(req: PartialMessage<AfterTurnKernelRequest>): Promise<AfterTurnKernelResponse>;
54
+ assembleContextInternal(req: PartialMessage<AssembleContextInternalRequest>): Promise<AssembleContextInternalResponse>;
55
+ compactSession(req: PartialMessage<CompactSessionRequest>): Promise<CompactSessionResponse>;
56
+ rankCandidates(req: PartialMessage<RankCandidatesRequest>): Promise<RankCandidatesResponse>;
57
+ close(): void;
58
+ }
59
+ export {};
@@ -0,0 +1,296 @@
1
+ import { createPromiseClient } from "@connectrpc/connect";
2
+ import { createGrpcTransport } from "@connectrpc/connect-node";
3
+ import { LibravDB } from "@xdarkicex/libravdb-contracts/client";
4
+ import { createHmac } from "node:crypto";
5
+ import fs from "node:fs";
6
+ import net from "node:net";
7
+ import os from "node:os";
8
+ import path from "node:path";
9
+ export function resolveClientEndpoint(configuredEndpoint) {
10
+ if (configuredEndpoint && configuredEndpoint !== "auto")
11
+ return configuredEndpoint;
12
+ if (process.env.LIBRAVDB_GRPC_ENDPOINT)
13
+ return process.env.LIBRAVDB_GRPC_ENDPOINT;
14
+ if (process.platform === "win32")
15
+ return "tcp:127.0.0.1:37421";
16
+ const sockName = "libravdb.sock";
17
+ const candidateDirs = [
18
+ path.join(os.homedir(), ".libravdbd", "run"),
19
+ "/opt/homebrew/var/libravdbd/run",
20
+ "/usr/local/var/libravdbd/run",
21
+ ];
22
+ for (const dir of candidateDirs) {
23
+ const fullPath = path.join(dir, sockName);
24
+ if (fs.existsSync(fullPath))
25
+ return `unix:${fullPath}`;
26
+ }
27
+ return `unix:${path.join(os.homedir(), ".libravdbd", "run", sockName)}`;
28
+ }
29
+ function createRpcMutex() {
30
+ return {
31
+ current: Promise.resolve(),
32
+ async lock() {
33
+ let release;
34
+ const p = new Promise(r => release = r);
35
+ const prev = this.current;
36
+ this.current = prev.then(() => p);
37
+ await prev;
38
+ return release;
39
+ }
40
+ };
41
+ }
42
+ export function createAuthInterceptor(state) {
43
+ return (next) => async (req) => {
44
+ // Health does not participate in the nonce chain — bypass the
45
+ // mutex entirely so recovery can call Health without deadlocking.
46
+ if (req.method.name === "Health") {
47
+ return next(req);
48
+ }
49
+ const release = await state.rpcMutex.lock();
50
+ try {
51
+ // Lost the nonce? Recover inside the lock so queued requests
52
+ // wait for the chain to be restored instead of failing spuriously.
53
+ if (state.secret && !state.nonceHex) {
54
+ await state.bootstrap();
55
+ if (!state.nonceHex) {
56
+ throw new Error("LibraVDB: bootstrap handshake did not return a nonce");
57
+ }
58
+ }
59
+ if (state.secret && state.nonceHex) {
60
+ const hmac = createHmac("sha256", state.secret);
61
+ hmac.update(state.nonceHex);
62
+ req.header.set("x-libravdb-nonce", state.nonceHex);
63
+ req.header.set("x-libravdb-auth", hmac.digest("hex"));
64
+ }
65
+ let res;
66
+ try {
67
+ res = await next(req);
68
+ }
69
+ catch (error) {
70
+ if (state.secret && state.nonceHex) {
71
+ state.nonceHex = undefined;
72
+ }
73
+ throw error;
74
+ }
75
+ if (state.secret) {
76
+ const nextNonce = res.header.get("x-libravdb-nonce") || res.trailer.get("x-libravdb-nonce");
77
+ if (nextNonce) {
78
+ state.nonceHex = nextNonce;
79
+ }
80
+ else {
81
+ state.nonceHex = undefined;
82
+ }
83
+ }
84
+ return res;
85
+ }
86
+ finally {
87
+ release();
88
+ }
89
+ };
90
+ }
91
+ export class LibravDBClient {
92
+ client;
93
+ secret;
94
+ nonceHex;
95
+ closed = false;
96
+ constructor(options = {}) {
97
+ this.secret = options.secret ?? loadSecretFromEnv();
98
+ const rawEndpoint = resolveClientEndpoint(options.endpoint);
99
+ const isUnix = rawEndpoint.startsWith("unix:");
100
+ const socketPath = isUnix ? rawEndpoint.slice(5) : undefined;
101
+ const credMode = resolveCredentialMode(rawEndpoint, options.tlsMode);
102
+ const isInsecure = isUnix || credMode === "insecure";
103
+ const targetUrl = isUnix
104
+ ? "http://localhost"
105
+ : rawEndpoint.replace(/^tcp:/, isInsecure ? "http://" : "https://");
106
+ let rootCerts = null;
107
+ let clientKey = null;
108
+ let clientCert = null;
109
+ if (!isInsecure && options.tlsCaPath) {
110
+ rootCerts = fs.readFileSync(options.tlsCaPath);
111
+ }
112
+ if (options.tlsClientCertPath && options.tlsClientKeyPath) {
113
+ clientCert = fs.readFileSync(options.tlsClientCertPath);
114
+ clientKey = fs.readFileSync(options.tlsClientKeyPath);
115
+ }
116
+ const rpcMutex = createRpcMutex();
117
+ const self = this;
118
+ const authInterceptor = createAuthInterceptor({
119
+ secret: this.secret,
120
+ get nonceHex() { return self.nonceHex; },
121
+ set nonceHex(v) { self.nonceHex = v; },
122
+ bootstrap: () => self.bootstrapHandshake(),
123
+ rpcMutex,
124
+ });
125
+ const transport = createGrpcTransport({
126
+ baseUrl: targetUrl,
127
+ httpVersion: "2",
128
+ nodeOptions: isUnix
129
+ ? { createConnection: () => net.connect(socketPath) }
130
+ : {
131
+ ...(rootCerts ? { ca: rootCerts } : {}),
132
+ ...(clientKey ? { key: clientKey } : {}),
133
+ ...(clientCert ? { cert: clientCert } : {}),
134
+ ...(isInsecure ? { rejectUnauthorized: false } : {}),
135
+ },
136
+ defaultTimeoutMs: options.timeoutMs ?? 30000,
137
+ interceptors: [authInterceptor],
138
+ });
139
+ this.client = createPromiseClient(LibravDB, transport);
140
+ }
141
+ async bootstrapHandshake() {
142
+ this.guardOpen();
143
+ try {
144
+ await this.client.health({ service: "" }, {
145
+ onHeader: (headers) => {
146
+ const nonce = headers.get("x-libravdb-nonce");
147
+ if (nonce)
148
+ this.nonceHex = nonce;
149
+ },
150
+ });
151
+ }
152
+ catch (error) {
153
+ throw new Error(`LibraVDB: failed to handshake with daemon: ${error instanceof Error ? error.message : String(error)}`);
154
+ }
155
+ }
156
+ guardOpen() {
157
+ if (this.closed) {
158
+ throw new Error("LibravDB client is closed");
159
+ }
160
+ }
161
+ // ── Session lifecycle ────────────────────────────────────────────
162
+ async health(req = {}) {
163
+ this.guardOpen();
164
+ return this.client.health(req);
165
+ }
166
+ async status(req = {}) {
167
+ this.guardOpen();
168
+ return this.client.status(req);
169
+ }
170
+ async flush(req = {}) {
171
+ this.guardOpen();
172
+ return this.client.flush(req);
173
+ }
174
+ async sessionLifecycleHint(req) {
175
+ this.guardOpen();
176
+ return this.client.sessionLifecycleHint(req);
177
+ }
178
+ async listLifecycleJournal(req) {
179
+ this.guardOpen();
180
+ return this.client.listLifecycleJournal(req);
181
+ }
182
+ // ── Ingest ───────────────────────────────────────────────────────
183
+ async ingestMarkdownDocument(req) {
184
+ this.guardOpen();
185
+ return this.client.ingestMarkdownDocument(req);
186
+ }
187
+ async promoteDreamEntries(req) {
188
+ this.guardOpen();
189
+ return this.client.promoteDreamEntries(req);
190
+ }
191
+ async reindexAuthoredDocument(req) {
192
+ this.guardOpen();
193
+ return this.client.reindexAuthoredDocument(req);
194
+ }
195
+ async deleteAuthoredDocument(req) {
196
+ this.guardOpen();
197
+ return this.client.deleteAuthoredDocument(req);
198
+ }
199
+ async markMemorySuperseded(req) {
200
+ this.guardOpen();
201
+ return this.client.markMemorySuperseded(req);
202
+ }
203
+ // ── Search / query ───────────────────────────────────────────────
204
+ async searchText(req) {
205
+ this.guardOpen();
206
+ return this.client.searchText(req);
207
+ }
208
+ async searchTextCollections(req) {
209
+ this.guardOpen();
210
+ return this.client.searchTextCollections(req);
211
+ }
212
+ async listCollection(req) {
213
+ this.guardOpen();
214
+ return this.client.listCollection(req);
215
+ }
216
+ // ── Memory ───────────────────────────────────────────────────────
217
+ async exportMemory(req) {
218
+ this.guardOpen();
219
+ return this.client.exportMemory(req);
220
+ }
221
+ async flushNamespace(req) {
222
+ this.guardOpen();
223
+ return this.client.flushNamespace(req);
224
+ }
225
+ // ── Index ────────────────────────────────────────────────────────
226
+ async rebuildIndex(req, opts) {
227
+ this.guardOpen();
228
+ return this.client.rebuildIndex(req, opts);
229
+ }
230
+ // ── Kernel ───────────────────────────────────────────────────────
231
+ async bootstrapSessionKernel(req) {
232
+ this.guardOpen();
233
+ return this.client.bootstrapSessionKernel(req);
234
+ }
235
+ async ingestMessageKernel(req) {
236
+ this.guardOpen();
237
+ return this.client.ingestMessageKernel(req);
238
+ }
239
+ async afterTurnKernel(req) {
240
+ this.guardOpen();
241
+ return this.client.afterTurnKernel(req);
242
+ }
243
+ async assembleContextInternal(req) {
244
+ this.guardOpen();
245
+ return this.client.assembleContextInternal(req);
246
+ }
247
+ async compactSession(req) {
248
+ this.guardOpen();
249
+ return this.client.compactSession(req);
250
+ }
251
+ async rankCandidates(req) {
252
+ this.guardOpen();
253
+ return this.client.rankCandidates(req);
254
+ }
255
+ close() {
256
+ this.closed = true;
257
+ }
258
+ }
259
+ function resolveCredentialMode(endpoint, tlsMode) {
260
+ if (tlsMode === "tls")
261
+ return "tls";
262
+ if (tlsMode === "insecure")
263
+ return "insecure";
264
+ const target = endpoint.startsWith("tcp:") ? endpoint.slice(4) : endpoint;
265
+ if (target.startsWith("unix:"))
266
+ return "insecure";
267
+ const host = extractHost(target);
268
+ const normalized = host.toLowerCase();
269
+ return normalized === "localhost" || normalized === "127.0.0.1" || normalized === "::1"
270
+ ? "insecure"
271
+ : "tls";
272
+ }
273
+ function extractHost(target) {
274
+ const withoutDns = target.startsWith("dns:///") ? target.slice("dns:///".length) : target;
275
+ if (withoutDns.startsWith("[")) {
276
+ const close = withoutDns.indexOf("]");
277
+ return close > 0 ? withoutDns.slice(1, close) : withoutDns;
278
+ }
279
+ const sep = withoutDns.lastIndexOf(":");
280
+ return sep > 0 ? withoutDns.slice(0, sep) : withoutDns;
281
+ }
282
+ function loadSecretFromEnv() {
283
+ const secret = process.env.LIBRAVDB_AUTH_SECRET;
284
+ if (secret)
285
+ return secret;
286
+ const secretPath = process.env.LIBRAVDB_AUTH_SECRET_FILE;
287
+ if (secretPath) {
288
+ try {
289
+ return fs.readFileSync(secretPath, "utf8").trim();
290
+ }
291
+ catch {
292
+ return undefined;
293
+ }
294
+ }
295
+ return undefined;
296
+ }
@@ -1,11 +1,8 @@
1
1
  import type { LoggerLike, PluginConfig } from "./types.js";
2
+ import type { ClientGetter } from "./plugin-runtime.js";
2
3
  type Disposable = {
3
4
  close(): void;
4
5
  };
5
- interface RpcLike {
6
- call<T>(method: string, params: unknown): Promise<T>;
7
- }
8
- type RpcGetterLike = () => Promise<RpcLike>;
9
6
  interface FsDirentLike {
10
7
  name: string;
11
8
  isDirectory(): boolean;
@@ -47,5 +44,5 @@ export interface MarkdownIngestionSnapshot {
47
44
  size: number;
48
45
  mtimeMs: number;
49
46
  }
50
- export declare function createMarkdownIngestionHandle(cfg: PluginConfig, getRpc: RpcGetterLike, logger?: LoggerLike, fsApi?: FsApi): MarkdownIngestionHandle;
47
+ export declare function createMarkdownIngestionHandle(cfg: PluginConfig, getClient: ClientGetter, logger?: LoggerLike, fsApi?: FsApi): MarkdownIngestionHandle;
51
48
  export {};
@@ -9,7 +9,7 @@ const DEFAULT_TOKENIZER_ID = "markdown-ingest:v1";
9
9
  const MARKDOWN_INGEST_VERSION = 3;
10
10
  const HASH_BACKEND = "wasm-fnv1a64";
11
11
  const STREAM_CHUNK_BYTES = 64 * 1024;
12
- export function createMarkdownIngestionHandle(cfg, getRpc, logger = console, fsApi = createRealFsApi()) {
12
+ export function createMarkdownIngestionHandle(cfg, getClient, logger = console, fsApi = createRealFsApi()) {
13
13
  const adapters = [];
14
14
  const genericRoots = normalizeMarkdownRoots(cfg.markdownIngestionRoots);
15
15
  if (isMarkdownIngestionEnabled(cfg, genericRoots)) {
@@ -21,7 +21,7 @@ export function createMarkdownIngestionHandle(cfg, getRpc, logger = console, fsA
21
21
  snapshotPath: resolveMarkdownSnapshotPath("generic", cfg.markdownIngestionSnapshotPath),
22
22
  priorityMode: cfg.markdownIngestionPriorityMode,
23
23
  maxTokensPerFile: cfg.markdownIngestionMaxTokensPerFile,
24
- }, getRpc, logger, fsApi));
24
+ }, getClient, logger, fsApi));
25
25
  }
26
26
  const obsidianRoots = normalizeMarkdownRoots(cfg.markdownIngestionObsidianRoots);
27
27
  if (cfg.markdownIngestionObsidianEnabled === true && obsidianRoots.length > 0) {
@@ -33,7 +33,7 @@ export function createMarkdownIngestionHandle(cfg, getRpc, logger = console, fsA
33
33
  snapshotPath: resolveMarkdownSnapshotPath("obsidian", cfg.markdownIngestionObsidianSnapshotPath),
34
34
  priorityMode: cfg.markdownIngestionPriorityMode,
35
35
  maxTokensPerFile: cfg.markdownIngestionMaxTokensPerFile,
36
- }, getRpc, logger, fsApi));
36
+ }, getClient, logger, fsApi));
37
37
  }
38
38
  if (adapters.length === 0) {
39
39
  return {
@@ -78,7 +78,7 @@ class DirectoryMarkdownSourceAdapter {
78
78
  excludePatterns;
79
79
  debounceMs;
80
80
  fsApi;
81
- getRpc;
81
+ getClient;
82
82
  logger;
83
83
  snapshotPath;
84
84
  priorityMode;
@@ -104,14 +104,14 @@ class DirectoryMarkdownSourceAdapter {
104
104
  lastWalCapacity = 0;
105
105
  snapshotLoaded = false;
106
106
  snapshotDirty = false;
107
- constructor(kind, config, getRpc, logger, fsApi) {
107
+ constructor(kind, config, getClient, logger, fsApi) {
108
108
  this.kind = kind;
109
109
  this.roots = config.roots;
110
110
  this.includePatterns = config.include?.length ? config.include : [];
111
111
  this.excludePatterns = config.exclude?.length ? config.exclude : [];
112
112
  this.debounceMs = config.debounceMs ?? DEFAULT_DEBOUNCE_MS;
113
113
  this.fsApi = fsApi;
114
- this.getRpc = getRpc;
114
+ this.getClient = getClient;
115
115
  this.logger = logger;
116
116
  this.snapshotPath = config.snapshotPath ?? resolveMarkdownSnapshotPath(kind);
117
117
  this.priorityMode = config.priorityMode ?? "mtime";
@@ -536,8 +536,40 @@ class DirectoryMarkdownSourceAdapter {
536
536
  }
537
537
  async getIngestQueue() {
538
538
  if (!this.ingestQueue) {
539
- const rpc = await this.getRpc();
540
- this.ingestQueue = new IngestQueue(rpc.call.bind(rpc), this.logger, {
539
+ const client = await this.getClient();
540
+ this.ingestQueue = new IngestQueue((params) => client.ingestMarkdownDocument({
541
+ sourceDoc: params.sourceDoc,
542
+ text: params.text,
543
+ tokenizerId: params.tokenizerId,
544
+ coreDoc: params.coreDoc,
545
+ mode: params.mode,
546
+ sourceMeta: params.sourceMeta ? {
547
+ sourceRoot: params.sourceMeta.sourceRoot,
548
+ sourcePath: params.sourceMeta.sourcePath,
549
+ sourceKind: params.sourceMeta.sourceKind,
550
+ fileHash: params.sourceMeta.fileHash,
551
+ sourceSize: BigInt(params.sourceMeta.sourceSize),
552
+ sourceMtimeMs: BigInt(Math.trunc(params.sourceMeta.sourceMtimeMs)),
553
+ sourceCtimeMs: BigInt(Math.trunc(params.sourceMeta.sourceCtimeMs)),
554
+ ingestVersion: params.sourceMeta.ingestVersion,
555
+ hashBackend: params.sourceMeta.hashBackend,
556
+ } : undefined,
557
+ }).then((r) => ({
558
+ ok: r.ok,
559
+ feedback: r.feedback ? {
560
+ queueDepth: r.feedback.queueDepth,
561
+ queueCapacity: r.feedback.queueCapacity,
562
+ acceptMore: r.feedback.acceptMore,
563
+ retryAfterMs: r.feedback.retryAfterMs,
564
+ processingTimeUs: Number(r.feedback.processingTimeUs),
565
+ nodesAccepted: r.feedback.nodesAccepted,
566
+ nodesRejected: r.feedback.nodesRejected,
567
+ tokensIngested: r.feedback.tokensIngested,
568
+ tokenBurstLimit: r.feedback.tokenBurstLimit,
569
+ walDepth: r.feedback.walDepth,
570
+ walCapacity: r.feedback.walCapacity,
571
+ } : undefined,
572
+ })), (params) => client.deleteAuthoredDocument(params).then(() => undefined), this.logger, {
541
573
  onChunkFeedback: (feedback) => this.applyIngestFeedback(feedback),
542
574
  });
543
575
  }
@@ -1,4 +1,4 @@
1
1
  import type { MemoryPromptSectionBuilder } from "openclaw/plugin-sdk/plugin-entry";
2
2
  import type { PluginConfig } from "./types.js";
3
- import type { RpcGetter } from "./plugin-runtime.js";
4
- export declare function buildMemoryPromptSection(_getRpc: RpcGetter, _cfg: PluginConfig): MemoryPromptSectionBuilder;
3
+ import type { ClientGetter } from "./plugin-runtime.js";
4
+ export declare function buildMemoryPromptSection(_getClient: ClientGetter, _cfg: PluginConfig): MemoryPromptSectionBuilder;
@@ -4,7 +4,7 @@ const MEMORY_PROMPT_HEADER = [
4
4
  "in context via the context-engine assembler when available and relevant.",
5
5
  "",
6
6
  ];
7
- export function buildMemoryPromptSection(_getRpc, _cfg) {
7
+ export function buildMemoryPromptSection(_getClient, _cfg) {
8
8
  return function memoryPromptSection({ availableTools: _availableTools, citationsMode: _citationsMode, }) {
9
9
  // OpenClaw builds the memory prompt section synchronously for embedded runs.
10
10
  // Actual retrieval and ranking happen in the context engine during assemble().
@@ -1,4 +1,4 @@
1
- import type { RpcGetter } from "./plugin-runtime.js";
1
+ import type { ClientGetter } from "./plugin-runtime.js";
2
2
  import type { PluginConfig } from "./types.js";
3
3
  type MemorySearchParams = {
4
4
  query?: string;
@@ -30,7 +30,7 @@ type MemoryRuntimeStatus = {
30
30
  abstractiveReady?: boolean;
31
31
  embeddingProfile?: string;
32
32
  };
33
- export declare function buildMemoryRuntimeBridge(getRpc: RpcGetter, cfg: PluginConfig): {
33
+ export declare function buildMemoryRuntimeBridge(getClient: ClientGetter, cfg: PluginConfig): {
34
34
  getMemorySearchManager(params?: {
35
35
  agentId?: string;
36
36
  purpose?: string;
@@ -53,37 +53,8 @@ export declare function buildMemoryRuntimeBridge(getRpc: RpcGetter, cfg: PluginC
53
53
  id: string;
54
54
  score: number;
55
55
  text: string;
56
- metadata: {
57
- ts?: number;
58
- sessionId?: string;
59
- userId?: string;
60
- role?: string;
61
- source_doc?: string;
62
- node_kind?: string;
63
- ordinal?: number;
64
- position?: number;
65
- tier?: number;
66
- authored?: boolean;
67
- authority?: number;
68
- access_count?: number;
69
- collection?: string;
70
- hop_targets?: string[] | string;
71
- token_estimate?: number;
72
- continuity_tail?: boolean;
73
- continuity_base?: boolean;
74
- continuity_bundle_id?: string;
75
- elevated_guidance?: boolean;
76
- source_turn_id?: string;
77
- source_turn_ts?: number;
78
- provenance_class?: string;
79
- stability_weight?: number;
80
- expanded_from_summary?: boolean;
81
- parent_summary_id?: string;
82
- expansion_depth?: number;
83
- cascade_tier?: number;
84
- [key: string]: unknown;
85
- };
86
- finalScore?: number;
56
+ metadataJson: Uint8Array<ArrayBuffer>;
57
+ version: bigint;
87
58
  }[];
88
59
  error?: undefined;
89
60
  }>;