openclaw-cloudflare-vectorize-memory 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants.js +1 -0
- package/dist/constants.js.map +1 -1
- package/dist/embeddings-client.js +22 -9
- package/dist/embeddings-client.js.map +1 -1
- package/dist/record-mapper.js +28 -22
- package/dist/record-mapper.js.map +1 -1
- package/dist/service.js +53 -19
- package/dist/service.js.map +1 -1
- package/dist/types/constants.d.ts +1 -0
- package/dist/types/embeddings-client.d.ts +1 -0
- package/dist/types/record-mapper.d.ts +3 -1
- package/dist/types/service.d.ts +1 -0
- package/package.json +1 -1
package/dist/constants.js
CHANGED
|
@@ -5,6 +5,7 @@ var e = "memory-cloudflare-vectorize", t = "Cloudflare Vectorize Memory", n = "O
|
|
|
5
5
|
hasSubcommands: !0
|
|
6
6
|
}, o = "CLOUDFLARE_ACCOUNT_ID", s = "CLOUDFLARE_API_TOKEN", c = "CLOUDFLARE_VECTORIZE_INDEX_NAME", l = "CLOUDFLARE_VECTORIZE_NAMESPACE", u = "CLOUDFLARE_WORKERS_AI_EMBEDDING_MODEL", d = "CLOUDFLARE_VECTORIZE_TOP_K", f = "OPENCLAW_CF_MEMORY_STORAGE_MODE", p = "OPENCLAW_CF_MEMORY_COMPANION_PATH", m = "@cf/baai/bge-base-en-v1.5", h = 6e3, g = "cosine", _ = "vectorize-inline", v = "https://api.cloudflare.com/client/v4", y = "OpenClaw memory index backed by Cloudflare Vectorize.", b = {
|
|
7
7
|
logicalId: "oc_record_id",
|
|
8
|
+
namespace: "oc_namespace",
|
|
8
9
|
title: "oc_title",
|
|
9
10
|
text: "oc_text",
|
|
10
11
|
storageMode: "oc_storage_mode",
|
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","names":[],"sources":["../src/constants.ts"],"sourcesContent":["import type { StorageMode, VectorizeMetric } from \"./types.js\";\n\nexport const PLUGIN_ID = \"memory-cloudflare-vectorize\";\nexport const PLUGIN_NAME = \"Cloudflare Vectorize Memory\";\nexport const PLUGIN_DESCRIPTION = \"OpenClaw memory plugin backed by Cloudflare Vectorize and Workers AI embeddings.\";\nexport const CLI_ROOT_COMMAND = \"cf-memory\";\nexport const CLI_ROOT_DESCRIPTION = \"Manage Cloudflare memory records.\";\nexport const CLI_ROOT_DESCRIPTOR = {\n\tname: CLI_ROOT_COMMAND,\n\tdescription: CLI_ROOT_DESCRIPTION,\n\thasSubcommands: true,\n} as const;\n\nexport const CLOUDFLARE_ACCOUNT_ID_ENV = \"CLOUDFLARE_ACCOUNT_ID\";\nexport const CLOUDFLARE_API_TOKEN_ENV = \"CLOUDFLARE_API_TOKEN\";\nexport const VECTORIZE_INDEX_ENV = \"CLOUDFLARE_VECTORIZE_INDEX_NAME\";\nexport const VECTORIZE_NAMESPACE_ENV = \"CLOUDFLARE_VECTORIZE_NAMESPACE\";\nexport const WORKERS_AI_MODEL_ENV = \"CLOUDFLARE_WORKERS_AI_EMBEDDING_MODEL\";\nexport const VECTORIZE_TOP_K_ENV = \"CLOUDFLARE_VECTORIZE_TOP_K\";\nexport const STORAGE_MODE_ENV = \"OPENCLAW_CF_MEMORY_STORAGE_MODE\";\nexport const COMPANION_PATH_ENV = \"OPENCLAW_CF_MEMORY_COMPANION_PATH\";\n\nexport const DEFAULT_EMBEDDING_MODEL = \"@cf/baai/bge-base-en-v1.5\";\nexport const DEFAULT_TOP_K = 5;\nexport const DEFAULT_MIN_SCORE = 0;\nexport const DEFAULT_INLINE_TEXT_MAX_BYTES = 6_000;\nexport const DEFAULT_VECTORIZE_METRIC: VectorizeMetric = \"cosine\";\nexport const DEFAULT_STORAGE_MODE: StorageMode = \"vectorize-inline\";\nexport const DEFAULT_CLOUDFLARE_API_BASE_URL = \"https://api.cloudflare.com/client/v4\";\nexport const DEFAULT_INDEX_DESCRIPTION = \"OpenClaw memory index backed by Cloudflare Vectorize.\";\n\nexport const RESERVED_METADATA_PREFIX = \"oc_\";\nexport const RESERVED_METADATA_KEYS = {\n\tlogicalId: \"oc_record_id\",\n\ttitle: \"oc_title\",\n\ttext: \"oc_text\",\n\tstorageMode: \"oc_storage_mode\",\n\tpointer: \"oc_pointer\",\n\tsource: \"oc_source\",\n\tcreatedAt: \"oc_created_at\",\n\tupdatedAt: \"oc_updated_at\",\n} as const;\n"],"mappings":";AAEA,IAAa,IAAY,+BACZ,IAAc,+BACd,IAAqB,oFACrB,IAAmB,aACnB,IAAuB,qCACvB,IAAsB;CAClC,MAAM;CACN,aAAa;CACb,gBAAgB;CAChB,EAEY,IAA4B,yBAC5B,IAA2B,wBAC3B,IAAsB,mCACtB,IAA0B,kCAC1B,IAAuB,yCACvB,IAAsB,8BACtB,IAAmB,mCACnB,IAAqB,qCAErB,IAA0B,6BAG1B,IAAgC,KAChC,IAA4C,UAC5C,IAAoC,oBACpC,IAAkC,wCAClC,IAA4B,yDAG5B,IAAyB;CACrC,WAAW;CACX,OAAO;CACP,MAAM;CACN,aAAa;CACb,SAAS;CACT,QAAQ;CACR,WAAW;CACX,WAAW;CACX"}
|
|
1
|
+
{"version":3,"file":"constants.js","names":[],"sources":["../src/constants.ts"],"sourcesContent":["import type { StorageMode, VectorizeMetric } from \"./types.js\";\n\nexport const PLUGIN_ID = \"memory-cloudflare-vectorize\";\nexport const PLUGIN_NAME = \"Cloudflare Vectorize Memory\";\nexport const PLUGIN_DESCRIPTION = \"OpenClaw memory plugin backed by Cloudflare Vectorize and Workers AI embeddings.\";\nexport const CLI_ROOT_COMMAND = \"cf-memory\";\nexport const CLI_ROOT_DESCRIPTION = \"Manage Cloudflare memory records.\";\nexport const CLI_ROOT_DESCRIPTOR = {\n\tname: CLI_ROOT_COMMAND,\n\tdescription: CLI_ROOT_DESCRIPTION,\n\thasSubcommands: true,\n} as const;\n\nexport const CLOUDFLARE_ACCOUNT_ID_ENV = \"CLOUDFLARE_ACCOUNT_ID\";\nexport const CLOUDFLARE_API_TOKEN_ENV = \"CLOUDFLARE_API_TOKEN\";\nexport const VECTORIZE_INDEX_ENV = \"CLOUDFLARE_VECTORIZE_INDEX_NAME\";\nexport const VECTORIZE_NAMESPACE_ENV = \"CLOUDFLARE_VECTORIZE_NAMESPACE\";\nexport const WORKERS_AI_MODEL_ENV = \"CLOUDFLARE_WORKERS_AI_EMBEDDING_MODEL\";\nexport const VECTORIZE_TOP_K_ENV = \"CLOUDFLARE_VECTORIZE_TOP_K\";\nexport const STORAGE_MODE_ENV = \"OPENCLAW_CF_MEMORY_STORAGE_MODE\";\nexport const COMPANION_PATH_ENV = \"OPENCLAW_CF_MEMORY_COMPANION_PATH\";\n\nexport const DEFAULT_EMBEDDING_MODEL = \"@cf/baai/bge-base-en-v1.5\";\nexport const DEFAULT_TOP_K = 5;\nexport const DEFAULT_MIN_SCORE = 0;\nexport const DEFAULT_INLINE_TEXT_MAX_BYTES = 6_000;\nexport const DEFAULT_VECTORIZE_METRIC: VectorizeMetric = \"cosine\";\nexport const DEFAULT_STORAGE_MODE: StorageMode = \"vectorize-inline\";\nexport const DEFAULT_CLOUDFLARE_API_BASE_URL = \"https://api.cloudflare.com/client/v4\";\nexport const DEFAULT_INDEX_DESCRIPTION = \"OpenClaw memory index backed by Cloudflare Vectorize.\";\n\nexport const RESERVED_METADATA_PREFIX = \"oc_\";\nexport const RESERVED_METADATA_KEYS = {\n\tlogicalId: \"oc_record_id\",\n\tnamespace: \"oc_namespace\",\n\ttitle: \"oc_title\",\n\ttext: \"oc_text\",\n\tstorageMode: \"oc_storage_mode\",\n\tpointer: \"oc_pointer\",\n\tsource: \"oc_source\",\n\tcreatedAt: \"oc_created_at\",\n\tupdatedAt: \"oc_updated_at\",\n} as const;\n"],"mappings":";AAEA,IAAa,IAAY,+BACZ,IAAc,+BACd,IAAqB,oFACrB,IAAmB,aACnB,IAAuB,qCACvB,IAAsB;CAClC,MAAM;CACN,aAAa;CACb,gBAAgB;CAChB,EAEY,IAA4B,yBAC5B,IAA2B,wBAC3B,IAAsB,mCACtB,IAA0B,kCAC1B,IAAuB,yCACvB,IAAsB,8BACtB,IAAmB,mCACnB,IAAqB,qCAErB,IAA0B,6BAG1B,IAAgC,KAChC,IAA4C,UAC5C,IAAoC,oBACpC,IAAkC,wCAClC,IAA4B,yDAG5B,IAAyB;CACrC,WAAW;CACX,WAAW;CACX,OAAO;CACP,MAAM;CACN,aAAa;CACb,SAAS;CACT,QAAQ;CACR,WAAW;CACX,WAAW;CACX"}
|
|
@@ -1,34 +1,47 @@
|
|
|
1
1
|
import { requestCloudflare as e } from "./cloudflare-api.js";
|
|
2
2
|
//#region src/embeddings-client.ts
|
|
3
|
-
|
|
3
|
+
var t = 64;
|
|
4
|
+
function n(e) {
|
|
4
5
|
return e.data.every((e) => !!e && typeof e == "object" && "embedding" in e && Array.isArray(e.embedding) && "index" in e && typeof e.index == "number");
|
|
5
6
|
}
|
|
6
|
-
var
|
|
7
|
+
var r = class {
|
|
8
|
+
queryCache = /* @__PURE__ */ new Map();
|
|
7
9
|
constructor(e) {
|
|
8
10
|
this.config = e;
|
|
9
11
|
}
|
|
10
12
|
async embedQuery(e) {
|
|
11
|
-
let
|
|
12
|
-
return
|
|
13
|
+
let n = this.queryCache.get(e);
|
|
14
|
+
if (n) return [...await n];
|
|
15
|
+
let r = this.embedBatch([e]).then(([e]) => {
|
|
16
|
+
if (!e) throw Error("Workers AI did not return an embedding.");
|
|
17
|
+
return e;
|
|
18
|
+
}).catch((t) => {
|
|
19
|
+
throw this.queryCache.delete(e), t;
|
|
20
|
+
});
|
|
21
|
+
if (this.queryCache.set(e, r), this.queryCache.size > t) {
|
|
22
|
+
let e = this.queryCache.keys().next().value;
|
|
23
|
+
typeof e == "string" && this.queryCache.delete(e);
|
|
24
|
+
}
|
|
25
|
+
return [...await r];
|
|
13
26
|
}
|
|
14
|
-
async embedBatch(
|
|
15
|
-
if (
|
|
27
|
+
async embedBatch(t) {
|
|
28
|
+
if (t.length === 0) return [];
|
|
16
29
|
let r = await e({
|
|
17
30
|
url: `${this.config.workersAiBaseUrl}/embeddings`,
|
|
18
31
|
apiToken: this.config.apiToken,
|
|
19
32
|
body: JSON.stringify({
|
|
20
33
|
model: this.config.model,
|
|
21
|
-
input:
|
|
34
|
+
input: t
|
|
22
35
|
}),
|
|
23
36
|
responseMode: "auto"
|
|
24
37
|
});
|
|
25
|
-
return
|
|
38
|
+
return n(r) ? [...r.data].sort((e, t) => e.index - t.index).map((e) => e.embedding) : r.data;
|
|
26
39
|
}
|
|
27
40
|
async probeDimensions() {
|
|
28
41
|
return (await this.embedQuery("openclaw-memory-dimension-probe")).length;
|
|
29
42
|
}
|
|
30
43
|
};
|
|
31
44
|
//#endregion
|
|
32
|
-
export {
|
|
45
|
+
export { r as WorkersAiEmbeddingsClient };
|
|
33
46
|
|
|
34
47
|
//# sourceMappingURL=embeddings-client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embeddings-client.js","names":[],"sources":["../src/embeddings-client.ts"],"sourcesContent":["import { requestCloudflare } from \"./cloudflare-api.js\";\nimport type { ResolvedPluginConfig } from \"./types.js\";\n\ntype OpenAiEmbeddingResponse = {\n\tdata: Array<{\n\t\tembedding: number[];\n\t\tindex: number;\n\t}>;\n};\n\ntype NativeEmbeddingResponse = {\n\tdata: number[][];\n\tshape?: number[];\n};\n\ntype EmbeddingResponse = OpenAiEmbeddingResponse | NativeEmbeddingResponse;\n\nfunction isOpenAiEmbeddingResponse(response: EmbeddingResponse): response is OpenAiEmbeddingResponse {\n\treturn response.data.every(\n\t\t(entry) =>\n\t\t\tBoolean(entry) &&\n\t\t\ttypeof entry === \"object\" &&\n\t\t\t\"embedding\" in entry &&\n\t\t\tArray.isArray(entry.embedding) &&\n\t\t\t\"index\" in entry &&\n\t\t\ttypeof entry.index === \"number\",\n\t);\n}\n\nexport class WorkersAiEmbeddingsClient {\n\tconstructor(private readonly config: ResolvedPluginConfig) {}\n\n\tasync embedQuery(text: string): Promise<number[]> {\n\t\tconst [
|
|
1
|
+
{"version":3,"file":"embeddings-client.js","names":[],"sources":["../src/embeddings-client.ts"],"sourcesContent":["import { requestCloudflare } from \"./cloudflare-api.js\";\nimport type { ResolvedPluginConfig } from \"./types.js\";\n\nconst QUERY_CACHE_LIMIT = 64;\n\ntype OpenAiEmbeddingResponse = {\n\tdata: Array<{\n\t\tembedding: number[];\n\t\tindex: number;\n\t}>;\n};\n\ntype NativeEmbeddingResponse = {\n\tdata: number[][];\n\tshape?: number[];\n};\n\ntype EmbeddingResponse = OpenAiEmbeddingResponse | NativeEmbeddingResponse;\n\nfunction isOpenAiEmbeddingResponse(response: EmbeddingResponse): response is OpenAiEmbeddingResponse {\n\treturn response.data.every(\n\t\t(entry) =>\n\t\t\tBoolean(entry) &&\n\t\t\ttypeof entry === \"object\" &&\n\t\t\t\"embedding\" in entry &&\n\t\t\tArray.isArray(entry.embedding) &&\n\t\t\t\"index\" in entry &&\n\t\t\ttypeof entry.index === \"number\",\n\t);\n}\n\nexport class WorkersAiEmbeddingsClient {\n\tprivate readonly queryCache = new Map<string, Promise<number[]>>();\n\n\tconstructor(private readonly config: ResolvedPluginConfig) {}\n\n\tasync embedQuery(text: string): Promise<number[]> {\n\t\tconst cached = this.queryCache.get(text);\n\t\tif (cached) {\n\t\t\treturn [...(await cached)];\n\t\t}\n\n\t\tconst pending = this.embedBatch([text])\n\t\t\t.then(([embedding]) => {\n\t\t\t\tif (!embedding) {\n\t\t\t\t\tthrow new Error(\"Workers AI did not return an embedding.\");\n\t\t\t\t}\n\t\t\t\treturn embedding;\n\t\t\t})\n\t\t\t.catch((error) => {\n\t\t\t\tthis.queryCache.delete(text);\n\t\t\t\tthrow error;\n\t\t\t});\n\t\tthis.queryCache.set(text, pending);\n\t\tif (this.queryCache.size > QUERY_CACHE_LIMIT) {\n\t\t\tconst oldestKey = this.queryCache.keys().next().value;\n\t\t\tif (typeof oldestKey === \"string\") {\n\t\t\t\tthis.queryCache.delete(oldestKey);\n\t\t\t}\n\t\t}\n\n\t\treturn [...(await pending)];\n\t}\n\n\tasync embedBatch(texts: string[]): Promise<number[][]> {\n\t\tif (texts.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\tconst response = await requestCloudflare<EmbeddingResponse>({\n\t\t\turl: `${this.config.workersAiBaseUrl}/embeddings`,\n\t\t\tapiToken: this.config.apiToken,\n\t\t\tbody: JSON.stringify({\n\t\t\t\tmodel: this.config.model,\n\t\t\t\tinput: texts,\n\t\t\t}),\n\t\t\tresponseMode: \"auto\",\n\t\t});\n\n\t\tif (isOpenAiEmbeddingResponse(response)) {\n\t\t\treturn [...response.data].sort((left, right) => left.index - right.index).map((entry) => entry.embedding);\n\t\t}\n\n\t\treturn response.data;\n\t}\n\n\tasync probeDimensions(): Promise<number> {\n\t\tconst embedding = await this.embedQuery(\"openclaw-memory-dimension-probe\");\n\t\treturn embedding.length;\n\t}\n}\n"],"mappings":";;AAGA,IAAM,IAAoB;AAgB1B,SAAS,EAA0B,GAAkE;AACpG,QAAO,EAAS,KAAK,OACnB,MACA,EAAQ,KACR,OAAO,KAAU,YACjB,eAAe,KACf,MAAM,QAAQ,EAAM,UAAU,IAC9B,WAAW,KACX,OAAO,EAAM,SAAU,SACxB;;AAGF,IAAa,IAAb,MAAuC;CACtC,6BAA8B,IAAI,KAAgC;CAElE,YAAY,GAA+C;AAA9B,OAAA,SAAA;;CAE7B,MAAM,WAAW,GAAiC;EACjD,IAAM,IAAS,KAAK,WAAW,IAAI,EAAK;AACxC,MAAI,EACH,QAAO,CAAC,GAAI,MAAM,EAAQ;EAG3B,IAAM,IAAU,KAAK,WAAW,CAAC,EAAK,CAAC,CACrC,MAAM,CAAC,OAAe;AACtB,OAAI,CAAC,EACJ,OAAU,MAAM,0CAA0C;AAE3D,UAAO;IACN,CACD,OAAO,MAAU;AAEjB,SADA,KAAK,WAAW,OAAO,EAAK,EACtB;IACL;AAEH,MADA,KAAK,WAAW,IAAI,GAAM,EAAQ,EAC9B,KAAK,WAAW,OAAO,GAAmB;GAC7C,IAAM,IAAY,KAAK,WAAW,MAAM,CAAC,MAAM,CAAC;AAChD,GAAI,OAAO,KAAc,YACxB,KAAK,WAAW,OAAO,EAAU;;AAInC,SAAO,CAAC,GAAI,MAAM,EAAS;;CAG5B,MAAM,WAAW,GAAsC;AACtD,MAAI,EAAM,WAAW,EACpB,QAAO,EAAE;EAEV,IAAM,IAAW,MAAM,EAAqC;GAC3D,KAAK,GAAG,KAAK,OAAO,iBAAiB;GACrC,UAAU,KAAK,OAAO;GACtB,MAAM,KAAK,UAAU;IACpB,OAAO,KAAK,OAAO;IACnB,OAAO;IACP,CAAC;GACF,cAAc;GACd,CAAC;AAMF,SAJI,EAA0B,EAAS,GAC/B,CAAC,GAAG,EAAS,KAAK,CAAC,MAAM,GAAM,MAAU,EAAK,QAAQ,EAAM,MAAM,CAAC,KAAK,MAAU,EAAM,UAAU,GAGnG,EAAS;;CAGjB,MAAM,kBAAmC;AAExC,UADkB,MAAM,KAAK,WAAW,kCAAkC,EACzD"}
|
package/dist/record-mapper.js
CHANGED
|
@@ -20,17 +20,22 @@ function s(e, t) {
|
|
|
20
20
|
let r = `${e}::${t}`;
|
|
21
21
|
return i.byteLength(r, "utf8") <= 64 ? r : `cfm_${n("sha256").update(r).digest("hex").slice(0, 48)}`;
|
|
22
22
|
}
|
|
23
|
-
function c(e
|
|
23
|
+
function c(e) {
|
|
24
|
+
if (!e || e.startsWith("cfm_")) return;
|
|
25
|
+
let t = e.indexOf("::");
|
|
26
|
+
if (!(t <= 0)) return e.slice(0, t);
|
|
27
|
+
}
|
|
28
|
+
function l(e, t) {
|
|
24
29
|
return `${e}/${t}.md`;
|
|
25
30
|
}
|
|
26
|
-
function
|
|
31
|
+
function u(e) {
|
|
27
32
|
let t = e.replace(/\\/g, "/").replace(/^\//, "").split("/");
|
|
28
33
|
return t.length !== 2 || !t[1].endsWith(".md") ? null : {
|
|
29
34
|
namespace: t[0],
|
|
30
35
|
logicalId: t[1].slice(0, -3)
|
|
31
36
|
};
|
|
32
37
|
}
|
|
33
|
-
function
|
|
38
|
+
function d(e, t) {
|
|
34
39
|
let n = e.trim().replace(/\s+/g, " ");
|
|
35
40
|
if (!n) return "";
|
|
36
41
|
let r = n.toLowerCase().indexOf(t.trim().toLowerCase());
|
|
@@ -38,10 +43,11 @@ function u(e, t) {
|
|
|
38
43
|
let i = Math.max(0, r - 80), a = Math.min(n.length, r + Math.max(t.length, 40) + 80);
|
|
39
44
|
return n.slice(i, a);
|
|
40
45
|
}
|
|
41
|
-
function
|
|
42
|
-
let a = n.input.id?.trim() || r(),
|
|
46
|
+
function f(n) {
|
|
47
|
+
let a = n.input.id?.trim() || r(), c = s(n.namespace, a), u = (/* @__PURE__ */ new Date()).toISOString(), d = o(n.input.metadata), f = {
|
|
43
48
|
...d,
|
|
44
49
|
[e.logicalId]: a,
|
|
50
|
+
[e.namespace]: n.namespace,
|
|
45
51
|
[e.storageMode]: n.config.storageMode,
|
|
46
52
|
[e.createdAt]: u,
|
|
47
53
|
[e.updatedAt]: u
|
|
@@ -53,7 +59,7 @@ function d(n) {
|
|
|
53
59
|
if (r > n.config.inlineTextMaxBytes) throw new t(`Memory text is ${r} bytes, which exceeds the inline metadata limit of ${n.config.inlineTextMaxBytes}. Switch storage.mode to "companion-store" or reduce the payload size.`);
|
|
54
60
|
f[e.text] = n.input.text;
|
|
55
61
|
} else {
|
|
56
|
-
let t =
|
|
62
|
+
let t = l(n.namespace, a);
|
|
57
63
|
f[e.pointer] = t, p = {
|
|
58
64
|
id: a,
|
|
59
65
|
namespace: n.namespace,
|
|
@@ -67,10 +73,10 @@ function d(n) {
|
|
|
67
73
|
}
|
|
68
74
|
return {
|
|
69
75
|
logicalId: a,
|
|
70
|
-
vectorId:
|
|
71
|
-
path:
|
|
76
|
+
vectorId: c,
|
|
77
|
+
path: l(n.namespace, a),
|
|
72
78
|
vector: {
|
|
73
|
-
id:
|
|
79
|
+
id: c,
|
|
74
80
|
namespace: n.namespace,
|
|
75
81
|
values: n.embedding,
|
|
76
82
|
metadata: f
|
|
@@ -78,22 +84,22 @@ function d(n) {
|
|
|
78
84
|
companionRecord: p
|
|
79
85
|
};
|
|
80
86
|
}
|
|
81
|
-
function
|
|
82
|
-
let
|
|
87
|
+
function p(t, n) {
|
|
88
|
+
let r = t.metadata ?? {}, i = typeof r[e.pointer] == "string" ? u(String(r[e.pointer])) : null, a = typeof t.namespace == "string" ? t.namespace : typeof r[e.namespace] == "string" ? String(r[e.namespace]) : i?.namespace ?? c(typeof t.id == "string" ? String(t.id) : void 0) ?? n?.defaultNamespace ?? "main", o = typeof r[e.logicalId] == "string" ? String(r[e.logicalId]) : String(t.id ?? ""), s = Object.fromEntries(Object.entries(r).filter(([e]) => !e.startsWith("oc_")));
|
|
83
89
|
return {
|
|
84
|
-
logicalId:
|
|
85
|
-
vectorId: String(t.id ??
|
|
86
|
-
namespace:
|
|
87
|
-
title: typeof
|
|
88
|
-
text: typeof
|
|
89
|
-
metadata:
|
|
90
|
-
source: typeof
|
|
91
|
-
createdAt: typeof
|
|
92
|
-
updatedAt: typeof
|
|
93
|
-
path:
|
|
90
|
+
logicalId: o,
|
|
91
|
+
vectorId: String(t.id ?? o),
|
|
92
|
+
namespace: a,
|
|
93
|
+
title: typeof r[e.title] == "string" ? String(r[e.title]) : void 0,
|
|
94
|
+
text: typeof r[e.text] == "string" ? String(r[e.text]) : void 0,
|
|
95
|
+
metadata: s,
|
|
96
|
+
source: typeof r[e.source] == "string" ? String(r[e.source]) : void 0,
|
|
97
|
+
createdAt: typeof r[e.createdAt] == "string" ? String(r[e.createdAt]) : void 0,
|
|
98
|
+
updatedAt: typeof r[e.updatedAt] == "string" ? String(r[e.updatedAt]) : void 0,
|
|
99
|
+
path: l(a, o)
|
|
94
100
|
};
|
|
95
101
|
}
|
|
96
102
|
//#endregion
|
|
97
|
-
export {
|
|
103
|
+
export { d as buildSnippet, s as buildVectorId, p as hydrateInlineRecord, f as mapRecordForUpsert, u as parseVirtualPath };
|
|
98
104
|
|
|
99
105
|
//# sourceMappingURL=record-mapper.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record-mapper.js","names":[],"sources":["../src/record-mapper.ts"],"sourcesContent":["import { Buffer } from \"node:buffer\";\nimport { createHash, randomUUID } from \"node:crypto\";\nimport { RESERVED_METADATA_KEYS, RESERVED_METADATA_PREFIX } from \"./constants.js\";\nimport { RecordSizeError } from \"./errors.js\";\nimport type {\n\tCompanionRecord,\n\tHydratedMemoryRecord,\n\tMemoryRecordInput,\n\tMetadataValue,\n\tResolvedPluginConfig,\n\tVectorizeQueryMatch,\n\tVectorizeVector,\n} from \"./types.js\";\n\nfunction sanitizeMetadataKey(key: string): string {\n\tconst sanitized = key.trim().replace(/[.$\"]/g, \"_\").replace(/\\s+/g, \"_\");\n\tif (!sanitized) {\n\t\treturn \"metadata\";\n\t}\n\tif (sanitized.startsWith(RESERVED_METADATA_PREFIX)) {\n\t\treturn `user_${sanitized}`;\n\t}\n\treturn sanitized;\n}\n\nfunction sanitizeMetadata(metadata: Record<string, MetadataValue> | undefined): Record<string, MetadataValue> {\n\tif (!metadata) {\n\t\treturn {};\n\t}\n\tconst entries = Object.entries(metadata).filter(([, value]) => [\"string\", \"number\", \"boolean\"].includes(typeof value));\n\treturn Object.fromEntries(entries.map(([key, value]) => [sanitizeMetadataKey(key), value]));\n}\n\nexport function buildVectorId(namespace: string, logicalId: string): string {\n\tconst rawId = `${namespace}::${logicalId}`;\n\tif (Buffer.byteLength(rawId, \"utf8\") <= 64) {\n\t\treturn rawId;\n\t}\n\treturn `cfm_${createHash(\"sha256\").update(rawId).digest(\"hex\").slice(0, 48)}`;\n}\n\nexport function buildVirtualPath(namespace: string, logicalId: string): string {\n\treturn `${namespace}/${logicalId}.md`;\n}\n\nexport function parseVirtualPath(path: string): { namespace: string; logicalId: string } | null {\n\tconst normalized = path.replace(/\\\\/g, \"/\").replace(/^\\//, \"\");\n\tconst segments = normalized.split(\"/\");\n\tif (segments.length !== 2 || !segments[1].endsWith(\".md\")) {\n\t\treturn null;\n\t}\n\treturn {\n\t\tnamespace: segments[0],\n\t\tlogicalId: segments[1].slice(0, -3),\n\t};\n}\n\nexport function buildSnippet(text: string, query: string): string {\n\tconst normalized = text.trim().replace(/\\s+/g, \" \");\n\tif (!normalized) {\n\t\treturn \"\";\n\t}\n\tconst lower = normalized.toLowerCase();\n\tconst index = lower.indexOf(query.trim().toLowerCase());\n\tif (index === -1) {\n\t\treturn normalized.slice(0, 220);\n\t}\n\tconst start = Math.max(0, index - 80);\n\tconst end = Math.min(normalized.length, index + Math.max(query.length, 40) + 80);\n\treturn normalized.slice(start, end);\n}\n\nexport function mapRecordForUpsert(params: { input: MemoryRecordInput; namespace: string; embedding: number[]; config: ResolvedPluginConfig }): {\n\tlogicalId: string;\n\tvectorId: string;\n\tpath: string;\n\tvector: VectorizeVector;\n\tcompanionRecord?: CompanionRecord;\n} {\n\tconst logicalId = params.input.id?.trim() || randomUUID();\n\tconst vectorId = buildVectorId(params.namespace, logicalId);\n\tconst now = new Date().toISOString();\n\tconst userMetadata = sanitizeMetadata(params.input.metadata);\n\tconst metadataBase: Record<string, MetadataValue> = {\n\t\t...userMetadata,\n\t\t[RESERVED_METADATA_KEYS.logicalId]: logicalId,\n\t\t[RESERVED_METADATA_KEYS.storageMode]: params.config.storageMode,\n\t\t[RESERVED_METADATA_KEYS.createdAt]: now,\n\t\t[RESERVED_METADATA_KEYS.updatedAt]: now,\n\t};\n\n\tif (params.input.title) {\n\t\tmetadataBase[RESERVED_METADATA_KEYS.title] = params.input.title;\n\t}\n\tif (params.input.source) {\n\t\tmetadataBase[RESERVED_METADATA_KEYS.source] = params.input.source;\n\t}\n\n\tlet companionRecord: CompanionRecord | undefined;\n\tif (params.config.storageMode === \"vectorize-inline\") {\n\t\tconst byteLength = Buffer.byteLength(params.input.text, \"utf8\");\n\t\tif (byteLength > params.config.inlineTextMaxBytes) {\n\t\t\tthrow new RecordSizeError(\n\t\t\t\t`Memory text is ${byteLength} bytes, which exceeds the inline metadata limit of ${params.config.inlineTextMaxBytes}. Switch storage.mode to \"companion-store\" or reduce the payload size.`,\n\t\t\t);\n\t\t}\n\t\tmetadataBase[RESERVED_METADATA_KEYS.text] = params.input.text;\n\t} else {\n\t\tconst pointer = buildVirtualPath(params.namespace, logicalId);\n\t\tmetadataBase[RESERVED_METADATA_KEYS.pointer] = pointer;\n\t\tcompanionRecord = {\n\t\t\tid: logicalId,\n\t\t\tnamespace: params.namespace,\n\t\t\ttitle: params.input.title,\n\t\t\ttext: params.input.text,\n\t\t\tmetadata: userMetadata,\n\t\t\tsource: params.input.source,\n\t\t\tcreatedAt: now,\n\t\t\tupdatedAt: now,\n\t\t};\n\t}\n\n\treturn {\n\t\tlogicalId,\n\t\tvectorId,\n\t\tpath: buildVirtualPath(params.namespace, logicalId),\n\t\tvector: {\n\t\t\tid: vectorId,\n\t\t\tnamespace: params.namespace,\n\t\t\tvalues: params.embedding,\n\t\t\tmetadata: metadataBase,\n\t\t},\n\t\tcompanionRecord,\n\t};\n}\n\nexport function hydrateInlineRecord(match: VectorizeQueryMatch): Omit<HydratedMemoryRecord, \"text\" | \"path\"> & {\n\ttext?: string;\n\tpath: string;\n} {\n\tconst metadata = match.metadata ?? {};\n\tconst namespace =\n\t\tmatch.namespace ?? (typeof metadata[RESERVED_METADATA_KEYS.pointer] === \"string\" ? String(metadata[RESERVED_METADATA_KEYS.pointer]).split(\"/\")[0] : \"main\");\n\tconst logicalId =\n\t\ttypeof metadata[RESERVED_METADATA_KEYS.logicalId] === \"string\" ? String(metadata[RESERVED_METADATA_KEYS.logicalId]) : String(match.id ?? \"\");\n\tconst userMetadata = Object.fromEntries(Object.entries(metadata).filter(([key]) => !key.startsWith(RESERVED_METADATA_PREFIX)));\n\treturn {\n\t\tlogicalId,\n\t\tvectorId: String(match.id ?? logicalId),\n\t\tnamespace,\n\t\ttitle: typeof metadata[RESERVED_METADATA_KEYS.title] === \"string\" ? String(metadata[RESERVED_METADATA_KEYS.title]) : undefined,\n\t\ttext: typeof metadata[RESERVED_METADATA_KEYS.text] === \"string\" ? String(metadata[RESERVED_METADATA_KEYS.text]) : undefined,\n\t\tmetadata: userMetadata,\n\t\tsource: typeof metadata[RESERVED_METADATA_KEYS.source] === \"string\" ? String(metadata[RESERVED_METADATA_KEYS.source]) : undefined,\n\t\tcreatedAt: typeof metadata[RESERVED_METADATA_KEYS.createdAt] === \"string\" ? String(metadata[RESERVED_METADATA_KEYS.createdAt]) : undefined,\n\t\tupdatedAt: typeof metadata[RESERVED_METADATA_KEYS.updatedAt] === \"string\" ? String(metadata[RESERVED_METADATA_KEYS.updatedAt]) : undefined,\n\t\tpath: buildVirtualPath(namespace, logicalId),\n\t};\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"record-mapper.js","names":[],"sources":["../src/record-mapper.ts"],"sourcesContent":["import { Buffer } from \"node:buffer\";\nimport { createHash, randomUUID } from \"node:crypto\";\nimport { RESERVED_METADATA_KEYS, RESERVED_METADATA_PREFIX } from \"./constants.js\";\nimport { RecordSizeError } from \"./errors.js\";\nimport type {\n\tCompanionRecord,\n\tHydratedMemoryRecord,\n\tMemoryRecordInput,\n\tMetadataValue,\n\tResolvedPluginConfig,\n\tVectorizeQueryMatch,\n\tVectorizeVector,\n} from \"./types.js\";\n\nfunction sanitizeMetadataKey(key: string): string {\n\tconst sanitized = key.trim().replace(/[.$\"]/g, \"_\").replace(/\\s+/g, \"_\");\n\tif (!sanitized) {\n\t\treturn \"metadata\";\n\t}\n\tif (sanitized.startsWith(RESERVED_METADATA_PREFIX)) {\n\t\treturn `user_${sanitized}`;\n\t}\n\treturn sanitized;\n}\n\nfunction sanitizeMetadata(metadata: Record<string, MetadataValue> | undefined): Record<string, MetadataValue> {\n\tif (!metadata) {\n\t\treturn {};\n\t}\n\tconst entries = Object.entries(metadata).filter(([, value]) => [\"string\", \"number\", \"boolean\"].includes(typeof value));\n\treturn Object.fromEntries(entries.map(([key, value]) => [sanitizeMetadataKey(key), value]));\n}\n\nexport function buildVectorId(namespace: string, logicalId: string): string {\n\tconst rawId = `${namespace}::${logicalId}`;\n\tif (Buffer.byteLength(rawId, \"utf8\") <= 64) {\n\t\treturn rawId;\n\t}\n\treturn `cfm_${createHash(\"sha256\").update(rawId).digest(\"hex\").slice(0, 48)}`;\n}\n\nfunction parseNamespaceFromVectorId(vectorId: string | undefined): string | undefined {\n\tif (!vectorId || vectorId.startsWith(\"cfm_\")) {\n\t\treturn undefined;\n\t}\n\tconst separatorIndex = vectorId.indexOf(\"::\");\n\tif (separatorIndex <= 0) {\n\t\treturn undefined;\n\t}\n\treturn vectorId.slice(0, separatorIndex);\n}\n\nexport function buildVirtualPath(namespace: string, logicalId: string): string {\n\treturn `${namespace}/${logicalId}.md`;\n}\n\nexport function parseVirtualPath(path: string): { namespace: string; logicalId: string } | null {\n\tconst normalized = path.replace(/\\\\/g, \"/\").replace(/^\\//, \"\");\n\tconst segments = normalized.split(\"/\");\n\tif (segments.length !== 2 || !segments[1].endsWith(\".md\")) {\n\t\treturn null;\n\t}\n\treturn {\n\t\tnamespace: segments[0],\n\t\tlogicalId: segments[1].slice(0, -3),\n\t};\n}\n\nexport function buildSnippet(text: string, query: string): string {\n\tconst normalized = text.trim().replace(/\\s+/g, \" \");\n\tif (!normalized) {\n\t\treturn \"\";\n\t}\n\tconst lower = normalized.toLowerCase();\n\tconst index = lower.indexOf(query.trim().toLowerCase());\n\tif (index === -1) {\n\t\treturn normalized.slice(0, 220);\n\t}\n\tconst start = Math.max(0, index - 80);\n\tconst end = Math.min(normalized.length, index + Math.max(query.length, 40) + 80);\n\treturn normalized.slice(start, end);\n}\n\nexport function mapRecordForUpsert(params: { input: MemoryRecordInput; namespace: string; embedding: number[]; config: ResolvedPluginConfig }): {\n\tlogicalId: string;\n\tvectorId: string;\n\tpath: string;\n\tvector: VectorizeVector;\n\tcompanionRecord?: CompanionRecord;\n} {\n\tconst logicalId = params.input.id?.trim() || randomUUID();\n\tconst vectorId = buildVectorId(params.namespace, logicalId);\n\tconst now = new Date().toISOString();\n\tconst userMetadata = sanitizeMetadata(params.input.metadata);\n\tconst metadataBase: Record<string, MetadataValue> = {\n\t\t...userMetadata,\n\t\t[RESERVED_METADATA_KEYS.logicalId]: logicalId,\n\t\t[RESERVED_METADATA_KEYS.namespace]: params.namespace,\n\t\t[RESERVED_METADATA_KEYS.storageMode]: params.config.storageMode,\n\t\t[RESERVED_METADATA_KEYS.createdAt]: now,\n\t\t[RESERVED_METADATA_KEYS.updatedAt]: now,\n\t};\n\n\tif (params.input.title) {\n\t\tmetadataBase[RESERVED_METADATA_KEYS.title] = params.input.title;\n\t}\n\tif (params.input.source) {\n\t\tmetadataBase[RESERVED_METADATA_KEYS.source] = params.input.source;\n\t}\n\n\tlet companionRecord: CompanionRecord | undefined;\n\tif (params.config.storageMode === \"vectorize-inline\") {\n\t\tconst byteLength = Buffer.byteLength(params.input.text, \"utf8\");\n\t\tif (byteLength > params.config.inlineTextMaxBytes) {\n\t\t\tthrow new RecordSizeError(\n\t\t\t\t`Memory text is ${byteLength} bytes, which exceeds the inline metadata limit of ${params.config.inlineTextMaxBytes}. Switch storage.mode to \"companion-store\" or reduce the payload size.`,\n\t\t\t);\n\t\t}\n\t\tmetadataBase[RESERVED_METADATA_KEYS.text] = params.input.text;\n\t} else {\n\t\tconst pointer = buildVirtualPath(params.namespace, logicalId);\n\t\tmetadataBase[RESERVED_METADATA_KEYS.pointer] = pointer;\n\t\tcompanionRecord = {\n\t\t\tid: logicalId,\n\t\t\tnamespace: params.namespace,\n\t\t\ttitle: params.input.title,\n\t\t\ttext: params.input.text,\n\t\t\tmetadata: userMetadata,\n\t\t\tsource: params.input.source,\n\t\t\tcreatedAt: now,\n\t\t\tupdatedAt: now,\n\t\t};\n\t}\n\n\treturn {\n\t\tlogicalId,\n\t\tvectorId,\n\t\tpath: buildVirtualPath(params.namespace, logicalId),\n\t\tvector: {\n\t\t\tid: vectorId,\n\t\t\tnamespace: params.namespace,\n\t\t\tvalues: params.embedding,\n\t\t\tmetadata: metadataBase,\n\t\t},\n\t\tcompanionRecord,\n\t};\n}\n\nexport function hydrateInlineRecord(\n\tmatch: VectorizeQueryMatch,\n\toptions?: {\n\t\tdefaultNamespace?: string;\n\t},\n): Omit<HydratedMemoryRecord, \"text\" | \"path\"> & {\n\ttext?: string;\n\tpath: string;\n} {\n\tconst metadata = match.metadata ?? {};\n\tconst pointerPath = typeof metadata[RESERVED_METADATA_KEYS.pointer] === \"string\" ? parseVirtualPath(String(metadata[RESERVED_METADATA_KEYS.pointer])) : null;\n\tconst namespace =\n\t\ttypeof match.namespace === \"string\"\n\t\t\t? match.namespace\n\t\t\t: typeof metadata[RESERVED_METADATA_KEYS.namespace] === \"string\"\n\t\t\t\t? String(metadata[RESERVED_METADATA_KEYS.namespace])\n\t\t\t\t: (pointerPath?.namespace ??\n\t\t\t\t\tparseNamespaceFromVectorId(typeof match.id === \"string\" ? String(match.id) : undefined) ??\n\t\t\t\t\toptions?.defaultNamespace ??\n\t\t\t\t\t\"main\");\n\tconst logicalId =\n\t\ttypeof metadata[RESERVED_METADATA_KEYS.logicalId] === \"string\" ? String(metadata[RESERVED_METADATA_KEYS.logicalId]) : String(match.id ?? \"\");\n\tconst userMetadata = Object.fromEntries(Object.entries(metadata).filter(([key]) => !key.startsWith(RESERVED_METADATA_PREFIX)));\n\treturn {\n\t\tlogicalId,\n\t\tvectorId: String(match.id ?? logicalId),\n\t\tnamespace,\n\t\ttitle: typeof metadata[RESERVED_METADATA_KEYS.title] === \"string\" ? String(metadata[RESERVED_METADATA_KEYS.title]) : undefined,\n\t\ttext: typeof metadata[RESERVED_METADATA_KEYS.text] === \"string\" ? String(metadata[RESERVED_METADATA_KEYS.text]) : undefined,\n\t\tmetadata: userMetadata,\n\t\tsource: typeof metadata[RESERVED_METADATA_KEYS.source] === \"string\" ? String(metadata[RESERVED_METADATA_KEYS.source]) : undefined,\n\t\tcreatedAt: typeof metadata[RESERVED_METADATA_KEYS.createdAt] === \"string\" ? String(metadata[RESERVED_METADATA_KEYS.createdAt]) : undefined,\n\t\tupdatedAt: typeof metadata[RESERVED_METADATA_KEYS.updatedAt] === \"string\" ? String(metadata[RESERVED_METADATA_KEYS.updatedAt]) : undefined,\n\t\tpath: buildVirtualPath(namespace, logicalId),\n\t};\n}\n"],"mappings":"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"}
|
package/dist/service.js
CHANGED
|
@@ -30,21 +30,21 @@ var d = 3e4, f = 1e3, p = class {
|
|
|
30
30
|
filter: e.filter
|
|
31
31
|
});
|
|
32
32
|
return (await Promise.all(r.map(async (e) => {
|
|
33
|
-
let
|
|
33
|
+
let n = s(e, { defaultNamespace: t }), r = n.text ?? (await this.companionStore.get(n.namespace, n.logicalId))?.text ?? "";
|
|
34
34
|
return {
|
|
35
|
-
...
|
|
36
|
-
text:
|
|
35
|
+
...n,
|
|
36
|
+
text: r,
|
|
37
37
|
score: e.score ?? 0
|
|
38
38
|
};
|
|
39
39
|
}))).filter((t) => t.score >= (e.minScore ?? this.config.minScore));
|
|
40
40
|
}
|
|
41
41
|
async get(e) {
|
|
42
|
-
let t =
|
|
43
|
-
if (!
|
|
44
|
-
let
|
|
42
|
+
let t = this.resolveNamespace(e), n = o(t, e.id), [r] = await this.vectorize.getByIds([n]);
|
|
43
|
+
if (!r) return null;
|
|
44
|
+
let i = s(r, { defaultNamespace: t }), a = await this.companionStore.get(i.namespace, i.logicalId);
|
|
45
45
|
return {
|
|
46
|
-
...
|
|
47
|
-
text:
|
|
46
|
+
...i,
|
|
47
|
+
text: i.text ?? a?.text ?? ""
|
|
48
48
|
};
|
|
49
49
|
}
|
|
50
50
|
async upsert(e) {
|
|
@@ -229,7 +229,18 @@ var d = 3e4, f = 1e3, p = class {
|
|
|
229
229
|
status: "pass",
|
|
230
230
|
message: `Inserted smoke-test record ${o} in namespace ${a}.`
|
|
231
231
|
});
|
|
232
|
-
let t = await this.
|
|
232
|
+
let t = await this.waitForGetHit({
|
|
233
|
+
namespace: a,
|
|
234
|
+
logicalId: o,
|
|
235
|
+
timeoutMs: e?.timeoutMs ?? d,
|
|
236
|
+
pollIntervalMs: e?.pollIntervalMs ?? f
|
|
237
|
+
});
|
|
238
|
+
n.push({
|
|
239
|
+
name: "probe-get",
|
|
240
|
+
status: t?.namespace === a ? "pass" : "fail",
|
|
241
|
+
message: t ? t.namespace === a ? "Get-by-id returned the smoke-test record in the expected namespace." : `Get-by-id returned namespace ${t.namespace}, expected ${a}.` : `Get-by-id did not return the smoke-test record within ${(e?.timeoutMs ?? d) / 1e3} seconds.`
|
|
242
|
+
});
|
|
243
|
+
let r = await this.waitForSearchHit({
|
|
233
244
|
query: s,
|
|
234
245
|
namespace: a,
|
|
235
246
|
logicalId: o,
|
|
@@ -238,8 +249,8 @@ var d = 3e4, f = 1e3, p = class {
|
|
|
238
249
|
});
|
|
239
250
|
n.push({
|
|
240
251
|
name: "probe-search",
|
|
241
|
-
status:
|
|
242
|
-
message:
|
|
252
|
+
status: r?.namespace === a ? "pass" : "fail",
|
|
253
|
+
message: r ? r.namespace === a ? "Semantic search returned the smoke-test record in the expected namespace." : `Semantic search returned namespace ${r.namespace}, expected ${a}.` : `Semantic search did not return the smoke-test record within ${(e?.timeoutMs ?? d) / 1e3} seconds.`
|
|
243
254
|
});
|
|
244
255
|
} catch (e) {
|
|
245
256
|
n.push({
|
|
@@ -308,19 +319,42 @@ var d = 3e4, f = 1e3, p = class {
|
|
|
308
319
|
text: t.text ?? ""
|
|
309
320
|
};
|
|
310
321
|
}
|
|
311
|
-
async
|
|
322
|
+
async waitForGetHit(e) {
|
|
312
323
|
let t = Date.now() + e.timeoutMs;
|
|
313
324
|
for (; Date.now() <= t;) {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
namespace: e.namespace
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
})).some((t) => t.logicalId === e.logicalId)) return !0;
|
|
325
|
+
let n = await this.get({
|
|
326
|
+
id: e.logicalId,
|
|
327
|
+
namespace: e.namespace
|
|
328
|
+
});
|
|
329
|
+
if (n) return n;
|
|
320
330
|
if (Date.now() + e.pollIntervalMs > t) break;
|
|
321
331
|
await this.pause(e.pollIntervalMs);
|
|
322
332
|
}
|
|
323
|
-
return
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
async waitForSearchHit(e) {
|
|
336
|
+
let t = await this.embeddings.embedQuery(e.query), n = Date.now() + e.timeoutMs;
|
|
337
|
+
for (; Date.now() <= n;) {
|
|
338
|
+
let r = await this.vectorize.query({
|
|
339
|
+
vector: t,
|
|
340
|
+
namespace: e.namespace,
|
|
341
|
+
topK: 5
|
|
342
|
+
});
|
|
343
|
+
for (let t of r) {
|
|
344
|
+
let n = s(t, { defaultNamespace: e.namespace });
|
|
345
|
+
if (n.logicalId === e.logicalId) {
|
|
346
|
+
let e = n.text ?? (await this.companionStore.get(n.namespace, n.logicalId))?.text ?? "";
|
|
347
|
+
return {
|
|
348
|
+
...n,
|
|
349
|
+
text: e,
|
|
350
|
+
score: t.score ?? 0
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (Date.now() + e.pollIntervalMs > n) break;
|
|
355
|
+
await this.pause(e.pollIntervalMs);
|
|
356
|
+
}
|
|
357
|
+
return null;
|
|
324
358
|
}
|
|
325
359
|
async pause(e) {
|
|
326
360
|
await new Promise((t) => setTimeout(t, e));
|
package/dist/service.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","names":[],"sources":["../src/service.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { OpenClawConfig } from \"openclaw/plugin-sdk/config-runtime\";\nimport { isCloudflareNotFoundError } from \"./cloudflare-api.js\";\nimport { CompanionStore } from \"./companion-store.js\";\nimport { runDoctor } from \"./doctor.js\";\nimport { WorkersAiEmbeddingsClient } from \"./embeddings-client.js\";\nimport { sanitizeNamespace, resolveDefaultNamespace } from \"./namespace.js\";\nimport { buildVectorId, hydrateInlineRecord, mapRecordForUpsert } from \"./record-mapper.js\";\nimport type {\n\tCompanionRecord,\n\tDoctorCheck,\n\tDoctorReport,\n\tEmbeddingDimensionsInspection,\n\tHydratedMemoryRecord,\n\tIndexInitializationReport,\n\tMemoryRecordInput,\n\tMetadataFilter,\n\tResolvedPluginConfig,\n\tSmokeTestReport,\n\tUpsertedMemoryRecord,\n\tVectorizeIndexDescription,\n} from \"./types.js\";\nimport { VectorizeClient } from \"./vectorize-client.js\";\n\nconst SMOKE_TEST_TIMEOUT_MS = 30_000;\nconst SMOKE_TEST_POLL_INTERVAL_MS = 1_000;\n\nexport class CloudflareMemoryService {\n\treadonly embeddings: WorkersAiEmbeddingsClient;\n\treadonly vectorize: VectorizeClient;\n\treadonly companionStore: CompanionStore;\n\n\tconstructor(\n\t\treadonly config: ResolvedPluginConfig,\n\t\treadonly openClawConfig: OpenClawConfig,\n\t) {\n\t\tthis.embeddings = new WorkersAiEmbeddingsClient(config);\n\t\tthis.vectorize = new VectorizeClient(config);\n\t\tthis.companionStore = new CompanionStore(config.companionStorePath);\n\t}\n\n\tresolveNamespace(params: { namespace?: string; sessionKey?: string; agentId?: string; workspaceDir?: string }): string {\n\t\treturn resolveDefaultNamespace({\n\t\t\tfixedNamespace: params.namespace ?? this.config.fixedNamespace,\n\t\t\tsessionKey: params.sessionKey,\n\t\t\tagentId: params.agentId,\n\t\t\tworkspaceDir: params.workspaceDir,\n\t\t});\n\t}\n\n\tasync search(params: {\n\t\tquery: string;\n\t\tnamespace?: string;\n\t\tmaxResults?: number;\n\t\tminScore?: number;\n\t\tfilter?: MetadataFilter;\n\t\tsessionKey?: string;\n\t\tagentId?: string;\n\t\tworkspaceDir?: string;\n\t}): Promise<Array<HydratedMemoryRecord & { score: number }>> {\n\t\tconst namespace = this.resolveNamespace(params);\n\t\tconst vector = await this.embeddings.embedQuery(params.query);\n\t\tconst matches = await this.vectorize.query({\n\t\t\tvector,\n\t\t\tnamespace,\n\t\t\ttopK: params.maxResults ?? this.config.topK,\n\t\t\tfilter: params.filter,\n\t\t});\n\n\t\tconst hydrated = await Promise.all(\n\t\t\tmatches.map(async (match) => {\n\t\t\t\tconst base = hydrateInlineRecord(match);\n\t\t\t\tconst text = base.text ?? (await this.companionStore.get(base.namespace, base.logicalId))?.text ?? \"\";\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\ttext,\n\t\t\t\t\tscore: match.score ?? 0,\n\t\t\t\t};\n\t\t\t}),\n\t\t);\n\n\t\treturn hydrated.filter((record) => record.score >= (params.minScore ?? this.config.minScore));\n\t}\n\n\tasync get(params: { id: string; namespace?: string; sessionKey?: string; agentId?: string; workspaceDir?: string }): Promise<HydratedMemoryRecord | null> {\n\t\tconst namespace = this.resolveNamespace(params);\n\t\tconst vectorId = buildVectorId(namespace, params.id);\n\t\tconst [match] = await this.vectorize.getByIds([vectorId]);\n\t\tif (!match) {\n\t\t\treturn null;\n\t\t}\n\t\tconst base = hydrateInlineRecord(match);\n\t\tconst companion = await this.companionStore.get(base.namespace, base.logicalId);\n\t\treturn {\n\t\t\t...base,\n\t\t\ttext: base.text ?? companion?.text ?? \"\",\n\t\t};\n\t}\n\n\tasync upsert(params: { input: MemoryRecordInput; sessionKey?: string; agentId?: string; workspaceDir?: string }): Promise<UpsertedMemoryRecord> {\n\t\tconst namespace = this.resolveNamespace({\n\t\t\tnamespace: params.input.namespace,\n\t\t\tsessionKey: params.sessionKey,\n\t\t\tagentId: params.agentId,\n\t\t\tworkspaceDir: params.workspaceDir,\n\t\t});\n\t\tconst embedding = await this.embeddings.embedQuery(params.input.text);\n\t\tconst mapped = mapRecordForUpsert({\n\t\t\tinput: params.input,\n\t\t\tnamespace,\n\t\t\tembedding,\n\t\t\tconfig: this.config,\n\t\t});\n\n\t\tif (mapped.companionRecord) {\n\t\t\tawait this.companionStore.upsert(mapped.companionRecord);\n\t\t}\n\n\t\tconst mutationId = await this.vectorize.upsert([mapped.vector]);\n\t\tconst hydrated = await this.get({\n\t\t\tid: mapped.logicalId,\n\t\t\tnamespace,\n\t\t});\n\t\tconst fallback =\n\t\t\tmapped.companionRecord === undefined\n\t\t\t\t? this.fromInlineFallback(mapped.vector)\n\t\t\t\t: this.fromCompanionFallback(mapped.companionRecord, mapped.logicalId, namespace, mapped.path);\n\t\tconst resolved = hydrated\n\t\t\t? {\n\t\t\t\t\t...fallback,\n\t\t\t\t\t...hydrated,\n\t\t\t\t\ttitle: hydrated.title ?? fallback.title,\n\t\t\t\t\ttext: hydrated.text || fallback.text,\n\t\t\t\t\tmetadata: Object.keys(hydrated.metadata).length > 0 ? hydrated.metadata : fallback.metadata,\n\t\t\t\t\tsource: hydrated.source ?? fallback.source,\n\t\t\t\t\tcreatedAt: hydrated.createdAt ?? fallback.createdAt,\n\t\t\t\t\tupdatedAt: hydrated.updatedAt ?? fallback.updatedAt,\n\t\t\t\t}\n\t\t\t: fallback;\n\n\t\treturn {\n\t\t\t...resolved,\n\t\t\tmutationId,\n\t\t};\n\t}\n\n\tasync delete(params: { id: string; namespace?: string; sessionKey?: string; agentId?: string; workspaceDir?: string }): Promise<string | undefined> {\n\t\tconst namespace = this.resolveNamespace(params);\n\t\tawait this.companionStore.delete(namespace, params.id);\n\t\treturn this.vectorize.deleteByIds([buildVectorId(namespace, params.id)]);\n\t}\n\n\tasync doctor(options: { createIndexIfMissing?: boolean }): Promise<DoctorReport> {\n\t\treturn runDoctor({\n\t\t\tservice: this,\n\t\t\tcreateIndexIfMissing: options.createIndexIfMissing ?? false,\n\t\t});\n\t}\n\n\tasync inspectEmbeddingDimensions(): Promise<EmbeddingDimensionsInspection> {\n\t\tconst embeddingDimensions = await this.embeddings.probeDimensions();\n\t\tconst configuredDimensions = this.config.createIndex.dimensions;\n\t\treturn {\n\t\t\tembeddingDimensions,\n\t\t\tconfiguredDimensions,\n\t\t\tconfiguredDimensionsMatchModel: configuredDimensions === undefined || configuredDimensions === embeddingDimensions,\n\t\t\ttargetDimensions: embeddingDimensions,\n\t\t};\n\t}\n\n\tasync describeIndexIfExists(): Promise<VectorizeIndexDescription | null> {\n\t\ttry {\n\t\t\treturn await this.vectorize.describeIndex();\n\t\t} catch (error) {\n\t\t\tif (isCloudflareNotFoundError(error)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync initializeIndex(options?: { recreateIfDimensionMismatch?: boolean }): Promise<IndexInitializationReport> {\n\t\tconst recreateIfDimensionMismatch = options?.recreateIfDimensionMismatch ?? true;\n\t\tconst checks: DoctorCheck[] = [];\n\t\tchecks.push({\n\t\t\tname: \"credentials\",\n\t\t\tstatus: \"pass\",\n\t\t\tmessage: `Using Cloudflare account ${this.config.accountId} and Vectorize index ${this.config.indexName}.`,\n\t\t});\n\n\t\tconst embedding = await this.inspectEmbeddingDimensions();\n\t\tchecks.push({\n\t\t\tname: \"workers-ai-embeddings\",\n\t\t\tstatus: \"pass\",\n\t\t\tmessage: `Workers AI model ${this.config.model} returned ${embedding.embeddingDimensions} dimensions.`,\n\t\t});\n\t\tif (embedding.configuredDimensions !== undefined) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"create-index-dimensions\",\n\t\t\t\tstatus: embedding.configuredDimensionsMatchModel ? \"pass\" : \"warn\",\n\t\t\t\tmessage: embedding.configuredDimensionsMatchModel\n\t\t\t\t\t? `Configured createIndex.dimensions matches the embedding model (${embedding.embeddingDimensions}).`\n\t\t\t\t\t: `Configured createIndex.dimensions (${embedding.configuredDimensions}) does not match the embedding model (${embedding.embeddingDimensions}). Using the live embedding dimensions for initialization.`,\n\t\t\t});\n\t\t}\n\n\t\tconst existingIndex = await this.describeIndexIfExists();\n\t\tlet created = false;\n\t\tlet recreated = false;\n\t\tlet indexDimensions = existingIndex?.config.dimensions;\n\n\t\tif (!existingIndex) {\n\t\t\tconst createdIndex = await this.vectorize.createIndex(embedding.targetDimensions);\n\t\t\tcreated = true;\n\t\t\tindexDimensions = createdIndex.config.dimensions;\n\t\t\tchecks.push({\n\t\t\t\tname: \"vectorize-index\",\n\t\t\t\tstatus: \"pass\",\n\t\t\t\tmessage: `Created Vectorize index \"${this.config.indexName}\" with ${indexDimensions} dimensions.`,\n\t\t\t});\n\t\t} else if (existingIndex.config.dimensions === embedding.targetDimensions) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"vectorize-index\",\n\t\t\t\tstatus: \"pass\",\n\t\t\t\tmessage: `Vectorize index \"${this.config.indexName}\" already uses ${existingIndex.config.dimensions} dimensions.`,\n\t\t\t});\n\t\t} else if (!recreateIfDimensionMismatch) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"vectorize-index\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tmessage: `Vectorize index \"${this.config.indexName}\" uses ${existingIndex.config.dimensions} dimensions, but the embedding model requires ${embedding.targetDimensions}. Recreate the index or rerun init with recreation enabled.`,\n\t\t\t});\n\t\t} else {\n\t\t\tawait this.vectorize.deleteIndex();\n\t\t\tconst recreatedIndex = await this.vectorize.createIndex(embedding.targetDimensions);\n\t\t\trecreated = true;\n\t\t\tindexDimensions = recreatedIndex.config.dimensions;\n\t\t\tchecks.push({\n\t\t\t\tname: \"vectorize-index\",\n\t\t\t\tstatus: \"pass\",\n\t\t\t\tmessage: `Recreated Vectorize index \"${this.config.indexName}\" from ${existingIndex.config.dimensions} to ${indexDimensions} dimensions.`,\n\t\t\t});\n\t\t}\n\n\t\tchecks.push({\n\t\t\tname: \"dimension-match\",\n\t\t\tstatus: indexDimensions === embedding.embeddingDimensions ? \"pass\" : \"fail\",\n\t\t\tmessage:\n\t\t\t\tindexDimensions === embedding.embeddingDimensions\n\t\t\t\t\t? \"Embedding dimensions match the Vectorize index.\"\n\t\t\t\t\t: `Embedding dimensions (${embedding.embeddingDimensions}) do not match the Vectorize index dimensions (${indexDimensions ?? \"unknown\"}).`,\n\t\t});\n\t\tchecks.push({\n\t\t\tname: \"metadata-filters\",\n\t\t\tstatus: this.config.metadataIndexedFields.length > 0 ? \"pass\" : \"warn\",\n\t\t\tmessage:\n\t\t\t\tthis.config.metadataIndexedFields.length > 0\n\t\t\t\t\t? `Configured metadata-index guidance for: ${this.config.metadataIndexedFields.join(\", \")}.`\n\t\t\t\t\t: \"No metadataIndexedFields configured. Add metadata indexes in Cloudflare before relying on filter-heavy queries.\",\n\t\t});\n\n\t\treturn {\n\t\t\tok: checks.every((check) => check.status !== \"fail\"),\n\t\t\tchecks,\n\t\t\tcreated,\n\t\t\trecreated,\n\t\t\tembeddingDimensions: embedding.embeddingDimensions,\n\t\t\tindexDimensions,\n\t\t};\n\t}\n\n\tasync runSmokeTest(options?: { timeoutMs?: number; pollIntervalMs?: number }): Promise<SmokeTestReport> {\n\t\tconst checks: DoctorCheck[] = [];\n\t\tchecks.push({\n\t\t\tname: \"credentials\",\n\t\t\tstatus: \"pass\",\n\t\t\tmessage: `Using Cloudflare account ${this.config.accountId} and Vectorize index ${this.config.indexName}.`,\n\t\t});\n\n\t\tconst embedding = await this.inspectEmbeddingDimensions();\n\t\tchecks.push({\n\t\t\tname: \"workers-ai-embeddings\",\n\t\t\tstatus: \"pass\",\n\t\t\tmessage: `Workers AI model ${this.config.model} returned ${embedding.embeddingDimensions} dimensions.`,\n\t\t});\n\t\tif (embedding.configuredDimensions !== undefined) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"create-index-dimensions\",\n\t\t\t\tstatus: embedding.configuredDimensionsMatchModel ? \"pass\" : \"warn\",\n\t\t\t\tmessage: embedding.configuredDimensionsMatchModel\n\t\t\t\t\t? `Configured createIndex.dimensions matches the embedding model (${embedding.embeddingDimensions}).`\n\t\t\t\t\t: `Configured createIndex.dimensions (${embedding.configuredDimensions}) does not match the embedding model (${embedding.embeddingDimensions}). Using the live embedding dimensions for validation.`,\n\t\t\t});\n\t\t}\n\n\t\tconst existingIndex = await this.describeIndexIfExists();\n\t\tif (!existingIndex) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"vectorize-index\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tmessage: `Vectorize index \"${this.config.indexName}\" was not found. Run \"openclaw cf-memory init\" before rerunning this test.`,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tchecks,\n\t\t\t\tnamespace: \"n/a\",\n\t\t\t\tlogicalId: \"n/a\",\n\t\t\t};\n\t\t}\n\n\t\tchecks.push({\n\t\t\tname: \"vectorize-index\",\n\t\t\tstatus: \"pass\",\n\t\t\tmessage: `Vectorize index \"${this.config.indexName}\" is reachable.`,\n\t\t});\n\t\tif (existingIndex.config.dimensions !== embedding.embeddingDimensions) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"dimension-match\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tmessage: `Embedding dimensions (${embedding.embeddingDimensions}) do not match the Vectorize index dimensions (${existingIndex.config.dimensions}). Run \"openclaw cf-memory init\" to repair the index.`,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tchecks,\n\t\t\t\tnamespace: \"n/a\",\n\t\t\t\tlogicalId: \"n/a\",\n\t\t\t};\n\t\t}\n\n\t\tchecks.push({\n\t\t\tname: \"dimension-match\",\n\t\t\tstatus: \"pass\",\n\t\t\tmessage: \"Embedding dimensions match the Vectorize index.\",\n\t\t});\n\n\t\tconst namespace = sanitizeNamespace(`cf-memory-test-${randomUUID()}`);\n\t\tconst logicalId = `cf-memory-test-${randomUUID()}`;\n\t\tconst probeText = `OpenClaw Cloudflare memory smoke test ${logicalId}`;\n\t\tlet probeUpserted = false;\n\n\t\ttry {\n\t\t\tawait this.upsert({\n\t\t\t\tinput: {\n\t\t\t\t\tid: logicalId,\n\t\t\t\t\tnamespace,\n\t\t\t\t\ttext: probeText,\n\t\t\t\t\tsource: \"cf-memory-test\",\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\tprobe: true,\n\t\t\t\t\t\tprobeId: logicalId,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t});\n\t\t\tprobeUpserted = true;\n\t\t\tchecks.push({\n\t\t\t\tname: \"probe-upsert\",\n\t\t\t\tstatus: \"pass\",\n\t\t\t\tmessage: `Inserted smoke-test record ${logicalId} in namespace ${namespace}.`,\n\t\t\t});\n\n\t\t\tconst found = await this.waitForSearchHit({\n\t\t\t\tquery: probeText,\n\t\t\t\tnamespace,\n\t\t\t\tlogicalId,\n\t\t\t\ttimeoutMs: options?.timeoutMs ?? SMOKE_TEST_TIMEOUT_MS,\n\t\t\t\tpollIntervalMs: options?.pollIntervalMs ?? SMOKE_TEST_POLL_INTERVAL_MS,\n\t\t\t});\n\t\t\tchecks.push({\n\t\t\t\tname: \"probe-search\",\n\t\t\t\tstatus: found ? \"pass\" : \"fail\",\n\t\t\t\tmessage: found\n\t\t\t\t\t? \"Semantic search returned the smoke-test record.\"\n\t\t\t\t\t: `Semantic search did not return the smoke-test record within ${(options?.timeoutMs ?? SMOKE_TEST_TIMEOUT_MS) / 1000} seconds.`,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tchecks.push({\n\t\t\t\tname: probeUpserted ? \"probe-search\" : \"probe-upsert\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Smoke test failed with an unknown error.\",\n\t\t\t});\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tawait this.delete({ id: logicalId, namespace });\n\t\t\t\tchecks.push({\n\t\t\t\t\tname: \"probe-cleanup\",\n\t\t\t\t\tstatus: \"pass\",\n\t\t\t\t\tmessage: `Deleted smoke-test record ${logicalId}.`,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tchecks.push({\n\t\t\t\t\tname: \"probe-cleanup\",\n\t\t\t\t\tstatus: \"fail\",\n\t\t\t\t\tmessage: error instanceof Error ? error.message : `Failed to delete smoke-test record ${logicalId}.`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tok: checks.every((check) => check.status !== \"fail\"),\n\t\t\tchecks,\n\t\t\tnamespace,\n\t\t\tlogicalId,\n\t\t};\n\t}\n\n\tasync ensureIndexExists(createIfMissing: boolean, targetDimensions?: number): Promise<{ created: boolean; dimensions: number }> {\n\t\ttry {\n\t\t\tconst description = await this.vectorize.describeIndex();\n\t\t\treturn {\n\t\t\t\tcreated: false,\n\t\t\t\tdimensions: description.config.dimensions,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tif (!createIfMissing || !isCloudflareNotFoundError(error)) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tconst dimensions = targetDimensions ?? (await this.inspectEmbeddingDimensions()).targetDimensions;\n\t\t\tconst createdIndex = await this.vectorize.createIndex(dimensions);\n\t\t\treturn {\n\t\t\t\tcreated: true,\n\t\t\t\tdimensions: createdIndex.config.dimensions,\n\t\t\t};\n\t\t}\n\t}\n\n\tprivate fromCompanionFallback(companionRecord: CompanionRecord | undefined, logicalId: string, namespace: string, path: string): UpsertedMemoryRecord {\n\t\treturn {\n\t\t\tlogicalId,\n\t\t\tvectorId: buildVectorId(namespace, logicalId),\n\t\t\tnamespace,\n\t\t\ttitle: companionRecord?.title,\n\t\t\ttext: companionRecord?.text ?? \"\",\n\t\t\tmetadata: companionRecord?.metadata ?? {},\n\t\t\tsource: companionRecord?.source,\n\t\t\tcreatedAt: companionRecord?.createdAt,\n\t\t\tupdatedAt: companionRecord?.updatedAt,\n\t\t\tpath,\n\t\t};\n\t}\n\n\tprivate fromInlineFallback(vector: { id: string; namespace?: string; metadata?: Record<string, string | number | boolean> }): UpsertedMemoryRecord {\n\t\tconst record = hydrateInlineRecord(vector);\n\t\treturn {\n\t\t\t...record,\n\t\t\ttext: record.text ?? \"\",\n\t\t};\n\t}\n\n\tprivate async waitForSearchHit(params: { query: string; namespace: string; logicalId: string; timeoutMs: number; pollIntervalMs: number }): Promise<boolean> {\n\t\tconst deadline = Date.now() + params.timeoutMs;\n\t\twhile (Date.now() <= deadline) {\n\t\t\tconst results = await this.search({\n\t\t\t\tquery: params.query,\n\t\t\t\tnamespace: params.namespace,\n\t\t\t\tmaxResults: 5,\n\t\t\t\tminScore: 0,\n\t\t\t});\n\t\t\tif (results.some((record) => record.logicalId === params.logicalId)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (Date.now() + params.pollIntervalMs > deadline) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tawait this.pause(params.pollIntervalMs);\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate async pause(ms: number): Promise<void> {\n\t\tawait new Promise((resolve) => setTimeout(resolve, ms));\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"service.js","names":[],"sources":["../src/service.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { OpenClawConfig } from \"openclaw/plugin-sdk/config-runtime\";\nimport { isCloudflareNotFoundError } from \"./cloudflare-api.js\";\nimport { CompanionStore } from \"./companion-store.js\";\nimport { runDoctor } from \"./doctor.js\";\nimport { WorkersAiEmbeddingsClient } from \"./embeddings-client.js\";\nimport { sanitizeNamespace, resolveDefaultNamespace } from \"./namespace.js\";\nimport { buildVectorId, hydrateInlineRecord, mapRecordForUpsert } from \"./record-mapper.js\";\nimport type {\n\tCompanionRecord,\n\tDoctorCheck,\n\tDoctorReport,\n\tEmbeddingDimensionsInspection,\n\tHydratedMemoryRecord,\n\tIndexInitializationReport,\n\tMemoryRecordInput,\n\tMetadataFilter,\n\tResolvedPluginConfig,\n\tSmokeTestReport,\n\tUpsertedMemoryRecord,\n\tVectorizeIndexDescription,\n} from \"./types.js\";\nimport { VectorizeClient } from \"./vectorize-client.js\";\n\nconst SMOKE_TEST_TIMEOUT_MS = 30_000;\nconst SMOKE_TEST_POLL_INTERVAL_MS = 1_000;\n\nexport class CloudflareMemoryService {\n\treadonly embeddings: WorkersAiEmbeddingsClient;\n\treadonly vectorize: VectorizeClient;\n\treadonly companionStore: CompanionStore;\n\n\tconstructor(\n\t\treadonly config: ResolvedPluginConfig,\n\t\treadonly openClawConfig: OpenClawConfig,\n\t) {\n\t\tthis.embeddings = new WorkersAiEmbeddingsClient(config);\n\t\tthis.vectorize = new VectorizeClient(config);\n\t\tthis.companionStore = new CompanionStore(config.companionStorePath);\n\t}\n\n\tresolveNamespace(params: { namespace?: string; sessionKey?: string; agentId?: string; workspaceDir?: string }): string {\n\t\treturn resolveDefaultNamespace({\n\t\t\tfixedNamespace: params.namespace ?? this.config.fixedNamespace,\n\t\t\tsessionKey: params.sessionKey,\n\t\t\tagentId: params.agentId,\n\t\t\tworkspaceDir: params.workspaceDir,\n\t\t});\n\t}\n\n\tasync search(params: {\n\t\tquery: string;\n\t\tnamespace?: string;\n\t\tmaxResults?: number;\n\t\tminScore?: number;\n\t\tfilter?: MetadataFilter;\n\t\tsessionKey?: string;\n\t\tagentId?: string;\n\t\tworkspaceDir?: string;\n\t}): Promise<Array<HydratedMemoryRecord & { score: number }>> {\n\t\tconst namespace = this.resolveNamespace(params);\n\t\tconst vector = await this.embeddings.embedQuery(params.query);\n\t\tconst matches = await this.vectorize.query({\n\t\t\tvector,\n\t\t\tnamespace,\n\t\t\ttopK: params.maxResults ?? this.config.topK,\n\t\t\tfilter: params.filter,\n\t\t});\n\n\t\tconst hydrated = await Promise.all(\n\t\t\tmatches.map(async (match) => {\n\t\t\t\tconst base = hydrateInlineRecord(match, { defaultNamespace: namespace });\n\t\t\t\tconst text = base.text ?? (await this.companionStore.get(base.namespace, base.logicalId))?.text ?? \"\";\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\ttext,\n\t\t\t\t\tscore: match.score ?? 0,\n\t\t\t\t};\n\t\t\t}),\n\t\t);\n\n\t\treturn hydrated.filter((record) => record.score >= (params.minScore ?? this.config.minScore));\n\t}\n\n\tasync get(params: { id: string; namespace?: string; sessionKey?: string; agentId?: string; workspaceDir?: string }): Promise<HydratedMemoryRecord | null> {\n\t\tconst namespace = this.resolveNamespace(params);\n\t\tconst vectorId = buildVectorId(namespace, params.id);\n\t\tconst [match] = await this.vectorize.getByIds([vectorId]);\n\t\tif (!match) {\n\t\t\treturn null;\n\t\t}\n\t\tconst base = hydrateInlineRecord(match, { defaultNamespace: namespace });\n\t\tconst companion = await this.companionStore.get(base.namespace, base.logicalId);\n\t\treturn {\n\t\t\t...base,\n\t\t\ttext: base.text ?? companion?.text ?? \"\",\n\t\t};\n\t}\n\n\tasync upsert(params: { input: MemoryRecordInput; sessionKey?: string; agentId?: string; workspaceDir?: string }): Promise<UpsertedMemoryRecord> {\n\t\tconst namespace = this.resolveNamespace({\n\t\t\tnamespace: params.input.namespace,\n\t\t\tsessionKey: params.sessionKey,\n\t\t\tagentId: params.agentId,\n\t\t\tworkspaceDir: params.workspaceDir,\n\t\t});\n\t\tconst embedding = await this.embeddings.embedQuery(params.input.text);\n\t\tconst mapped = mapRecordForUpsert({\n\t\t\tinput: params.input,\n\t\t\tnamespace,\n\t\t\tembedding,\n\t\t\tconfig: this.config,\n\t\t});\n\n\t\tif (mapped.companionRecord) {\n\t\t\tawait this.companionStore.upsert(mapped.companionRecord);\n\t\t}\n\n\t\tconst mutationId = await this.vectorize.upsert([mapped.vector]);\n\t\tconst hydrated = await this.get({\n\t\t\tid: mapped.logicalId,\n\t\t\tnamespace,\n\t\t});\n\t\tconst fallback =\n\t\t\tmapped.companionRecord === undefined\n\t\t\t\t? this.fromInlineFallback(mapped.vector)\n\t\t\t\t: this.fromCompanionFallback(mapped.companionRecord, mapped.logicalId, namespace, mapped.path);\n\t\tconst resolved = hydrated\n\t\t\t? {\n\t\t\t\t\t...fallback,\n\t\t\t\t\t...hydrated,\n\t\t\t\t\ttitle: hydrated.title ?? fallback.title,\n\t\t\t\t\ttext: hydrated.text || fallback.text,\n\t\t\t\t\tmetadata: Object.keys(hydrated.metadata).length > 0 ? hydrated.metadata : fallback.metadata,\n\t\t\t\t\tsource: hydrated.source ?? fallback.source,\n\t\t\t\t\tcreatedAt: hydrated.createdAt ?? fallback.createdAt,\n\t\t\t\t\tupdatedAt: hydrated.updatedAt ?? fallback.updatedAt,\n\t\t\t\t}\n\t\t\t: fallback;\n\n\t\treturn {\n\t\t\t...resolved,\n\t\t\tmutationId,\n\t\t};\n\t}\n\n\tasync delete(params: { id: string; namespace?: string; sessionKey?: string; agentId?: string; workspaceDir?: string }): Promise<string | undefined> {\n\t\tconst namespace = this.resolveNamespace(params);\n\t\tawait this.companionStore.delete(namespace, params.id);\n\t\treturn this.vectorize.deleteByIds([buildVectorId(namespace, params.id)]);\n\t}\n\n\tasync doctor(options: { createIndexIfMissing?: boolean }): Promise<DoctorReport> {\n\t\treturn runDoctor({\n\t\t\tservice: this,\n\t\t\tcreateIndexIfMissing: options.createIndexIfMissing ?? false,\n\t\t});\n\t}\n\n\tasync inspectEmbeddingDimensions(): Promise<EmbeddingDimensionsInspection> {\n\t\tconst embeddingDimensions = await this.embeddings.probeDimensions();\n\t\tconst configuredDimensions = this.config.createIndex.dimensions;\n\t\treturn {\n\t\t\tembeddingDimensions,\n\t\t\tconfiguredDimensions,\n\t\t\tconfiguredDimensionsMatchModel: configuredDimensions === undefined || configuredDimensions === embeddingDimensions,\n\t\t\ttargetDimensions: embeddingDimensions,\n\t\t};\n\t}\n\n\tasync describeIndexIfExists(): Promise<VectorizeIndexDescription | null> {\n\t\ttry {\n\t\t\treturn await this.vectorize.describeIndex();\n\t\t} catch (error) {\n\t\t\tif (isCloudflareNotFoundError(error)) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync initializeIndex(options?: { recreateIfDimensionMismatch?: boolean }): Promise<IndexInitializationReport> {\n\t\tconst recreateIfDimensionMismatch = options?.recreateIfDimensionMismatch ?? true;\n\t\tconst checks: DoctorCheck[] = [];\n\t\tchecks.push({\n\t\t\tname: \"credentials\",\n\t\t\tstatus: \"pass\",\n\t\t\tmessage: `Using Cloudflare account ${this.config.accountId} and Vectorize index ${this.config.indexName}.`,\n\t\t});\n\n\t\tconst embedding = await this.inspectEmbeddingDimensions();\n\t\tchecks.push({\n\t\t\tname: \"workers-ai-embeddings\",\n\t\t\tstatus: \"pass\",\n\t\t\tmessage: `Workers AI model ${this.config.model} returned ${embedding.embeddingDimensions} dimensions.`,\n\t\t});\n\t\tif (embedding.configuredDimensions !== undefined) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"create-index-dimensions\",\n\t\t\t\tstatus: embedding.configuredDimensionsMatchModel ? \"pass\" : \"warn\",\n\t\t\t\tmessage: embedding.configuredDimensionsMatchModel\n\t\t\t\t\t? `Configured createIndex.dimensions matches the embedding model (${embedding.embeddingDimensions}).`\n\t\t\t\t\t: `Configured createIndex.dimensions (${embedding.configuredDimensions}) does not match the embedding model (${embedding.embeddingDimensions}). Using the live embedding dimensions for initialization.`,\n\t\t\t});\n\t\t}\n\n\t\tconst existingIndex = await this.describeIndexIfExists();\n\t\tlet created = false;\n\t\tlet recreated = false;\n\t\tlet indexDimensions = existingIndex?.config.dimensions;\n\n\t\tif (!existingIndex) {\n\t\t\tconst createdIndex = await this.vectorize.createIndex(embedding.targetDimensions);\n\t\t\tcreated = true;\n\t\t\tindexDimensions = createdIndex.config.dimensions;\n\t\t\tchecks.push({\n\t\t\t\tname: \"vectorize-index\",\n\t\t\t\tstatus: \"pass\",\n\t\t\t\tmessage: `Created Vectorize index \"${this.config.indexName}\" with ${indexDimensions} dimensions.`,\n\t\t\t});\n\t\t} else if (existingIndex.config.dimensions === embedding.targetDimensions) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"vectorize-index\",\n\t\t\t\tstatus: \"pass\",\n\t\t\t\tmessage: `Vectorize index \"${this.config.indexName}\" already uses ${existingIndex.config.dimensions} dimensions.`,\n\t\t\t});\n\t\t} else if (!recreateIfDimensionMismatch) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"vectorize-index\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tmessage: `Vectorize index \"${this.config.indexName}\" uses ${existingIndex.config.dimensions} dimensions, but the embedding model requires ${embedding.targetDimensions}. Recreate the index or rerun init with recreation enabled.`,\n\t\t\t});\n\t\t} else {\n\t\t\tawait this.vectorize.deleteIndex();\n\t\t\tconst recreatedIndex = await this.vectorize.createIndex(embedding.targetDimensions);\n\t\t\trecreated = true;\n\t\t\tindexDimensions = recreatedIndex.config.dimensions;\n\t\t\tchecks.push({\n\t\t\t\tname: \"vectorize-index\",\n\t\t\t\tstatus: \"pass\",\n\t\t\t\tmessage: `Recreated Vectorize index \"${this.config.indexName}\" from ${existingIndex.config.dimensions} to ${indexDimensions} dimensions.`,\n\t\t\t});\n\t\t}\n\n\t\tchecks.push({\n\t\t\tname: \"dimension-match\",\n\t\t\tstatus: indexDimensions === embedding.embeddingDimensions ? \"pass\" : \"fail\",\n\t\t\tmessage:\n\t\t\t\tindexDimensions === embedding.embeddingDimensions\n\t\t\t\t\t? \"Embedding dimensions match the Vectorize index.\"\n\t\t\t\t\t: `Embedding dimensions (${embedding.embeddingDimensions}) do not match the Vectorize index dimensions (${indexDimensions ?? \"unknown\"}).`,\n\t\t});\n\t\tchecks.push({\n\t\t\tname: \"metadata-filters\",\n\t\t\tstatus: this.config.metadataIndexedFields.length > 0 ? \"pass\" : \"warn\",\n\t\t\tmessage:\n\t\t\t\tthis.config.metadataIndexedFields.length > 0\n\t\t\t\t\t? `Configured metadata-index guidance for: ${this.config.metadataIndexedFields.join(\", \")}.`\n\t\t\t\t\t: \"No metadataIndexedFields configured. Add metadata indexes in Cloudflare before relying on filter-heavy queries.\",\n\t\t});\n\n\t\treturn {\n\t\t\tok: checks.every((check) => check.status !== \"fail\"),\n\t\t\tchecks,\n\t\t\tcreated,\n\t\t\trecreated,\n\t\t\tembeddingDimensions: embedding.embeddingDimensions,\n\t\t\tindexDimensions,\n\t\t};\n\t}\n\n\tasync runSmokeTest(options?: { timeoutMs?: number; pollIntervalMs?: number }): Promise<SmokeTestReport> {\n\t\tconst checks: DoctorCheck[] = [];\n\t\tchecks.push({\n\t\t\tname: \"credentials\",\n\t\t\tstatus: \"pass\",\n\t\t\tmessage: `Using Cloudflare account ${this.config.accountId} and Vectorize index ${this.config.indexName}.`,\n\t\t});\n\n\t\tconst embedding = await this.inspectEmbeddingDimensions();\n\t\tchecks.push({\n\t\t\tname: \"workers-ai-embeddings\",\n\t\t\tstatus: \"pass\",\n\t\t\tmessage: `Workers AI model ${this.config.model} returned ${embedding.embeddingDimensions} dimensions.`,\n\t\t});\n\t\tif (embedding.configuredDimensions !== undefined) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"create-index-dimensions\",\n\t\t\t\tstatus: embedding.configuredDimensionsMatchModel ? \"pass\" : \"warn\",\n\t\t\t\tmessage: embedding.configuredDimensionsMatchModel\n\t\t\t\t\t? `Configured createIndex.dimensions matches the embedding model (${embedding.embeddingDimensions}).`\n\t\t\t\t\t: `Configured createIndex.dimensions (${embedding.configuredDimensions}) does not match the embedding model (${embedding.embeddingDimensions}). Using the live embedding dimensions for validation.`,\n\t\t\t});\n\t\t}\n\n\t\tconst existingIndex = await this.describeIndexIfExists();\n\t\tif (!existingIndex) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"vectorize-index\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tmessage: `Vectorize index \"${this.config.indexName}\" was not found. Run \"openclaw cf-memory init\" before rerunning this test.`,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tchecks,\n\t\t\t\tnamespace: \"n/a\",\n\t\t\t\tlogicalId: \"n/a\",\n\t\t\t};\n\t\t}\n\n\t\tchecks.push({\n\t\t\tname: \"vectorize-index\",\n\t\t\tstatus: \"pass\",\n\t\t\tmessage: `Vectorize index \"${this.config.indexName}\" is reachable.`,\n\t\t});\n\t\tif (existingIndex.config.dimensions !== embedding.embeddingDimensions) {\n\t\t\tchecks.push({\n\t\t\t\tname: \"dimension-match\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tmessage: `Embedding dimensions (${embedding.embeddingDimensions}) do not match the Vectorize index dimensions (${existingIndex.config.dimensions}). Run \"openclaw cf-memory init\" to repair the index.`,\n\t\t\t});\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tchecks,\n\t\t\t\tnamespace: \"n/a\",\n\t\t\t\tlogicalId: \"n/a\",\n\t\t\t};\n\t\t}\n\n\t\tchecks.push({\n\t\t\tname: \"dimension-match\",\n\t\t\tstatus: \"pass\",\n\t\t\tmessage: \"Embedding dimensions match the Vectorize index.\",\n\t\t});\n\n\t\tconst namespace = sanitizeNamespace(`cf-memory-test-${randomUUID()}`);\n\t\tconst logicalId = `cf-memory-test-${randomUUID()}`;\n\t\tconst probeText = `OpenClaw Cloudflare memory smoke test ${logicalId}`;\n\t\tlet probeUpserted = false;\n\n\t\ttry {\n\t\t\tawait this.upsert({\n\t\t\t\tinput: {\n\t\t\t\t\tid: logicalId,\n\t\t\t\t\tnamespace,\n\t\t\t\t\ttext: probeText,\n\t\t\t\t\tsource: \"cf-memory-test\",\n\t\t\t\t\tmetadata: {\n\t\t\t\t\t\tprobe: true,\n\t\t\t\t\t\tprobeId: logicalId,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t});\n\t\t\tprobeUpserted = true;\n\t\t\tchecks.push({\n\t\t\t\tname: \"probe-upsert\",\n\t\t\t\tstatus: \"pass\",\n\t\t\t\tmessage: `Inserted smoke-test record ${logicalId} in namespace ${namespace}.`,\n\t\t\t});\n\n\t\t\tconst fetched = await this.waitForGetHit({\n\t\t\t\tnamespace,\n\t\t\t\tlogicalId,\n\t\t\t\ttimeoutMs: options?.timeoutMs ?? SMOKE_TEST_TIMEOUT_MS,\n\t\t\t\tpollIntervalMs: options?.pollIntervalMs ?? SMOKE_TEST_POLL_INTERVAL_MS,\n\t\t\t});\n\t\t\tchecks.push({\n\t\t\t\tname: \"probe-get\",\n\t\t\t\tstatus: fetched?.namespace === namespace ? \"pass\" : \"fail\",\n\t\t\t\tmessage: !fetched\n\t\t\t\t\t? `Get-by-id did not return the smoke-test record within ${(options?.timeoutMs ?? SMOKE_TEST_TIMEOUT_MS) / 1000} seconds.`\n\t\t\t\t\t: fetched.namespace === namespace\n\t\t\t\t\t\t? \"Get-by-id returned the smoke-test record in the expected namespace.\"\n\t\t\t\t\t\t: `Get-by-id returned namespace ${fetched.namespace}, expected ${namespace}.`,\n\t\t\t});\n\n\t\t\tconst found = await this.waitForSearchHit({\n\t\t\t\tquery: probeText,\n\t\t\t\tnamespace,\n\t\t\t\tlogicalId,\n\t\t\t\ttimeoutMs: options?.timeoutMs ?? SMOKE_TEST_TIMEOUT_MS,\n\t\t\t\tpollIntervalMs: options?.pollIntervalMs ?? SMOKE_TEST_POLL_INTERVAL_MS,\n\t\t\t});\n\t\t\tchecks.push({\n\t\t\t\tname: \"probe-search\",\n\t\t\t\tstatus: found?.namespace === namespace ? \"pass\" : \"fail\",\n\t\t\t\tmessage: !found\n\t\t\t\t\t? `Semantic search did not return the smoke-test record within ${(options?.timeoutMs ?? SMOKE_TEST_TIMEOUT_MS) / 1000} seconds.`\n\t\t\t\t\t: found.namespace === namespace\n\t\t\t\t\t\t? \"Semantic search returned the smoke-test record in the expected namespace.\"\n\t\t\t\t\t\t: `Semantic search returned namespace ${found.namespace}, expected ${namespace}.`,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tchecks.push({\n\t\t\t\tname: probeUpserted ? \"probe-search\" : \"probe-upsert\",\n\t\t\t\tstatus: \"fail\",\n\t\t\t\tmessage: error instanceof Error ? error.message : \"Smoke test failed with an unknown error.\",\n\t\t\t});\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tawait this.delete({ id: logicalId, namespace });\n\t\t\t\tchecks.push({\n\t\t\t\t\tname: \"probe-cleanup\",\n\t\t\t\t\tstatus: \"pass\",\n\t\t\t\t\tmessage: `Deleted smoke-test record ${logicalId}.`,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tchecks.push({\n\t\t\t\t\tname: \"probe-cleanup\",\n\t\t\t\t\tstatus: \"fail\",\n\t\t\t\t\tmessage: error instanceof Error ? error.message : `Failed to delete smoke-test record ${logicalId}.`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tok: checks.every((check) => check.status !== \"fail\"),\n\t\t\tchecks,\n\t\t\tnamespace,\n\t\t\tlogicalId,\n\t\t};\n\t}\n\n\tasync ensureIndexExists(createIfMissing: boolean, targetDimensions?: number): Promise<{ created: boolean; dimensions: number }> {\n\t\ttry {\n\t\t\tconst description = await this.vectorize.describeIndex();\n\t\t\treturn {\n\t\t\t\tcreated: false,\n\t\t\t\tdimensions: description.config.dimensions,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tif (!createIfMissing || !isCloudflareNotFoundError(error)) {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tconst dimensions = targetDimensions ?? (await this.inspectEmbeddingDimensions()).targetDimensions;\n\t\t\tconst createdIndex = await this.vectorize.createIndex(dimensions);\n\t\t\treturn {\n\t\t\t\tcreated: true,\n\t\t\t\tdimensions: createdIndex.config.dimensions,\n\t\t\t};\n\t\t}\n\t}\n\n\tprivate fromCompanionFallback(companionRecord: CompanionRecord | undefined, logicalId: string, namespace: string, path: string): UpsertedMemoryRecord {\n\t\treturn {\n\t\t\tlogicalId,\n\t\t\tvectorId: buildVectorId(namespace, logicalId),\n\t\t\tnamespace,\n\t\t\ttitle: companionRecord?.title,\n\t\t\ttext: companionRecord?.text ?? \"\",\n\t\t\tmetadata: companionRecord?.metadata ?? {},\n\t\t\tsource: companionRecord?.source,\n\t\t\tcreatedAt: companionRecord?.createdAt,\n\t\t\tupdatedAt: companionRecord?.updatedAt,\n\t\t\tpath,\n\t\t};\n\t}\n\n\tprivate fromInlineFallback(vector: { id: string; namespace?: string; metadata?: Record<string, string | number | boolean> }): UpsertedMemoryRecord {\n\t\tconst record = hydrateInlineRecord(vector);\n\t\treturn {\n\t\t\t...record,\n\t\t\ttext: record.text ?? \"\",\n\t\t};\n\t}\n\n\tprivate async waitForGetHit(params: {\n\t\tnamespace: string;\n\t\tlogicalId: string;\n\t\ttimeoutMs: number;\n\t\tpollIntervalMs: number;\n\t}): Promise<HydratedMemoryRecord | null> {\n\t\tconst deadline = Date.now() + params.timeoutMs;\n\t\twhile (Date.now() <= deadline) {\n\t\t\tconst record = await this.get({\n\t\t\t\tid: params.logicalId,\n\t\t\t\tnamespace: params.namespace,\n\t\t\t});\n\t\t\tif (record) {\n\t\t\t\treturn record;\n\t\t\t}\n\t\t\tif (Date.now() + params.pollIntervalMs > deadline) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tawait this.pause(params.pollIntervalMs);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate async waitForSearchHit(params: {\n\t\tquery: string;\n\t\tnamespace: string;\n\t\tlogicalId: string;\n\t\ttimeoutMs: number;\n\t\tpollIntervalMs: number;\n\t}): Promise<(HydratedMemoryRecord & { score: number }) | null> {\n\t\tconst vector = await this.embeddings.embedQuery(params.query);\n\t\tconst deadline = Date.now() + params.timeoutMs;\n\t\twhile (Date.now() <= deadline) {\n\t\t\tconst matches = await this.vectorize.query({\n\t\t\t\tvector,\n\t\t\t\tnamespace: params.namespace,\n\t\t\t\ttopK: 5,\n\t\t\t});\n\t\t\tfor (const match of matches) {\n\t\t\t\tconst record = hydrateInlineRecord(match, { defaultNamespace: params.namespace });\n\t\t\t\tif (record.logicalId === params.logicalId) {\n\t\t\t\t\tconst text = record.text ?? (await this.companionStore.get(record.namespace, record.logicalId))?.text ?? \"\";\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...record,\n\t\t\t\t\t\ttext,\n\t\t\t\t\t\tscore: match.score ?? 0,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (Date.now() + params.pollIntervalMs > deadline) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tawait this.pause(params.pollIntervalMs);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate async pause(ms: number): Promise<void> {\n\t\tawait new Promise((resolve) => setTimeout(resolve, ms));\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -28,6 +28,7 @@ export declare const DEFAULT_INDEX_DESCRIPTION = "OpenClaw memory index backed b
|
|
|
28
28
|
export declare const RESERVED_METADATA_PREFIX = "oc_";
|
|
29
29
|
export declare const RESERVED_METADATA_KEYS: {
|
|
30
30
|
readonly logicalId: "oc_record_id";
|
|
31
|
+
readonly namespace: "oc_namespace";
|
|
31
32
|
readonly title: "oc_title";
|
|
32
33
|
readonly text: "oc_text";
|
|
33
34
|
readonly storageMode: "oc_storage_mode";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ResolvedPluginConfig } from "./types.js";
|
|
2
2
|
export declare class WorkersAiEmbeddingsClient {
|
|
3
3
|
private readonly config;
|
|
4
|
+
private readonly queryCache;
|
|
4
5
|
constructor(config: ResolvedPluginConfig);
|
|
5
6
|
embedQuery(text: string): Promise<number[]>;
|
|
6
7
|
embedBatch(texts: string[]): Promise<number[][]>;
|
|
@@ -18,7 +18,9 @@ export declare function mapRecordForUpsert(params: {
|
|
|
18
18
|
vector: VectorizeVector;
|
|
19
19
|
companionRecord?: CompanionRecord;
|
|
20
20
|
};
|
|
21
|
-
export declare function hydrateInlineRecord(match: VectorizeQueryMatch
|
|
21
|
+
export declare function hydrateInlineRecord(match: VectorizeQueryMatch, options?: {
|
|
22
|
+
defaultNamespace?: string;
|
|
23
|
+
}): Omit<HydratedMemoryRecord, "text" | "path"> & {
|
|
22
24
|
text?: string;
|
|
23
25
|
path: string;
|
|
24
26
|
};
|
package/dist/types/service.d.ts
CHANGED
package/package.json
CHANGED