@langchain/langgraph-checkpoint 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base.cjs +4 -5
- package/dist/base.cjs.map +1 -1
- package/dist/base.d.cts +0 -1
- package/dist/base.d.cts.map +1 -1
- package/dist/base.d.ts +0 -1
- package/dist/base.d.ts.map +1 -1
- package/dist/base.js +1 -2
- package/dist/base.js.map +1 -1
- package/dist/cache/base.cjs +2 -3
- package/dist/cache/base.cjs.map +1 -1
- package/dist/cache/base.d.cts.map +1 -1
- package/dist/cache/base.d.ts.map +1 -1
- package/dist/cache/base.js +1 -2
- package/dist/cache/base.js.map +1 -1
- package/dist/cache/index.cjs +2 -2
- package/dist/cache/index.js +3 -4
- package/dist/cache/memory.cjs +7 -10
- package/dist/cache/memory.cjs.map +1 -1
- package/dist/cache/memory.d.cts.map +1 -1
- package/dist/cache/memory.d.ts.map +1 -1
- package/dist/cache/memory.js +6 -9
- package/dist/cache/memory.js.map +1 -1
- package/dist/id.cjs +2 -4
- package/dist/id.cjs.map +1 -1
- package/dist/id.d.cts +0 -4
- package/dist/id.d.cts.map +1 -1
- package/dist/id.d.ts +0 -4
- package/dist/id.d.ts.map +1 -1
- package/dist/id.js +1 -2
- package/dist/id.js.map +1 -1
- package/dist/index.cjs +12 -12
- package/dist/index.js +1 -2
- package/dist/memory.cjs +5 -8
- package/dist/memory.cjs.map +1 -1
- package/dist/memory.d.cts +0 -1
- package/dist/memory.d.cts.map +1 -1
- package/dist/memory.d.ts +0 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +3 -6
- package/dist/memory.js.map +1 -1
- package/dist/serde/base.d.cts +0 -2
- package/dist/serde/base.d.cts.map +1 -1
- package/dist/serde/base.d.ts +0 -2
- package/dist/serde/base.d.ts.map +1 -1
- package/dist/serde/jsonplus.cjs +13 -15
- package/dist/serde/jsonplus.cjs.map +1 -1
- package/dist/serde/jsonplus.js +10 -11
- package/dist/serde/jsonplus.js.map +1 -1
- package/dist/serde/types.cjs +1 -2
- package/dist/serde/types.cjs.map +1 -1
- package/dist/serde/types.d.cts +0 -3
- package/dist/serde/types.d.cts.map +1 -1
- package/dist/serde/types.d.ts +0 -3
- package/dist/serde/types.d.ts.map +1 -1
- package/dist/serde/types.js +1 -1
- package/dist/serde/utils/fast-safe-stringify/index.cjs +1 -2
- package/dist/serde/utils/fast-safe-stringify/index.cjs.map +1 -1
- package/dist/serde/utils/fast-safe-stringify/index.js +1 -1
- package/dist/serde/utils/fast-safe-stringify/index.js.map +1 -1
- package/dist/store/base.cjs +1 -2
- package/dist/store/base.cjs.map +1 -1
- package/dist/store/base.d.cts +0 -1
- package/dist/store/base.d.cts.map +1 -1
- package/dist/store/base.d.ts +0 -1
- package/dist/store/base.d.ts.map +1 -1
- package/dist/store/base.js +1 -1
- package/dist/store/base.js.map +1 -1
- package/dist/store/batch.cjs +3 -5
- package/dist/store/batch.cjs.map +1 -1
- package/dist/store/batch.d.cts +0 -3
- package/dist/store/batch.d.cts.map +1 -1
- package/dist/store/batch.d.ts +0 -3
- package/dist/store/batch.d.ts.map +1 -1
- package/dist/store/batch.js +2 -4
- package/dist/store/batch.js.map +1 -1
- package/dist/store/memory.cjs +8 -14
- package/dist/store/memory.cjs.map +1 -1
- package/dist/store/memory.d.cts +0 -2
- package/dist/store/memory.d.cts.map +1 -1
- package/dist/store/memory.d.ts +0 -2
- package/dist/store/memory.d.ts.map +1 -1
- package/dist/store/memory.js +6 -12
- package/dist/store/memory.js.map +1 -1
- package/dist/store/utils.cjs +31 -35
- package/dist/store/utils.cjs.map +1 -1
- package/dist/store/utils.js +31 -34
- package/dist/store/utils.js.map +1 -1
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +20 -19
- package/CHANGELOG.md +0 -25
- package/dist/_virtual/rolldown_runtime.cjs +0 -25
package/dist/store/batch.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { BaseStore } from "./base.js";
|
|
2
|
-
|
|
3
2
|
//#region src/store/batch.ts
|
|
4
3
|
/**
|
|
5
4
|
* Extracts and returns the underlying store from an `AsyncBatchedStore`,
|
|
@@ -95,8 +94,7 @@ var AsyncBatchedStore = class extends BaseStore {
|
|
|
95
94
|
const operations = Array.from(batch.values()).map(({ operation }) => operation);
|
|
96
95
|
const results = await this.store.batch(operations);
|
|
97
96
|
batch.forEach(({ resolve }, key) => {
|
|
98
|
-
|
|
99
|
-
resolve(results[index]);
|
|
97
|
+
resolve(results[Array.from(batch.keys()).indexOf(key)]);
|
|
100
98
|
});
|
|
101
99
|
} catch (e) {
|
|
102
100
|
batch.forEach(({ reject }) => {
|
|
@@ -114,7 +112,7 @@ var AsyncBatchedStore = class extends BaseStore {
|
|
|
114
112
|
};
|
|
115
113
|
}
|
|
116
114
|
};
|
|
117
|
-
|
|
118
115
|
//#endregion
|
|
119
116
|
export { AsyncBatchedStore };
|
|
117
|
+
|
|
120
118
|
//# sourceMappingURL=batch.js.map
|
package/dist/store/batch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch.js","names":[],"sources":["../../src/store/batch.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport {\n BaseStore,\n type Item,\n type SearchOperation,\n type PutOperation,\n type GetOperation,\n type Operation,\n OperationResults,\n} from \"./base.js\";\n\n/**\n * Extracts and returns the underlying store from an `AsyncBatchedStore`,\n * or returns the input if it is not an `AsyncBatchedStore`.\n */\nconst extractStore = (input: BaseStore | AsyncBatchedStore): BaseStore => {\n if (\"lg_name\" in input && input.lg_name === \"AsyncBatchedStore\") {\n // @ts-expect-error is a protected property\n return input.store;\n }\n return input;\n};\n\nexport class AsyncBatchedStore extends BaseStore {\n lg_name = \"AsyncBatchedStore\";\n\n protected store: BaseStore;\n\n private queue: Map<\n number,\n {\n operation: Operation;\n resolve: (value: any) => void;\n reject: (reason?: any) => void;\n }\n > = new Map();\n\n private nextKey: number = 0;\n\n private running = false;\n\n private processingTask: Promise<void> | null = null;\n\n constructor(store: BaseStore) {\n super();\n this.store = extractStore(store);\n }\n\n get isRunning(): boolean {\n return this.running;\n }\n\n /**\n * @ignore\n * Batch is not implemented here as we're only extending `BaseStore`\n * to allow it to be passed where `BaseStore` is expected, and implement\n * the convenience methods (get, search, put, delete).\n */\n async batch<Op extends Operation[]>(\n _operations: Op\n ): Promise<OperationResults<Op>> {\n throw new Error(\n \"The `batch` method is not implemented on `AsyncBatchedStore`.\" +\n \"\\n Instead, it calls the `batch` method on the wrapped store.\" +\n \"\\n If you are seeing this error, something is wrong.\"\n );\n }\n\n async get(namespace: string[], key: string): Promise<Item | null> {\n return this.enqueueOperation({ namespace, key } as GetOperation);\n }\n\n async search(\n namespacePrefix: string[],\n options?: {\n filter?: Record<string, any>;\n limit?: number;\n offset?: number;\n query?: string;\n }\n ): Promise<Item[]> {\n const { filter, limit = 10, offset = 0, query } = options || {};\n return this.enqueueOperation({\n namespacePrefix,\n filter,\n limit,\n offset,\n query,\n } as SearchOperation);\n }\n\n async put(\n namespace: string[],\n key: string,\n value: Record<string, any>\n ): Promise<void> {\n return this.enqueueOperation({ namespace, key, value } as PutOperation);\n }\n\n async delete(namespace: string[], key: string): Promise<void> {\n return this.enqueueOperation({\n namespace,\n key,\n value: null,\n } as PutOperation);\n }\n\n start(): void {\n if (!this.running) {\n this.running = true;\n this.processingTask = this.processBatchQueue();\n }\n }\n\n async stop(): Promise<void> {\n this.running = false;\n if (this.processingTask) {\n await this.processingTask;\n }\n }\n\n private enqueueOperation<T>(operation: Operation): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const key = this.nextKey;\n this.nextKey += 1;\n this.queue.set(key, { operation, resolve, reject });\n });\n }\n\n private async processBatchQueue(): Promise<void> {\n while (this.running) {\n await new Promise((resolve) => {\n setTimeout(resolve, 0);\n });\n if (this.queue.size === 0) continue;\n\n const batch = new Map(this.queue);\n this.queue.clear();\n\n try {\n const operations = Array.from(batch.values()).map(\n ({ operation }) => operation\n );\n const results = await this.store.batch(operations);\n\n batch.forEach(({ resolve }, key) => {\n const index = Array.from(batch.keys()).indexOf(key);\n resolve(results[index]);\n });\n } catch (e) {\n batch.forEach(({ reject }) => {\n reject(e);\n });\n }\n }\n }\n\n // AsyncBatchedStore is internal and gets passed as args into traced tasks\n // some BaseStores contain circular references so just serialize without it\n // as this causes warnings when tracing with LangSmith.\n toJSON() {\n return {\n queue: this.queue,\n nextKey: this.nextKey,\n running: this.running,\n store: \"[LangGraphStore]\",\n };\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"batch.js","names":[],"sources":["../../src/store/batch.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport {\n BaseStore,\n type Item,\n type SearchOperation,\n type PutOperation,\n type GetOperation,\n type Operation,\n OperationResults,\n} from \"./base.js\";\n\n/**\n * Extracts and returns the underlying store from an `AsyncBatchedStore`,\n * or returns the input if it is not an `AsyncBatchedStore`.\n */\nconst extractStore = (input: BaseStore | AsyncBatchedStore): BaseStore => {\n if (\"lg_name\" in input && input.lg_name === \"AsyncBatchedStore\") {\n // @ts-expect-error is a protected property\n return input.store;\n }\n return input;\n};\n\nexport class AsyncBatchedStore extends BaseStore {\n lg_name = \"AsyncBatchedStore\";\n\n protected store: BaseStore;\n\n private queue: Map<\n number,\n {\n operation: Operation;\n resolve: (value: any) => void;\n reject: (reason?: any) => void;\n }\n > = new Map();\n\n private nextKey: number = 0;\n\n private running = false;\n\n private processingTask: Promise<void> | null = null;\n\n constructor(store: BaseStore) {\n super();\n this.store = extractStore(store);\n }\n\n get isRunning(): boolean {\n return this.running;\n }\n\n /**\n * @ignore\n * Batch is not implemented here as we're only extending `BaseStore`\n * to allow it to be passed where `BaseStore` is expected, and implement\n * the convenience methods (get, search, put, delete).\n */\n async batch<Op extends Operation[]>(\n _operations: Op\n ): Promise<OperationResults<Op>> {\n throw new Error(\n \"The `batch` method is not implemented on `AsyncBatchedStore`.\" +\n \"\\n Instead, it calls the `batch` method on the wrapped store.\" +\n \"\\n If you are seeing this error, something is wrong.\"\n );\n }\n\n async get(namespace: string[], key: string): Promise<Item | null> {\n return this.enqueueOperation({ namespace, key } as GetOperation);\n }\n\n async search(\n namespacePrefix: string[],\n options?: {\n filter?: Record<string, any>;\n limit?: number;\n offset?: number;\n query?: string;\n }\n ): Promise<Item[]> {\n const { filter, limit = 10, offset = 0, query } = options || {};\n return this.enqueueOperation({\n namespacePrefix,\n filter,\n limit,\n offset,\n query,\n } as SearchOperation);\n }\n\n async put(\n namespace: string[],\n key: string,\n value: Record<string, any>\n ): Promise<void> {\n return this.enqueueOperation({ namespace, key, value } as PutOperation);\n }\n\n async delete(namespace: string[], key: string): Promise<void> {\n return this.enqueueOperation({\n namespace,\n key,\n value: null,\n } as PutOperation);\n }\n\n start(): void {\n if (!this.running) {\n this.running = true;\n this.processingTask = this.processBatchQueue();\n }\n }\n\n async stop(): Promise<void> {\n this.running = false;\n if (this.processingTask) {\n await this.processingTask;\n }\n }\n\n private enqueueOperation<T>(operation: Operation): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const key = this.nextKey;\n this.nextKey += 1;\n this.queue.set(key, { operation, resolve, reject });\n });\n }\n\n private async processBatchQueue(): Promise<void> {\n while (this.running) {\n await new Promise((resolve) => {\n setTimeout(resolve, 0);\n });\n if (this.queue.size === 0) continue;\n\n const batch = new Map(this.queue);\n this.queue.clear();\n\n try {\n const operations = Array.from(batch.values()).map(\n ({ operation }) => operation\n );\n const results = await this.store.batch(operations);\n\n batch.forEach(({ resolve }, key) => {\n const index = Array.from(batch.keys()).indexOf(key);\n resolve(results[index]);\n });\n } catch (e) {\n batch.forEach(({ reject }) => {\n reject(e);\n });\n }\n }\n }\n\n // AsyncBatchedStore is internal and gets passed as args into traced tasks\n // some BaseStores contain circular references so just serialize without it\n // as this causes warnings when tracing with LangSmith.\n toJSON() {\n return {\n queue: this.queue,\n nextKey: this.nextKey,\n running: this.running,\n store: \"[LangGraphStore]\",\n };\n }\n}\n"],"mappings":";;;;;;AAgBA,MAAM,gBAAgB,UAAoD;AACxE,KAAI,aAAa,SAAS,MAAM,YAAY,oBAE1C,QAAO,MAAM;AAEf,QAAO;;AAGT,IAAa,oBAAb,cAAuC,UAAU;CAC/C,UAAU;CAEV;CAEA,wBAOI,IAAI,KAAK;CAEb,UAA0B;CAE1B,UAAkB;CAElB,iBAA+C;CAE/C,YAAY,OAAkB;AAC5B,SAAO;AACP,OAAK,QAAQ,aAAa,MAAM;;CAGlC,IAAI,YAAqB;AACvB,SAAO,KAAK;;;;;;;;CASd,MAAM,MACJ,aAC+B;AAC/B,QAAM,IAAI,MACR,iLAGD;;CAGH,MAAM,IAAI,WAAqB,KAAmC;AAChE,SAAO,KAAK,iBAAiB;GAAE;GAAW;GAAK,CAAiB;;CAGlE,MAAM,OACJ,iBACA,SAMiB;EACjB,MAAM,EAAE,QAAQ,QAAQ,IAAI,SAAS,GAAG,UAAU,WAAW,EAAE;AAC/D,SAAO,KAAK,iBAAiB;GAC3B;GACA;GACA;GACA;GACA;GACD,CAAoB;;CAGvB,MAAM,IACJ,WACA,KACA,OACe;AACf,SAAO,KAAK,iBAAiB;GAAE;GAAW;GAAK;GAAO,CAAiB;;CAGzE,MAAM,OAAO,WAAqB,KAA4B;AAC5D,SAAO,KAAK,iBAAiB;GAC3B;GACA;GACA,OAAO;GACR,CAAiB;;CAGpB,QAAc;AACZ,MAAI,CAAC,KAAK,SAAS;AACjB,QAAK,UAAU;AACf,QAAK,iBAAiB,KAAK,mBAAmB;;;CAIlD,MAAM,OAAsB;AAC1B,OAAK,UAAU;AACf,MAAI,KAAK,eACP,OAAM,KAAK;;CAIf,iBAA4B,WAAkC;AAC5D,SAAO,IAAI,SAAY,SAAS,WAAW;GACzC,MAAM,MAAM,KAAK;AACjB,QAAK,WAAW;AAChB,QAAK,MAAM,IAAI,KAAK;IAAE;IAAW;IAAS;IAAQ,CAAC;IACnD;;CAGJ,MAAc,oBAAmC;AAC/C,SAAO,KAAK,SAAS;AACnB,SAAM,IAAI,SAAS,YAAY;AAC7B,eAAW,SAAS,EAAE;KACtB;AACF,OAAI,KAAK,MAAM,SAAS,EAAG;GAE3B,MAAM,QAAQ,IAAI,IAAI,KAAK,MAAM;AACjC,QAAK,MAAM,OAAO;AAElB,OAAI;IACF,MAAM,aAAa,MAAM,KAAK,MAAM,QAAQ,CAAC,CAAC,KAC3C,EAAE,gBAAgB,UACpB;IACD,MAAM,UAAU,MAAM,KAAK,MAAM,MAAM,WAAW;AAElD,UAAM,SAAS,EAAE,WAAW,QAAQ;AAElC,aAAQ,QADM,MAAM,KAAK,MAAM,MAAM,CAAC,CAAC,QAAQ,IAAI,EAC5B;MACvB;YACK,GAAG;AACV,UAAM,SAAS,EAAE,aAAa;AAC5B,YAAO,EAAE;MACT;;;;CAQR,SAAS;AACP,SAAO;GACL,OAAO,KAAK;GACZ,SAAS,KAAK;GACd,SAAS,KAAK;GACd,OAAO;GACR"}
|
package/dist/store/memory.cjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
const require_base = require(
|
|
2
|
-
const require_utils = require(
|
|
3
|
-
|
|
1
|
+
const require_base = require("./base.cjs");
|
|
2
|
+
const require_utils = require("./utils.cjs");
|
|
4
3
|
//#region src/store/memory.ts
|
|
5
4
|
/**
|
|
6
5
|
* In-memory key-value store with optional vector search.
|
|
@@ -70,8 +69,7 @@ var InMemoryStore = class extends require_base.BaseStore {
|
|
|
70
69
|
const queryVectors = Object.fromEntries(Array.from(queries).map((q, i) => [q, queryEmbeddings[i]]));
|
|
71
70
|
for (const [i, [op, candidates]] of searchOps.entries()) if (op.query && queryVectors[op.query]) {
|
|
72
71
|
const queryVector = queryVectors[op.query];
|
|
73
|
-
|
|
74
|
-
results[i] = scoredResults;
|
|
72
|
+
results[i] = this.scoreResults(candidates, queryVector, op.offset ?? 0, op.limit ?? 10);
|
|
75
73
|
} else results[i] = this.paginateResults(candidates.map((item) => ({
|
|
76
74
|
...item,
|
|
77
75
|
score: void 0
|
|
@@ -92,8 +90,7 @@ var InMemoryStore = class extends require_base.BaseStore {
|
|
|
92
90
|
}
|
|
93
91
|
getOperation(op) {
|
|
94
92
|
const namespaceKey = op.namespace.join(":");
|
|
95
|
-
|
|
96
|
-
return item ?? null;
|
|
93
|
+
return this.data.get(namespaceKey)?.get(op.key) ?? null;
|
|
97
94
|
}
|
|
98
95
|
putOperation(op) {
|
|
99
96
|
const namespaceKey = op.namespace.join(":");
|
|
@@ -116,8 +113,7 @@ var InMemoryStore = class extends require_base.BaseStore {
|
|
|
116
113
|
}
|
|
117
114
|
}
|
|
118
115
|
listNamespacesOperation(op) {
|
|
119
|
-
|
|
120
|
-
let namespaces = allNamespaces;
|
|
116
|
+
let namespaces = Array.from(this.data.keys()).map((ns) => ns.split(":"));
|
|
121
117
|
if (op.matchConditions && op.matchConditions.length > 0) namespaces = namespaces.filter((ns) => op.matchConditions.every((condition) => this.doesMatch(condition, ns)));
|
|
122
118
|
if (op.maxDepth !== void 0) namespaces = Array.from(new Set(namespaces.map((ns) => ns.slice(0, op.maxDepth).join(":")))).map((ns) => ns.split(":"));
|
|
123
119
|
namespaces.sort((a, b) => a.join(":").localeCompare(b.join(":")));
|
|
@@ -159,8 +155,7 @@ var InMemoryStore = class extends require_base.BaseStore {
|
|
|
159
155
|
}
|
|
160
156
|
else scoreless.push(item);
|
|
161
157
|
}
|
|
162
|
-
const
|
|
163
|
-
const sortedResults = scores.map((score, i) => [score, flatItems[i]]).sort((a, b) => b[0] - a[0]);
|
|
158
|
+
const sortedResults = this.cosineSimilarity(queryVector, flatVectors).map((score, i) => [score, flatItems[i]]).sort((a, b) => b[0] - a[0]);
|
|
164
159
|
const seen = /* @__PURE__ */ new Set();
|
|
165
160
|
const kept = [];
|
|
166
161
|
for (const [score, item] of sortedResults) {
|
|
@@ -226,8 +221,7 @@ var InMemoryStore = class extends require_base.BaseStore {
|
|
|
226
221
|
if (!this.vectors.has(namespaceKey)) this.vectors.set(namespaceKey, /* @__PURE__ */ new Map());
|
|
227
222
|
const namespaceMap = this.vectors.get(namespaceKey);
|
|
228
223
|
if (!namespaceMap.has(key)) namespaceMap.set(key, /* @__PURE__ */ new Map());
|
|
229
|
-
|
|
230
|
-
itemMap.set(field, embedding);
|
|
224
|
+
namespaceMap.get(key).set(field, embedding);
|
|
231
225
|
}
|
|
232
226
|
}
|
|
233
227
|
}
|
|
@@ -258,8 +252,8 @@ var InMemoryStore = class extends require_base.BaseStore {
|
|
|
258
252
|
};
|
|
259
253
|
/** @deprecated Alias for InMemoryStore */
|
|
260
254
|
var MemoryStore = class extends InMemoryStore {};
|
|
261
|
-
|
|
262
255
|
//#endregion
|
|
263
256
|
exports.InMemoryStore = InMemoryStore;
|
|
264
257
|
exports.MemoryStore = MemoryStore;
|
|
258
|
+
|
|
265
259
|
//# sourceMappingURL=memory.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.cjs","names":["BaseStore","tokenizePath","candidates: Item[]","compareValues","flatItems: Item[]","flatVectors: number[][]","scoreless: Item[]","kept: Array<[number | undefined, Item]>","toEmbed: { [text: string]: [string[], string, string][] }","getTextAtPath"],"sources":["../../src/store/memory.ts"],"sourcesContent":["import {\n BaseStore,\n type OperationResults,\n type Item,\n type Operation,\n MatchCondition,\n ListNamespacesOperation,\n PutOperation,\n SearchOperation,\n GetOperation,\n type IndexConfig,\n type SearchItem,\n} from \"./base.js\";\nimport { tokenizePath, compareValues, getTextAtPath } from \"./utils.js\";\n\n/**\n * In-memory key-value store with optional vector search.\n *\n * A lightweight store implementation using JavaScript Maps. Supports basic\n * key-value operations and vector search when configured with embeddings.\n *\n * @example\n * ```typescript\n * // Basic key-value storage\n * const store = new InMemoryStore();\n * await store.put([\"users\", \"123\"], \"prefs\", { theme: \"dark\" });\n * const item = await store.get([\"users\", \"123\"], \"prefs\");\n *\n * // Vector search with embeddings\n * import { OpenAIEmbeddings } from \"@langchain/openai\";\n * const store = new InMemoryStore({\n * index: {\n * dims: 1536,\n * embeddings: new OpenAIEmbeddings({ modelName: \"text-embedding-3-small\" }),\n * }\n * });\n *\n * // Store documents\n * await store.put([\"docs\"], \"doc1\", { text: \"Python tutorial\" });\n * await store.put([\"docs\"], \"doc2\", { text: \"TypeScript guide\" });\n *\n * // Search by similarity\n * const results = await store.search([\"docs\"], { query: \"python programming\" });\n * ```\n *\n * **Warning**: This store keeps all data in memory. Data is lost when the process exits.\n * For persistence, use a database-backed store.\n */\nexport class InMemoryStore extends BaseStore {\n private data: Map<string, Map<string, Item>> = new Map();\n\n // Namespace -> Key -> Path/field -> Vector\n private vectors: Map<string, Map<string, Map<string, number[]>>> = new Map();\n\n private _indexConfig?: IndexConfig & {\n __tokenizedFields: Array<[string, string[]]>;\n };\n\n constructor(options?: { index?: IndexConfig }) {\n super();\n if (options?.index) {\n this._indexConfig = {\n ...options.index,\n __tokenizedFields: (options.index.fields ?? [\"$\"]).map((p) => [\n p,\n p === \"$\" ? [p] : tokenizePath(p),\n ]),\n };\n }\n }\n\n async batch<Op extends readonly Operation[]>(\n operations: Op\n ): Promise<OperationResults<Op>> {\n const results = [];\n const putOps = new Map<string, PutOperation>();\n const searchOps = new Map<number, [SearchOperation, Item[]]>();\n\n // First pass - handle gets and prepare search/put operations\n for (let i = 0; i < operations.length; i += 1) {\n const op = operations[i];\n if (\"key\" in op && \"namespace\" in op && !(\"value\" in op)) {\n // GetOperation\n results.push(this.getOperation(op));\n } else if (\"namespacePrefix\" in op) {\n // SearchOperation\n const candidates = this.filterItems(op);\n searchOps.set(i, [op, candidates]);\n results.push(null);\n } else if (\"value\" in op) {\n // PutOperation\n const key = `${op.namespace.join(\":\")}:${op.key}`;\n putOps.set(key, op);\n results.push(null);\n } else if (\"matchConditions\" in op) {\n // ListNamespacesOperation\n results.push(this.listNamespacesOperation(op));\n }\n }\n\n // Handle search operations with embeddings\n if (searchOps.size > 0) {\n if (this._indexConfig?.embeddings) {\n const queries = new Set<string>();\n for (const [op] of searchOps.values()) {\n if (op.query) queries.add(op.query);\n }\n\n // Get embeddings for all queries\n const queryEmbeddings =\n queries.size > 0\n ? await Promise.all(\n Array.from(queries).map((q) =>\n this._indexConfig!.embeddings.embedQuery(q)\n )\n )\n : [];\n const queryVectors = Object.fromEntries(\n Array.from(queries).map((q, i) => [q, queryEmbeddings[i]])\n );\n\n // Process each search operation\n for (const [i, [op, candidates]] of searchOps.entries()) {\n if (op.query && queryVectors[op.query]) {\n const queryVector = queryVectors[op.query];\n const scoredResults = this.scoreResults(\n candidates,\n queryVector,\n op.offset ?? 0,\n op.limit ?? 10\n );\n results[i] = scoredResults;\n } else {\n results[i] = this.paginateResults(\n candidates.map((item) => ({ ...item, score: undefined })),\n op.offset ?? 0,\n op.limit ?? 10\n );\n }\n }\n } else {\n // No embeddings - just paginate the filtered results\n for (const [i, [op, candidates]] of searchOps.entries()) {\n results[i] = this.paginateResults(\n candidates.map((item) => ({ ...item, score: undefined })),\n op.offset ?? 0,\n op.limit ?? 10\n );\n }\n }\n }\n\n // Handle put operations with embeddings\n if (putOps.size > 0 && this._indexConfig?.embeddings) {\n const toEmbed = this.extractTexts(Array.from(putOps.values()));\n if (Object.keys(toEmbed).length > 0) {\n const embeddings = await this._indexConfig.embeddings.embedDocuments(\n Object.keys(toEmbed)\n );\n this.insertVectors(toEmbed, embeddings);\n }\n }\n\n // Apply all put operations\n for (const op of putOps.values()) {\n this.putOperation(op);\n }\n\n return results as OperationResults<Op>;\n }\n\n private getOperation(op: GetOperation): Item | null {\n const namespaceKey = op.namespace.join(\":\");\n const item = this.data.get(namespaceKey)?.get(op.key);\n return item ?? null;\n }\n\n private putOperation(op: PutOperation): void {\n const namespaceKey = op.namespace.join(\":\");\n if (!this.data.has(namespaceKey)) {\n this.data.set(namespaceKey, new Map());\n }\n const namespaceMap = this.data.get(namespaceKey)!;\n\n if (op.value === null) {\n namespaceMap.delete(op.key);\n } else {\n const now = new Date();\n if (namespaceMap.has(op.key)) {\n const item = namespaceMap.get(op.key)!;\n item.value = op.value;\n item.updatedAt = now;\n } else {\n namespaceMap.set(op.key, {\n value: op.value,\n key: op.key,\n namespace: op.namespace,\n createdAt: now,\n updatedAt: now,\n });\n }\n }\n }\n\n private listNamespacesOperation(op: ListNamespacesOperation): string[][] {\n const allNamespaces = Array.from(this.data.keys()).map((ns) =>\n ns.split(\":\")\n );\n let namespaces = allNamespaces;\n\n if (op.matchConditions && op.matchConditions.length > 0) {\n namespaces = namespaces.filter((ns) =>\n op.matchConditions!.every((condition) => this.doesMatch(condition, ns))\n );\n }\n\n if (op.maxDepth !== undefined) {\n namespaces = Array.from(\n new Set(namespaces.map((ns) => ns.slice(0, op.maxDepth).join(\":\")))\n ).map((ns) => ns.split(\":\"));\n }\n\n namespaces.sort((a, b) => a.join(\":\").localeCompare(b.join(\":\")));\n\n return namespaces.slice(\n op.offset ?? 0,\n (op.offset ?? 0) + (op.limit ?? namespaces.length)\n );\n }\n\n private doesMatch(matchCondition: MatchCondition, key: string[]): boolean {\n const { matchType, path } = matchCondition;\n\n if (matchType === \"prefix\") {\n if (path.length > key.length) return false;\n return path.every((pElem, index) => {\n const kElem = key[index];\n return pElem === \"*\" || kElem === pElem;\n });\n } else if (matchType === \"suffix\") {\n if (path.length > key.length) return false;\n return path.every((pElem, index) => {\n const kElem = key[key.length - path.length + index];\n return pElem === \"*\" || kElem === pElem;\n });\n }\n\n throw new Error(`Unsupported match type: ${matchType}`);\n }\n\n private filterItems(op: SearchOperation): Item[] {\n const candidates: Item[] = [];\n for (const [namespace, items] of this.data.entries()) {\n if (namespace.startsWith(op.namespacePrefix.join(\":\"))) {\n candidates.push(...items.values());\n }\n }\n\n let filteredCandidates = candidates;\n if (op.filter) {\n filteredCandidates = candidates.filter((item) =>\n Object.entries(op.filter!).every(([key, value]) =>\n compareValues(item.value[key], value)\n )\n );\n }\n return filteredCandidates;\n }\n\n private scoreResults(\n candidates: Item[],\n queryVector: number[],\n offset: number = 0,\n limit: number = 10\n ): SearchItem[] {\n const flatItems: Item[] = [];\n const flatVectors: number[][] = [];\n const scoreless: Item[] = [];\n\n for (const item of candidates) {\n const vectors = this.getVectors(item);\n if (vectors.length) {\n for (const vector of vectors) {\n flatItems.push(item);\n flatVectors.push(vector);\n }\n } else {\n scoreless.push(item);\n }\n }\n\n const scores = this.cosineSimilarity(queryVector, flatVectors);\n\n const sortedResults = scores\n .map((score, i) => [score, flatItems[i]] as [number, Item])\n .sort((a, b) => b[0] - a[0]);\n\n const seen = new Set<string>();\n const kept: Array<[number | undefined, Item]> = [];\n\n for (const [score, item] of sortedResults) {\n const key = `${item.namespace.join(\":\")}:${item.key}`;\n if (seen.has(key)) continue;\n\n const ix = seen.size;\n if (ix >= offset + limit) break;\n if (ix < offset) {\n seen.add(key);\n continue;\n }\n\n seen.add(key);\n kept.push([score, item]);\n }\n\n if (scoreless.length && kept.length < limit) {\n for (const item of scoreless.slice(0, limit - kept.length)) {\n const key = `${item.namespace.join(\":\")}:${item.key}`;\n if (!seen.has(key)) {\n seen.add(key);\n kept.push([undefined, item]);\n }\n }\n }\n return kept.map(([score, item]) => ({\n ...item,\n score,\n }));\n }\n\n private paginateResults(\n results: SearchItem[],\n offset: number,\n limit: number\n ): SearchItem[] {\n return results.slice(offset, offset + limit);\n }\n\n private extractTexts(ops: PutOperation[]): {\n [text: string]: [string[], string, string][];\n } {\n if (!ops.length || !this._indexConfig) {\n return {};\n }\n\n const toEmbed: { [text: string]: [string[], string, string][] } = {};\n\n for (const op of ops) {\n if (op.value !== null && op.index !== false) {\n const paths =\n op.index === null || op.index === undefined\n ? this._indexConfig.__tokenizedFields ?? []\n : op.index.map(\n (ix) => [ix, tokenizePath(ix)] as [string, string[]]\n );\n for (const [path, field] of paths) {\n const texts = getTextAtPath(op.value, field);\n if (texts.length) {\n if (texts.length > 1) {\n texts.forEach((text, i) => {\n if (!toEmbed[text]) toEmbed[text] = [];\n toEmbed[text].push([op.namespace, op.key, `${path}.${i}`]);\n });\n } else {\n if (!toEmbed[texts[0]]) toEmbed[texts[0]] = [];\n toEmbed[texts[0]].push([op.namespace, op.key, path]);\n }\n }\n }\n }\n }\n\n return toEmbed;\n }\n\n private insertVectors(\n texts: { [text: string]: [string[], string, string][] },\n embeddings: number[][]\n ): void {\n for (const [text, metadata] of Object.entries(texts)) {\n const embedding = embeddings.shift();\n if (!embedding) {\n throw new Error(`No embedding found for text: ${text}`);\n }\n\n for (const [namespace, key, field] of metadata) {\n const namespaceKey = namespace.join(\":\");\n if (!this.vectors.has(namespaceKey)) {\n this.vectors.set(namespaceKey, new Map());\n }\n const namespaceMap = this.vectors.get(namespaceKey)!;\n if (!namespaceMap.has(key)) {\n namespaceMap.set(key, new Map());\n }\n const itemMap = namespaceMap.get(key)!;\n itemMap.set(field, embedding);\n }\n }\n }\n\n private getVectors(item: Item): number[][] {\n const namespaceKey = item.namespace.join(\":\");\n const itemKey = item.key;\n if (!this.vectors.has(namespaceKey)) {\n return [];\n }\n const namespaceMap = this.vectors.get(namespaceKey)!;\n if (!namespaceMap.has(itemKey)) {\n return [];\n }\n const itemMap = namespaceMap.get(itemKey)!;\n const vectors = Array.from(itemMap.values());\n if (!vectors.length) {\n return [];\n }\n return vectors;\n }\n\n private cosineSimilarity(X: number[], Y: number[][]): number[] {\n if (!Y.length) return [];\n\n // Calculate dot products for all vectors at once\n const dotProducts = Y.map((vector) =>\n vector.reduce((acc, val, i) => acc + val * X[i], 0)\n );\n\n // Calculate magnitudes\n const magnitude1 = Math.sqrt(X.reduce((acc, val) => acc + val * val, 0));\n const magnitudes2 = Y.map((vector) =>\n Math.sqrt(vector.reduce((acc, val) => acc + val * val, 0))\n );\n\n // Calculate similarities\n return dotProducts.map((dot, i) => {\n const magnitude2 = magnitudes2[i];\n return magnitude1 && magnitude2 ? dot / (magnitude1 * magnitude2) : 0;\n });\n }\n\n public get indexConfig(): IndexConfig | undefined {\n return this._indexConfig;\n }\n}\n\n/** @deprecated Alias for InMemoryStore */\nexport class MemoryStore extends InMemoryStore {}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"memory.cjs","names":["BaseStore","tokenizePath","compareValues","getTextAtPath"],"sources":["../../src/store/memory.ts"],"sourcesContent":["import {\n BaseStore,\n type OperationResults,\n type Item,\n type Operation,\n MatchCondition,\n ListNamespacesOperation,\n PutOperation,\n SearchOperation,\n GetOperation,\n type IndexConfig,\n type SearchItem,\n} from \"./base.js\";\nimport { tokenizePath, compareValues, getTextAtPath } from \"./utils.js\";\n\n/**\n * In-memory key-value store with optional vector search.\n *\n * A lightweight store implementation using JavaScript Maps. Supports basic\n * key-value operations and vector search when configured with embeddings.\n *\n * @example\n * ```typescript\n * // Basic key-value storage\n * const store = new InMemoryStore();\n * await store.put([\"users\", \"123\"], \"prefs\", { theme: \"dark\" });\n * const item = await store.get([\"users\", \"123\"], \"prefs\");\n *\n * // Vector search with embeddings\n * import { OpenAIEmbeddings } from \"@langchain/openai\";\n * const store = new InMemoryStore({\n * index: {\n * dims: 1536,\n * embeddings: new OpenAIEmbeddings({ modelName: \"text-embedding-3-small\" }),\n * }\n * });\n *\n * // Store documents\n * await store.put([\"docs\"], \"doc1\", { text: \"Python tutorial\" });\n * await store.put([\"docs\"], \"doc2\", { text: \"TypeScript guide\" });\n *\n * // Search by similarity\n * const results = await store.search([\"docs\"], { query: \"python programming\" });\n * ```\n *\n * **Warning**: This store keeps all data in memory. Data is lost when the process exits.\n * For persistence, use a database-backed store.\n */\nexport class InMemoryStore extends BaseStore {\n private data: Map<string, Map<string, Item>> = new Map();\n\n // Namespace -> Key -> Path/field -> Vector\n private vectors: Map<string, Map<string, Map<string, number[]>>> = new Map();\n\n private _indexConfig?: IndexConfig & {\n __tokenizedFields: Array<[string, string[]]>;\n };\n\n constructor(options?: { index?: IndexConfig }) {\n super();\n if (options?.index) {\n this._indexConfig = {\n ...options.index,\n __tokenizedFields: (options.index.fields ?? [\"$\"]).map((p) => [\n p,\n p === \"$\" ? [p] : tokenizePath(p),\n ]),\n };\n }\n }\n\n async batch<Op extends readonly Operation[]>(\n operations: Op\n ): Promise<OperationResults<Op>> {\n const results = [];\n const putOps = new Map<string, PutOperation>();\n const searchOps = new Map<number, [SearchOperation, Item[]]>();\n\n // First pass - handle gets and prepare search/put operations\n for (let i = 0; i < operations.length; i += 1) {\n const op = operations[i];\n if (\"key\" in op && \"namespace\" in op && !(\"value\" in op)) {\n // GetOperation\n results.push(this.getOperation(op));\n } else if (\"namespacePrefix\" in op) {\n // SearchOperation\n const candidates = this.filterItems(op);\n searchOps.set(i, [op, candidates]);\n results.push(null);\n } else if (\"value\" in op) {\n // PutOperation\n const key = `${op.namespace.join(\":\")}:${op.key}`;\n putOps.set(key, op);\n results.push(null);\n } else if (\"matchConditions\" in op) {\n // ListNamespacesOperation\n results.push(this.listNamespacesOperation(op));\n }\n }\n\n // Handle search operations with embeddings\n if (searchOps.size > 0) {\n if (this._indexConfig?.embeddings) {\n const queries = new Set<string>();\n for (const [op] of searchOps.values()) {\n if (op.query) queries.add(op.query);\n }\n\n // Get embeddings for all queries\n const queryEmbeddings =\n queries.size > 0\n ? await Promise.all(\n Array.from(queries).map((q) =>\n this._indexConfig!.embeddings.embedQuery(q)\n )\n )\n : [];\n const queryVectors = Object.fromEntries(\n Array.from(queries).map((q, i) => [q, queryEmbeddings[i]])\n );\n\n // Process each search operation\n for (const [i, [op, candidates]] of searchOps.entries()) {\n if (op.query && queryVectors[op.query]) {\n const queryVector = queryVectors[op.query];\n const scoredResults = this.scoreResults(\n candidates,\n queryVector,\n op.offset ?? 0,\n op.limit ?? 10\n );\n results[i] = scoredResults;\n } else {\n results[i] = this.paginateResults(\n candidates.map((item) => ({ ...item, score: undefined })),\n op.offset ?? 0,\n op.limit ?? 10\n );\n }\n }\n } else {\n // No embeddings - just paginate the filtered results\n for (const [i, [op, candidates]] of searchOps.entries()) {\n results[i] = this.paginateResults(\n candidates.map((item) => ({ ...item, score: undefined })),\n op.offset ?? 0,\n op.limit ?? 10\n );\n }\n }\n }\n\n // Handle put operations with embeddings\n if (putOps.size > 0 && this._indexConfig?.embeddings) {\n const toEmbed = this.extractTexts(Array.from(putOps.values()));\n if (Object.keys(toEmbed).length > 0) {\n const embeddings = await this._indexConfig.embeddings.embedDocuments(\n Object.keys(toEmbed)\n );\n this.insertVectors(toEmbed, embeddings);\n }\n }\n\n // Apply all put operations\n for (const op of putOps.values()) {\n this.putOperation(op);\n }\n\n return results as OperationResults<Op>;\n }\n\n private getOperation(op: GetOperation): Item | null {\n const namespaceKey = op.namespace.join(\":\");\n const item = this.data.get(namespaceKey)?.get(op.key);\n return item ?? null;\n }\n\n private putOperation(op: PutOperation): void {\n const namespaceKey = op.namespace.join(\":\");\n if (!this.data.has(namespaceKey)) {\n this.data.set(namespaceKey, new Map());\n }\n const namespaceMap = this.data.get(namespaceKey)!;\n\n if (op.value === null) {\n namespaceMap.delete(op.key);\n } else {\n const now = new Date();\n if (namespaceMap.has(op.key)) {\n const item = namespaceMap.get(op.key)!;\n item.value = op.value;\n item.updatedAt = now;\n } else {\n namespaceMap.set(op.key, {\n value: op.value,\n key: op.key,\n namespace: op.namespace,\n createdAt: now,\n updatedAt: now,\n });\n }\n }\n }\n\n private listNamespacesOperation(op: ListNamespacesOperation): string[][] {\n const allNamespaces = Array.from(this.data.keys()).map((ns) =>\n ns.split(\":\")\n );\n let namespaces = allNamespaces;\n\n if (op.matchConditions && op.matchConditions.length > 0) {\n namespaces = namespaces.filter((ns) =>\n op.matchConditions!.every((condition) => this.doesMatch(condition, ns))\n );\n }\n\n if (op.maxDepth !== undefined) {\n namespaces = Array.from(\n new Set(namespaces.map((ns) => ns.slice(0, op.maxDepth).join(\":\")))\n ).map((ns) => ns.split(\":\"));\n }\n\n namespaces.sort((a, b) => a.join(\":\").localeCompare(b.join(\":\")));\n\n return namespaces.slice(\n op.offset ?? 0,\n (op.offset ?? 0) + (op.limit ?? namespaces.length)\n );\n }\n\n private doesMatch(matchCondition: MatchCondition, key: string[]): boolean {\n const { matchType, path } = matchCondition;\n\n if (matchType === \"prefix\") {\n if (path.length > key.length) return false;\n return path.every((pElem, index) => {\n const kElem = key[index];\n return pElem === \"*\" || kElem === pElem;\n });\n } else if (matchType === \"suffix\") {\n if (path.length > key.length) return false;\n return path.every((pElem, index) => {\n const kElem = key[key.length - path.length + index];\n return pElem === \"*\" || kElem === pElem;\n });\n }\n\n throw new Error(`Unsupported match type: ${matchType}`);\n }\n\n private filterItems(op: SearchOperation): Item[] {\n const candidates: Item[] = [];\n for (const [namespace, items] of this.data.entries()) {\n if (namespace.startsWith(op.namespacePrefix.join(\":\"))) {\n candidates.push(...items.values());\n }\n }\n\n let filteredCandidates = candidates;\n if (op.filter) {\n filteredCandidates = candidates.filter((item) =>\n Object.entries(op.filter!).every(([key, value]) =>\n compareValues(item.value[key], value)\n )\n );\n }\n return filteredCandidates;\n }\n\n private scoreResults(\n candidates: Item[],\n queryVector: number[],\n offset: number = 0,\n limit: number = 10\n ): SearchItem[] {\n const flatItems: Item[] = [];\n const flatVectors: number[][] = [];\n const scoreless: Item[] = [];\n\n for (const item of candidates) {\n const vectors = this.getVectors(item);\n if (vectors.length) {\n for (const vector of vectors) {\n flatItems.push(item);\n flatVectors.push(vector);\n }\n } else {\n scoreless.push(item);\n }\n }\n\n const scores = this.cosineSimilarity(queryVector, flatVectors);\n\n const sortedResults = scores\n .map((score, i) => [score, flatItems[i]] as [number, Item])\n .sort((a, b) => b[0] - a[0]);\n\n const seen = new Set<string>();\n const kept: Array<[number | undefined, Item]> = [];\n\n for (const [score, item] of sortedResults) {\n const key = `${item.namespace.join(\":\")}:${item.key}`;\n if (seen.has(key)) continue;\n\n const ix = seen.size;\n if (ix >= offset + limit) break;\n if (ix < offset) {\n seen.add(key);\n continue;\n }\n\n seen.add(key);\n kept.push([score, item]);\n }\n\n if (scoreless.length && kept.length < limit) {\n for (const item of scoreless.slice(0, limit - kept.length)) {\n const key = `${item.namespace.join(\":\")}:${item.key}`;\n if (!seen.has(key)) {\n seen.add(key);\n kept.push([undefined, item]);\n }\n }\n }\n return kept.map(([score, item]) => ({\n ...item,\n score,\n }));\n }\n\n private paginateResults(\n results: SearchItem[],\n offset: number,\n limit: number\n ): SearchItem[] {\n return results.slice(offset, offset + limit);\n }\n\n private extractTexts(ops: PutOperation[]): {\n [text: string]: [string[], string, string][];\n } {\n if (!ops.length || !this._indexConfig) {\n return {};\n }\n\n const toEmbed: { [text: string]: [string[], string, string][] } = {};\n\n for (const op of ops) {\n if (op.value !== null && op.index !== false) {\n const paths =\n op.index === null || op.index === undefined\n ? this._indexConfig.__tokenizedFields ?? []\n : op.index.map(\n (ix) => [ix, tokenizePath(ix)] as [string, string[]]\n );\n for (const [path, field] of paths) {\n const texts = getTextAtPath(op.value, field);\n if (texts.length) {\n if (texts.length > 1) {\n texts.forEach((text, i) => {\n if (!toEmbed[text]) toEmbed[text] = [];\n toEmbed[text].push([op.namespace, op.key, `${path}.${i}`]);\n });\n } else {\n if (!toEmbed[texts[0]]) toEmbed[texts[0]] = [];\n toEmbed[texts[0]].push([op.namespace, op.key, path]);\n }\n }\n }\n }\n }\n\n return toEmbed;\n }\n\n private insertVectors(\n texts: { [text: string]: [string[], string, string][] },\n embeddings: number[][]\n ): void {\n for (const [text, metadata] of Object.entries(texts)) {\n const embedding = embeddings.shift();\n if (!embedding) {\n throw new Error(`No embedding found for text: ${text}`);\n }\n\n for (const [namespace, key, field] of metadata) {\n const namespaceKey = namespace.join(\":\");\n if (!this.vectors.has(namespaceKey)) {\n this.vectors.set(namespaceKey, new Map());\n }\n const namespaceMap = this.vectors.get(namespaceKey)!;\n if (!namespaceMap.has(key)) {\n namespaceMap.set(key, new Map());\n }\n const itemMap = namespaceMap.get(key)!;\n itemMap.set(field, embedding);\n }\n }\n }\n\n private getVectors(item: Item): number[][] {\n const namespaceKey = item.namespace.join(\":\");\n const itemKey = item.key;\n if (!this.vectors.has(namespaceKey)) {\n return [];\n }\n const namespaceMap = this.vectors.get(namespaceKey)!;\n if (!namespaceMap.has(itemKey)) {\n return [];\n }\n const itemMap = namespaceMap.get(itemKey)!;\n const vectors = Array.from(itemMap.values());\n if (!vectors.length) {\n return [];\n }\n return vectors;\n }\n\n private cosineSimilarity(X: number[], Y: number[][]): number[] {\n if (!Y.length) return [];\n\n // Calculate dot products for all vectors at once\n const dotProducts = Y.map((vector) =>\n vector.reduce((acc, val, i) => acc + val * X[i], 0)\n );\n\n // Calculate magnitudes\n const magnitude1 = Math.sqrt(X.reduce((acc, val) => acc + val * val, 0));\n const magnitudes2 = Y.map((vector) =>\n Math.sqrt(vector.reduce((acc, val) => acc + val * val, 0))\n );\n\n // Calculate similarities\n return dotProducts.map((dot, i) => {\n const magnitude2 = magnitudes2[i];\n return magnitude1 && magnitude2 ? dot / (magnitude1 * magnitude2) : 0;\n });\n }\n\n public get indexConfig(): IndexConfig | undefined {\n return this._indexConfig;\n }\n}\n\n/** @deprecated Alias for InMemoryStore */\nexport class MemoryStore extends InMemoryStore {}\n"],"mappings":"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"}
|
package/dist/store/memory.d.cts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { BaseStore, IndexConfig, Operation, OperationResults } from "./base.cjs";
|
|
2
2
|
|
|
3
3
|
//#region src/store/memory.d.ts
|
|
4
|
-
|
|
5
4
|
/**
|
|
6
5
|
* In-memory key-value store with optional vector search.
|
|
7
6
|
*
|
|
@@ -37,7 +36,6 @@ import { BaseStore, IndexConfig, Operation, OperationResults } from "./base.cjs"
|
|
|
37
36
|
*/
|
|
38
37
|
declare class InMemoryStore extends BaseStore {
|
|
39
38
|
private data;
|
|
40
|
-
// Namespace -> Key -> Path/field -> Vector
|
|
41
39
|
private vectors;
|
|
42
40
|
private _indexConfig?;
|
|
43
41
|
constructor(options?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.cts","names":[
|
|
1
|
+
{"version":3,"file":"memory.d.cts","names":[],"sources":["../../src/store/memory.ts"],"mappings":";;;;;AAgDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAa,aAAA,SAAsB,SAAA;EAAA,QACzB,IAAA;EAAA,QAGA,OAAA;EAAA,QAEA,YAAA;EAIR,WAAA,CAAY,OAAA;IAAY,KAAA,GAAQ,WAAA;EAAA;EAa1B,KAAA,qBAA0B,SAAA,GAAA,CAC9B,UAAA,EAAY,EAAA,GACX,OAAA,CAAQ,gBAAA,CAAiB,EAAA;EAAA,QAkGpB,YAAA;EAAA,QAMA,YAAA;EAAA,QA2BA,uBAAA;EAAA,QA0BA,SAAA;EAAA,QAoBA,WAAA;EAAA,QAmBA,YAAA;EAAA,QA6DA,eAAA;EAAA,QAQA,YAAA;EAAA,QAqCA,aAAA;EAAA,QAyBA,UAAA;EAAA,QAkBA,gBAAA;EAAA,IAqBG,WAAA,CAAA,GAAe,WAAA;AAAA;;cAMf,WAAA,SAAoB,aAAA"}
|
package/dist/store/memory.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { BaseStore, IndexConfig, Operation, OperationResults } from "./base.js";
|
|
2
2
|
|
|
3
3
|
//#region src/store/memory.d.ts
|
|
4
|
-
|
|
5
4
|
/**
|
|
6
5
|
* In-memory key-value store with optional vector search.
|
|
7
6
|
*
|
|
@@ -37,7 +36,6 @@ import { BaseStore, IndexConfig, Operation, OperationResults } from "./base.js";
|
|
|
37
36
|
*/
|
|
38
37
|
declare class InMemoryStore extends BaseStore {
|
|
39
38
|
private data;
|
|
40
|
-
// Namespace -> Key -> Path/field -> Vector
|
|
41
39
|
private vectors;
|
|
42
40
|
private _indexConfig?;
|
|
43
41
|
constructor(options?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","names":[
|
|
1
|
+
{"version":3,"file":"memory.d.ts","names":[],"sources":["../../src/store/memory.ts"],"mappings":";;;;;AAgDA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAa,aAAA,SAAsB,SAAA;EAAA,QACzB,IAAA;EAAA,QAGA,OAAA;EAAA,QAEA,YAAA;EAIR,WAAA,CAAY,OAAA;IAAY,KAAA,GAAQ,WAAA;EAAA;EAa1B,KAAA,qBAA0B,SAAA,GAAA,CAC9B,UAAA,EAAY,EAAA,GACX,OAAA,CAAQ,gBAAA,CAAiB,EAAA;EAAA,QAkGpB,YAAA;EAAA,QAMA,YAAA;EAAA,QA2BA,uBAAA;EAAA,QA0BA,SAAA;EAAA,QAoBA,WAAA;EAAA,QAmBA,YAAA;EAAA,QA6DA,eAAA;EAAA,QAQA,YAAA;EAAA,QAqCA,aAAA;EAAA,QAyBA,UAAA;EAAA,QAkBA,gBAAA;EAAA,IAqBG,WAAA,CAAA,GAAe,WAAA;AAAA;;cAMf,WAAA,SAAoB,aAAA"}
|
package/dist/store/memory.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { BaseStore } from "./base.js";
|
|
2
2
|
import { compareValues, getTextAtPath, tokenizePath } from "./utils.js";
|
|
3
|
-
|
|
4
3
|
//#region src/store/memory.ts
|
|
5
4
|
/**
|
|
6
5
|
* In-memory key-value store with optional vector search.
|
|
@@ -70,8 +69,7 @@ var InMemoryStore = class extends BaseStore {
|
|
|
70
69
|
const queryVectors = Object.fromEntries(Array.from(queries).map((q, i) => [q, queryEmbeddings[i]]));
|
|
71
70
|
for (const [i, [op, candidates]] of searchOps.entries()) if (op.query && queryVectors[op.query]) {
|
|
72
71
|
const queryVector = queryVectors[op.query];
|
|
73
|
-
|
|
74
|
-
results[i] = scoredResults;
|
|
72
|
+
results[i] = this.scoreResults(candidates, queryVector, op.offset ?? 0, op.limit ?? 10);
|
|
75
73
|
} else results[i] = this.paginateResults(candidates.map((item) => ({
|
|
76
74
|
...item,
|
|
77
75
|
score: void 0
|
|
@@ -92,8 +90,7 @@ var InMemoryStore = class extends BaseStore {
|
|
|
92
90
|
}
|
|
93
91
|
getOperation(op) {
|
|
94
92
|
const namespaceKey = op.namespace.join(":");
|
|
95
|
-
|
|
96
|
-
return item ?? null;
|
|
93
|
+
return this.data.get(namespaceKey)?.get(op.key) ?? null;
|
|
97
94
|
}
|
|
98
95
|
putOperation(op) {
|
|
99
96
|
const namespaceKey = op.namespace.join(":");
|
|
@@ -116,8 +113,7 @@ var InMemoryStore = class extends BaseStore {
|
|
|
116
113
|
}
|
|
117
114
|
}
|
|
118
115
|
listNamespacesOperation(op) {
|
|
119
|
-
|
|
120
|
-
let namespaces = allNamespaces;
|
|
116
|
+
let namespaces = Array.from(this.data.keys()).map((ns) => ns.split(":"));
|
|
121
117
|
if (op.matchConditions && op.matchConditions.length > 0) namespaces = namespaces.filter((ns) => op.matchConditions.every((condition) => this.doesMatch(condition, ns)));
|
|
122
118
|
if (op.maxDepth !== void 0) namespaces = Array.from(new Set(namespaces.map((ns) => ns.slice(0, op.maxDepth).join(":")))).map((ns) => ns.split(":"));
|
|
123
119
|
namespaces.sort((a, b) => a.join(":").localeCompare(b.join(":")));
|
|
@@ -159,8 +155,7 @@ var InMemoryStore = class extends BaseStore {
|
|
|
159
155
|
}
|
|
160
156
|
else scoreless.push(item);
|
|
161
157
|
}
|
|
162
|
-
const
|
|
163
|
-
const sortedResults = scores.map((score, i) => [score, flatItems[i]]).sort((a, b) => b[0] - a[0]);
|
|
158
|
+
const sortedResults = this.cosineSimilarity(queryVector, flatVectors).map((score, i) => [score, flatItems[i]]).sort((a, b) => b[0] - a[0]);
|
|
164
159
|
const seen = /* @__PURE__ */ new Set();
|
|
165
160
|
const kept = [];
|
|
166
161
|
for (const [score, item] of sortedResults) {
|
|
@@ -226,8 +221,7 @@ var InMemoryStore = class extends BaseStore {
|
|
|
226
221
|
if (!this.vectors.has(namespaceKey)) this.vectors.set(namespaceKey, /* @__PURE__ */ new Map());
|
|
227
222
|
const namespaceMap = this.vectors.get(namespaceKey);
|
|
228
223
|
if (!namespaceMap.has(key)) namespaceMap.set(key, /* @__PURE__ */ new Map());
|
|
229
|
-
|
|
230
|
-
itemMap.set(field, embedding);
|
|
224
|
+
namespaceMap.get(key).set(field, embedding);
|
|
231
225
|
}
|
|
232
226
|
}
|
|
233
227
|
}
|
|
@@ -258,7 +252,7 @@ var InMemoryStore = class extends BaseStore {
|
|
|
258
252
|
};
|
|
259
253
|
/** @deprecated Alias for InMemoryStore */
|
|
260
254
|
var MemoryStore = class extends InMemoryStore {};
|
|
261
|
-
|
|
262
255
|
//#endregion
|
|
263
256
|
export { InMemoryStore, MemoryStore };
|
|
257
|
+
|
|
264
258
|
//# sourceMappingURL=memory.js.map
|
package/dist/store/memory.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.js","names":["candidates: Item[]","flatItems: Item[]","flatVectors: number[][]","scoreless: Item[]","kept: Array<[number | undefined, Item]>","toEmbed: { [text: string]: [string[], string, string][] }"],"sources":["../../src/store/memory.ts"],"sourcesContent":["import {\n BaseStore,\n type OperationResults,\n type Item,\n type Operation,\n MatchCondition,\n ListNamespacesOperation,\n PutOperation,\n SearchOperation,\n GetOperation,\n type IndexConfig,\n type SearchItem,\n} from \"./base.js\";\nimport { tokenizePath, compareValues, getTextAtPath } from \"./utils.js\";\n\n/**\n * In-memory key-value store with optional vector search.\n *\n * A lightweight store implementation using JavaScript Maps. Supports basic\n * key-value operations and vector search when configured with embeddings.\n *\n * @example\n * ```typescript\n * // Basic key-value storage\n * const store = new InMemoryStore();\n * await store.put([\"users\", \"123\"], \"prefs\", { theme: \"dark\" });\n * const item = await store.get([\"users\", \"123\"], \"prefs\");\n *\n * // Vector search with embeddings\n * import { OpenAIEmbeddings } from \"@langchain/openai\";\n * const store = new InMemoryStore({\n * index: {\n * dims: 1536,\n * embeddings: new OpenAIEmbeddings({ modelName: \"text-embedding-3-small\" }),\n * }\n * });\n *\n * // Store documents\n * await store.put([\"docs\"], \"doc1\", { text: \"Python tutorial\" });\n * await store.put([\"docs\"], \"doc2\", { text: \"TypeScript guide\" });\n *\n * // Search by similarity\n * const results = await store.search([\"docs\"], { query: \"python programming\" });\n * ```\n *\n * **Warning**: This store keeps all data in memory. Data is lost when the process exits.\n * For persistence, use a database-backed store.\n */\nexport class InMemoryStore extends BaseStore {\n private data: Map<string, Map<string, Item>> = new Map();\n\n // Namespace -> Key -> Path/field -> Vector\n private vectors: Map<string, Map<string, Map<string, number[]>>> = new Map();\n\n private _indexConfig?: IndexConfig & {\n __tokenizedFields: Array<[string, string[]]>;\n };\n\n constructor(options?: { index?: IndexConfig }) {\n super();\n if (options?.index) {\n this._indexConfig = {\n ...options.index,\n __tokenizedFields: (options.index.fields ?? [\"$\"]).map((p) => [\n p,\n p === \"$\" ? [p] : tokenizePath(p),\n ]),\n };\n }\n }\n\n async batch<Op extends readonly Operation[]>(\n operations: Op\n ): Promise<OperationResults<Op>> {\n const results = [];\n const putOps = new Map<string, PutOperation>();\n const searchOps = new Map<number, [SearchOperation, Item[]]>();\n\n // First pass - handle gets and prepare search/put operations\n for (let i = 0; i < operations.length; i += 1) {\n const op = operations[i];\n if (\"key\" in op && \"namespace\" in op && !(\"value\" in op)) {\n // GetOperation\n results.push(this.getOperation(op));\n } else if (\"namespacePrefix\" in op) {\n // SearchOperation\n const candidates = this.filterItems(op);\n searchOps.set(i, [op, candidates]);\n results.push(null);\n } else if (\"value\" in op) {\n // PutOperation\n const key = `${op.namespace.join(\":\")}:${op.key}`;\n putOps.set(key, op);\n results.push(null);\n } else if (\"matchConditions\" in op) {\n // ListNamespacesOperation\n results.push(this.listNamespacesOperation(op));\n }\n }\n\n // Handle search operations with embeddings\n if (searchOps.size > 0) {\n if (this._indexConfig?.embeddings) {\n const queries = new Set<string>();\n for (const [op] of searchOps.values()) {\n if (op.query) queries.add(op.query);\n }\n\n // Get embeddings for all queries\n const queryEmbeddings =\n queries.size > 0\n ? await Promise.all(\n Array.from(queries).map((q) =>\n this._indexConfig!.embeddings.embedQuery(q)\n )\n )\n : [];\n const queryVectors = Object.fromEntries(\n Array.from(queries).map((q, i) => [q, queryEmbeddings[i]])\n );\n\n // Process each search operation\n for (const [i, [op, candidates]] of searchOps.entries()) {\n if (op.query && queryVectors[op.query]) {\n const queryVector = queryVectors[op.query];\n const scoredResults = this.scoreResults(\n candidates,\n queryVector,\n op.offset ?? 0,\n op.limit ?? 10\n );\n results[i] = scoredResults;\n } else {\n results[i] = this.paginateResults(\n candidates.map((item) => ({ ...item, score: undefined })),\n op.offset ?? 0,\n op.limit ?? 10\n );\n }\n }\n } else {\n // No embeddings - just paginate the filtered results\n for (const [i, [op, candidates]] of searchOps.entries()) {\n results[i] = this.paginateResults(\n candidates.map((item) => ({ ...item, score: undefined })),\n op.offset ?? 0,\n op.limit ?? 10\n );\n }\n }\n }\n\n // Handle put operations with embeddings\n if (putOps.size > 0 && this._indexConfig?.embeddings) {\n const toEmbed = this.extractTexts(Array.from(putOps.values()));\n if (Object.keys(toEmbed).length > 0) {\n const embeddings = await this._indexConfig.embeddings.embedDocuments(\n Object.keys(toEmbed)\n );\n this.insertVectors(toEmbed, embeddings);\n }\n }\n\n // Apply all put operations\n for (const op of putOps.values()) {\n this.putOperation(op);\n }\n\n return results as OperationResults<Op>;\n }\n\n private getOperation(op: GetOperation): Item | null {\n const namespaceKey = op.namespace.join(\":\");\n const item = this.data.get(namespaceKey)?.get(op.key);\n return item ?? null;\n }\n\n private putOperation(op: PutOperation): void {\n const namespaceKey = op.namespace.join(\":\");\n if (!this.data.has(namespaceKey)) {\n this.data.set(namespaceKey, new Map());\n }\n const namespaceMap = this.data.get(namespaceKey)!;\n\n if (op.value === null) {\n namespaceMap.delete(op.key);\n } else {\n const now = new Date();\n if (namespaceMap.has(op.key)) {\n const item = namespaceMap.get(op.key)!;\n item.value = op.value;\n item.updatedAt = now;\n } else {\n namespaceMap.set(op.key, {\n value: op.value,\n key: op.key,\n namespace: op.namespace,\n createdAt: now,\n updatedAt: now,\n });\n }\n }\n }\n\n private listNamespacesOperation(op: ListNamespacesOperation): string[][] {\n const allNamespaces = Array.from(this.data.keys()).map((ns) =>\n ns.split(\":\")\n );\n let namespaces = allNamespaces;\n\n if (op.matchConditions && op.matchConditions.length > 0) {\n namespaces = namespaces.filter((ns) =>\n op.matchConditions!.every((condition) => this.doesMatch(condition, ns))\n );\n }\n\n if (op.maxDepth !== undefined) {\n namespaces = Array.from(\n new Set(namespaces.map((ns) => ns.slice(0, op.maxDepth).join(\":\")))\n ).map((ns) => ns.split(\":\"));\n }\n\n namespaces.sort((a, b) => a.join(\":\").localeCompare(b.join(\":\")));\n\n return namespaces.slice(\n op.offset ?? 0,\n (op.offset ?? 0) + (op.limit ?? namespaces.length)\n );\n }\n\n private doesMatch(matchCondition: MatchCondition, key: string[]): boolean {\n const { matchType, path } = matchCondition;\n\n if (matchType === \"prefix\") {\n if (path.length > key.length) return false;\n return path.every((pElem, index) => {\n const kElem = key[index];\n return pElem === \"*\" || kElem === pElem;\n });\n } else if (matchType === \"suffix\") {\n if (path.length > key.length) return false;\n return path.every((pElem, index) => {\n const kElem = key[key.length - path.length + index];\n return pElem === \"*\" || kElem === pElem;\n });\n }\n\n throw new Error(`Unsupported match type: ${matchType}`);\n }\n\n private filterItems(op: SearchOperation): Item[] {\n const candidates: Item[] = [];\n for (const [namespace, items] of this.data.entries()) {\n if (namespace.startsWith(op.namespacePrefix.join(\":\"))) {\n candidates.push(...items.values());\n }\n }\n\n let filteredCandidates = candidates;\n if (op.filter) {\n filteredCandidates = candidates.filter((item) =>\n Object.entries(op.filter!).every(([key, value]) =>\n compareValues(item.value[key], value)\n )\n );\n }\n return filteredCandidates;\n }\n\n private scoreResults(\n candidates: Item[],\n queryVector: number[],\n offset: number = 0,\n limit: number = 10\n ): SearchItem[] {\n const flatItems: Item[] = [];\n const flatVectors: number[][] = [];\n const scoreless: Item[] = [];\n\n for (const item of candidates) {\n const vectors = this.getVectors(item);\n if (vectors.length) {\n for (const vector of vectors) {\n flatItems.push(item);\n flatVectors.push(vector);\n }\n } else {\n scoreless.push(item);\n }\n }\n\n const scores = this.cosineSimilarity(queryVector, flatVectors);\n\n const sortedResults = scores\n .map((score, i) => [score, flatItems[i]] as [number, Item])\n .sort((a, b) => b[0] - a[0]);\n\n const seen = new Set<string>();\n const kept: Array<[number | undefined, Item]> = [];\n\n for (const [score, item] of sortedResults) {\n const key = `${item.namespace.join(\":\")}:${item.key}`;\n if (seen.has(key)) continue;\n\n const ix = seen.size;\n if (ix >= offset + limit) break;\n if (ix < offset) {\n seen.add(key);\n continue;\n }\n\n seen.add(key);\n kept.push([score, item]);\n }\n\n if (scoreless.length && kept.length < limit) {\n for (const item of scoreless.slice(0, limit - kept.length)) {\n const key = `${item.namespace.join(\":\")}:${item.key}`;\n if (!seen.has(key)) {\n seen.add(key);\n kept.push([undefined, item]);\n }\n }\n }\n return kept.map(([score, item]) => ({\n ...item,\n score,\n }));\n }\n\n private paginateResults(\n results: SearchItem[],\n offset: number,\n limit: number\n ): SearchItem[] {\n return results.slice(offset, offset + limit);\n }\n\n private extractTexts(ops: PutOperation[]): {\n [text: string]: [string[], string, string][];\n } {\n if (!ops.length || !this._indexConfig) {\n return {};\n }\n\n const toEmbed: { [text: string]: [string[], string, string][] } = {};\n\n for (const op of ops) {\n if (op.value !== null && op.index !== false) {\n const paths =\n op.index === null || op.index === undefined\n ? this._indexConfig.__tokenizedFields ?? []\n : op.index.map(\n (ix) => [ix, tokenizePath(ix)] as [string, string[]]\n );\n for (const [path, field] of paths) {\n const texts = getTextAtPath(op.value, field);\n if (texts.length) {\n if (texts.length > 1) {\n texts.forEach((text, i) => {\n if (!toEmbed[text]) toEmbed[text] = [];\n toEmbed[text].push([op.namespace, op.key, `${path}.${i}`]);\n });\n } else {\n if (!toEmbed[texts[0]]) toEmbed[texts[0]] = [];\n toEmbed[texts[0]].push([op.namespace, op.key, path]);\n }\n }\n }\n }\n }\n\n return toEmbed;\n }\n\n private insertVectors(\n texts: { [text: string]: [string[], string, string][] },\n embeddings: number[][]\n ): void {\n for (const [text, metadata] of Object.entries(texts)) {\n const embedding = embeddings.shift();\n if (!embedding) {\n throw new Error(`No embedding found for text: ${text}`);\n }\n\n for (const [namespace, key, field] of metadata) {\n const namespaceKey = namespace.join(\":\");\n if (!this.vectors.has(namespaceKey)) {\n this.vectors.set(namespaceKey, new Map());\n }\n const namespaceMap = this.vectors.get(namespaceKey)!;\n if (!namespaceMap.has(key)) {\n namespaceMap.set(key, new Map());\n }\n const itemMap = namespaceMap.get(key)!;\n itemMap.set(field, embedding);\n }\n }\n }\n\n private getVectors(item: Item): number[][] {\n const namespaceKey = item.namespace.join(\":\");\n const itemKey = item.key;\n if (!this.vectors.has(namespaceKey)) {\n return [];\n }\n const namespaceMap = this.vectors.get(namespaceKey)!;\n if (!namespaceMap.has(itemKey)) {\n return [];\n }\n const itemMap = namespaceMap.get(itemKey)!;\n const vectors = Array.from(itemMap.values());\n if (!vectors.length) {\n return [];\n }\n return vectors;\n }\n\n private cosineSimilarity(X: number[], Y: number[][]): number[] {\n if (!Y.length) return [];\n\n // Calculate dot products for all vectors at once\n const dotProducts = Y.map((vector) =>\n vector.reduce((acc, val, i) => acc + val * X[i], 0)\n );\n\n // Calculate magnitudes\n const magnitude1 = Math.sqrt(X.reduce((acc, val) => acc + val * val, 0));\n const magnitudes2 = Y.map((vector) =>\n Math.sqrt(vector.reduce((acc, val) => acc + val * val, 0))\n );\n\n // Calculate similarities\n return dotProducts.map((dot, i) => {\n const magnitude2 = magnitudes2[i];\n return magnitude1 && magnitude2 ? dot / (magnitude1 * magnitude2) : 0;\n });\n }\n\n public get indexConfig(): IndexConfig | undefined {\n return this._indexConfig;\n }\n}\n\n/** @deprecated Alias for InMemoryStore */\nexport class MemoryStore extends InMemoryStore {}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"memory.js","names":[],"sources":["../../src/store/memory.ts"],"sourcesContent":["import {\n BaseStore,\n type OperationResults,\n type Item,\n type Operation,\n MatchCondition,\n ListNamespacesOperation,\n PutOperation,\n SearchOperation,\n GetOperation,\n type IndexConfig,\n type SearchItem,\n} from \"./base.js\";\nimport { tokenizePath, compareValues, getTextAtPath } from \"./utils.js\";\n\n/**\n * In-memory key-value store with optional vector search.\n *\n * A lightweight store implementation using JavaScript Maps. Supports basic\n * key-value operations and vector search when configured with embeddings.\n *\n * @example\n * ```typescript\n * // Basic key-value storage\n * const store = new InMemoryStore();\n * await store.put([\"users\", \"123\"], \"prefs\", { theme: \"dark\" });\n * const item = await store.get([\"users\", \"123\"], \"prefs\");\n *\n * // Vector search with embeddings\n * import { OpenAIEmbeddings } from \"@langchain/openai\";\n * const store = new InMemoryStore({\n * index: {\n * dims: 1536,\n * embeddings: new OpenAIEmbeddings({ modelName: \"text-embedding-3-small\" }),\n * }\n * });\n *\n * // Store documents\n * await store.put([\"docs\"], \"doc1\", { text: \"Python tutorial\" });\n * await store.put([\"docs\"], \"doc2\", { text: \"TypeScript guide\" });\n *\n * // Search by similarity\n * const results = await store.search([\"docs\"], { query: \"python programming\" });\n * ```\n *\n * **Warning**: This store keeps all data in memory. Data is lost when the process exits.\n * For persistence, use a database-backed store.\n */\nexport class InMemoryStore extends BaseStore {\n private data: Map<string, Map<string, Item>> = new Map();\n\n // Namespace -> Key -> Path/field -> Vector\n private vectors: Map<string, Map<string, Map<string, number[]>>> = new Map();\n\n private _indexConfig?: IndexConfig & {\n __tokenizedFields: Array<[string, string[]]>;\n };\n\n constructor(options?: { index?: IndexConfig }) {\n super();\n if (options?.index) {\n this._indexConfig = {\n ...options.index,\n __tokenizedFields: (options.index.fields ?? [\"$\"]).map((p) => [\n p,\n p === \"$\" ? [p] : tokenizePath(p),\n ]),\n };\n }\n }\n\n async batch<Op extends readonly Operation[]>(\n operations: Op\n ): Promise<OperationResults<Op>> {\n const results = [];\n const putOps = new Map<string, PutOperation>();\n const searchOps = new Map<number, [SearchOperation, Item[]]>();\n\n // First pass - handle gets and prepare search/put operations\n for (let i = 0; i < operations.length; i += 1) {\n const op = operations[i];\n if (\"key\" in op && \"namespace\" in op && !(\"value\" in op)) {\n // GetOperation\n results.push(this.getOperation(op));\n } else if (\"namespacePrefix\" in op) {\n // SearchOperation\n const candidates = this.filterItems(op);\n searchOps.set(i, [op, candidates]);\n results.push(null);\n } else if (\"value\" in op) {\n // PutOperation\n const key = `${op.namespace.join(\":\")}:${op.key}`;\n putOps.set(key, op);\n results.push(null);\n } else if (\"matchConditions\" in op) {\n // ListNamespacesOperation\n results.push(this.listNamespacesOperation(op));\n }\n }\n\n // Handle search operations with embeddings\n if (searchOps.size > 0) {\n if (this._indexConfig?.embeddings) {\n const queries = new Set<string>();\n for (const [op] of searchOps.values()) {\n if (op.query) queries.add(op.query);\n }\n\n // Get embeddings for all queries\n const queryEmbeddings =\n queries.size > 0\n ? await Promise.all(\n Array.from(queries).map((q) =>\n this._indexConfig!.embeddings.embedQuery(q)\n )\n )\n : [];\n const queryVectors = Object.fromEntries(\n Array.from(queries).map((q, i) => [q, queryEmbeddings[i]])\n );\n\n // Process each search operation\n for (const [i, [op, candidates]] of searchOps.entries()) {\n if (op.query && queryVectors[op.query]) {\n const queryVector = queryVectors[op.query];\n const scoredResults = this.scoreResults(\n candidates,\n queryVector,\n op.offset ?? 0,\n op.limit ?? 10\n );\n results[i] = scoredResults;\n } else {\n results[i] = this.paginateResults(\n candidates.map((item) => ({ ...item, score: undefined })),\n op.offset ?? 0,\n op.limit ?? 10\n );\n }\n }\n } else {\n // No embeddings - just paginate the filtered results\n for (const [i, [op, candidates]] of searchOps.entries()) {\n results[i] = this.paginateResults(\n candidates.map((item) => ({ ...item, score: undefined })),\n op.offset ?? 0,\n op.limit ?? 10\n );\n }\n }\n }\n\n // Handle put operations with embeddings\n if (putOps.size > 0 && this._indexConfig?.embeddings) {\n const toEmbed = this.extractTexts(Array.from(putOps.values()));\n if (Object.keys(toEmbed).length > 0) {\n const embeddings = await this._indexConfig.embeddings.embedDocuments(\n Object.keys(toEmbed)\n );\n this.insertVectors(toEmbed, embeddings);\n }\n }\n\n // Apply all put operations\n for (const op of putOps.values()) {\n this.putOperation(op);\n }\n\n return results as OperationResults<Op>;\n }\n\n private getOperation(op: GetOperation): Item | null {\n const namespaceKey = op.namespace.join(\":\");\n const item = this.data.get(namespaceKey)?.get(op.key);\n return item ?? null;\n }\n\n private putOperation(op: PutOperation): void {\n const namespaceKey = op.namespace.join(\":\");\n if (!this.data.has(namespaceKey)) {\n this.data.set(namespaceKey, new Map());\n }\n const namespaceMap = this.data.get(namespaceKey)!;\n\n if (op.value === null) {\n namespaceMap.delete(op.key);\n } else {\n const now = new Date();\n if (namespaceMap.has(op.key)) {\n const item = namespaceMap.get(op.key)!;\n item.value = op.value;\n item.updatedAt = now;\n } else {\n namespaceMap.set(op.key, {\n value: op.value,\n key: op.key,\n namespace: op.namespace,\n createdAt: now,\n updatedAt: now,\n });\n }\n }\n }\n\n private listNamespacesOperation(op: ListNamespacesOperation): string[][] {\n const allNamespaces = Array.from(this.data.keys()).map((ns) =>\n ns.split(\":\")\n );\n let namespaces = allNamespaces;\n\n if (op.matchConditions && op.matchConditions.length > 0) {\n namespaces = namespaces.filter((ns) =>\n op.matchConditions!.every((condition) => this.doesMatch(condition, ns))\n );\n }\n\n if (op.maxDepth !== undefined) {\n namespaces = Array.from(\n new Set(namespaces.map((ns) => ns.slice(0, op.maxDepth).join(\":\")))\n ).map((ns) => ns.split(\":\"));\n }\n\n namespaces.sort((a, b) => a.join(\":\").localeCompare(b.join(\":\")));\n\n return namespaces.slice(\n op.offset ?? 0,\n (op.offset ?? 0) + (op.limit ?? namespaces.length)\n );\n }\n\n private doesMatch(matchCondition: MatchCondition, key: string[]): boolean {\n const { matchType, path } = matchCondition;\n\n if (matchType === \"prefix\") {\n if (path.length > key.length) return false;\n return path.every((pElem, index) => {\n const kElem = key[index];\n return pElem === \"*\" || kElem === pElem;\n });\n } else if (matchType === \"suffix\") {\n if (path.length > key.length) return false;\n return path.every((pElem, index) => {\n const kElem = key[key.length - path.length + index];\n return pElem === \"*\" || kElem === pElem;\n });\n }\n\n throw new Error(`Unsupported match type: ${matchType}`);\n }\n\n private filterItems(op: SearchOperation): Item[] {\n const candidates: Item[] = [];\n for (const [namespace, items] of this.data.entries()) {\n if (namespace.startsWith(op.namespacePrefix.join(\":\"))) {\n candidates.push(...items.values());\n }\n }\n\n let filteredCandidates = candidates;\n if (op.filter) {\n filteredCandidates = candidates.filter((item) =>\n Object.entries(op.filter!).every(([key, value]) =>\n compareValues(item.value[key], value)\n )\n );\n }\n return filteredCandidates;\n }\n\n private scoreResults(\n candidates: Item[],\n queryVector: number[],\n offset: number = 0,\n limit: number = 10\n ): SearchItem[] {\n const flatItems: Item[] = [];\n const flatVectors: number[][] = [];\n const scoreless: Item[] = [];\n\n for (const item of candidates) {\n const vectors = this.getVectors(item);\n if (vectors.length) {\n for (const vector of vectors) {\n flatItems.push(item);\n flatVectors.push(vector);\n }\n } else {\n scoreless.push(item);\n }\n }\n\n const scores = this.cosineSimilarity(queryVector, flatVectors);\n\n const sortedResults = scores\n .map((score, i) => [score, flatItems[i]] as [number, Item])\n .sort((a, b) => b[0] - a[0]);\n\n const seen = new Set<string>();\n const kept: Array<[number | undefined, Item]> = [];\n\n for (const [score, item] of sortedResults) {\n const key = `${item.namespace.join(\":\")}:${item.key}`;\n if (seen.has(key)) continue;\n\n const ix = seen.size;\n if (ix >= offset + limit) break;\n if (ix < offset) {\n seen.add(key);\n continue;\n }\n\n seen.add(key);\n kept.push([score, item]);\n }\n\n if (scoreless.length && kept.length < limit) {\n for (const item of scoreless.slice(0, limit - kept.length)) {\n const key = `${item.namespace.join(\":\")}:${item.key}`;\n if (!seen.has(key)) {\n seen.add(key);\n kept.push([undefined, item]);\n }\n }\n }\n return kept.map(([score, item]) => ({\n ...item,\n score,\n }));\n }\n\n private paginateResults(\n results: SearchItem[],\n offset: number,\n limit: number\n ): SearchItem[] {\n return results.slice(offset, offset + limit);\n }\n\n private extractTexts(ops: PutOperation[]): {\n [text: string]: [string[], string, string][];\n } {\n if (!ops.length || !this._indexConfig) {\n return {};\n }\n\n const toEmbed: { [text: string]: [string[], string, string][] } = {};\n\n for (const op of ops) {\n if (op.value !== null && op.index !== false) {\n const paths =\n op.index === null || op.index === undefined\n ? this._indexConfig.__tokenizedFields ?? []\n : op.index.map(\n (ix) => [ix, tokenizePath(ix)] as [string, string[]]\n );\n for (const [path, field] of paths) {\n const texts = getTextAtPath(op.value, field);\n if (texts.length) {\n if (texts.length > 1) {\n texts.forEach((text, i) => {\n if (!toEmbed[text]) toEmbed[text] = [];\n toEmbed[text].push([op.namespace, op.key, `${path}.${i}`]);\n });\n } else {\n if (!toEmbed[texts[0]]) toEmbed[texts[0]] = [];\n toEmbed[texts[0]].push([op.namespace, op.key, path]);\n }\n }\n }\n }\n }\n\n return toEmbed;\n }\n\n private insertVectors(\n texts: { [text: string]: [string[], string, string][] },\n embeddings: number[][]\n ): void {\n for (const [text, metadata] of Object.entries(texts)) {\n const embedding = embeddings.shift();\n if (!embedding) {\n throw new Error(`No embedding found for text: ${text}`);\n }\n\n for (const [namespace, key, field] of metadata) {\n const namespaceKey = namespace.join(\":\");\n if (!this.vectors.has(namespaceKey)) {\n this.vectors.set(namespaceKey, new Map());\n }\n const namespaceMap = this.vectors.get(namespaceKey)!;\n if (!namespaceMap.has(key)) {\n namespaceMap.set(key, new Map());\n }\n const itemMap = namespaceMap.get(key)!;\n itemMap.set(field, embedding);\n }\n }\n }\n\n private getVectors(item: Item): number[][] {\n const namespaceKey = item.namespace.join(\":\");\n const itemKey = item.key;\n if (!this.vectors.has(namespaceKey)) {\n return [];\n }\n const namespaceMap = this.vectors.get(namespaceKey)!;\n if (!namespaceMap.has(itemKey)) {\n return [];\n }\n const itemMap = namespaceMap.get(itemKey)!;\n const vectors = Array.from(itemMap.values());\n if (!vectors.length) {\n return [];\n }\n return vectors;\n }\n\n private cosineSimilarity(X: number[], Y: number[][]): number[] {\n if (!Y.length) return [];\n\n // Calculate dot products for all vectors at once\n const dotProducts = Y.map((vector) =>\n vector.reduce((acc, val, i) => acc + val * X[i], 0)\n );\n\n // Calculate magnitudes\n const magnitude1 = Math.sqrt(X.reduce((acc, val) => acc + val * val, 0));\n const magnitudes2 = Y.map((vector) =>\n Math.sqrt(vector.reduce((acc, val) => acc + val * val, 0))\n );\n\n // Calculate similarities\n return dotProducts.map((dot, i) => {\n const magnitude2 = magnitudes2[i];\n return magnitude1 && magnitude2 ? dot / (magnitude1 * magnitude2) : 0;\n });\n }\n\n public get indexConfig(): IndexConfig | undefined {\n return this._indexConfig;\n }\n}\n\n/** @deprecated Alias for InMemoryStore */\nexport class MemoryStore extends InMemoryStore {}\n"],"mappings":"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"}
|
package/dist/store/utils.cjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
//#region src/store/utils.ts
|
|
3
2
|
/**
|
|
4
3
|
* Tokenize a JSON path into parts.
|
|
@@ -66,23 +65,20 @@ function isFilterOperators(obj) {
|
|
|
66
65
|
* Compare values for filtering, supporting operator-based comparisons.
|
|
67
66
|
*/
|
|
68
67
|
function compareValues(itemValue, filterValue) {
|
|
69
|
-
if (isFilterOperators(filterValue)) {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
});
|
|
85
|
-
}
|
|
68
|
+
if (isFilterOperators(filterValue)) return Object.keys(filterValue).filter((k) => k.startsWith("$")).every((op) => {
|
|
69
|
+
const value = filterValue[op];
|
|
70
|
+
switch (op) {
|
|
71
|
+
case "$eq": return itemValue === value;
|
|
72
|
+
case "$ne": return itemValue !== value;
|
|
73
|
+
case "$gt": return Number(itemValue) > Number(value);
|
|
74
|
+
case "$gte": return Number(itemValue) >= Number(value);
|
|
75
|
+
case "$lt": return Number(itemValue) < Number(value);
|
|
76
|
+
case "$lte": return Number(itemValue) <= Number(value);
|
|
77
|
+
case "$in": return Array.isArray(value) ? value.includes(itemValue) : false;
|
|
78
|
+
case "$nin": return Array.isArray(value) ? !value.includes(itemValue) : true;
|
|
79
|
+
default: return false;
|
|
80
|
+
}
|
|
81
|
+
});
|
|
86
82
|
return itemValue === filterValue;
|
|
87
83
|
}
|
|
88
84
|
/**
|
|
@@ -98,34 +94,34 @@ function compareValues(itemValue, filterValue) {
|
|
|
98
94
|
function getTextAtPath(obj, path) {
|
|
99
95
|
if (!path || path === "$") return [JSON.stringify(obj, null, 2)];
|
|
100
96
|
const tokens = Array.isArray(path) ? path : tokenizePath(path);
|
|
101
|
-
function extractFromObj(obj
|
|
102
|
-
if (pos >= tokens
|
|
103
|
-
if (typeof obj
|
|
104
|
-
if (obj
|
|
105
|
-
if (Array.isArray(obj
|
|
97
|
+
function extractFromObj(obj, tokens, pos) {
|
|
98
|
+
if (pos >= tokens.length) {
|
|
99
|
+
if (typeof obj === "string" || typeof obj === "number" || typeof obj === "boolean") return [String(obj)];
|
|
100
|
+
if (obj === null || obj === void 0) return [];
|
|
101
|
+
if (Array.isArray(obj) || typeof obj === "object") return [JSON.stringify(obj, null, 2)];
|
|
106
102
|
return [];
|
|
107
103
|
}
|
|
108
|
-
const token = tokens
|
|
104
|
+
const token = tokens[pos];
|
|
109
105
|
const results = [];
|
|
110
|
-
if (pos === 0 && token === "$") results.push(JSON.stringify(obj
|
|
106
|
+
if (pos === 0 && token === "$") results.push(JSON.stringify(obj, null, 2));
|
|
111
107
|
if (token.startsWith("[") && token.endsWith("]")) {
|
|
112
|
-
if (!Array.isArray(obj
|
|
108
|
+
if (!Array.isArray(obj)) return [];
|
|
113
109
|
const index = token.slice(1, -1);
|
|
114
|
-
if (index === "*") for (const item of obj
|
|
110
|
+
if (index === "*") for (const item of obj) results.push(...extractFromObj(item, tokens, pos + 1));
|
|
115
111
|
else try {
|
|
116
112
|
let idx = parseInt(index, 10);
|
|
117
|
-
if (idx < 0) idx = obj
|
|
118
|
-
if (idx >= 0 && idx < obj
|
|
113
|
+
if (idx < 0) idx = obj.length + idx;
|
|
114
|
+
if (idx >= 0 && idx < obj.length) results.push(...extractFromObj(obj[idx], tokens, pos + 1));
|
|
119
115
|
} catch {
|
|
120
116
|
return [];
|
|
121
117
|
}
|
|
122
118
|
} else if (token.startsWith("{") && token.endsWith("}")) {
|
|
123
|
-
if (typeof obj
|
|
119
|
+
if (typeof obj !== "object" || obj === null) return [];
|
|
124
120
|
const fields = token.slice(1, -1).split(",").map((f) => f.trim());
|
|
125
121
|
for (const field of fields) {
|
|
126
122
|
const nestedTokens = tokenizePath(field);
|
|
127
123
|
if (nestedTokens.length) {
|
|
128
|
-
let currentObj = obj
|
|
124
|
+
let currentObj = obj;
|
|
129
125
|
for (const nestedToken of nestedTokens) if (currentObj && typeof currentObj === "object" && nestedToken in currentObj) currentObj = currentObj[nestedToken];
|
|
130
126
|
else {
|
|
131
127
|
currentObj = void 0;
|
|
@@ -138,16 +134,16 @@ function getTextAtPath(obj, path) {
|
|
|
138
134
|
}
|
|
139
135
|
}
|
|
140
136
|
} else if (token === "*") {
|
|
141
|
-
if (Array.isArray(obj
|
|
142
|
-
else if (typeof obj
|
|
143
|
-
} else if (typeof obj
|
|
137
|
+
if (Array.isArray(obj)) for (const item of obj) results.push(...extractFromObj(item, tokens, pos + 1));
|
|
138
|
+
else if (typeof obj === "object" && obj !== null) for (const value of Object.values(obj)) results.push(...extractFromObj(value, tokens, pos + 1));
|
|
139
|
+
} else if (typeof obj === "object" && obj !== null && token in obj) results.push(...extractFromObj(obj[token], tokens, pos + 1));
|
|
144
140
|
return results;
|
|
145
141
|
}
|
|
146
142
|
return extractFromObj(obj, tokens, 0);
|
|
147
143
|
}
|
|
148
|
-
|
|
149
144
|
//#endregion
|
|
150
145
|
exports.compareValues = compareValues;
|
|
151
146
|
exports.getTextAtPath = getTextAtPath;
|
|
152
147
|
exports.tokenizePath = tokenizePath;
|
|
148
|
+
|
|
153
149
|
//# sourceMappingURL=utils.cjs.map
|