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/LICENSE +674 -0
- package/README.md +197 -0
- package/dist/index.js +1459 -0
- package/dist/index.js.map +1 -0
- package/dist/types/cli.d.ts +17 -0
- package/dist/types/cloudflare-api.d.ts +8 -0
- package/dist/types/companion-store.d.ts +10 -0
- package/dist/types/config.d.ts +172 -0
- package/dist/types/constants.d.ts +31 -0
- package/dist/types/doctor.d.ts +6 -0
- package/dist/types/embeddings-client.d.ts +8 -0
- package/dist/types/errors.d.ts +11 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/migration.d.ts +35 -0
- package/dist/types/namespace.d.ts +7 -0
- package/dist/types/prompt.d.ts +2 -0
- package/dist/types/public-artifacts.d.ts +2 -0
- package/dist/types/record-mapper.d.ts +24 -0
- package/dist/types/runtime.d.ts +5 -0
- package/dist/types/search-manager.d.ts +24 -0
- package/dist/types/service-factory.d.ts +8 -0
- package/dist/types/service.d.ts +59 -0
- package/dist/types/tools.d.ts +5 -0
- package/dist/types/types.d.ts +169 -0
- package/dist/types/vectorize-client.d.ts +17 -0
- package/openclaw.plugin.json +169 -0
- package/package.json +63 -0
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
|