openclaw-cloudflare-vectorize-memory 0.1.0

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/index.js ADDED
@@ -0,0 +1,1459 @@
1
+ import { definePluginEntry as e } from "openclaw/plugin-sdk/plugin-entry";
2
+ import { createHash as t, randomUUID as n } from "node:crypto";
3
+ import { access as r, glob as i, mkdir as a, readFile as o, rm as s, stat as c, writeFile as l } from "node:fs/promises";
4
+ import { basename as u, dirname as d, extname as f, isAbsolute as p, join as m, relative as ee, resolve as h } from "node:path";
5
+ import { listMemoryFiles as g } from "openclaw/plugin-sdk/memory-core";
6
+ import { resolveAgentIdFromSessionKey as te } from "openclaw/plugin-sdk/routing";
7
+ import { resolveConfiguredSecretInputWithFallback as ne } from "openclaw/plugin-sdk/config-runtime";
8
+ import { z as _ } from "zod";
9
+ import { Buffer as re } from "node:buffer";
10
+ import { Type as v } from "@sinclair/typebox";
11
+ //#region src/namespace.ts
12
+ function ie(e) {
13
+ return e.trim().toLowerCase().replace(/[^a-z0-9-_]+/g, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
14
+ }
15
+ function y(e) {
16
+ return ie(e) || "main";
17
+ }
18
+ function ae(e) {
19
+ if (e.fixedNamespace) return y(e.fixedNamespace);
20
+ let t = e.sessionKey ? te(e.sessionKey) : e.agentId;
21
+ return t ? y(`agent-${t}`) : e.workspaceDir ? y(`workspace-${u(e.workspaceDir)}`) : "main";
22
+ }
23
+ //#endregion
24
+ //#region src/migration.ts
25
+ var oe = new Set([".md", ".markdown"]), se = new Set([
26
+ "id",
27
+ "namespace",
28
+ "source",
29
+ "title"
30
+ ]);
31
+ function b(e) {
32
+ return e.replace(/\\/g, "/").replace(/^\.\//, "");
33
+ }
34
+ function x(e) {
35
+ return b(e).replace(/^\/+/, "") || u(e);
36
+ }
37
+ function S(e) {
38
+ return oe.has(f(e).toLowerCase());
39
+ }
40
+ function ce(e) {
41
+ return /[*?[\]{}]/.test(e);
42
+ }
43
+ function C(e) {
44
+ let t = b(e).toLowerCase();
45
+ return t.includes("/node_modules/") || t.includes("/.git/");
46
+ }
47
+ async function w(e) {
48
+ try {
49
+ return await c(e);
50
+ } catch {
51
+ return null;
52
+ }
53
+ }
54
+ async function le(e) {
55
+ let t = [];
56
+ for await (let n of i("**/*.{md,markdown}", { cwd: e })) {
57
+ let r = h(e, n);
58
+ C(r) || t.push(r);
59
+ }
60
+ return t;
61
+ }
62
+ async function ue(e, t) {
63
+ let n = [], r = b(e), a = p(e) ? i(r) : i(r, { cwd: t });
64
+ for await (let e of a) {
65
+ let r = p(e) ? e : h(t, e);
66
+ C(r) || !S(r) || (await w(r))?.isFile() && n.push(r);
67
+ }
68
+ return n;
69
+ }
70
+ async function de(e) {
71
+ let t = h(e.workspaceDir), n = /* @__PURE__ */ new Map();
72
+ if (e.sourceMode === "default-provider") for (let e of await g(t)) {
73
+ let r = x(e), i = h(t, r);
74
+ C(i) || !S(r) || (await w(i))?.isFile() && n.set(i.toLowerCase(), {
75
+ absolutePath: i,
76
+ relativePath: r
77
+ });
78
+ }
79
+ for (let r of e.sourcePaths ?? []) {
80
+ let e = h(t, r), i = await w(e), a = [];
81
+ i?.isDirectory() ? a = await le(e) : i?.isFile() ? a = S(e) ? [e] : [] : ce(r) && (a = await ue(r, t));
82
+ for (let e of a) {
83
+ let r = x(ee(t, e));
84
+ n.set(e.toLowerCase(), {
85
+ absolutePath: e,
86
+ relativePath: r
87
+ });
88
+ }
89
+ }
90
+ return [...n.values()].sort((e, t) => e.relativePath.localeCompare(t.relativePath));
91
+ }
92
+ function fe(e) {
93
+ let t = e.trim();
94
+ if (!t) return "";
95
+ if (/^"(.*)"$/.test(t) || /^'(.*)'$/.test(t)) return t.slice(1, -1);
96
+ if (t === "true") return !0;
97
+ if (t === "false") return !1;
98
+ let n = Number(t);
99
+ if (!Number.isNaN(n) && t !== "") return n;
100
+ if (!(t.startsWith("[") || t.startsWith("{"))) return t;
101
+ }
102
+ function pe(e) {
103
+ let t = e.replace(/\r\n/g, "\n");
104
+ if (!t.startsWith("---\n")) return {
105
+ body: t,
106
+ attributes: {}
107
+ };
108
+ let n = t.split("\n"), r = n.findIndex((e, t) => t > 0 && e.trim() === "---");
109
+ if (r === -1) return {
110
+ body: t,
111
+ attributes: {}
112
+ };
113
+ let i = {};
114
+ for (let e of n.slice(1, r)) {
115
+ let t = e.indexOf(":");
116
+ if (t === -1) continue;
117
+ let n = e.slice(0, t).trim();
118
+ if (!n) continue;
119
+ let r = fe(e.slice(t + 1));
120
+ r !== void 0 && (i[n] = r);
121
+ }
122
+ return {
123
+ body: n.slice(r + 1).join("\n"),
124
+ attributes: i
125
+ };
126
+ }
127
+ function me(e) {
128
+ let t = e.split("\n"), n = t.findIndex((e) => e.trim().length > 0);
129
+ if (n === -1) return { text: "" };
130
+ let r = /^#\s+(.+?)\s*$/.exec(t[n]?.trim() ?? "");
131
+ if (!r) return { text: e.trim() };
132
+ let i = [...t];
133
+ i.splice(n, 1), (i[n] ?? "").trim() === "" && i.splice(n, 1);
134
+ let a = i.join("\n").trim();
135
+ return {
136
+ title: r[1].trim(),
137
+ text: a || e.trim()
138
+ };
139
+ }
140
+ function he(e) {
141
+ let n = e.replace(/\.(md|markdown)$/i, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "").slice(0, 80), r = t("sha1").update(e).digest("hex").slice(0, 10);
142
+ return `${n || "memory"}-${r}`;
143
+ }
144
+ function ge(e, t, n) {
145
+ return typeof t == "string" && t.trim().length > 0 ? t.trim() : n || u(e, f(e)).trim() || void 0;
146
+ }
147
+ function _e(e, t, n) {
148
+ return e.resolveNamespace({
149
+ namespace: t.namespace,
150
+ workspaceDir: n
151
+ });
152
+ }
153
+ function ve(e) {
154
+ if (e.namespaceStrategy === "single-target") return e.targetNamespace;
155
+ if (typeof e.frontmatterNamespace == "string" && e.frontmatterNamespace.trim().length > 0) return y(e.frontmatterNamespace);
156
+ let t = x(e.relativePath).split("/")[0];
157
+ return !t || t === "." || t === ".." ? e.targetNamespace : y(t);
158
+ }
159
+ async function ye(e) {
160
+ let { body: t, attributes: n } = pe(await o(e.file.absolutePath, "utf8")), { title: r, text: i } = me(t), a = ge(e.file.relativePath, n.title, r), s = i.trim() || a || "";
161
+ if (!s) return null;
162
+ let c = {
163
+ legacySourceMode: e.sourceMode,
164
+ legacySourcePath: e.file.relativePath.startsWith("..") ? e.file.absolutePath : e.file.relativePath
165
+ };
166
+ for (let [e, t] of Object.entries(n)) se.has(e) || (c[e] = t);
167
+ let l = typeof n.id == "string" && n.id.trim().length > 0 ? n.id.trim() : he(e.file.relativePath), u = ve({
168
+ relativePath: e.file.relativePath,
169
+ frontmatterNamespace: n.namespace,
170
+ targetNamespace: e.targetNamespace,
171
+ namespaceStrategy: e.namespaceStrategy
172
+ }), d = typeof n.source == "string" && n.source.trim().length > 0 ? n.source.trim() : e.sourceMode === "default-provider" ? "openclaw-default-memory" : "markdown-import";
173
+ return {
174
+ sourcePath: e.file.absolutePath,
175
+ relativePath: e.file.relativePath,
176
+ input: {
177
+ id: l,
178
+ namespace: u,
179
+ title: a,
180
+ text: s,
181
+ source: d,
182
+ metadata: c
183
+ }
184
+ };
185
+ }
186
+ function be(e) {
187
+ return e.checks.filter((e) => e.status === "fail").map((e) => `${e.name}: ${e.message}`).join(" | ");
188
+ }
189
+ async function xe(e) {
190
+ let t = e.options ?? {}, n = h(t.workspaceDir ?? process.cwd()), r = (t.sourcePaths?.length ?? 0) > 0 ? "paths" : "default-provider", i = t.namespaceStrategy ?? "single-target", a = t.duplicateStrategy ?? "overwrite", o = t.dryRun ?? !1, s = _e(e.service, t, n), c = await e.service.doctor({ createIndexIfMissing: t.createIndexIfMissing ?? !1 });
191
+ if (!c.ok) throw Error(`Migration validation failed. ${be(c)}`);
192
+ let l = await de({
193
+ workspaceDir: n,
194
+ sourceMode: r,
195
+ sourcePaths: t.sourcePaths
196
+ });
197
+ if (l.length === 0) throw Error(r === "default-provider" ? `No default OpenClaw markdown memory files were found under ${n}.` : "No markdown files matched the provided migration sources.");
198
+ let u = [], d = 0, f = 0, p = 0, m = 0;
199
+ for (let t of l) try {
200
+ let n = await ye({
201
+ file: t,
202
+ sourceMode: r,
203
+ targetNamespace: s,
204
+ namespaceStrategy: i
205
+ });
206
+ if (!n) {
207
+ p += 1, u.push({
208
+ action: "skipped",
209
+ sourcePath: t.absolutePath,
210
+ relativePath: t.relativePath,
211
+ reason: "File did not contain any importable markdown content."
212
+ });
213
+ continue;
214
+ }
215
+ d += 1;
216
+ let c = n.input.id, l = n.input.namespace;
217
+ if (!c || !l) throw Error("Parsed migration record is missing a logical id or namespace.");
218
+ if (a !== "overwrite" && await e.service.get({
219
+ id: c,
220
+ namespace: l
221
+ })) {
222
+ if (a === "skip") {
223
+ p += 1, u.push({
224
+ action: "skipped",
225
+ sourcePath: n.sourcePath,
226
+ relativePath: n.relativePath,
227
+ logicalId: c,
228
+ namespace: l,
229
+ title: n.input.title,
230
+ reason: "A record with the same logical id already exists."
231
+ });
232
+ continue;
233
+ }
234
+ throw Error(`A record with logical id ${c} already exists in namespace ${l}.`);
235
+ }
236
+ if (o) {
237
+ u.push({
238
+ action: "would-import",
239
+ sourcePath: n.sourcePath,
240
+ relativePath: n.relativePath,
241
+ logicalId: c,
242
+ namespace: l,
243
+ title: n.input.title
244
+ });
245
+ continue;
246
+ }
247
+ await e.service.upsert({ input: n.input }), f += 1, u.push({
248
+ action: "imported",
249
+ sourcePath: n.sourcePath,
250
+ relativePath: n.relativePath,
251
+ logicalId: c,
252
+ namespace: l,
253
+ title: n.input.title
254
+ });
255
+ } catch (e) {
256
+ m += 1, u.push({
257
+ action: "failed",
258
+ sourcePath: t.absolutePath,
259
+ relativePath: t.relativePath,
260
+ error: e instanceof Error ? e.message : "Unknown migration failure."
261
+ });
262
+ }
263
+ return {
264
+ dryRun: o,
265
+ sourceMode: r,
266
+ workspaceDir: n,
267
+ namespaceStrategy: i,
268
+ targetNamespace: i === "single-target" ? s : void 0,
269
+ discoveredFiles: l.length,
270
+ preparedRecords: d,
271
+ imported: f,
272
+ skipped: p,
273
+ failed: m,
274
+ doctor: c,
275
+ results: u
276
+ };
277
+ }
278
+ function Se(e) {
279
+ let t = [
280
+ `${e.dryRun ? "Dry-run" : "Migration"} ${e.failed > 0 ? "completed with failures" : "completed"}.`,
281
+ `Source mode: ${e.sourceMode}`,
282
+ `Workspace: ${e.workspaceDir}`,
283
+ `Files scanned: ${e.discoveredFiles}`,
284
+ `Records prepared: ${e.preparedRecords}`,
285
+ `Imported: ${e.imported}`,
286
+ `Skipped: ${e.skipped}`,
287
+ `Failed: ${e.failed}`
288
+ ];
289
+ e.targetNamespace && t.splice(3, 0, `Target namespace: ${e.targetNamespace}`);
290
+ let n = e.results.filter((e) => e.action === "failed").slice(0, 10);
291
+ if (n.length > 0) {
292
+ t.push("", "Failures:");
293
+ for (let e of n) t.push(`- ${e.relativePath}: ${e.error}`);
294
+ }
295
+ return t.join("\n");
296
+ }
297
+ //#endregion
298
+ //#region src/constants.ts
299
+ var T = "memory-cloudflare-vectorize", Ce = "Cloudflare Vectorize Memory", we = "OpenClaw memory plugin backed by Cloudflare Vectorize and Workers AI embeddings.", E = "CLOUDFLARE_ACCOUNT_ID", D = "CLOUDFLARE_API_TOKEN", O = "CLOUDFLARE_VECTORIZE_INDEX_NAME", k = "CLOUDFLARE_VECTORIZE_NAMESPACE", A = "CLOUDFLARE_WORKERS_AI_EMBEDDING_MODEL", j = "CLOUDFLARE_VECTORIZE_TOP_K", M = "OPENCLAW_CF_MEMORY_STORAGE_MODE", Te = "OPENCLAW_CF_MEMORY_COMPANION_PATH", N = "@cf/baai/bge-base-en-v1.5", Ee = "vectorize-inline", P = "https://api.cloudflare.com/client/v4", F = {
300
+ logicalId: "oc_record_id",
301
+ title: "oc_title",
302
+ text: "oc_text",
303
+ storageMode: "oc_storage_mode",
304
+ pointer: "oc_pointer",
305
+ source: "oc_source",
306
+ createdAt: "oc_created_at",
307
+ updatedAt: "oc_updated_at"
308
+ }, I = class extends Error {
309
+ constructor(e) {
310
+ super(e), this.name = "ConfigurationError";
311
+ }
312
+ }, L = class extends Error {
313
+ constructor(e, t, n) {
314
+ super(e), this.status = t, this.details = n, this.name = "CloudflareApiError";
315
+ }
316
+ }, De = class extends Error {
317
+ constructor(e) {
318
+ super(e), this.name = "RecordSizeError";
319
+ }
320
+ }, Oe = _.object({
321
+ source: _.enum([
322
+ "env",
323
+ "file",
324
+ "exec"
325
+ ]),
326
+ provider: _.string().min(1),
327
+ id: _.string().min(1)
328
+ }).strict(), ke = _.union([_.string().min(1), Oe]), Ae = _.object({
329
+ description: _.string().min(1).optional(),
330
+ dimensions: _.number().int().min(1).max(1536).optional(),
331
+ metric: _.enum([
332
+ "cosine",
333
+ "euclidean",
334
+ "dot-product"
335
+ ]).optional()
336
+ }).strict(), R = _.object({
337
+ cloudflare: _.object({
338
+ accountId: _.string().min(1).optional(),
339
+ apiToken: ke.optional(),
340
+ apiBaseUrl: _.string().url().optional(),
341
+ workersAiBaseUrl: _.string().url().optional(),
342
+ vectorizeBaseUrl: _.string().url().optional()
343
+ }).strict().optional(),
344
+ vectorize: _.object({
345
+ indexName: _.string().min(1).optional(),
346
+ namespace: _.string().min(1).optional(),
347
+ topK: _.number().int().min(1).max(50).optional(),
348
+ minScore: _.number().min(0).max(1).optional(),
349
+ metric: _.enum([
350
+ "cosine",
351
+ "euclidean",
352
+ "dot-product"
353
+ ]).optional(),
354
+ createIndex: Ae.optional(),
355
+ metadataIndexedFields: _.array(_.string().min(1)).default([])
356
+ }).strict().optional(),
357
+ embeddings: _.object({ model: _.string().min(1).optional() }).strict().optional(),
358
+ storage: _.object({
359
+ mode: _.enum(["vectorize-inline", "companion-store"]).optional(),
360
+ companionStorePath: _.string().min(1).optional(),
361
+ inlineTextMaxBytes: _.number().int().min(256).max(1e4).optional()
362
+ }).strict().optional()
363
+ }).strict(), z = {
364
+ parse(e) {
365
+ return R.parse(e ?? {});
366
+ },
367
+ safeParse(e) {
368
+ let t = R.safeParse(e ?? {});
369
+ return t.success ? {
370
+ success: !0,
371
+ data: t.data
372
+ } : {
373
+ success: !1,
374
+ error: { issues: t.error.issues.map((e) => ({
375
+ path: e.path.filter((e) => typeof e == "string" || typeof e == "number"),
376
+ message: e.message
377
+ })) }
378
+ };
379
+ },
380
+ jsonSchema: {
381
+ type: "object",
382
+ additionalProperties: !1,
383
+ properties: {
384
+ cloudflare: {
385
+ type: "object",
386
+ additionalProperties: !1,
387
+ properties: {
388
+ accountId: { type: "string" },
389
+ apiToken: { anyOf: [{ type: "string" }, {
390
+ type: "object",
391
+ additionalProperties: !1,
392
+ properties: {
393
+ source: {
394
+ type: "string",
395
+ enum: [
396
+ "env",
397
+ "file",
398
+ "exec"
399
+ ]
400
+ },
401
+ provider: { type: "string" },
402
+ id: { type: "string" }
403
+ },
404
+ required: [
405
+ "source",
406
+ "provider",
407
+ "id"
408
+ ]
409
+ }] },
410
+ apiBaseUrl: {
411
+ type: "string",
412
+ format: "uri"
413
+ },
414
+ workersAiBaseUrl: {
415
+ type: "string",
416
+ format: "uri"
417
+ },
418
+ vectorizeBaseUrl: {
419
+ type: "string",
420
+ format: "uri"
421
+ }
422
+ }
423
+ },
424
+ vectorize: {
425
+ type: "object",
426
+ additionalProperties: !1,
427
+ properties: {
428
+ indexName: { type: "string" },
429
+ namespace: { type: "string" },
430
+ topK: {
431
+ type: "integer",
432
+ minimum: 1,
433
+ maximum: 50
434
+ },
435
+ minScore: {
436
+ type: "number",
437
+ minimum: 0,
438
+ maximum: 1
439
+ },
440
+ metric: {
441
+ type: "string",
442
+ enum: [
443
+ "cosine",
444
+ "euclidean",
445
+ "dot-product"
446
+ ]
447
+ },
448
+ createIndex: {
449
+ type: "object",
450
+ additionalProperties: !1,
451
+ properties: {
452
+ description: { type: "string" },
453
+ dimensions: {
454
+ type: "integer",
455
+ minimum: 1,
456
+ maximum: 1536
457
+ },
458
+ metric: {
459
+ type: "string",
460
+ enum: [
461
+ "cosine",
462
+ "euclidean",
463
+ "dot-product"
464
+ ]
465
+ }
466
+ }
467
+ },
468
+ metadataIndexedFields: {
469
+ type: "array",
470
+ items: { type: "string" }
471
+ }
472
+ }
473
+ },
474
+ embeddings: {
475
+ type: "object",
476
+ additionalProperties: !1,
477
+ properties: { model: { type: "string" } }
478
+ },
479
+ storage: {
480
+ type: "object",
481
+ additionalProperties: !1,
482
+ properties: {
483
+ mode: {
484
+ type: "string",
485
+ enum: ["vectorize-inline", "companion-store"]
486
+ },
487
+ companionStorePath: { type: "string" },
488
+ inlineTextMaxBytes: {
489
+ type: "integer",
490
+ minimum: 256,
491
+ maximum: 1e4
492
+ }
493
+ }
494
+ }
495
+ }
496
+ },
497
+ uiHints: {
498
+ "cloudflare.accountId": {
499
+ label: "Cloudflare account ID",
500
+ help: `Defaults to \${${E}}.`
501
+ },
502
+ "cloudflare.apiToken": {
503
+ label: "Cloudflare API token",
504
+ sensitive: !0,
505
+ help: `Defaults to \${${D}}.`
506
+ },
507
+ "vectorize.indexName": {
508
+ label: "Vectorize index name",
509
+ help: `Defaults to \${${O}}.`
510
+ },
511
+ "vectorize.namespace": {
512
+ label: "Fixed namespace override",
513
+ help: `Defaults to \${${k}} or derives from the agent/session context.`
514
+ },
515
+ "vectorize.topK": {
516
+ label: "Top-K results",
517
+ help: `Defaults to \${${j}} or 5.`
518
+ },
519
+ "embeddings.model": {
520
+ label: "Workers AI embedding model",
521
+ help: `Defaults to \${${A}} or ${N}.`
522
+ },
523
+ "storage.mode": {
524
+ label: "Storage mode",
525
+ help: `Defaults to \${${M}} or ${Ee}.`
526
+ },
527
+ "storage.companionStorePath": {
528
+ label: "Companion store path",
529
+ help: `Defaults to \${${Te}} or the OpenClaw state directory.`
530
+ }
531
+ }
532
+ };
533
+ function B(...e) {
534
+ return e.find((e) => e !== void 0);
535
+ }
536
+ function V(...e) {
537
+ for (let t of e) if (t && t.trim().length > 0) return t.trim();
538
+ }
539
+ function H(...e) {
540
+ return e.find((e) => typeof e == "number" && Number.isFinite(e));
541
+ }
542
+ function je(e) {
543
+ return [...new Set((e ?? []).map((e) => e.trim()).filter(Boolean))];
544
+ }
545
+ function Me(e) {
546
+ return e ?? "cosine";
547
+ }
548
+ function Ne(e) {
549
+ return e ?? "vectorize-inline";
550
+ }
551
+ function U(e) {
552
+ return R.parse(e ?? {});
553
+ }
554
+ function Pe(e) {
555
+ let t = e.plugins?.entries?.[T];
556
+ return U(t ?? {});
557
+ }
558
+ async function W(e) {
559
+ let t = U(e.pluginConfig), n = e.env ?? process.env, r = `plugins.entries.${T}`, i = V(t.cloudflare?.accountId, n[E]);
560
+ if (!i) throw new I(`Missing Cloudflare account id. Set ${E} or ${r}.cloudflare.accountId.`);
561
+ let a = await ne({
562
+ config: e.openClawConfig,
563
+ env: n,
564
+ value: t.cloudflare?.apiToken,
565
+ path: `${r}.cloudflare.apiToken`,
566
+ unresolvedReasonStyle: "detailed",
567
+ readFallback: () => n[D]
568
+ });
569
+ if (!a.value) throw new I(`Missing Cloudflare API token. Set ${D} or ${r}.cloudflare.apiToken.${a.unresolvedRefReason ? ` ${a.unresolvedRefReason}` : ""}`.trim());
570
+ let o = V(t.vectorize?.indexName, n[O]);
571
+ if (!o) throw new I(`Missing Vectorize index name. Set ${O} or ${r}.vectorize.indexName.`);
572
+ let s = V(t.cloudflare?.apiBaseUrl, P);
573
+ if (!s) throw new I(`Invalid Cloudflare API base URL. Set ${r}.cloudflare.apiBaseUrl or ensure ${P} is a valid URL.`);
574
+ let c = V(t.vectorize?.namespace, n[k]), l = H(t.vectorize?.topK, n.CLOUDFLARE_VECTORIZE_TOP_K ? Number(n[j]) : void 0), u = Ne(B(t.storage?.mode, n[M])), d = V(t.storage?.companionStorePath, n.OPENCLAW_CF_MEMORY_COMPANION_PATH) ?? m(".openclaw", "memory-cloudflare-vectorize", "companion-store.json"), f = e.resolvePath ?? ((e) => e), p = V(t.embeddings?.model, n[A], N);
575
+ if (!p) throw new I(`Missing Workers AI embedding model. Set ${A} or ${r}.embeddings.model.`);
576
+ let ee = H(t.storage?.inlineTextMaxBytes) ?? 6e3, h = H(t.vectorize?.minScore) ?? 0, g = Me(B(t.vectorize?.metric, t.vectorize?.createIndex?.metric));
577
+ return {
578
+ accountId: i,
579
+ apiToken: a.value,
580
+ apiBaseUrl: s,
581
+ workersAiBaseUrl: V(t.cloudflare?.workersAiBaseUrl) ?? `${s}/accounts/${i}/ai/v1`,
582
+ vectorizeBaseUrl: V(t.cloudflare?.vectorizeBaseUrl) ?? `${s}/accounts/${i}/vectorize/v2/indexes/${o}`,
583
+ indexName: o,
584
+ fixedNamespace: c,
585
+ topK: l ?? 5,
586
+ minScore: h,
587
+ metric: g,
588
+ model: p,
589
+ storageMode: u,
590
+ companionStorePath: f(d),
591
+ inlineTextMaxBytes: ee,
592
+ metadataIndexedFields: je(t.vectorize?.metadataIndexedFields),
593
+ createIndex: {
594
+ description: t.vectorize?.createIndex?.description ?? "OpenClaw memory index backed by Cloudflare Vectorize.",
595
+ dimensions: t.vectorize?.createIndex?.dimensions,
596
+ metric: g
597
+ }
598
+ };
599
+ }
600
+ //#endregion
601
+ //#region src/cloudflare-api.ts
602
+ function G(e, t) {
603
+ return e?.errors?.map((e) => e.message).filter(Boolean).join("; ") || t;
604
+ }
605
+ function Fe(e) {
606
+ return e instanceof L && e.status === 404;
607
+ }
608
+ async function K(e) {
609
+ let t = new Headers(e.headers);
610
+ t.set("Authorization", `Bearer ${e.apiToken}`), !t.has("Content-Type") && e.body && t.set("Content-Type", "application/json");
611
+ let n = await fetch(e.url, {
612
+ method: e.method ?? (e.body ? "POST" : "GET"),
613
+ headers: t,
614
+ body: e.body
615
+ }), r = await n.text(), i = r ? JSON.parse(r) : void 0;
616
+ if (!n.ok) throw new L(G(i, `Cloudflare request failed with ${n.status}.`), n.status, i);
617
+ if (!i?.success) throw new L(G(i, "Cloudflare request failed."), n.status, i);
618
+ return i.result;
619
+ }
620
+ //#endregion
621
+ //#region src/companion-store.ts
622
+ function q(e, t) {
623
+ return `${e}::${t}`;
624
+ }
625
+ async function J(e) {
626
+ try {
627
+ let t = await o(e, "utf8");
628
+ return JSON.parse(t);
629
+ } catch {
630
+ return {
631
+ version: 1,
632
+ records: {}
633
+ };
634
+ }
635
+ }
636
+ var Ie = class {
637
+ constructor(e) {
638
+ this.path = e;
639
+ }
640
+ get filePath() {
641
+ return this.path;
642
+ }
643
+ async upsert(e) {
644
+ let t = await J(this.path);
645
+ t.records[q(e.namespace, e.id)] = e, await a(d(this.path), { recursive: !0 }), await l(this.path, JSON.stringify(t, null, 2), "utf8");
646
+ }
647
+ async get(e, t) {
648
+ return (await J(this.path)).records[q(e, t)] ?? null;
649
+ }
650
+ async delete(e, t) {
651
+ let n = await J(this.path);
652
+ delete n.records[q(e, t)], await a(d(this.path), { recursive: !0 }), await l(this.path, JSON.stringify(n, null, 2), "utf8");
653
+ }
654
+ async clear() {
655
+ await s(this.path, { force: !0 });
656
+ }
657
+ };
658
+ //#endregion
659
+ //#region src/doctor.ts
660
+ async function Le(e) {
661
+ let t = [];
662
+ t.push({
663
+ name: "credentials",
664
+ status: "pass",
665
+ message: `Using Cloudflare account ${e.service.config.accountId} and Vectorize index ${e.service.config.indexName}.`
666
+ });
667
+ let n = await e.service.ensureIndexExists(e.createIndexIfMissing);
668
+ t.push({
669
+ name: "vectorize-index",
670
+ status: "pass",
671
+ message: n.created ? `Created Vectorize index "${e.service.config.indexName}" with ${n.dimensions} dimensions.` : `Vectorize index "${e.service.config.indexName}" is reachable.`
672
+ });
673
+ let r = await e.service.embeddings.probeDimensions();
674
+ return t.push({
675
+ name: "workers-ai-embeddings",
676
+ status: "pass",
677
+ message: `Workers AI model ${e.service.config.model} returned ${r} dimensions.`
678
+ }), r === n.dimensions ? t.push({
679
+ name: "dimension-match",
680
+ status: "pass",
681
+ message: "Embedding dimensions match the Vectorize index."
682
+ }) : t.push({
683
+ name: "dimension-match",
684
+ status: "fail",
685
+ message: `Embedding dimensions (${r}) do not match the Vectorize index dimensions (${n.dimensions}).`
686
+ }), t.push({
687
+ name: "metadata-filters",
688
+ status: e.service.config.metadataIndexedFields.length > 0 ? "pass" : "warn",
689
+ message: e.service.config.metadataIndexedFields.length > 0 ? `Configured metadata-index guidance for: ${e.service.config.metadataIndexedFields.join(", ")}.` : "No metadataIndexedFields configured. Add metadata indexes in Cloudflare before relying on filter-heavy queries."
690
+ }), {
691
+ ok: t.every((e) => e.status !== "fail"),
692
+ checks: t
693
+ };
694
+ }
695
+ //#endregion
696
+ //#region src/embeddings-client.ts
697
+ var Re = class {
698
+ constructor(e) {
699
+ this.config = e;
700
+ }
701
+ async embedQuery(e) {
702
+ let [t] = await this.embedBatch([e]);
703
+ return t;
704
+ }
705
+ async embedBatch(e) {
706
+ return e.length === 0 ? [] : [...(await K({
707
+ url: `${this.config.workersAiBaseUrl}/embeddings`,
708
+ apiToken: this.config.apiToken,
709
+ body: JSON.stringify({
710
+ model: this.config.model,
711
+ input: e
712
+ })
713
+ })).data].sort((e, t) => e.index - t.index).map((e) => e.embedding);
714
+ }
715
+ async probeDimensions() {
716
+ return (await this.embedQuery("openclaw-memory-dimension-probe")).length;
717
+ }
718
+ };
719
+ //#endregion
720
+ //#region src/record-mapper.ts
721
+ function ze(e) {
722
+ let t = e.trim().replace(/[.$"]/g, "_").replace(/\s+/g, "_");
723
+ return t ? t.startsWith("oc_") ? `user_${t}` : t : "metadata";
724
+ }
725
+ function Be(e) {
726
+ if (!e) return {};
727
+ let t = Object.entries(e).filter(([, e]) => [
728
+ "string",
729
+ "number",
730
+ "boolean"
731
+ ].includes(typeof e));
732
+ return Object.fromEntries(t.map(([e, t]) => [ze(e), t]));
733
+ }
734
+ function Ve(e, t) {
735
+ return `${e}::${t}`;
736
+ }
737
+ function Y(e, t) {
738
+ return `${e}/${t}.md`;
739
+ }
740
+ function He(e) {
741
+ let t = e.replace(/\\/g, "/").replace(/^\//, "").split("/");
742
+ return t.length !== 2 || !t[1].endsWith(".md") ? null : {
743
+ namespace: t[0],
744
+ logicalId: t[1].slice(0, -3)
745
+ };
746
+ }
747
+ function Ue(e, t) {
748
+ let n = e.trim().replace(/\s+/g, " ");
749
+ if (!n) return "";
750
+ let r = n.toLowerCase().indexOf(t.trim().toLowerCase());
751
+ if (r === -1) return n.slice(0, 220);
752
+ let i = Math.max(0, r - 80), a = Math.min(n.length, r + Math.max(t.length, 40) + 80);
753
+ return n.slice(i, a);
754
+ }
755
+ function We(e) {
756
+ let t = e.input.id?.trim() || n(), r = Ve(e.namespace, t), i = (/* @__PURE__ */ new Date()).toISOString(), a = Be(e.input.metadata), o = {
757
+ ...a,
758
+ [F.logicalId]: t,
759
+ [F.storageMode]: e.config.storageMode,
760
+ [F.createdAt]: i,
761
+ [F.updatedAt]: i
762
+ };
763
+ e.input.title && (o[F.title] = e.input.title), e.input.source && (o[F.source] = e.input.source);
764
+ let s;
765
+ if (e.config.storageMode === "vectorize-inline") {
766
+ let t = re.byteLength(e.input.text, "utf8");
767
+ if (t > e.config.inlineTextMaxBytes) throw new De(`Memory text is ${t} bytes, which exceeds the inline metadata limit of ${e.config.inlineTextMaxBytes}. Switch storage.mode to "companion-store" or reduce the payload size.`);
768
+ o[F.text] = e.input.text;
769
+ } else {
770
+ let n = Y(e.namespace, t);
771
+ o[F.pointer] = n, s = {
772
+ id: t,
773
+ namespace: e.namespace,
774
+ title: e.input.title,
775
+ text: e.input.text,
776
+ metadata: a,
777
+ source: e.input.source,
778
+ createdAt: i,
779
+ updatedAt: i
780
+ };
781
+ }
782
+ return {
783
+ logicalId: t,
784
+ vectorId: r,
785
+ path: Y(e.namespace, t),
786
+ vector: {
787
+ id: r,
788
+ namespace: e.namespace,
789
+ values: e.embedding,
790
+ metadata: o
791
+ },
792
+ companionRecord: s
793
+ };
794
+ }
795
+ function Ge(e) {
796
+ let t = e.metadata ?? {}, n = e.namespace ?? (typeof t[F.pointer] == "string" ? String(t[F.pointer]).split("/")[0] : "main"), r = typeof t[F.logicalId] == "string" ? String(t[F.logicalId]) : String(e.id ?? ""), i = Object.fromEntries(Object.entries(t).filter(([e]) => !e.startsWith("oc_")));
797
+ return {
798
+ logicalId: r,
799
+ vectorId: String(e.id ?? r),
800
+ namespace: n,
801
+ title: typeof t[F.title] == "string" ? String(t[F.title]) : void 0,
802
+ text: typeof t[F.text] == "string" ? String(t[F.text]) : void 0,
803
+ metadata: i,
804
+ source: typeof t[F.source] == "string" ? String(t[F.source]) : void 0,
805
+ createdAt: typeof t[F.createdAt] == "string" ? String(t[F.createdAt]) : void 0,
806
+ updatedAt: typeof t[F.updatedAt] == "string" ? String(t[F.updatedAt]) : void 0,
807
+ path: Y(n, r)
808
+ };
809
+ }
810
+ //#endregion
811
+ //#region src/vectorize-client.ts
812
+ var Ke = class {
813
+ constructor(e) {
814
+ this.config = e;
815
+ }
816
+ async describeIndex() {
817
+ return K({
818
+ url: this.config.vectorizeBaseUrl,
819
+ apiToken: this.config.apiToken,
820
+ method: "GET"
821
+ });
822
+ }
823
+ async createIndex(e, t = this.config.createIndex.metric) {
824
+ return K({
825
+ url: `${this.config.apiBaseUrl}/accounts/${this.config.accountId}/vectorize/v2/indexes`,
826
+ apiToken: this.config.apiToken,
827
+ body: JSON.stringify({
828
+ name: this.config.indexName,
829
+ description: this.config.createIndex.description,
830
+ config: {
831
+ dimensions: e,
832
+ metric: t
833
+ }
834
+ })
835
+ });
836
+ }
837
+ async upsert(e) {
838
+ let t = e.map((e) => JSON.stringify(e)).join("\n");
839
+ return (await K({
840
+ url: `${this.config.vectorizeBaseUrl}/upsert`,
841
+ apiToken: this.config.apiToken,
842
+ headers: { "Content-Type": "application/x-ndjson" },
843
+ body: t
844
+ })).mutationId;
845
+ }
846
+ async query(e) {
847
+ return (await K({
848
+ url: `${this.config.vectorizeBaseUrl}/query`,
849
+ apiToken: this.config.apiToken,
850
+ body: JSON.stringify({
851
+ vector: e.vector,
852
+ topK: e.topK ?? this.config.topK,
853
+ filter: e.filter,
854
+ namespace: e.namespace,
855
+ returnValues: e.returnValues ?? !1
856
+ })
857
+ })).matches ?? [];
858
+ }
859
+ async getByIds(e) {
860
+ return e.length === 0 ? [] : K({
861
+ url: `${this.config.vectorizeBaseUrl}/get_by_ids`,
862
+ apiToken: this.config.apiToken,
863
+ body: JSON.stringify({ ids: e })
864
+ });
865
+ }
866
+ async deleteByIds(e) {
867
+ if (e.length !== 0) return (await K({
868
+ url: `${this.config.vectorizeBaseUrl}/delete_by_ids`,
869
+ apiToken: this.config.apiToken,
870
+ body: JSON.stringify({ ids: e })
871
+ })).mutationId;
872
+ }
873
+ }, qe = class {
874
+ embeddings;
875
+ vectorize;
876
+ companionStore;
877
+ constructor(e, t) {
878
+ this.config = e, this.openClawConfig = t, this.embeddings = new Re(e), this.vectorize = new Ke(e), this.companionStore = new Ie(e.companionStorePath);
879
+ }
880
+ resolveNamespace(e) {
881
+ return ae({
882
+ fixedNamespace: e.namespace ?? this.config.fixedNamespace,
883
+ sessionKey: e.sessionKey,
884
+ agentId: e.agentId,
885
+ workspaceDir: e.workspaceDir
886
+ });
887
+ }
888
+ async search(e) {
889
+ let t = this.resolveNamespace(e), n = await this.embeddings.embedQuery(e.query), r = await this.vectorize.query({
890
+ vector: n,
891
+ namespace: t,
892
+ topK: e.maxResults ?? this.config.topK,
893
+ filter: e.filter
894
+ });
895
+ return (await Promise.all(r.map(async (e) => {
896
+ let t = Ge(e), n = t.text ?? (await this.companionStore.get(t.namespace, t.logicalId))?.text ?? "";
897
+ return {
898
+ ...t,
899
+ text: n,
900
+ score: e.score ?? 0
901
+ };
902
+ }))).filter((t) => t.score >= (e.minScore ?? this.config.minScore));
903
+ }
904
+ async get(e) {
905
+ let t = `${this.resolveNamespace(e)}::${e.id}`, [n] = await this.vectorize.getByIds([t]);
906
+ if (!n) return null;
907
+ let r = Ge(n), i = await this.companionStore.get(r.namespace, r.logicalId);
908
+ return {
909
+ ...r,
910
+ text: r.text ?? i?.text ?? ""
911
+ };
912
+ }
913
+ async upsert(e) {
914
+ let t = this.resolveNamespace({
915
+ namespace: e.input.namespace,
916
+ sessionKey: e.sessionKey,
917
+ agentId: e.agentId,
918
+ workspaceDir: e.workspaceDir
919
+ }), n = await this.embeddings.embedQuery(e.input.text), r = We({
920
+ input: e.input,
921
+ namespace: t,
922
+ embedding: n,
923
+ config: this.config
924
+ });
925
+ r.companionRecord && await this.companionStore.upsert(r.companionRecord);
926
+ let i = await this.vectorize.upsert([r.vector]);
927
+ return {
928
+ ...await this.get({
929
+ id: r.logicalId,
930
+ namespace: t
931
+ }) ?? this.fromCompanionFallback(r.companionRecord, r.logicalId, t, r.path),
932
+ mutationId: i
933
+ };
934
+ }
935
+ async delete(e) {
936
+ let t = this.resolveNamespace(e);
937
+ return await this.companionStore.delete(t, e.id), this.vectorize.deleteByIds([`${t}::${e.id}`]);
938
+ }
939
+ async doctor(e) {
940
+ return Le({
941
+ service: this,
942
+ createIndexIfMissing: e.createIndexIfMissing ?? !1
943
+ });
944
+ }
945
+ async ensureIndexExists(e) {
946
+ try {
947
+ return {
948
+ created: !1,
949
+ dimensions: (await this.vectorize.describeIndex()).config.dimensions
950
+ };
951
+ } catch (t) {
952
+ if (!e || !Fe(t)) throw t;
953
+ let n = this.config.createIndex.dimensions ?? await this.embeddings.probeDimensions();
954
+ return await this.vectorize.createIndex(n), {
955
+ created: !0,
956
+ dimensions: n
957
+ };
958
+ }
959
+ }
960
+ fromCompanionFallback(e, t, n, r) {
961
+ return {
962
+ logicalId: t,
963
+ vectorId: `${n}::${t}`,
964
+ namespace: n,
965
+ title: e?.title,
966
+ text: e?.text ?? "",
967
+ metadata: e?.metadata ?? {},
968
+ source: e?.source,
969
+ createdAt: e?.createdAt,
970
+ updatedAt: e?.updatedAt,
971
+ path: r
972
+ };
973
+ }
974
+ };
975
+ //#endregion
976
+ //#region src/service-factory.ts
977
+ async function X(e) {
978
+ return new qe(await W(e), e.openClawConfig);
979
+ }
980
+ //#endregion
981
+ //#region src/cli.ts
982
+ function Z(e) {
983
+ console.log(JSON.stringify(e, null, 2));
984
+ }
985
+ function Je(e) {
986
+ if (!e) return;
987
+ let t = JSON.parse(e);
988
+ if (!t || typeof t != "object" || Array.isArray(t)) throw Error("--metadata must be a JSON object.");
989
+ return t;
990
+ }
991
+ function Ye(e) {
992
+ if (!e) return;
993
+ let t = JSON.parse(e);
994
+ if (!t || typeof t != "object" || Array.isArray(t)) throw Error("--filter must be a JSON object.");
995
+ return t;
996
+ }
997
+ function Xe(e) {
998
+ return !!e && typeof e == "object" && typeof e.opts == "function";
999
+ }
1000
+ function Ze(e) {
1001
+ let t = e.at(-1);
1002
+ return Xe(t) ? {
1003
+ positionals: e.slice(0, -1),
1004
+ options: t.opts?.() ?? {}
1005
+ } : {
1006
+ positionals: e,
1007
+ options: {}
1008
+ };
1009
+ }
1010
+ function Qe(e) {
1011
+ if (e !== void 0) {
1012
+ if (e === "overwrite" || e === "skip" || e === "fail") return e;
1013
+ throw Error("--if-exists must be overwrite, skip, or fail.");
1014
+ }
1015
+ }
1016
+ function $e(e, t) {
1017
+ let n = e.command("cf-memory").description("Manage Cloudflare memory records.");
1018
+ function r(e) {
1019
+ return Ze(e).options;
1020
+ }
1021
+ n.command("doctor").description("Validate Workers AI and Vectorize configuration.").option("--create-index", "Create the Vectorize index if missing.").option("--json", "Print structured JSON output.").action(async (...e) => {
1022
+ let n = r(e), i = await (await X({
1023
+ pluginConfig: t.pluginConfig,
1024
+ openClawConfig: t.openClawConfig,
1025
+ env: process.env,
1026
+ resolvePath: t.resolvePath
1027
+ })).doctor({ createIndexIfMissing: !!n.createIndex });
1028
+ if (n.json) Z(i);
1029
+ else for (let e of i.checks) console.log(`[${e.status}] ${e.name}: ${e.message}`);
1030
+ i.ok || (process.exitCode = 1);
1031
+ }), n.command("search").description("Search stored Cloudflare memory.").argument("<query>", "Semantic search query.").option("--namespace <namespace>", "Optional namespace override.").option("--limit <count>", "Maximum number of results.").option("--filter <json>", "Optional metadata filter JSON.").action(async (e, n) => {
1032
+ let r = n;
1033
+ Z(await (await X({
1034
+ pluginConfig: t.pluginConfig,
1035
+ openClawConfig: t.openClawConfig,
1036
+ env: process.env,
1037
+ resolvePath: t.resolvePath
1038
+ })).search({
1039
+ query: String(e),
1040
+ namespace: r.namespace,
1041
+ maxResults: r.limit ? Number(r.limit) : void 0,
1042
+ filter: Ye(r.filter)
1043
+ }));
1044
+ }), n.command("upsert").description("Insert or update a memory record.").argument("<text>", "Memory text.").option("--id <id>", "Stable logical id.").option("--title <title>", "Optional title.").option("--namespace <namespace>", "Optional namespace override.").option("--source <source>", "Optional source label.").option("--metadata <json>", "Optional metadata JSON object.").action(async (e, n) => {
1045
+ let r = n;
1046
+ Z(await (await X({
1047
+ pluginConfig: t.pluginConfig,
1048
+ openClawConfig: t.openClawConfig,
1049
+ env: process.env,
1050
+ resolvePath: t.resolvePath
1051
+ })).upsert({ input: {
1052
+ id: r.id,
1053
+ title: r.title,
1054
+ text: String(e),
1055
+ namespace: r.namespace,
1056
+ source: r.source,
1057
+ metadata: Je(r.metadata)
1058
+ } }));
1059
+ }), n.command("delete").description("Delete a memory record.").argument("<id>", "Logical memory record id.").option("--namespace <namespace>", "Optional namespace override.").action(async (e, n) => {
1060
+ let r = n;
1061
+ Z({
1062
+ id: e,
1063
+ mutationId: await (await X({
1064
+ pluginConfig: t.pluginConfig,
1065
+ openClawConfig: t.openClawConfig,
1066
+ env: process.env,
1067
+ resolvePath: t.resolvePath
1068
+ })).delete({
1069
+ id: String(e),
1070
+ namespace: r.namespace
1071
+ })
1072
+ });
1073
+ }), n.command("migrate").description("Migrate legacy markdown memory into Cloudflare Vectorize.").argument("[sources...]", "Markdown files, directories, or glob patterns. Defaults to the current OpenClaw memory corpus when omitted.").option("--workspace <path>", "Workspace root used for default-provider discovery and relative path normalization.").option("--namespace <namespace>", "Target namespace override.").option("--derive-namespace-from-path", "Derive namespaces from the first relative path segment instead of using a single target namespace.").option("--if-exists <strategy>", "Duplicate handling: overwrite, skip, or fail.").option("--create-index", "Create the Vectorize index if missing.").option("--dry-run", "Plan the migration without writing records.").option("--json", "Print structured JSON output.").action(async (...e) => {
1074
+ let { positionals: n, options: r } = Ze(e), i = n[0], a = n.length === 0 ? [] : Array.isArray(i) ? i.map((e) => String(e)) : n.map((e) => String(e)), o = await xe({
1075
+ service: await X({
1076
+ pluginConfig: t.pluginConfig,
1077
+ openClawConfig: t.openClawConfig,
1078
+ env: process.env,
1079
+ resolvePath: t.resolvePath
1080
+ }),
1081
+ options: {
1082
+ sourcePaths: a,
1083
+ workspaceDir: r.workspace,
1084
+ namespace: r.namespace,
1085
+ namespaceStrategy: r.deriveNamespaceFromPath ? "path" : "single-target",
1086
+ duplicateStrategy: Qe(r.ifExists),
1087
+ dryRun: !!r.dryRun,
1088
+ createIndexIfMissing: !!r.createIndex
1089
+ }
1090
+ });
1091
+ r.json ? Z(o) : console.log(Se(o)), o.failed > 0 && (process.exitCode = 1);
1092
+ });
1093
+ }
1094
+ //#endregion
1095
+ //#region src/prompt.ts
1096
+ var et = ({ availableTools: e }) => {
1097
+ let t = ["Cloudflare memory is available through Vectorize semantic search and Workers AI embeddings.", "Use the memory tools for recalling past facts, preferences, and durable notes before asking repetitive follow-up questions."];
1098
+ return e.has("cloudflare_memory_upsert") && t.push("When the user wants something remembered long-term, store it with cloudflare_memory_upsert."), e.has("cloudflare_memory_search") && t.push("Use cloudflare_memory_search to retrieve prior memories by semantic similarity or metadata filters."), t;
1099
+ };
1100
+ //#endregion
1101
+ //#region src/public-artifacts.ts
1102
+ function tt(e, t) {
1103
+ return { async listArtifacts({ cfg: n }) {
1104
+ let i = (await X({
1105
+ pluginConfig: e,
1106
+ openClawConfig: n,
1107
+ env: process.env,
1108
+ resolvePath: t
1109
+ })).config;
1110
+ try {
1111
+ await r(i.companionStorePath);
1112
+ } catch {
1113
+ return [];
1114
+ }
1115
+ return [{
1116
+ kind: "cloudflare-companion-store",
1117
+ workspaceDir: d(i.companionStorePath),
1118
+ relativePath: i.companionStorePath.split(/[/\\]/).at(-1) ?? "companion-store.json",
1119
+ absolutePath: i.companionStorePath,
1120
+ agentIds: [],
1121
+ contentType: "json"
1122
+ }];
1123
+ } };
1124
+ }
1125
+ //#endregion
1126
+ //#region src/search-manager.ts
1127
+ var nt = class {
1128
+ constructor(e, t) {
1129
+ this.service = e, this.agentId = t;
1130
+ }
1131
+ async search(e, t) {
1132
+ return (await this.service.search({
1133
+ query: e,
1134
+ maxResults: t?.maxResults,
1135
+ minScore: t?.minScore,
1136
+ sessionKey: t?.sessionKey,
1137
+ agentId: this.agentId
1138
+ })).map((t) => ({
1139
+ path: t.path,
1140
+ startLine: 1,
1141
+ endLine: Math.max(1, t.text.split(/\r?\n/).length),
1142
+ score: t.score,
1143
+ snippet: Ue(t.text, e),
1144
+ source: "memory",
1145
+ citation: t.path
1146
+ }));
1147
+ }
1148
+ async readFile(e) {
1149
+ let t = He(e.relPath);
1150
+ if (!t) throw Error(`Unsupported memory lookup path: ${e.relPath}`);
1151
+ let n = await this.service.get({
1152
+ id: t.logicalId,
1153
+ namespace: t.namespace,
1154
+ agentId: this.agentId
1155
+ });
1156
+ if (!n) throw Error(`Memory record not found for ${e.relPath}`);
1157
+ let r = Math.max(1, e.from ?? 1), i = Math.max(1, e.lines ?? n.text.split(/\r?\n/).length);
1158
+ return {
1159
+ text: n.text.split(/\r?\n/).slice(r - 1, r - 1 + i).join("\n"),
1160
+ path: n.path
1161
+ };
1162
+ }
1163
+ status() {
1164
+ return {
1165
+ backend: "builtin",
1166
+ provider: "cloudflare-vectorize",
1167
+ model: this.service.config.model,
1168
+ workspaceDir: this.service.config.companionStorePath,
1169
+ custom: {
1170
+ indexName: this.service.config.indexName,
1171
+ storageMode: this.service.config.storageMode,
1172
+ fixedNamespace: this.service.config.fixedNamespace
1173
+ }
1174
+ };
1175
+ }
1176
+ async probeEmbeddingAvailability() {
1177
+ try {
1178
+ return await this.service.embeddings.probeDimensions(), { ok: !0 };
1179
+ } catch (e) {
1180
+ return {
1181
+ ok: !1,
1182
+ error: e instanceof Error ? e.message : "Embedding probe failed."
1183
+ };
1184
+ }
1185
+ }
1186
+ async probeVectorAvailability() {
1187
+ try {
1188
+ return await this.service.vectorize.describeIndex(), !0;
1189
+ } catch {
1190
+ return !1;
1191
+ }
1192
+ }
1193
+ async close() {}
1194
+ };
1195
+ //#endregion
1196
+ //#region src/runtime.ts
1197
+ function rt(e) {
1198
+ let t = /* @__PURE__ */ new Map();
1199
+ async function n(n, r) {
1200
+ let i = await X({
1201
+ pluginConfig: e.pluginConfig,
1202
+ openClawConfig: n,
1203
+ env: process.env,
1204
+ resolvePath: e.resolvePath
1205
+ }), a = `${r}::${i.config.indexName}::${i.config.storageMode}`, o = t.get(a);
1206
+ if (o) return o;
1207
+ let s = new nt(i, r);
1208
+ return t.set(a, s), s;
1209
+ }
1210
+ return {
1211
+ async getMemorySearchManager(e) {
1212
+ try {
1213
+ return { manager: await n(e.cfg, e.agentId) };
1214
+ } catch (e) {
1215
+ return {
1216
+ manager: null,
1217
+ error: e instanceof Error ? e.message : "Unable to create Cloudflare memory manager."
1218
+ };
1219
+ }
1220
+ },
1221
+ resolveMemoryBackendConfig() {
1222
+ return { backend: "builtin" };
1223
+ },
1224
+ async closeAllMemorySearchManagers() {
1225
+ await Promise.all([...t.values()].map((e) => e.close?.())), t.clear();
1226
+ }
1227
+ };
1228
+ }
1229
+ //#endregion
1230
+ //#region src/tools.ts
1231
+ async function Q(e, t) {
1232
+ let n = t.runtimeConfig ?? t.config;
1233
+ if (!n) throw Error("Cloudflare memory tools require an OpenClaw runtime config.");
1234
+ return X({
1235
+ pluginConfig: e,
1236
+ openClawConfig: n,
1237
+ env: process.env
1238
+ });
1239
+ }
1240
+ function it(e, t) {
1241
+ if (!e) return;
1242
+ let n = JSON.parse(e);
1243
+ if (!n || typeof n != "object" || Array.isArray(n)) throw Error(`${t} must be a JSON object.`);
1244
+ return n;
1245
+ }
1246
+ var at = v.Union([
1247
+ v.String(),
1248
+ v.Number(),
1249
+ v.Boolean()
1250
+ ]);
1251
+ function $(e, t) {
1252
+ return {
1253
+ content: [{
1254
+ type: "text",
1255
+ text: e
1256
+ }],
1257
+ details: t
1258
+ };
1259
+ }
1260
+ function ot(e, t) {
1261
+ return {
1262
+ name: "cloudflare_memory_search",
1263
+ label: "Cloudflare Memory Search",
1264
+ description: "Search Cloudflare-backed memory records using semantic retrieval.",
1265
+ parameters: v.Object({
1266
+ query: v.String({ description: "Semantic search query." }),
1267
+ namespace: v.Optional(v.String({ description: "Optional namespace override." })),
1268
+ maxResults: v.Optional(v.Number({ description: "Maximum results to return." })),
1269
+ minScore: v.Optional(v.Number({ description: "Minimum similarity score from 0 to 1." })),
1270
+ filterJson: v.Optional(v.String({ description: "Optional JSON object for Vectorize metadata filtering." }))
1271
+ }),
1272
+ async execute(n, r, i, a) {
1273
+ let o = await Q(e, t), s = it(r.filterJson, "filterJson"), c = await o.search({
1274
+ query: r.query,
1275
+ namespace: r.namespace,
1276
+ maxResults: r.maxResults,
1277
+ minScore: r.minScore,
1278
+ filter: s,
1279
+ sessionKey: t.sessionKey,
1280
+ agentId: t.agentId,
1281
+ workspaceDir: t.workspaceDir
1282
+ });
1283
+ return c.length === 0 ? $("No matching memories found.", {
1284
+ count: 0,
1285
+ records: []
1286
+ }) : $(c.map((e, t) => `${t + 1}. [${e.namespace}] ${e.title ?? e.logicalId} (${e.score.toFixed(3)})\n${e.text}`).join("\n\n"), {
1287
+ count: c.length,
1288
+ records: c.map((e) => ({
1289
+ id: e.logicalId,
1290
+ namespace: e.namespace,
1291
+ title: e.title,
1292
+ score: e.score,
1293
+ path: e.path
1294
+ }))
1295
+ });
1296
+ }
1297
+ };
1298
+ }
1299
+ function st(e, t) {
1300
+ return {
1301
+ name: "cloudflare_memory_get",
1302
+ label: "Cloudflare Memory Get",
1303
+ description: "Get a Cloudflare-backed memory record by id.",
1304
+ parameters: v.Object({
1305
+ id: v.String({ description: "Logical memory record id." }),
1306
+ namespace: v.Optional(v.String({ description: "Optional namespace override." }))
1307
+ }),
1308
+ async execute(n, r, i, a) {
1309
+ let o = await (await Q(e, t)).get({
1310
+ id: r.id,
1311
+ namespace: r.namespace,
1312
+ sessionKey: t.sessionKey,
1313
+ agentId: t.agentId,
1314
+ workspaceDir: t.workspaceDir
1315
+ });
1316
+ return o ? $(`${o.title ?? o.logicalId}\nNamespace: ${o.namespace}\nPath: ${o.path}\n\n${o.text}`, {
1317
+ found: !0,
1318
+ id: o.logicalId,
1319
+ namespace: o.namespace,
1320
+ metadata: o.metadata
1321
+ }) : $("Memory record not found.", { found: !1 });
1322
+ }
1323
+ };
1324
+ }
1325
+ function ct(e, t) {
1326
+ return {
1327
+ name: "cloudflare_memory_upsert",
1328
+ label: "Cloudflare Memory Upsert",
1329
+ description: "Insert or update a Cloudflare-backed memory record.",
1330
+ parameters: v.Object({
1331
+ id: v.Optional(v.String({ description: "Optional stable logical id." })),
1332
+ title: v.Optional(v.String({ description: "Optional title." })),
1333
+ text: v.String({ description: "Memory text to store." }),
1334
+ namespace: v.Optional(v.String({ description: "Optional namespace override." })),
1335
+ source: v.Optional(v.String({ description: "Optional source label." })),
1336
+ metadata: v.Optional(v.Record(v.String(), at, { description: "Flat metadata object with string, number, or boolean values." }))
1337
+ }),
1338
+ async execute(n, r, i, a) {
1339
+ let o = await (await Q(e, t)).upsert({
1340
+ input: {
1341
+ id: r.id,
1342
+ title: r.title,
1343
+ text: r.text,
1344
+ namespace: r.namespace,
1345
+ source: r.source,
1346
+ metadata: r.metadata
1347
+ },
1348
+ sessionKey: t.sessionKey,
1349
+ agentId: t.agentId,
1350
+ workspaceDir: t.workspaceDir
1351
+ });
1352
+ return $(`Stored memory ${o.logicalId} in namespace ${o.namespace}.`, {
1353
+ id: o.logicalId,
1354
+ namespace: o.namespace,
1355
+ path: o.path,
1356
+ mutationId: o.mutationId
1357
+ });
1358
+ }
1359
+ };
1360
+ }
1361
+ function lt(e, t) {
1362
+ return {
1363
+ name: "cloudflare_memory_delete",
1364
+ label: "Cloudflare Memory Delete",
1365
+ description: "Delete a Cloudflare-backed memory record by id.",
1366
+ parameters: v.Object({
1367
+ id: v.String({ description: "Logical memory record id." }),
1368
+ namespace: v.Optional(v.String({ description: "Optional namespace override." }))
1369
+ }),
1370
+ async execute(n, r, i, a) {
1371
+ let o = await (await Q(e, t)).delete({
1372
+ id: r.id,
1373
+ namespace: r.namespace,
1374
+ sessionKey: t.sessionKey,
1375
+ agentId: t.agentId,
1376
+ workspaceDir: t.workspaceDir
1377
+ });
1378
+ return $(`Deleted memory ${r.id}.`, { mutationId: o });
1379
+ }
1380
+ };
1381
+ }
1382
+ //#endregion
1383
+ //#region src/index.ts
1384
+ function ut() {
1385
+ return {
1386
+ id: "cloudflare-workers-ai",
1387
+ defaultModel: N,
1388
+ transport: "remote",
1389
+ allowExplicitWhenConfiguredAuto: !0,
1390
+ async create(e) {
1391
+ let t = await W({
1392
+ pluginConfig: Pe(e.config),
1393
+ openClawConfig: e.config,
1394
+ env: process.env
1395
+ }), n = new qe({
1396
+ ...t,
1397
+ model: e.model || t.model,
1398
+ workersAiBaseUrl: e.remote?.baseUrl && e.remote.baseUrl.trim().length > 0 ? e.remote.baseUrl : t.workersAiBaseUrl,
1399
+ apiToken: typeof e.remote?.apiKey == "string" && e.remote.apiKey.trim().length > 0 ? e.remote.apiKey : t.apiToken
1400
+ }, e.config);
1401
+ return {
1402
+ provider: {
1403
+ id: "cloudflare-workers-ai",
1404
+ model: e.model || t.model,
1405
+ embedQuery: (e) => n.embeddings.embedQuery(e),
1406
+ embedBatch: (e) => n.embeddings.embedBatch(e)
1407
+ },
1408
+ runtime: {
1409
+ id: "cloudflare-workers-ai",
1410
+ cacheKeyData: {
1411
+ accountId: t.accountId,
1412
+ model: e.model || t.model
1413
+ }
1414
+ }
1415
+ };
1416
+ }
1417
+ };
1418
+ }
1419
+ var dt = e({
1420
+ id: T,
1421
+ name: Ce,
1422
+ description: we,
1423
+ kind: "memory",
1424
+ configSchema: z,
1425
+ register(e) {
1426
+ z.parse?.(e.pluginConfig ?? {}), e.registerMemoryEmbeddingProvider(ut()), e.registerMemoryCapability({
1427
+ promptBuilder: et,
1428
+ runtime: rt({
1429
+ pluginConfig: e.pluginConfig,
1430
+ resolvePath: e.resolvePath
1431
+ }),
1432
+ publicArtifacts: tt(e.pluginConfig, e.resolvePath)
1433
+ }), e.registerTool((t) => ot(e.pluginConfig, t), { names: ["cloudflare_memory_search"] }), e.registerTool((t) => st(e.pluginConfig, t), { names: ["cloudflare_memory_get"] }), e.registerTool((t) => ct(e.pluginConfig, t), { names: ["cloudflare_memory_upsert"] }), e.registerTool((t) => lt(e.pluginConfig, t), { names: ["cloudflare_memory_delete"] }), e.registerCli(({ program: t }) => {
1434
+ $e(t, {
1435
+ pluginConfig: e.pluginConfig,
1436
+ openClawConfig: e.config,
1437
+ resolvePath: e.resolvePath
1438
+ });
1439
+ }, { descriptors: [{
1440
+ name: "cf-memory",
1441
+ description: "Manage Cloudflare Vectorize memory",
1442
+ hasSubcommands: !0
1443
+ }] }), W({
1444
+ pluginConfig: e.pluginConfig,
1445
+ openClawConfig: e.config,
1446
+ env: process.env,
1447
+ resolvePath: e.resolvePath
1448
+ }).then((t) => {
1449
+ e.logger.info(`${T}: registered for index ${t.indexName} using model ${t.model}.`);
1450
+ }).catch((t) => {
1451
+ let n = t instanceof Error ? t.message : "Unknown configuration error.";
1452
+ e.logger.warn(`${T}: deferred config validation reported: ${n}`);
1453
+ });
1454
+ }
1455
+ });
1456
+ //#endregion
1457
+ export { dt as default };
1458
+
1459
+ //# sourceMappingURL=index.js.map