@agentskit/memory 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # @agentskit/memory
2
+
3
+ Persistent and vector memory backends for [AgentsKit](https://github.com/EmersonBraun/agentskit).
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @agentskit/memory
9
+ ```
10
+
11
+ Then install the backend(s) you need:
12
+
13
+ ```bash
14
+ npm install better-sqlite3 # for sqliteChatMemory
15
+ npm install vectra # for fileVectorMemory (default, pure JS)
16
+ npm install redis # for redisChatMemory / redisVectorMemory
17
+ ```
18
+
19
+ ## Backends
20
+
21
+ | Factory | Contract | Underlying lib | Native? |
22
+ |---------|----------|---------------|---------|
23
+ | `sqliteChatMemory({ path })` | ChatMemory | better-sqlite3 | Yes |
24
+ | `redisChatMemory({ url })` | ChatMemory | redis | No |
25
+ | `redisVectorMemory({ url })` | VectorMemory | redis + RediSearch | No |
26
+ | `fileVectorMemory({ path })` | VectorMemory | vectra | No (pure JS) |
27
+
28
+ ## Quick example
29
+
30
+ ```ts
31
+ import { sqliteChatMemory, fileVectorMemory } from '@agentskit/memory'
32
+
33
+ // Chat persistence
34
+ const chatMemory = sqliteChatMemory({ path: './chat.db' })
35
+
36
+ // Vector search
37
+ const vectorMemory = fileVectorMemory({ path: './vectors' })
38
+ await vectorMemory.store([{
39
+ id: 'doc-1',
40
+ content: 'AgentsKit is awesome',
41
+ embedding: [0.1, 0.2, 0.3, ...],
42
+ }])
43
+ const results = await vectorMemory.search([0.1, 0.2, 0.3, ...], { topK: 5 })
44
+ ```
45
+
46
+ ## Custom vector store
47
+
48
+ Bring your own vector backend (LanceDB, usearch, Pinecone, etc.):
49
+
50
+ ```ts
51
+ import type { VectorStore } from '@agentskit/memory'
52
+
53
+ const myStore: VectorStore = {
54
+ async upsert(docs) { /* your logic */ },
55
+ async query(vector, topK) { /* your logic */ },
56
+ async delete(ids) { /* your logic */ },
57
+ }
58
+
59
+ const memory = fileVectorMemory({ path: './vectors', store: myStore })
60
+ ```
61
+
62
+ ## Docs
63
+
64
+ [Full documentation](https://emersonbraun.github.io/agentskit/)
package/dist/index.cjs ADDED
@@ -0,0 +1,374 @@
1
+ 'use strict';
2
+
3
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
+ }) : x)(function(x) {
6
+ if (typeof require !== "undefined") return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
9
+
10
+ // src/sqlite.ts
11
+ function serializeMessages(messages) {
12
+ const record = {
13
+ version: 1,
14
+ messages: messages.map((m) => ({
15
+ ...m,
16
+ createdAt: m.createdAt.toISOString()
17
+ }))
18
+ };
19
+ return JSON.stringify(record);
20
+ }
21
+ function deserializeMessages(json) {
22
+ if (!json) return [];
23
+ try {
24
+ const record = JSON.parse(json);
25
+ if (!record?.messages) return [];
26
+ return record.messages.map((m) => ({
27
+ ...m,
28
+ createdAt: new Date(m.createdAt)
29
+ }));
30
+ } catch {
31
+ return [];
32
+ }
33
+ }
34
+ async function openDatabase(path) {
35
+ try {
36
+ const mod = await import('better-sqlite3');
37
+ const Database = mod.default ?? mod;
38
+ return new Database(path);
39
+ } catch {
40
+ throw new Error("Install better-sqlite3 to use sqliteChatMemory: npm install better-sqlite3");
41
+ }
42
+ }
43
+ function sqliteChatMemory(config) {
44
+ const conversationId = config.conversationId ?? "default";
45
+ let dbPromise = null;
46
+ const getDb = () => {
47
+ if (!dbPromise) {
48
+ dbPromise = openDatabase(config.path).then((db) => {
49
+ db.prepare(`
50
+ CREATE TABLE IF NOT EXISTS conversations (
51
+ id TEXT PRIMARY KEY,
52
+ messages TEXT NOT NULL
53
+ )
54
+ `).run();
55
+ return db;
56
+ });
57
+ }
58
+ return dbPromise;
59
+ };
60
+ return {
61
+ async load() {
62
+ const db = await getDb();
63
+ const row = db.prepare("SELECT messages FROM conversations WHERE id = ?").get(conversationId);
64
+ return deserializeMessages(row?.messages);
65
+ },
66
+ async save(messages) {
67
+ const db = await getDb();
68
+ const json = serializeMessages(messages);
69
+ db.prepare(`
70
+ INSERT INTO conversations (id, messages) VALUES (?, ?)
71
+ ON CONFLICT(id) DO UPDATE SET messages = ?
72
+ `).run(conversationId, json, json);
73
+ },
74
+ async clear() {
75
+ const db = await getDb();
76
+ db.prepare("DELETE FROM conversations WHERE id = ?").run(conversationId);
77
+ }
78
+ };
79
+ }
80
+
81
+ // src/redis-client.ts
82
+ async function createRedisClientAdapter(url) {
83
+ let redis;
84
+ try {
85
+ redis = await import('redis');
86
+ } catch {
87
+ throw new Error("Install redis to use Redis memory backends: npm install redis");
88
+ }
89
+ const client = redis.createClient({ url });
90
+ await client.connect();
91
+ return {
92
+ async get(key) {
93
+ return await client.get(key);
94
+ },
95
+ async set(key, value) {
96
+ await client.set(key, value);
97
+ },
98
+ async del(key) {
99
+ const keys = Array.isArray(key) ? key : [key];
100
+ if (keys.length > 0) await client.del(keys);
101
+ },
102
+ async keys(pattern) {
103
+ return await client.keys(pattern);
104
+ },
105
+ async disconnect() {
106
+ await client.disconnect();
107
+ },
108
+ async call(command, ...args) {
109
+ return await client.sendCommand([command, ...args.map(String)]);
110
+ }
111
+ };
112
+ }
113
+
114
+ // src/redis-chat.ts
115
+ function serializeMessages2(messages) {
116
+ const record = {
117
+ version: 1,
118
+ messages: messages.map((m) => ({
119
+ ...m,
120
+ createdAt: m.createdAt.toISOString()
121
+ }))
122
+ };
123
+ return JSON.stringify(record);
124
+ }
125
+ function deserializeMessages2(json) {
126
+ if (!json) return [];
127
+ try {
128
+ const record = JSON.parse(json);
129
+ if (!record?.messages) return [];
130
+ return record.messages.map((m) => ({
131
+ ...m,
132
+ createdAt: new Date(m.createdAt)
133
+ }));
134
+ } catch {
135
+ return [];
136
+ }
137
+ }
138
+ function redisChatMemory(config) {
139
+ const prefix = config.keyPrefix ?? "agentskit:chat";
140
+ const convId = config.conversationId ?? "default";
141
+ const key = `${prefix}:${convId}`;
142
+ let clientPromise = null;
143
+ const getClient = () => {
144
+ if (config.client) return Promise.resolve(config.client);
145
+ if (!clientPromise) clientPromise = createRedisClientAdapter(config.url);
146
+ return clientPromise;
147
+ };
148
+ return {
149
+ async load() {
150
+ const client = await getClient();
151
+ const json = await client.get(key);
152
+ return deserializeMessages2(json);
153
+ },
154
+ async save(messages) {
155
+ const client = await getClient();
156
+ await client.set(key, serializeMessages2(messages));
157
+ },
158
+ async clear() {
159
+ const client = await getClient();
160
+ await client.del(key);
161
+ }
162
+ };
163
+ }
164
+
165
+ // src/redis-vector.ts
166
+ function float32Buffer(vector) {
167
+ const buffer = Buffer.alloc(vector.length * 4);
168
+ for (let i = 0; i < vector.length; i++) {
169
+ buffer.writeFloatLE(vector[i], i * 4);
170
+ }
171
+ return buffer;
172
+ }
173
+ function redisVectorMemory(config) {
174
+ const indexName = config.indexName ?? "agentskit:vectors:idx";
175
+ const prefix = config.keyPrefix ?? "agentskit:vec";
176
+ const dimensions = config.dimensions ?? 0;
177
+ let clientPromise = null;
178
+ let indexCreated = false;
179
+ const getClient = () => {
180
+ if (config.client) return Promise.resolve(config.client);
181
+ if (!clientPromise) clientPromise = createRedisClientAdapter(config.url);
182
+ return clientPromise;
183
+ };
184
+ const ensureIndex = async (client, dims) => {
185
+ if (indexCreated) return;
186
+ try {
187
+ await client.call(
188
+ "FT.CREATE",
189
+ indexName,
190
+ "ON",
191
+ "HASH",
192
+ "PREFIX",
193
+ "1",
194
+ `${prefix}:`,
195
+ "SCHEMA",
196
+ "content",
197
+ "TEXT",
198
+ "metadata",
199
+ "TEXT",
200
+ "embedding",
201
+ "VECTOR",
202
+ "HNSW",
203
+ "6",
204
+ "TYPE",
205
+ "FLOAT32",
206
+ "DIM",
207
+ dims,
208
+ "DISTANCE_METRIC",
209
+ "COSINE"
210
+ );
211
+ } catch (err) {
212
+ const msg = String(err);
213
+ if (!msg.includes("Index already exists")) throw err;
214
+ }
215
+ indexCreated = true;
216
+ };
217
+ return {
218
+ async store(docs) {
219
+ const client = await getClient();
220
+ const dims = dimensions || docs[0]?.embedding.length || 0;
221
+ if (dims > 0) await ensureIndex(client, dims);
222
+ for (const doc of docs) {
223
+ const key = `${prefix}:${doc.id}`;
224
+ await client.call(
225
+ "HSET",
226
+ key,
227
+ "content",
228
+ doc.content,
229
+ "metadata",
230
+ JSON.stringify(doc.metadata ?? {}),
231
+ "embedding",
232
+ float32Buffer(doc.embedding)
233
+ );
234
+ }
235
+ },
236
+ async search(embedding, options) {
237
+ const client = await getClient();
238
+ const topK = options?.topK ?? 5;
239
+ const threshold = options?.threshold ?? 0;
240
+ const result = await client.call(
241
+ "FT.SEARCH",
242
+ indexName,
243
+ `*=>[KNN ${topK} @embedding $vec AS score]`,
244
+ "PARAMS",
245
+ "2",
246
+ "vec",
247
+ float32Buffer(embedding),
248
+ "SORTBY",
249
+ "score",
250
+ "RETURN",
251
+ "3",
252
+ "content",
253
+ "metadata",
254
+ "score",
255
+ "DIALECT",
256
+ "2"
257
+ );
258
+ if (!Array.isArray(result) || result.length < 2) return [];
259
+ const docs = [];
260
+ for (let i = 1; i < result.length; i += 2) {
261
+ const key = String(result[i]);
262
+ const fields = result[i + 1];
263
+ if (!Array.isArray(fields)) continue;
264
+ const fieldMap = {};
265
+ for (let j = 0; j < fields.length; j += 2) {
266
+ fieldMap[fields[j]] = fields[j + 1];
267
+ }
268
+ const score = 1 - parseFloat(fieldMap.score ?? "1");
269
+ if (score < threshold) continue;
270
+ docs.push({
271
+ id: key.replace(`${prefix}:`, ""),
272
+ content: fieldMap.content ?? "",
273
+ score,
274
+ metadata: fieldMap.metadata ? JSON.parse(fieldMap.metadata) : void 0
275
+ });
276
+ }
277
+ return docs;
278
+ },
279
+ async delete(ids) {
280
+ const client = await getClient();
281
+ await client.del(ids.map((id) => `${prefix}:${id}`));
282
+ }
283
+ };
284
+ }
285
+
286
+ // src/file-vector.ts
287
+ function requireVectra() {
288
+ try {
289
+ return __require("vectra");
290
+ } catch {
291
+ throw new Error(
292
+ "Install vectra to use fileVectorMemory: npm install vectra"
293
+ );
294
+ }
295
+ }
296
+ function createVectraStore(dirPath) {
297
+ let index = null;
298
+ const getIndex = async () => {
299
+ if (index) return index;
300
+ const { LocalIndex } = requireVectra();
301
+ index = new LocalIndex(dirPath);
302
+ if (!await index.isIndexCreated()) {
303
+ await index.createIndex();
304
+ }
305
+ return index;
306
+ };
307
+ return {
308
+ async upsert(docs) {
309
+ const idx = await getIndex();
310
+ for (const doc of docs) {
311
+ await idx.insertItem({
312
+ vector: doc.vector,
313
+ metadata: { _id: doc.id, ...doc.metadata }
314
+ });
315
+ }
316
+ },
317
+ async query(vector, topK) {
318
+ const idx = await getIndex();
319
+ const results = await idx.queryItems(vector, topK);
320
+ return results.map((r) => ({
321
+ id: String(r.item.metadata._id ?? ""),
322
+ score: r.score,
323
+ metadata: r.item.metadata
324
+ }));
325
+ },
326
+ async delete(ids) {
327
+ const idx = await getIndex();
328
+ const items = await idx.listItems();
329
+ for (const item of items) {
330
+ if (ids.includes(String(item.metadata._id ?? item.id))) {
331
+ await idx.deleteItem(item.id);
332
+ }
333
+ }
334
+ }
335
+ };
336
+ }
337
+ function fileVectorMemory(config) {
338
+ const store = config.store ?? createVectraStore(config.path);
339
+ const contentCache = /* @__PURE__ */ new Map();
340
+ return {
341
+ async store(docs) {
342
+ for (const doc of docs) {
343
+ contentCache.set(doc.id, doc.content);
344
+ }
345
+ await store.upsert(docs.map((doc) => ({
346
+ id: doc.id,
347
+ vector: doc.embedding,
348
+ metadata: { content: doc.content, ...doc.metadata }
349
+ })));
350
+ },
351
+ async search(embedding, options) {
352
+ const topK = options?.topK ?? 5;
353
+ const threshold = options?.threshold ?? 0;
354
+ const results = await store.query(embedding, topK);
355
+ return results.filter((r) => r.score >= threshold).map((r) => ({
356
+ id: r.id,
357
+ content: String(r.metadata.content ?? contentCache.get(r.id) ?? ""),
358
+ score: r.score,
359
+ metadata: r.metadata
360
+ }));
361
+ },
362
+ async delete(ids) {
363
+ for (const id of ids) contentCache.delete(id);
364
+ await store.delete(ids);
365
+ }
366
+ };
367
+ }
368
+
369
+ exports.fileVectorMemory = fileVectorMemory;
370
+ exports.redisChatMemory = redisChatMemory;
371
+ exports.redisVectorMemory = redisVectorMemory;
372
+ exports.sqliteChatMemory = sqliteChatMemory;
373
+ //# sourceMappingURL=index.cjs.map
374
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sqlite.ts","../src/redis-client.ts","../src/redis-chat.ts","../src/redis-vector.ts","../src/file-vector.ts"],"names":["serializeMessages","deserializeMessages"],"mappings":";;;;;;;;;;AAOA,SAAS,kBAAkB,QAAA,EAA6B;AACtD,EAAA,MAAM,MAAA,GAAuB;AAAA,IAC3B,OAAA,EAAS,CAAA;AAAA,IACT,QAAA,EAAU,QAAA,CAAS,GAAA,CAAI,CAAA,CAAA,MAAM;AAAA,MAC3B,GAAG,CAAA;AAAA,MACH,SAAA,EAAW,CAAA,CAAE,SAAA,CAAU,WAAA;AAAY,KACrC,CAAE;AAAA,GACJ;AACA,EAAA,OAAO,IAAA,CAAK,UAAU,MAAM,CAAA;AAC9B;AAEA,SAAS,oBAAoB,IAAA,EAAqC;AAChE,EAAA,IAAI,CAAC,IAAA,EAAM,OAAO,EAAC;AACnB,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAC9B,IAAA,IAAI,CAAC,MAAA,EAAQ,QAAA,EAAU,OAAO,EAAC;AAC/B,IAAA,OAAO,MAAA,CAAO,QAAA,CAAS,GAAA,CAAI,CAAA,CAAA,MAAM;AAAA,MAC/B,GAAG,CAAA;AAAA,MACH,SAAA,EAAW,IAAI,IAAA,CAAK,CAAA,CAAE,SAAS;AAAA,KACjC,CAAE,CAAA;AAAA,EACJ,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAC;AAAA,EACV;AACF;AASA,eAAe,aAAa,IAAA,EAAiC;AAC3D,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAM,OAAO,gBAAgB,CAAA;AACzC,IAAA,MAAM,QAAA,GAAW,IAAI,OAAA,IAAW,GAAA;AAChC,IAAA,OAAO,IAAK,SAAyC,IAAI,CAAA;AAAA,EAC3D,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,MAAM,4EAA4E,CAAA;AAAA,EAC9F;AACF;AAEO,SAAS,iBAAiB,MAAA,EAA4C;AAC3E,EAAA,MAAM,cAAA,GAAiB,OAAO,cAAA,IAAkB,SAAA;AAChD,EAAA,IAAI,SAAA,GAAsC,IAAA;AAE1C,EAAA,MAAM,QAAQ,MAAyB;AACrC,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,SAAA,GAAY,YAAA,CAAa,MAAA,CAAO,IAAI,CAAA,CAAE,KAAK,CAAA,EAAA,KAAM;AAC/C,QAAA,EAAA,CAAG,OAAA,CAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,QAAA,CAKV,EAAE,GAAA,EAAI;AACP,QAAA,OAAO,EAAA;AAAA,MACT,CAAC,CAAA;AAAA,IACH;AACA,IAAA,OAAO,SAAA;AAAA,EACT,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,IAAA,GAAO;AACX,MAAA,MAAM,EAAA,GAAK,MAAM,KAAA,EAAM;AACvB,MAAA,MAAM,MAAM,EAAA,CAAG,OAAA,CAAQ,iDAAiD,CAAA,CAAE,IAAI,cAAc,CAAA;AAC5F,MAAA,OAAO,mBAAA,CAAoB,KAAK,QAA8B,CAAA;AAAA,IAChE,CAAA;AAAA,IACA,MAAM,KAAK,QAAA,EAAU;AACnB,MAAA,MAAM,EAAA,GAAK,MAAM,KAAA,EAAM;AACvB,MAAA,MAAM,IAAA,GAAO,kBAAkB,QAAQ,CAAA;AACvC,MAAA,EAAA,CAAG,OAAA,CAAQ;AAAA;AAAA;AAAA,MAAA,CAGV,CAAA,CAAE,GAAA,CAAI,cAAA,EAAgB,IAAA,EAAM,IAAI,CAAA;AAAA,IACnC,CAAA;AAAA,IACA,MAAM,KAAA,GAAQ;AACZ,MAAA,MAAM,EAAA,GAAK,MAAM,KAAA,EAAM;AACvB,MAAA,EAAA,CAAG,OAAA,CAAQ,wCAAwC,CAAA,CAAE,GAAA,CAAI,cAAc,CAAA;AAAA,IACzE;AAAA,GACF;AACF;;;ACpEA,eAAsB,yBAAyB,GAAA,EAA0C;AACvF,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI;AACF,IAAA,KAAA,GAAQ,MAAM,OAAO,OAAO,CAAA;AAAA,EAC9B,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,MAAM,+DAA+D,CAAA;AAAA,EACjF;AAEA,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,YAAA,CAAa,EAAE,KAAK,CAAA;AACzC,EAAA,MAAM,OAAO,OAAA,EAAQ;AAErB,EAAA,OAAO;AAAA,IACL,MAAM,IAAI,GAAA,EAAK;AACb,MAAA,OAAO,MAAM,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AAAA,IAC7B,CAAA;AAAA,IACA,MAAM,GAAA,CAAI,GAAA,EAAK,KAAA,EAAO;AACpB,MAAA,MAAM,MAAA,CAAO,GAAA,CAAI,GAAA,EAAK,KAAK,CAAA;AAAA,IAC7B,CAAA;AAAA,IACA,MAAM,IAAI,GAAA,EAAK;AACb,MAAA,MAAM,OAAO,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,GAAI,GAAA,GAAM,CAAC,GAAG,CAAA;AAC5C,MAAA,IAAI,KAAK,MAAA,GAAS,CAAA,EAAG,MAAM,MAAA,CAAO,IAAI,IAAI,CAAA;AAAA,IAC5C,CAAA;AAAA,IACA,MAAM,KAAK,OAAA,EAAS;AAClB,MAAA,OAAO,MAAM,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AAAA,IAClC,CAAA;AAAA,IACA,MAAM,UAAA,GAAa;AACjB,MAAA,MAAM,OAAO,UAAA,EAAW;AAAA,IAC1B,CAAA;AAAA,IACA,MAAM,IAAA,CAAK,OAAA,EAAA,GAAY,IAAA,EAAM;AAC3B,MAAA,OAAO,MAAM,MAAA,CAAO,WAAA,CAAY,CAAC,OAAA,EAAS,GAAG,IAAA,CAAK,GAAA,CAAI,MAAM,CAAC,CAAC,CAAA;AAAA,IAChE;AAAA,GACF;AACF;;;AC1CA,SAASA,mBAAkB,QAAA,EAA6B;AACtD,EAAA,MAAM,MAAA,GAAuB;AAAA,IAC3B,OAAA,EAAS,CAAA;AAAA,IACT,QAAA,EAAU,QAAA,CAAS,GAAA,CAAI,CAAA,CAAA,MAAM;AAAA,MAC3B,GAAG,CAAA;AAAA,MACH,SAAA,EAAW,CAAA,CAAE,SAAA,CAAU,WAAA;AAAY,KACrC,CAAE;AAAA,GACJ;AACA,EAAA,OAAO,IAAA,CAAK,UAAU,MAAM,CAAA;AAC9B;AAEA,SAASC,qBAAoB,IAAA,EAAgC;AAC3D,EAAA,IAAI,CAAC,IAAA,EAAM,OAAO,EAAC;AACnB,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAC9B,IAAA,IAAI,CAAC,MAAA,EAAQ,QAAA,EAAU,OAAO,EAAC;AAC/B,IAAA,OAAO,MAAA,CAAO,QAAA,CAAS,GAAA,CAAI,CAAA,CAAA,MAAM;AAAA,MAC/B,GAAG,CAAA;AAAA,MACH,SAAA,EAAW,IAAI,IAAA,CAAK,CAAA,CAAE,SAAS;AAAA,KACjC,CAAE,CAAA;AAAA,EACJ,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAC;AAAA,EACV;AACF;AAEO,SAAS,gBAAgB,MAAA,EAA2C;AACzE,EAAA,MAAM,MAAA,GAAS,OAAO,SAAA,IAAa,gBAAA;AACnC,EAAA,MAAM,MAAA,GAAS,OAAO,cAAA,IAAkB,SAAA;AACxC,EAAA,MAAM,GAAA,GAAM,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA;AAC/B,EAAA,IAAI,aAAA,GAAoD,IAAA;AAExD,EAAA,MAAM,YAAY,MAAmC;AACnD,IAAA,IAAI,OAAO,MAAA,EAAQ,OAAO,OAAA,CAAQ,OAAA,CAAQ,OAAO,MAAM,CAAA;AACvD,IAAA,IAAI,CAAC,aAAA,EAAe,aAAA,GAAgB,wBAAA,CAAyB,OAAO,GAAG,CAAA;AACvE,IAAA,OAAO,aAAA;AAAA,EACT,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,IAAA,GAAO;AACX,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAAU;AAC/B,MAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AACjC,MAAA,OAAOA,qBAAoB,IAAI,CAAA;AAAA,IACjC,CAAA;AAAA,IACA,MAAM,KAAK,QAAA,EAAU;AACnB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAAU;AAC/B,MAAA,MAAM,MAAA,CAAO,GAAA,CAAI,GAAA,EAAKD,kBAAAA,CAAkB,QAAQ,CAAC,CAAA;AAAA,IACnD,CAAA;AAAA,IACA,MAAM,KAAA,GAAQ;AACZ,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAAU;AAC/B,MAAA,MAAM,MAAA,CAAO,IAAI,GAAG,CAAA;AAAA,IACtB;AAAA,GACF;AACF;;;ACnDA,SAAS,cAAc,MAAA,EAA0B;AAC/C,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,SAAS,CAAC,CAAA;AAC7C,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AACtC,IAAA,MAAA,CAAO,YAAA,CAAa,MAAA,CAAO,CAAC,CAAA,EAAG,IAAI,CAAC,CAAA;AAAA,EACtC;AACA,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,kBAAkB,MAAA,EAA+C;AAC/E,EAAA,MAAM,SAAA,GAAY,OAAO,SAAA,IAAa,uBAAA;AACtC,EAAA,MAAM,MAAA,GAAS,OAAO,SAAA,IAAa,eAAA;AACnC,EAAA,MAAM,UAAA,GAAa,OAAO,UAAA,IAAc,CAAA;AACxC,EAAA,IAAI,aAAA,GAAoD,IAAA;AACxD,EAAA,IAAI,YAAA,GAAe,KAAA;AAEnB,EAAA,MAAM,YAAY,MAAmC;AACnD,IAAA,IAAI,OAAO,MAAA,EAAQ,OAAO,OAAA,CAAQ,OAAA,CAAQ,OAAO,MAAM,CAAA;AACvD,IAAA,IAAI,CAAC,aAAA,EAAe,aAAA,GAAgB,wBAAA,CAAyB,OAAO,GAAG,CAAA;AACvE,IAAA,OAAO,aAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,OAAO,MAAA,EAA4B,IAAA,KAAiB;AACtE,IAAA,IAAI,YAAA,EAAc;AAClB,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,CAAO,IAAA;AAAA,QACX,WAAA;AAAA,QAAa,SAAA;AAAA,QACb,IAAA;AAAA,QAAM,MAAA;AAAA,QACN,QAAA;AAAA,QAAU,GAAA;AAAA,QAAK,GAAG,MAAM,CAAA,CAAA,CAAA;AAAA,QACxB,QAAA;AAAA,QACA,SAAA;AAAA,QAAW,MAAA;AAAA,QACX,UAAA;AAAA,QAAY,MAAA;AAAA,QACZ,WAAA;AAAA,QAAa,QAAA;AAAA,QAAU,MAAA;AAAA,QAAQ,GAAA;AAAA,QAC/B,MAAA;AAAA,QAAQ,SAAA;AAAA,QACR,KAAA;AAAA,QAAO,IAAA;AAAA,QACP,iBAAA;AAAA,QAAmB;AAAA,OACrB;AAAA,IACF,SAAS,GAAA,EAAc;AACrB,MAAA,MAAM,GAAA,GAAM,OAAO,GAAG,CAAA;AACtB,MAAA,IAAI,CAAC,GAAA,CAAI,QAAA,CAAS,sBAAsB,GAAG,MAAM,GAAA;AAAA,IACnD;AACA,IAAA,YAAA,GAAe,IAAA;AAAA,EACjB,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,MAAM,IAAA,EAAwB;AAClC,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAAU;AAC/B,MAAA,MAAM,OAAO,UAAA,IAAc,IAAA,CAAK,CAAC,CAAA,EAAG,UAAU,MAAA,IAAU,CAAA;AACxD,MAAA,IAAI,IAAA,GAAO,CAAA,EAAG,MAAM,WAAA,CAAY,QAAQ,IAAI,CAAA;AAE5C,MAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,QAAA,MAAM,GAAA,GAAM,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,IAAI,EAAE,CAAA,CAAA;AAC/B,QAAA,MAAM,MAAA,CAAO,IAAA;AAAA,UACX,MAAA;AAAA,UAAQ,GAAA;AAAA,UACR,SAAA;AAAA,UAAW,GAAA,CAAI,OAAA;AAAA,UACf,UAAA;AAAA,UAAY,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,QAAA,IAAY,EAAE,CAAA;AAAA,UAC7C,WAAA;AAAA,UAAa,aAAA,CAAc,IAAI,SAAS;AAAA,SAC1C;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IACA,MAAM,MAAA,CAAO,SAAA,EAAW,OAAA,EAAS;AAC/B,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAAU;AAC/B,MAAA,MAAM,IAAA,GAAO,SAAS,IAAA,IAAQ,CAAA;AAC9B,MAAA,MAAM,SAAA,GAAY,SAAS,SAAA,IAAa,CAAA;AAExC,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,IAAA;AAAA,QAC1B,WAAA;AAAA,QAAa,SAAA;AAAA,QACb,WAAW,IAAI,CAAA,0BAAA,CAAA;AAAA,QACf,QAAA;AAAA,QAAU,GAAA;AAAA,QAAK,KAAA;AAAA,QAAO,cAAc,SAAS,CAAA;AAAA,QAC7C,QAAA;AAAA,QAAU,OAAA;AAAA,QACV,QAAA;AAAA,QAAU,GAAA;AAAA,QAAK,SAAA;AAAA,QAAW,UAAA;AAAA,QAAY,OAAA;AAAA,QACtC,SAAA;AAAA,QAAW;AAAA,OACb;AAEA,MAAA,IAAI,CAAC,MAAM,OAAA,CAAQ,MAAM,KAAK,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG,OAAO,EAAC;AAEzD,MAAA,MAAM,OAA4B,EAAC;AAEnC,MAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,MAAA,EAAQ,KAAK,CAAA,EAAG;AACzC,QAAA,MAAM,GAAA,GAAM,MAAA,CAAO,MAAA,CAAO,CAAC,CAAC,CAAA;AAC5B,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,CAAA,GAAI,CAAC,CAAA;AAC3B,QAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AAE5B,QAAA,MAAM,WAAmC,EAAC;AAC1C,QAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,MAAA,EAAQ,KAAK,CAAA,EAAG;AACzC,UAAA,QAAA,CAAS,OAAO,CAAC,CAAC,CAAA,GAAI,MAAA,CAAO,IAAI,CAAC,CAAA;AAAA,QACpC;AAEA,QAAA,MAAM,KAAA,GAAQ,CAAA,GAAI,UAAA,CAAW,QAAA,CAAS,SAAS,GAAG,CAAA;AAClD,QAAA,IAAI,QAAQ,SAAA,EAAW;AAEvB,QAAA,IAAA,CAAK,IAAA,CAAK;AAAA,UACR,IAAI,GAAA,CAAI,OAAA,CAAQ,CAAA,EAAG,MAAM,KAAK,EAAE,CAAA;AAAA,UAChC,OAAA,EAAS,SAAS,OAAA,IAAW,EAAA;AAAA,UAC7B,KAAA;AAAA,UACA,UAAU,QAAA,CAAS,QAAA,GAAW,KAAK,KAAA,CAAM,QAAA,CAAS,QAAQ,CAAA,GAAI;AAAA,SAC/D,CAAA;AAAA,MACH;AAEA,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAAA,IACA,MAAM,OAAO,GAAA,EAAK;AAChB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAAU;AAC/B,MAAA,MAAM,MAAA,CAAO,GAAA,CAAI,GAAA,CAAI,GAAA,CAAI,CAAA,EAAA,KAAM,GAAG,MAAM,CAAA,CAAA,EAAI,EAAE,CAAA,CAAE,CAAC,CAAA;AAAA,IACnD;AAAA,GACF;AACF;;;AC3GA,SAAS,aAAA,GAAmE;AAC1E,EAAA,IAAI;AAEF,IAAA,OAAO,UAAQ,QAAQ,CAAA;AAAA,EACzB,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AACF;AAWA,SAAS,kBAAkB,OAAA,EAA8B;AACvD,EAAA,IAAI,KAAA,GAA4B,IAAA;AAEhC,EAAA,MAAM,WAAW,YAAkC;AACjD,IAAA,IAAI,OAAO,OAAO,KAAA;AAClB,IAAA,MAAM,EAAE,UAAA,EAAW,GAAI,aAAA,EAAc;AACrC,IAAA,KAAA,GAAQ,IAAI,WAAW,OAAO,CAAA;AAC9B,IAAA,IAAI,CAAE,MAAM,KAAA,CAAM,cAAA,EAAe,EAAI;AACnC,MAAA,MAAM,MAAM,WAAA,EAAY;AAAA,IAC1B;AACA,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,OAAO,IAAA,EAAM;AACjB,MAAA,MAAM,GAAA,GAAM,MAAM,QAAA,EAAS;AAC3B,MAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,QAAA,MAAM,IAAI,UAAA,CAAW;AAAA,UACnB,QAAQ,GAAA,CAAI,MAAA;AAAA,UACZ,UAAU,EAAE,GAAA,EAAK,IAAI,EAAA,EAAI,GAAG,IAAI,QAAA;AAAS,SAC1C,CAAA;AAAA,MACH;AAAA,IACF,CAAA;AAAA,IACA,MAAM,KAAA,CAAM,MAAA,EAAQ,IAAA,EAAM;AACxB,MAAA,MAAM,GAAA,GAAM,MAAM,QAAA,EAAS;AAC3B,MAAA,MAAM,OAAA,GAAU,MAAM,GAAA,CAAI,UAAA,CAAW,QAAQ,IAAI,CAAA;AACjD,MAAA,OAAO,OAAA,CAAQ,IAAI,CAAA,CAAA,MAAM;AAAA,QACvB,IAAI,MAAA,CAAO,CAAA,CAAE,IAAA,CAAK,QAAA,CAAS,OAAO,EAAE,CAAA;AAAA,QACpC,OAAO,CAAA,CAAE,KAAA;AAAA,QACT,QAAA,EAAU,EAAE,IAAA,CAAK;AAAA,OACnB,CAAE,CAAA;AAAA,IACJ,CAAA;AAAA,IACA,MAAM,OAAO,GAAA,EAAK;AAChB,MAAA,MAAM,GAAA,GAAM,MAAM,QAAA,EAAS;AAC3B,MAAA,MAAM,KAAA,GAAQ,MAAM,GAAA,CAAI,SAAA,EAAU;AAClC,MAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,QAAA,IAAI,GAAA,CAAI,SAAS,MAAA,CAAO,IAAA,CAAK,SAAS,GAAA,IAAO,IAAA,CAAK,EAAE,CAAC,CAAA,EAAG;AACtD,UAAA,MAAM,GAAA,CAAI,UAAA,CAAW,IAAA,CAAK,EAAE,CAAA;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAAA,GACF;AACF;AAEO,SAAS,iBAAiB,MAAA,EAA8C;AAC7E,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,IAAS,iBAAA,CAAkB,OAAO,IAAI,CAAA;AAC3D,EAAA,MAAM,YAAA,uBAAmB,GAAA,EAAoB;AAE7C,EAAA,OAAO;AAAA,IACL,MAAM,MAAM,IAAA,EAAwB;AAClC,MAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,QAAA,YAAA,CAAa,GAAA,CAAI,GAAA,CAAI,EAAA,EAAI,GAAA,CAAI,OAAO,CAAA;AAAA,MACtC;AACA,MAAA,MAAM,KAAA,CAAM,MAAA,CAAO,IAAA,CAAK,GAAA,CAAI,CAAA,GAAA,MAAQ;AAAA,QAClC,IAAI,GAAA,CAAI,EAAA;AAAA,QACR,QAAQ,GAAA,CAAI,SAAA;AAAA,QACZ,UAAU,EAAE,OAAA,EAAS,IAAI,OAAA,EAAS,GAAG,IAAI,QAAA;AAAS,QAClD,CAAC,CAAA;AAAA,IACL,CAAA;AAAA,IACA,MAAM,MAAA,CAAO,SAAA,EAAW,OAAA,EAAS;AAC/B,MAAA,MAAM,IAAA,GAAO,SAAS,IAAA,IAAQ,CAAA;AAC9B,MAAA,MAAM,SAAA,GAAY,SAAS,SAAA,IAAa,CAAA;AACxC,MAAA,MAAM,OAAA,GAAU,MAAM,KAAA,CAAM,KAAA,CAAM,WAAW,IAAI,CAAA;AAEjD,MAAA,OAAO,OAAA,CACJ,OAAO,CAAA,CAAA,KAAK,CAAA,CAAE,SAAS,SAAS,CAAA,CAChC,GAAA,CAAI,CAAC,CAAA,MAA0B;AAAA,QAC9B,IAAI,CAAA,CAAE,EAAA;AAAA,QACN,OAAA,EAAS,MAAA,CAAO,CAAA,CAAE,QAAA,CAAS,OAAA,IAAW,aAAa,GAAA,CAAI,CAAA,CAAE,EAAE,CAAA,IAAK,EAAE,CAAA;AAAA,QAClE,OAAO,CAAA,CAAE,KAAA;AAAA,QACT,UAAU,CAAA,CAAE;AAAA,OACd,CAAE,CAAA;AAAA,IACN,CAAA;AAAA,IACA,MAAM,OAAO,GAAA,EAAK;AAChB,MAAA,KAAA,MAAW,EAAA,IAAM,GAAA,EAAK,YAAA,CAAa,MAAA,CAAO,EAAE,CAAA;AAC5C,MAAA,MAAM,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,IACxB;AAAA,GACF;AACF","file":"index.cjs","sourcesContent":["import type { ChatMemory, Message, MemoryRecord } from '@agentskit/core'\n\nexport interface SqliteChatMemoryConfig {\n path: string\n conversationId?: string\n}\n\nfunction serializeMessages(messages: Message[]): string {\n const record: MemoryRecord = {\n version: 1,\n messages: messages.map(m => ({\n ...m,\n createdAt: m.createdAt.toISOString(),\n })),\n }\n return JSON.stringify(record)\n}\n\nfunction deserializeMessages(json: string | undefined): Message[] {\n if (!json) return []\n try {\n const record = JSON.parse(json) as MemoryRecord\n if (!record?.messages) return []\n return record.messages.map(m => ({\n ...m,\n createdAt: new Date(m.createdAt),\n }))\n } catch {\n return []\n }\n}\n\ninterface SqliteDb {\n prepare(sql: string): {\n run(...args: unknown[]): void\n get(...args: unknown[]): Record<string, unknown> | undefined\n }\n}\n\nasync function openDatabase(path: string): Promise<SqliteDb> {\n try {\n const mod = await import('better-sqlite3')\n const Database = mod.default ?? mod\n return new (Database as new (p: string) => SqliteDb)(path)\n } catch {\n throw new Error('Install better-sqlite3 to use sqliteChatMemory: npm install better-sqlite3')\n }\n}\n\nexport function sqliteChatMemory(config: SqliteChatMemoryConfig): ChatMemory {\n const conversationId = config.conversationId ?? 'default'\n let dbPromise: Promise<SqliteDb> | null = null\n\n const getDb = (): Promise<SqliteDb> => {\n if (!dbPromise) {\n dbPromise = openDatabase(config.path).then(db => {\n db.prepare(`\n CREATE TABLE IF NOT EXISTS conversations (\n id TEXT PRIMARY KEY,\n messages TEXT NOT NULL\n )\n `).run()\n return db\n })\n }\n return dbPromise\n }\n\n return {\n async load() {\n const db = await getDb()\n const row = db.prepare('SELECT messages FROM conversations WHERE id = ?').get(conversationId)\n return deserializeMessages(row?.messages as string | undefined)\n },\n async save(messages) {\n const db = await getDb()\n const json = serializeMessages(messages)\n db.prepare(`\n INSERT INTO conversations (id, messages) VALUES (?, ?)\n ON CONFLICT(id) DO UPDATE SET messages = ?\n `).run(conversationId, json, json)\n },\n async clear() {\n const db = await getDb()\n db.prepare('DELETE FROM conversations WHERE id = ?').run(conversationId)\n },\n }\n}\n","/**\n * Internal Redis client adapter interface.\n * Abstracts the underlying Redis library so it can be swapped\n * (e.g., from `redis` to `ioredis`) without changing consumers.\n */\nexport interface RedisClientAdapter {\n get(key: string): Promise<string | null>\n set(key: string, value: string): Promise<void>\n del(key: string | string[]): Promise<void>\n keys(pattern: string): Promise<string[]>\n disconnect(): Promise<void>\n call(command: string, ...args: (string | number | Buffer)[]): Promise<unknown>\n}\n\nexport interface RedisConnectionConfig {\n url: string\n client?: RedisClientAdapter\n}\n\nexport async function createRedisClientAdapter(url: string): Promise<RedisClientAdapter> {\n let redis: typeof import('redis')\n try {\n redis = await import('redis')\n } catch {\n throw new Error('Install redis to use Redis memory backends: npm install redis')\n }\n\n const client = redis.createClient({ url })\n await client.connect()\n\n return {\n async get(key) {\n return await client.get(key)\n },\n async set(key, value) {\n await client.set(key, value)\n },\n async del(key) {\n const keys = Array.isArray(key) ? key : [key]\n if (keys.length > 0) await client.del(keys)\n },\n async keys(pattern) {\n return await client.keys(pattern)\n },\n async disconnect() {\n await client.disconnect()\n },\n async call(command, ...args) {\n return await client.sendCommand([command, ...args.map(String)])\n },\n }\n}\n","import type { ChatMemory, Message, MemoryRecord } from '@agentskit/core'\nimport type { RedisClientAdapter, RedisConnectionConfig } from './redis-client'\nimport { createRedisClientAdapter } from './redis-client'\n\nexport interface RedisChatMemoryConfig extends RedisConnectionConfig {\n keyPrefix?: string\n conversationId?: string\n}\n\nfunction serializeMessages(messages: Message[]): string {\n const record: MemoryRecord = {\n version: 1,\n messages: messages.map(m => ({\n ...m,\n createdAt: m.createdAt.toISOString(),\n })),\n }\n return JSON.stringify(record)\n}\n\nfunction deserializeMessages(json: string | null): Message[] {\n if (!json) return []\n try {\n const record = JSON.parse(json) as MemoryRecord\n if (!record?.messages) return []\n return record.messages.map(m => ({\n ...m,\n createdAt: new Date(m.createdAt),\n }))\n } catch {\n return []\n }\n}\n\nexport function redisChatMemory(config: RedisChatMemoryConfig): ChatMemory {\n const prefix = config.keyPrefix ?? 'agentskit:chat'\n const convId = config.conversationId ?? 'default'\n const key = `${prefix}:${convId}`\n let clientPromise: Promise<RedisClientAdapter> | null = null\n\n const getClient = (): Promise<RedisClientAdapter> => {\n if (config.client) return Promise.resolve(config.client)\n if (!clientPromise) clientPromise = createRedisClientAdapter(config.url)\n return clientPromise\n }\n\n return {\n async load() {\n const client = await getClient()\n const json = await client.get(key)\n return deserializeMessages(json)\n },\n async save(messages) {\n const client = await getClient()\n await client.set(key, serializeMessages(messages))\n },\n async clear() {\n const client = await getClient()\n await client.del(key)\n },\n }\n}\n","import type { VectorMemory, VectorDocument, RetrievedDocument } from '@agentskit/core'\nimport type { RedisClientAdapter, RedisConnectionConfig } from './redis-client'\nimport { createRedisClientAdapter } from './redis-client'\n\nexport interface RedisVectorMemoryConfig extends RedisConnectionConfig {\n indexName?: string\n keyPrefix?: string\n dimensions?: number\n}\n\nfunction float32Buffer(vector: number[]): Buffer {\n const buffer = Buffer.alloc(vector.length * 4)\n for (let i = 0; i < vector.length; i++) {\n buffer.writeFloatLE(vector[i], i * 4)\n }\n return buffer\n}\n\nexport function redisVectorMemory(config: RedisVectorMemoryConfig): VectorMemory {\n const indexName = config.indexName ?? 'agentskit:vectors:idx'\n const prefix = config.keyPrefix ?? 'agentskit:vec'\n const dimensions = config.dimensions ?? 0\n let clientPromise: Promise<RedisClientAdapter> | null = null\n let indexCreated = false\n\n const getClient = (): Promise<RedisClientAdapter> => {\n if (config.client) return Promise.resolve(config.client)\n if (!clientPromise) clientPromise = createRedisClientAdapter(config.url)\n return clientPromise\n }\n\n const ensureIndex = async (client: RedisClientAdapter, dims: number) => {\n if (indexCreated) return\n try {\n await client.call(\n 'FT.CREATE', indexName,\n 'ON', 'HASH',\n 'PREFIX', '1', `${prefix}:`,\n 'SCHEMA',\n 'content', 'TEXT',\n 'metadata', 'TEXT',\n 'embedding', 'VECTOR', 'HNSW', '6',\n 'TYPE', 'FLOAT32',\n 'DIM', dims,\n 'DISTANCE_METRIC', 'COSINE',\n )\n } catch (err: unknown) {\n const msg = String(err)\n if (!msg.includes('Index already exists')) throw err\n }\n indexCreated = true\n }\n\n return {\n async store(docs: VectorDocument[]) {\n const client = await getClient()\n const dims = dimensions || docs[0]?.embedding.length || 0\n if (dims > 0) await ensureIndex(client, dims)\n\n for (const doc of docs) {\n const key = `${prefix}:${doc.id}`\n await client.call(\n 'HSET', key,\n 'content', doc.content,\n 'metadata', JSON.stringify(doc.metadata ?? {}),\n 'embedding', float32Buffer(doc.embedding),\n )\n }\n },\n async search(embedding, options) {\n const client = await getClient()\n const topK = options?.topK ?? 5\n const threshold = options?.threshold ?? 0\n\n const result = await client.call(\n 'FT.SEARCH', indexName,\n `*=>[KNN ${topK} @embedding $vec AS score]`,\n 'PARAMS', '2', 'vec', float32Buffer(embedding),\n 'SORTBY', 'score',\n 'RETURN', '3', 'content', 'metadata', 'score',\n 'DIALECT', '2',\n ) as unknown[]\n\n if (!Array.isArray(result) || result.length < 2) return []\n\n const docs: RetrievedDocument[] = []\n // FT.SEARCH returns [total, key1, [field, val, ...], key2, [field, val, ...], ...]\n for (let i = 1; i < result.length; i += 2) {\n const key = String(result[i])\n const fields = result[i + 1] as string[]\n if (!Array.isArray(fields)) continue\n\n const fieldMap: Record<string, string> = {}\n for (let j = 0; j < fields.length; j += 2) {\n fieldMap[fields[j]] = fields[j + 1]\n }\n\n const score = 1 - parseFloat(fieldMap.score ?? '1') // COSINE distance → similarity\n if (score < threshold) continue\n\n docs.push({\n id: key.replace(`${prefix}:`, ''),\n content: fieldMap.content ?? '',\n score,\n metadata: fieldMap.metadata ? JSON.parse(fieldMap.metadata) : undefined,\n })\n }\n\n return docs\n },\n async delete(ids) {\n const client = await getClient()\n await client.del(ids.map(id => `${prefix}:${id}`))\n },\n }\n}\n","import type { VectorMemory, VectorDocument, RetrievedDocument } from '@agentskit/core'\nimport type { VectorStore } from './vector-store'\n\nexport interface FileVectorMemoryConfig {\n path: string\n store?: VectorStore\n}\n\nfunction requireVectra(): { LocalIndex: new (path: string) => VectraIndex } {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require('vectra')\n } catch {\n throw new Error(\n 'Install vectra to use fileVectorMemory: npm install vectra'\n )\n }\n}\n\ninterface VectraIndex {\n isIndexCreated(): Promise<boolean>\n createIndex(): Promise<void>\n insertItem(item: { vector: number[]; metadata: Record<string, unknown> }): Promise<unknown>\n queryItems(vector: number[], topK: number): Promise<Array<{ score: number; item: { metadata: Record<string, unknown> } }>>\n listItems(): Promise<Array<{ id: string; metadata: Record<string, unknown> }>>;\n deleteItem(id: string): Promise<void>\n}\n\nfunction createVectraStore(dirPath: string): VectorStore {\n let index: VectraIndex | null = null\n\n const getIndex = async (): Promise<VectraIndex> => {\n if (index) return index\n const { LocalIndex } = requireVectra()\n index = new LocalIndex(dirPath)\n if (!(await index.isIndexCreated())) {\n await index.createIndex()\n }\n return index\n }\n\n return {\n async upsert(docs) {\n const idx = await getIndex()\n for (const doc of docs) {\n await idx.insertItem({\n vector: doc.vector,\n metadata: { _id: doc.id, ...doc.metadata },\n })\n }\n },\n async query(vector, topK) {\n const idx = await getIndex()\n const results = await idx.queryItems(vector, topK)\n return results.map(r => ({\n id: String(r.item.metadata._id ?? ''),\n score: r.score,\n metadata: r.item.metadata,\n }))\n },\n async delete(ids) {\n const idx = await getIndex()\n const items = await idx.listItems()\n for (const item of items) {\n if (ids.includes(String(item.metadata._id ?? item.id))) {\n await idx.deleteItem(item.id)\n }\n }\n },\n }\n}\n\nexport function fileVectorMemory(config: FileVectorMemoryConfig): VectorMemory {\n const store = config.store ?? createVectraStore(config.path)\n const contentCache = new Map<string, string>()\n\n return {\n async store(docs: VectorDocument[]) {\n for (const doc of docs) {\n contentCache.set(doc.id, doc.content)\n }\n await store.upsert(docs.map(doc => ({\n id: doc.id,\n vector: doc.embedding,\n metadata: { content: doc.content, ...doc.metadata },\n })))\n },\n async search(embedding, options) {\n const topK = options?.topK ?? 5\n const threshold = options?.threshold ?? 0\n const results = await store.query(embedding, topK)\n\n return results\n .filter(r => r.score >= threshold)\n .map((r): RetrievedDocument => ({\n id: r.id,\n content: String(r.metadata.content ?? contentCache.get(r.id) ?? ''),\n score: r.score,\n metadata: r.metadata,\n }))\n },\n async delete(ids) {\n for (const id of ids) contentCache.delete(id)\n await store.delete(ids)\n },\n }\n}\n"]}
@@ -0,0 +1,62 @@
1
+ import { ChatMemory, VectorMemory } from '@agentskit/core';
2
+
3
+ interface SqliteChatMemoryConfig {
4
+ path: string;
5
+ conversationId?: string;
6
+ }
7
+ declare function sqliteChatMemory(config: SqliteChatMemoryConfig): ChatMemory;
8
+
9
+ /**
10
+ * Internal Redis client adapter interface.
11
+ * Abstracts the underlying Redis library so it can be swapped
12
+ * (e.g., from `redis` to `ioredis`) without changing consumers.
13
+ */
14
+ interface RedisClientAdapter {
15
+ get(key: string): Promise<string | null>;
16
+ set(key: string, value: string): Promise<void>;
17
+ del(key: string | string[]): Promise<void>;
18
+ keys(pattern: string): Promise<string[]>;
19
+ disconnect(): Promise<void>;
20
+ call(command: string, ...args: (string | number | Buffer)[]): Promise<unknown>;
21
+ }
22
+ interface RedisConnectionConfig {
23
+ url: string;
24
+ client?: RedisClientAdapter;
25
+ }
26
+
27
+ interface RedisChatMemoryConfig extends RedisConnectionConfig {
28
+ keyPrefix?: string;
29
+ conversationId?: string;
30
+ }
31
+ declare function redisChatMemory(config: RedisChatMemoryConfig): ChatMemory;
32
+
33
+ interface RedisVectorMemoryConfig extends RedisConnectionConfig {
34
+ indexName?: string;
35
+ keyPrefix?: string;
36
+ dimensions?: number;
37
+ }
38
+ declare function redisVectorMemory(config: RedisVectorMemoryConfig): VectorMemory;
39
+
40
+ interface VectorStoreDocument {
41
+ id: string;
42
+ vector: number[];
43
+ metadata: Record<string, unknown>;
44
+ }
45
+ interface VectorStoreResult {
46
+ id: string;
47
+ score: number;
48
+ metadata: Record<string, unknown>;
49
+ }
50
+ interface VectorStore {
51
+ upsert(docs: VectorStoreDocument[]): Promise<void>;
52
+ query(vector: number[], topK: number): Promise<VectorStoreResult[]>;
53
+ delete(ids: string[]): Promise<void>;
54
+ }
55
+
56
+ interface FileVectorMemoryConfig {
57
+ path: string;
58
+ store?: VectorStore;
59
+ }
60
+ declare function fileVectorMemory(config: FileVectorMemoryConfig): VectorMemory;
61
+
62
+ export { type FileVectorMemoryConfig, type RedisChatMemoryConfig, type RedisClientAdapter, type RedisConnectionConfig, type RedisVectorMemoryConfig, type SqliteChatMemoryConfig, type VectorStore, type VectorStoreDocument, type VectorStoreResult, fileVectorMemory, redisChatMemory, redisVectorMemory, sqliteChatMemory };
@@ -0,0 +1,62 @@
1
+ import { ChatMemory, VectorMemory } from '@agentskit/core';
2
+
3
+ interface SqliteChatMemoryConfig {
4
+ path: string;
5
+ conversationId?: string;
6
+ }
7
+ declare function sqliteChatMemory(config: SqliteChatMemoryConfig): ChatMemory;
8
+
9
+ /**
10
+ * Internal Redis client adapter interface.
11
+ * Abstracts the underlying Redis library so it can be swapped
12
+ * (e.g., from `redis` to `ioredis`) without changing consumers.
13
+ */
14
+ interface RedisClientAdapter {
15
+ get(key: string): Promise<string | null>;
16
+ set(key: string, value: string): Promise<void>;
17
+ del(key: string | string[]): Promise<void>;
18
+ keys(pattern: string): Promise<string[]>;
19
+ disconnect(): Promise<void>;
20
+ call(command: string, ...args: (string | number | Buffer)[]): Promise<unknown>;
21
+ }
22
+ interface RedisConnectionConfig {
23
+ url: string;
24
+ client?: RedisClientAdapter;
25
+ }
26
+
27
+ interface RedisChatMemoryConfig extends RedisConnectionConfig {
28
+ keyPrefix?: string;
29
+ conversationId?: string;
30
+ }
31
+ declare function redisChatMemory(config: RedisChatMemoryConfig): ChatMemory;
32
+
33
+ interface RedisVectorMemoryConfig extends RedisConnectionConfig {
34
+ indexName?: string;
35
+ keyPrefix?: string;
36
+ dimensions?: number;
37
+ }
38
+ declare function redisVectorMemory(config: RedisVectorMemoryConfig): VectorMemory;
39
+
40
+ interface VectorStoreDocument {
41
+ id: string;
42
+ vector: number[];
43
+ metadata: Record<string, unknown>;
44
+ }
45
+ interface VectorStoreResult {
46
+ id: string;
47
+ score: number;
48
+ metadata: Record<string, unknown>;
49
+ }
50
+ interface VectorStore {
51
+ upsert(docs: VectorStoreDocument[]): Promise<void>;
52
+ query(vector: number[], topK: number): Promise<VectorStoreResult[]>;
53
+ delete(ids: string[]): Promise<void>;
54
+ }
55
+
56
+ interface FileVectorMemoryConfig {
57
+ path: string;
58
+ store?: VectorStore;
59
+ }
60
+ declare function fileVectorMemory(config: FileVectorMemoryConfig): VectorMemory;
61
+
62
+ export { type FileVectorMemoryConfig, type RedisChatMemoryConfig, type RedisClientAdapter, type RedisConnectionConfig, type RedisVectorMemoryConfig, type SqliteChatMemoryConfig, type VectorStore, type VectorStoreDocument, type VectorStoreResult, fileVectorMemory, redisChatMemory, redisVectorMemory, sqliteChatMemory };
package/dist/index.js ADDED
@@ -0,0 +1,369 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/sqlite.ts
9
+ function serializeMessages(messages) {
10
+ const record = {
11
+ version: 1,
12
+ messages: messages.map((m) => ({
13
+ ...m,
14
+ createdAt: m.createdAt.toISOString()
15
+ }))
16
+ };
17
+ return JSON.stringify(record);
18
+ }
19
+ function deserializeMessages(json) {
20
+ if (!json) return [];
21
+ try {
22
+ const record = JSON.parse(json);
23
+ if (!record?.messages) return [];
24
+ return record.messages.map((m) => ({
25
+ ...m,
26
+ createdAt: new Date(m.createdAt)
27
+ }));
28
+ } catch {
29
+ return [];
30
+ }
31
+ }
32
+ async function openDatabase(path) {
33
+ try {
34
+ const mod = await import('better-sqlite3');
35
+ const Database = mod.default ?? mod;
36
+ return new Database(path);
37
+ } catch {
38
+ throw new Error("Install better-sqlite3 to use sqliteChatMemory: npm install better-sqlite3");
39
+ }
40
+ }
41
+ function sqliteChatMemory(config) {
42
+ const conversationId = config.conversationId ?? "default";
43
+ let dbPromise = null;
44
+ const getDb = () => {
45
+ if (!dbPromise) {
46
+ dbPromise = openDatabase(config.path).then((db) => {
47
+ db.prepare(`
48
+ CREATE TABLE IF NOT EXISTS conversations (
49
+ id TEXT PRIMARY KEY,
50
+ messages TEXT NOT NULL
51
+ )
52
+ `).run();
53
+ return db;
54
+ });
55
+ }
56
+ return dbPromise;
57
+ };
58
+ return {
59
+ async load() {
60
+ const db = await getDb();
61
+ const row = db.prepare("SELECT messages FROM conversations WHERE id = ?").get(conversationId);
62
+ return deserializeMessages(row?.messages);
63
+ },
64
+ async save(messages) {
65
+ const db = await getDb();
66
+ const json = serializeMessages(messages);
67
+ db.prepare(`
68
+ INSERT INTO conversations (id, messages) VALUES (?, ?)
69
+ ON CONFLICT(id) DO UPDATE SET messages = ?
70
+ `).run(conversationId, json, json);
71
+ },
72
+ async clear() {
73
+ const db = await getDb();
74
+ db.prepare("DELETE FROM conversations WHERE id = ?").run(conversationId);
75
+ }
76
+ };
77
+ }
78
+
79
+ // src/redis-client.ts
80
+ async function createRedisClientAdapter(url) {
81
+ let redis;
82
+ try {
83
+ redis = await import('redis');
84
+ } catch {
85
+ throw new Error("Install redis to use Redis memory backends: npm install redis");
86
+ }
87
+ const client = redis.createClient({ url });
88
+ await client.connect();
89
+ return {
90
+ async get(key) {
91
+ return await client.get(key);
92
+ },
93
+ async set(key, value) {
94
+ await client.set(key, value);
95
+ },
96
+ async del(key) {
97
+ const keys = Array.isArray(key) ? key : [key];
98
+ if (keys.length > 0) await client.del(keys);
99
+ },
100
+ async keys(pattern) {
101
+ return await client.keys(pattern);
102
+ },
103
+ async disconnect() {
104
+ await client.disconnect();
105
+ },
106
+ async call(command, ...args) {
107
+ return await client.sendCommand([command, ...args.map(String)]);
108
+ }
109
+ };
110
+ }
111
+
112
+ // src/redis-chat.ts
113
+ function serializeMessages2(messages) {
114
+ const record = {
115
+ version: 1,
116
+ messages: messages.map((m) => ({
117
+ ...m,
118
+ createdAt: m.createdAt.toISOString()
119
+ }))
120
+ };
121
+ return JSON.stringify(record);
122
+ }
123
+ function deserializeMessages2(json) {
124
+ if (!json) return [];
125
+ try {
126
+ const record = JSON.parse(json);
127
+ if (!record?.messages) return [];
128
+ return record.messages.map((m) => ({
129
+ ...m,
130
+ createdAt: new Date(m.createdAt)
131
+ }));
132
+ } catch {
133
+ return [];
134
+ }
135
+ }
136
+ function redisChatMemory(config) {
137
+ const prefix = config.keyPrefix ?? "agentskit:chat";
138
+ const convId = config.conversationId ?? "default";
139
+ const key = `${prefix}:${convId}`;
140
+ let clientPromise = null;
141
+ const getClient = () => {
142
+ if (config.client) return Promise.resolve(config.client);
143
+ if (!clientPromise) clientPromise = createRedisClientAdapter(config.url);
144
+ return clientPromise;
145
+ };
146
+ return {
147
+ async load() {
148
+ const client = await getClient();
149
+ const json = await client.get(key);
150
+ return deserializeMessages2(json);
151
+ },
152
+ async save(messages) {
153
+ const client = await getClient();
154
+ await client.set(key, serializeMessages2(messages));
155
+ },
156
+ async clear() {
157
+ const client = await getClient();
158
+ await client.del(key);
159
+ }
160
+ };
161
+ }
162
+
163
+ // src/redis-vector.ts
164
+ function float32Buffer(vector) {
165
+ const buffer = Buffer.alloc(vector.length * 4);
166
+ for (let i = 0; i < vector.length; i++) {
167
+ buffer.writeFloatLE(vector[i], i * 4);
168
+ }
169
+ return buffer;
170
+ }
171
+ function redisVectorMemory(config) {
172
+ const indexName = config.indexName ?? "agentskit:vectors:idx";
173
+ const prefix = config.keyPrefix ?? "agentskit:vec";
174
+ const dimensions = config.dimensions ?? 0;
175
+ let clientPromise = null;
176
+ let indexCreated = false;
177
+ const getClient = () => {
178
+ if (config.client) return Promise.resolve(config.client);
179
+ if (!clientPromise) clientPromise = createRedisClientAdapter(config.url);
180
+ return clientPromise;
181
+ };
182
+ const ensureIndex = async (client, dims) => {
183
+ if (indexCreated) return;
184
+ try {
185
+ await client.call(
186
+ "FT.CREATE",
187
+ indexName,
188
+ "ON",
189
+ "HASH",
190
+ "PREFIX",
191
+ "1",
192
+ `${prefix}:`,
193
+ "SCHEMA",
194
+ "content",
195
+ "TEXT",
196
+ "metadata",
197
+ "TEXT",
198
+ "embedding",
199
+ "VECTOR",
200
+ "HNSW",
201
+ "6",
202
+ "TYPE",
203
+ "FLOAT32",
204
+ "DIM",
205
+ dims,
206
+ "DISTANCE_METRIC",
207
+ "COSINE"
208
+ );
209
+ } catch (err) {
210
+ const msg = String(err);
211
+ if (!msg.includes("Index already exists")) throw err;
212
+ }
213
+ indexCreated = true;
214
+ };
215
+ return {
216
+ async store(docs) {
217
+ const client = await getClient();
218
+ const dims = dimensions || docs[0]?.embedding.length || 0;
219
+ if (dims > 0) await ensureIndex(client, dims);
220
+ for (const doc of docs) {
221
+ const key = `${prefix}:${doc.id}`;
222
+ await client.call(
223
+ "HSET",
224
+ key,
225
+ "content",
226
+ doc.content,
227
+ "metadata",
228
+ JSON.stringify(doc.metadata ?? {}),
229
+ "embedding",
230
+ float32Buffer(doc.embedding)
231
+ );
232
+ }
233
+ },
234
+ async search(embedding, options) {
235
+ const client = await getClient();
236
+ const topK = options?.topK ?? 5;
237
+ const threshold = options?.threshold ?? 0;
238
+ const result = await client.call(
239
+ "FT.SEARCH",
240
+ indexName,
241
+ `*=>[KNN ${topK} @embedding $vec AS score]`,
242
+ "PARAMS",
243
+ "2",
244
+ "vec",
245
+ float32Buffer(embedding),
246
+ "SORTBY",
247
+ "score",
248
+ "RETURN",
249
+ "3",
250
+ "content",
251
+ "metadata",
252
+ "score",
253
+ "DIALECT",
254
+ "2"
255
+ );
256
+ if (!Array.isArray(result) || result.length < 2) return [];
257
+ const docs = [];
258
+ for (let i = 1; i < result.length; i += 2) {
259
+ const key = String(result[i]);
260
+ const fields = result[i + 1];
261
+ if (!Array.isArray(fields)) continue;
262
+ const fieldMap = {};
263
+ for (let j = 0; j < fields.length; j += 2) {
264
+ fieldMap[fields[j]] = fields[j + 1];
265
+ }
266
+ const score = 1 - parseFloat(fieldMap.score ?? "1");
267
+ if (score < threshold) continue;
268
+ docs.push({
269
+ id: key.replace(`${prefix}:`, ""),
270
+ content: fieldMap.content ?? "",
271
+ score,
272
+ metadata: fieldMap.metadata ? JSON.parse(fieldMap.metadata) : void 0
273
+ });
274
+ }
275
+ return docs;
276
+ },
277
+ async delete(ids) {
278
+ const client = await getClient();
279
+ await client.del(ids.map((id) => `${prefix}:${id}`));
280
+ }
281
+ };
282
+ }
283
+
284
+ // src/file-vector.ts
285
+ function requireVectra() {
286
+ try {
287
+ return __require("vectra");
288
+ } catch {
289
+ throw new Error(
290
+ "Install vectra to use fileVectorMemory: npm install vectra"
291
+ );
292
+ }
293
+ }
294
+ function createVectraStore(dirPath) {
295
+ let index = null;
296
+ const getIndex = async () => {
297
+ if (index) return index;
298
+ const { LocalIndex } = requireVectra();
299
+ index = new LocalIndex(dirPath);
300
+ if (!await index.isIndexCreated()) {
301
+ await index.createIndex();
302
+ }
303
+ return index;
304
+ };
305
+ return {
306
+ async upsert(docs) {
307
+ const idx = await getIndex();
308
+ for (const doc of docs) {
309
+ await idx.insertItem({
310
+ vector: doc.vector,
311
+ metadata: { _id: doc.id, ...doc.metadata }
312
+ });
313
+ }
314
+ },
315
+ async query(vector, topK) {
316
+ const idx = await getIndex();
317
+ const results = await idx.queryItems(vector, topK);
318
+ return results.map((r) => ({
319
+ id: String(r.item.metadata._id ?? ""),
320
+ score: r.score,
321
+ metadata: r.item.metadata
322
+ }));
323
+ },
324
+ async delete(ids) {
325
+ const idx = await getIndex();
326
+ const items = await idx.listItems();
327
+ for (const item of items) {
328
+ if (ids.includes(String(item.metadata._id ?? item.id))) {
329
+ await idx.deleteItem(item.id);
330
+ }
331
+ }
332
+ }
333
+ };
334
+ }
335
+ function fileVectorMemory(config) {
336
+ const store = config.store ?? createVectraStore(config.path);
337
+ const contentCache = /* @__PURE__ */ new Map();
338
+ return {
339
+ async store(docs) {
340
+ for (const doc of docs) {
341
+ contentCache.set(doc.id, doc.content);
342
+ }
343
+ await store.upsert(docs.map((doc) => ({
344
+ id: doc.id,
345
+ vector: doc.embedding,
346
+ metadata: { content: doc.content, ...doc.metadata }
347
+ })));
348
+ },
349
+ async search(embedding, options) {
350
+ const topK = options?.topK ?? 5;
351
+ const threshold = options?.threshold ?? 0;
352
+ const results = await store.query(embedding, topK);
353
+ return results.filter((r) => r.score >= threshold).map((r) => ({
354
+ id: r.id,
355
+ content: String(r.metadata.content ?? contentCache.get(r.id) ?? ""),
356
+ score: r.score,
357
+ metadata: r.metadata
358
+ }));
359
+ },
360
+ async delete(ids) {
361
+ for (const id of ids) contentCache.delete(id);
362
+ await store.delete(ids);
363
+ }
364
+ };
365
+ }
366
+
367
+ export { fileVectorMemory, redisChatMemory, redisVectorMemory, sqliteChatMemory };
368
+ //# sourceMappingURL=index.js.map
369
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/sqlite.ts","../src/redis-client.ts","../src/redis-chat.ts","../src/redis-vector.ts","../src/file-vector.ts"],"names":["serializeMessages","deserializeMessages"],"mappings":";;;;;;;;AAOA,SAAS,kBAAkB,QAAA,EAA6B;AACtD,EAAA,MAAM,MAAA,GAAuB;AAAA,IAC3B,OAAA,EAAS,CAAA;AAAA,IACT,QAAA,EAAU,QAAA,CAAS,GAAA,CAAI,CAAA,CAAA,MAAM;AAAA,MAC3B,GAAG,CAAA;AAAA,MACH,SAAA,EAAW,CAAA,CAAE,SAAA,CAAU,WAAA;AAAY,KACrC,CAAE;AAAA,GACJ;AACA,EAAA,OAAO,IAAA,CAAK,UAAU,MAAM,CAAA;AAC9B;AAEA,SAAS,oBAAoB,IAAA,EAAqC;AAChE,EAAA,IAAI,CAAC,IAAA,EAAM,OAAO,EAAC;AACnB,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAC9B,IAAA,IAAI,CAAC,MAAA,EAAQ,QAAA,EAAU,OAAO,EAAC;AAC/B,IAAA,OAAO,MAAA,CAAO,QAAA,CAAS,GAAA,CAAI,CAAA,CAAA,MAAM;AAAA,MAC/B,GAAG,CAAA;AAAA,MACH,SAAA,EAAW,IAAI,IAAA,CAAK,CAAA,CAAE,SAAS;AAAA,KACjC,CAAE,CAAA;AAAA,EACJ,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAC;AAAA,EACV;AACF;AASA,eAAe,aAAa,IAAA,EAAiC;AAC3D,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAM,OAAO,gBAAgB,CAAA;AACzC,IAAA,MAAM,QAAA,GAAW,IAAI,OAAA,IAAW,GAAA;AAChC,IAAA,OAAO,IAAK,SAAyC,IAAI,CAAA;AAAA,EAC3D,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,MAAM,4EAA4E,CAAA;AAAA,EAC9F;AACF;AAEO,SAAS,iBAAiB,MAAA,EAA4C;AAC3E,EAAA,MAAM,cAAA,GAAiB,OAAO,cAAA,IAAkB,SAAA;AAChD,EAAA,IAAI,SAAA,GAAsC,IAAA;AAE1C,EAAA,MAAM,QAAQ,MAAyB;AACrC,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA,SAAA,GAAY,YAAA,CAAa,MAAA,CAAO,IAAI,CAAA,CAAE,KAAK,CAAA,EAAA,KAAM;AAC/C,QAAA,EAAA,CAAG,OAAA,CAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,QAAA,CAKV,EAAE,GAAA,EAAI;AACP,QAAA,OAAO,EAAA;AAAA,MACT,CAAC,CAAA;AAAA,IACH;AACA,IAAA,OAAO,SAAA;AAAA,EACT,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,IAAA,GAAO;AACX,MAAA,MAAM,EAAA,GAAK,MAAM,KAAA,EAAM;AACvB,MAAA,MAAM,MAAM,EAAA,CAAG,OAAA,CAAQ,iDAAiD,CAAA,CAAE,IAAI,cAAc,CAAA;AAC5F,MAAA,OAAO,mBAAA,CAAoB,KAAK,QAA8B,CAAA;AAAA,IAChE,CAAA;AAAA,IACA,MAAM,KAAK,QAAA,EAAU;AACnB,MAAA,MAAM,EAAA,GAAK,MAAM,KAAA,EAAM;AACvB,MAAA,MAAM,IAAA,GAAO,kBAAkB,QAAQ,CAAA;AACvC,MAAA,EAAA,CAAG,OAAA,CAAQ;AAAA;AAAA;AAAA,MAAA,CAGV,CAAA,CAAE,GAAA,CAAI,cAAA,EAAgB,IAAA,EAAM,IAAI,CAAA;AAAA,IACnC,CAAA;AAAA,IACA,MAAM,KAAA,GAAQ;AACZ,MAAA,MAAM,EAAA,GAAK,MAAM,KAAA,EAAM;AACvB,MAAA,EAAA,CAAG,OAAA,CAAQ,wCAAwC,CAAA,CAAE,GAAA,CAAI,cAAc,CAAA;AAAA,IACzE;AAAA,GACF;AACF;;;ACpEA,eAAsB,yBAAyB,GAAA,EAA0C;AACvF,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI;AACF,IAAA,KAAA,GAAQ,MAAM,OAAO,OAAO,CAAA;AAAA,EAC9B,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,MAAM,+DAA+D,CAAA;AAAA,EACjF;AAEA,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,YAAA,CAAa,EAAE,KAAK,CAAA;AACzC,EAAA,MAAM,OAAO,OAAA,EAAQ;AAErB,EAAA,OAAO;AAAA,IACL,MAAM,IAAI,GAAA,EAAK;AACb,MAAA,OAAO,MAAM,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AAAA,IAC7B,CAAA;AAAA,IACA,MAAM,GAAA,CAAI,GAAA,EAAK,KAAA,EAAO;AACpB,MAAA,MAAM,MAAA,CAAO,GAAA,CAAI,GAAA,EAAK,KAAK,CAAA;AAAA,IAC7B,CAAA;AAAA,IACA,MAAM,IAAI,GAAA,EAAK;AACb,MAAA,MAAM,OAAO,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,GAAI,GAAA,GAAM,CAAC,GAAG,CAAA;AAC5C,MAAA,IAAI,KAAK,MAAA,GAAS,CAAA,EAAG,MAAM,MAAA,CAAO,IAAI,IAAI,CAAA;AAAA,IAC5C,CAAA;AAAA,IACA,MAAM,KAAK,OAAA,EAAS;AAClB,MAAA,OAAO,MAAM,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AAAA,IAClC,CAAA;AAAA,IACA,MAAM,UAAA,GAAa;AACjB,MAAA,MAAM,OAAO,UAAA,EAAW;AAAA,IAC1B,CAAA;AAAA,IACA,MAAM,IAAA,CAAK,OAAA,EAAA,GAAY,IAAA,EAAM;AAC3B,MAAA,OAAO,MAAM,MAAA,CAAO,WAAA,CAAY,CAAC,OAAA,EAAS,GAAG,IAAA,CAAK,GAAA,CAAI,MAAM,CAAC,CAAC,CAAA;AAAA,IAChE;AAAA,GACF;AACF;;;AC1CA,SAASA,mBAAkB,QAAA,EAA6B;AACtD,EAAA,MAAM,MAAA,GAAuB;AAAA,IAC3B,OAAA,EAAS,CAAA;AAAA,IACT,QAAA,EAAU,QAAA,CAAS,GAAA,CAAI,CAAA,CAAA,MAAM;AAAA,MAC3B,GAAG,CAAA;AAAA,MACH,SAAA,EAAW,CAAA,CAAE,SAAA,CAAU,WAAA;AAAY,KACrC,CAAE;AAAA,GACJ;AACA,EAAA,OAAO,IAAA,CAAK,UAAU,MAAM,CAAA;AAC9B;AAEA,SAASC,qBAAoB,IAAA,EAAgC;AAC3D,EAAA,IAAI,CAAC,IAAA,EAAM,OAAO,EAAC;AACnB,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAC9B,IAAA,IAAI,CAAC,MAAA,EAAQ,QAAA,EAAU,OAAO,EAAC;AAC/B,IAAA,OAAO,MAAA,CAAO,QAAA,CAAS,GAAA,CAAI,CAAA,CAAA,MAAM;AAAA,MAC/B,GAAG,CAAA;AAAA,MACH,SAAA,EAAW,IAAI,IAAA,CAAK,CAAA,CAAE,SAAS;AAAA,KACjC,CAAE,CAAA;AAAA,EACJ,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAC;AAAA,EACV;AACF;AAEO,SAAS,gBAAgB,MAAA,EAA2C;AACzE,EAAA,MAAM,MAAA,GAAS,OAAO,SAAA,IAAa,gBAAA;AACnC,EAAA,MAAM,MAAA,GAAS,OAAO,cAAA,IAAkB,SAAA;AACxC,EAAA,MAAM,GAAA,GAAM,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA;AAC/B,EAAA,IAAI,aAAA,GAAoD,IAAA;AAExD,EAAA,MAAM,YAAY,MAAmC;AACnD,IAAA,IAAI,OAAO,MAAA,EAAQ,OAAO,OAAA,CAAQ,OAAA,CAAQ,OAAO,MAAM,CAAA;AACvD,IAAA,IAAI,CAAC,aAAA,EAAe,aAAA,GAAgB,wBAAA,CAAyB,OAAO,GAAG,CAAA;AACvE,IAAA,OAAO,aAAA;AAAA,EACT,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,IAAA,GAAO;AACX,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAAU;AAC/B,MAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AACjC,MAAA,OAAOA,qBAAoB,IAAI,CAAA;AAAA,IACjC,CAAA;AAAA,IACA,MAAM,KAAK,QAAA,EAAU;AACnB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAAU;AAC/B,MAAA,MAAM,MAAA,CAAO,GAAA,CAAI,GAAA,EAAKD,kBAAAA,CAAkB,QAAQ,CAAC,CAAA;AAAA,IACnD,CAAA;AAAA,IACA,MAAM,KAAA,GAAQ;AACZ,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAAU;AAC/B,MAAA,MAAM,MAAA,CAAO,IAAI,GAAG,CAAA;AAAA,IACtB;AAAA,GACF;AACF;;;ACnDA,SAAS,cAAc,MAAA,EAA0B;AAC/C,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,SAAS,CAAC,CAAA;AAC7C,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AACtC,IAAA,MAAA,CAAO,YAAA,CAAa,MAAA,CAAO,CAAC,CAAA,EAAG,IAAI,CAAC,CAAA;AAAA,EACtC;AACA,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,kBAAkB,MAAA,EAA+C;AAC/E,EAAA,MAAM,SAAA,GAAY,OAAO,SAAA,IAAa,uBAAA;AACtC,EAAA,MAAM,MAAA,GAAS,OAAO,SAAA,IAAa,eAAA;AACnC,EAAA,MAAM,UAAA,GAAa,OAAO,UAAA,IAAc,CAAA;AACxC,EAAA,IAAI,aAAA,GAAoD,IAAA;AACxD,EAAA,IAAI,YAAA,GAAe,KAAA;AAEnB,EAAA,MAAM,YAAY,MAAmC;AACnD,IAAA,IAAI,OAAO,MAAA,EAAQ,OAAO,OAAA,CAAQ,OAAA,CAAQ,OAAO,MAAM,CAAA;AACvD,IAAA,IAAI,CAAC,aAAA,EAAe,aAAA,GAAgB,wBAAA,CAAyB,OAAO,GAAG,CAAA;AACvE,IAAA,OAAO,aAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,OAAO,MAAA,EAA4B,IAAA,KAAiB;AACtE,IAAA,IAAI,YAAA,EAAc;AAClB,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,CAAO,IAAA;AAAA,QACX,WAAA;AAAA,QAAa,SAAA;AAAA,QACb,IAAA;AAAA,QAAM,MAAA;AAAA,QACN,QAAA;AAAA,QAAU,GAAA;AAAA,QAAK,GAAG,MAAM,CAAA,CAAA,CAAA;AAAA,QACxB,QAAA;AAAA,QACA,SAAA;AAAA,QAAW,MAAA;AAAA,QACX,UAAA;AAAA,QAAY,MAAA;AAAA,QACZ,WAAA;AAAA,QAAa,QAAA;AAAA,QAAU,MAAA;AAAA,QAAQ,GAAA;AAAA,QAC/B,MAAA;AAAA,QAAQ,SAAA;AAAA,QACR,KAAA;AAAA,QAAO,IAAA;AAAA,QACP,iBAAA;AAAA,QAAmB;AAAA,OACrB;AAAA,IACF,SAAS,GAAA,EAAc;AACrB,MAAA,MAAM,GAAA,GAAM,OAAO,GAAG,CAAA;AACtB,MAAA,IAAI,CAAC,GAAA,CAAI,QAAA,CAAS,sBAAsB,GAAG,MAAM,GAAA;AAAA,IACnD;AACA,IAAA,YAAA,GAAe,IAAA;AAAA,EACjB,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,MAAM,IAAA,EAAwB;AAClC,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAAU;AAC/B,MAAA,MAAM,OAAO,UAAA,IAAc,IAAA,CAAK,CAAC,CAAA,EAAG,UAAU,MAAA,IAAU,CAAA;AACxD,MAAA,IAAI,IAAA,GAAO,CAAA,EAAG,MAAM,WAAA,CAAY,QAAQ,IAAI,CAAA;AAE5C,MAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,QAAA,MAAM,GAAA,GAAM,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,IAAI,EAAE,CAAA,CAAA;AAC/B,QAAA,MAAM,MAAA,CAAO,IAAA;AAAA,UACX,MAAA;AAAA,UAAQ,GAAA;AAAA,UACR,SAAA;AAAA,UAAW,GAAA,CAAI,OAAA;AAAA,UACf,UAAA;AAAA,UAAY,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,QAAA,IAAY,EAAE,CAAA;AAAA,UAC7C,WAAA;AAAA,UAAa,aAAA,CAAc,IAAI,SAAS;AAAA,SAC1C;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IACA,MAAM,MAAA,CAAO,SAAA,EAAW,OAAA,EAAS;AAC/B,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAAU;AAC/B,MAAA,MAAM,IAAA,GAAO,SAAS,IAAA,IAAQ,CAAA;AAC9B,MAAA,MAAM,SAAA,GAAY,SAAS,SAAA,IAAa,CAAA;AAExC,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,IAAA;AAAA,QAC1B,WAAA;AAAA,QAAa,SAAA;AAAA,QACb,WAAW,IAAI,CAAA,0BAAA,CAAA;AAAA,QACf,QAAA;AAAA,QAAU,GAAA;AAAA,QAAK,KAAA;AAAA,QAAO,cAAc,SAAS,CAAA;AAAA,QAC7C,QAAA;AAAA,QAAU,OAAA;AAAA,QACV,QAAA;AAAA,QAAU,GAAA;AAAA,QAAK,SAAA;AAAA,QAAW,UAAA;AAAA,QAAY,OAAA;AAAA,QACtC,SAAA;AAAA,QAAW;AAAA,OACb;AAEA,MAAA,IAAI,CAAC,MAAM,OAAA,CAAQ,MAAM,KAAK,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG,OAAO,EAAC;AAEzD,MAAA,MAAM,OAA4B,EAAC;AAEnC,MAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,MAAA,EAAQ,KAAK,CAAA,EAAG;AACzC,QAAA,MAAM,GAAA,GAAM,MAAA,CAAO,MAAA,CAAO,CAAC,CAAC,CAAA;AAC5B,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,CAAA,GAAI,CAAC,CAAA;AAC3B,QAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AAE5B,QAAA,MAAM,WAAmC,EAAC;AAC1C,QAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,MAAA,EAAQ,KAAK,CAAA,EAAG;AACzC,UAAA,QAAA,CAAS,OAAO,CAAC,CAAC,CAAA,GAAI,MAAA,CAAO,IAAI,CAAC,CAAA;AAAA,QACpC;AAEA,QAAA,MAAM,KAAA,GAAQ,CAAA,GAAI,UAAA,CAAW,QAAA,CAAS,SAAS,GAAG,CAAA;AAClD,QAAA,IAAI,QAAQ,SAAA,EAAW;AAEvB,QAAA,IAAA,CAAK,IAAA,CAAK;AAAA,UACR,IAAI,GAAA,CAAI,OAAA,CAAQ,CAAA,EAAG,MAAM,KAAK,EAAE,CAAA;AAAA,UAChC,OAAA,EAAS,SAAS,OAAA,IAAW,EAAA;AAAA,UAC7B,KAAA;AAAA,UACA,UAAU,QAAA,CAAS,QAAA,GAAW,KAAK,KAAA,CAAM,QAAA,CAAS,QAAQ,CAAA,GAAI;AAAA,SAC/D,CAAA;AAAA,MACH;AAEA,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAAA,IACA,MAAM,OAAO,GAAA,EAAK;AAChB,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAAU;AAC/B,MAAA,MAAM,MAAA,CAAO,GAAA,CAAI,GAAA,CAAI,GAAA,CAAI,CAAA,EAAA,KAAM,GAAG,MAAM,CAAA,CAAA,EAAI,EAAE,CAAA,CAAE,CAAC,CAAA;AAAA,IACnD;AAAA,GACF;AACF;;;AC3GA,SAAS,aAAA,GAAmE;AAC1E,EAAA,IAAI;AAEF,IAAA,OAAO,UAAQ,QAAQ,CAAA;AAAA,EACzB,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AACF;AAWA,SAAS,kBAAkB,OAAA,EAA8B;AACvD,EAAA,IAAI,KAAA,GAA4B,IAAA;AAEhC,EAAA,MAAM,WAAW,YAAkC;AACjD,IAAA,IAAI,OAAO,OAAO,KAAA;AAClB,IAAA,MAAM,EAAE,UAAA,EAAW,GAAI,aAAA,EAAc;AACrC,IAAA,KAAA,GAAQ,IAAI,WAAW,OAAO,CAAA;AAC9B,IAAA,IAAI,CAAE,MAAM,KAAA,CAAM,cAAA,EAAe,EAAI;AACnC,MAAA,MAAM,MAAM,WAAA,EAAY;AAAA,IAC1B;AACA,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,OAAO,IAAA,EAAM;AACjB,MAAA,MAAM,GAAA,GAAM,MAAM,QAAA,EAAS;AAC3B,MAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,QAAA,MAAM,IAAI,UAAA,CAAW;AAAA,UACnB,QAAQ,GAAA,CAAI,MAAA;AAAA,UACZ,UAAU,EAAE,GAAA,EAAK,IAAI,EAAA,EAAI,GAAG,IAAI,QAAA;AAAS,SAC1C,CAAA;AAAA,MACH;AAAA,IACF,CAAA;AAAA,IACA,MAAM,KAAA,CAAM,MAAA,EAAQ,IAAA,EAAM;AACxB,MAAA,MAAM,GAAA,GAAM,MAAM,QAAA,EAAS;AAC3B,MAAA,MAAM,OAAA,GAAU,MAAM,GAAA,CAAI,UAAA,CAAW,QAAQ,IAAI,CAAA;AACjD,MAAA,OAAO,OAAA,CAAQ,IAAI,CAAA,CAAA,MAAM;AAAA,QACvB,IAAI,MAAA,CAAO,CAAA,CAAE,IAAA,CAAK,QAAA,CAAS,OAAO,EAAE,CAAA;AAAA,QACpC,OAAO,CAAA,CAAE,KAAA;AAAA,QACT,QAAA,EAAU,EAAE,IAAA,CAAK;AAAA,OACnB,CAAE,CAAA;AAAA,IACJ,CAAA;AAAA,IACA,MAAM,OAAO,GAAA,EAAK;AAChB,MAAA,MAAM,GAAA,GAAM,MAAM,QAAA,EAAS;AAC3B,MAAA,MAAM,KAAA,GAAQ,MAAM,GAAA,CAAI,SAAA,EAAU;AAClC,MAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,QAAA,IAAI,GAAA,CAAI,SAAS,MAAA,CAAO,IAAA,CAAK,SAAS,GAAA,IAAO,IAAA,CAAK,EAAE,CAAC,CAAA,EAAG;AACtD,UAAA,MAAM,GAAA,CAAI,UAAA,CAAW,IAAA,CAAK,EAAE,CAAA;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAAA,GACF;AACF;AAEO,SAAS,iBAAiB,MAAA,EAA8C;AAC7E,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,IAAS,iBAAA,CAAkB,OAAO,IAAI,CAAA;AAC3D,EAAA,MAAM,YAAA,uBAAmB,GAAA,EAAoB;AAE7C,EAAA,OAAO;AAAA,IACL,MAAM,MAAM,IAAA,EAAwB;AAClC,MAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,QAAA,YAAA,CAAa,GAAA,CAAI,GAAA,CAAI,EAAA,EAAI,GAAA,CAAI,OAAO,CAAA;AAAA,MACtC;AACA,MAAA,MAAM,KAAA,CAAM,MAAA,CAAO,IAAA,CAAK,GAAA,CAAI,CAAA,GAAA,MAAQ;AAAA,QAClC,IAAI,GAAA,CAAI,EAAA;AAAA,QACR,QAAQ,GAAA,CAAI,SAAA;AAAA,QACZ,UAAU,EAAE,OAAA,EAAS,IAAI,OAAA,EAAS,GAAG,IAAI,QAAA;AAAS,QAClD,CAAC,CAAA;AAAA,IACL,CAAA;AAAA,IACA,MAAM,MAAA,CAAO,SAAA,EAAW,OAAA,EAAS;AAC/B,MAAA,MAAM,IAAA,GAAO,SAAS,IAAA,IAAQ,CAAA;AAC9B,MAAA,MAAM,SAAA,GAAY,SAAS,SAAA,IAAa,CAAA;AACxC,MAAA,MAAM,OAAA,GAAU,MAAM,KAAA,CAAM,KAAA,CAAM,WAAW,IAAI,CAAA;AAEjD,MAAA,OAAO,OAAA,CACJ,OAAO,CAAA,CAAA,KAAK,CAAA,CAAE,SAAS,SAAS,CAAA,CAChC,GAAA,CAAI,CAAC,CAAA,MAA0B;AAAA,QAC9B,IAAI,CAAA,CAAE,EAAA;AAAA,QACN,OAAA,EAAS,MAAA,CAAO,CAAA,CAAE,QAAA,CAAS,OAAA,IAAW,aAAa,GAAA,CAAI,CAAA,CAAE,EAAE,CAAA,IAAK,EAAE,CAAA;AAAA,QAClE,OAAO,CAAA,CAAE,KAAA;AAAA,QACT,UAAU,CAAA,CAAE;AAAA,OACd,CAAE,CAAA;AAAA,IACN,CAAA;AAAA,IACA,MAAM,OAAO,GAAA,EAAK;AAChB,MAAA,KAAA,MAAW,EAAA,IAAM,GAAA,EAAK,YAAA,CAAa,MAAA,CAAO,EAAE,CAAA;AAC5C,MAAA,MAAM,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,IACxB;AAAA,GACF;AACF","file":"index.js","sourcesContent":["import type { ChatMemory, Message, MemoryRecord } from '@agentskit/core'\n\nexport interface SqliteChatMemoryConfig {\n path: string\n conversationId?: string\n}\n\nfunction serializeMessages(messages: Message[]): string {\n const record: MemoryRecord = {\n version: 1,\n messages: messages.map(m => ({\n ...m,\n createdAt: m.createdAt.toISOString(),\n })),\n }\n return JSON.stringify(record)\n}\n\nfunction deserializeMessages(json: string | undefined): Message[] {\n if (!json) return []\n try {\n const record = JSON.parse(json) as MemoryRecord\n if (!record?.messages) return []\n return record.messages.map(m => ({\n ...m,\n createdAt: new Date(m.createdAt),\n }))\n } catch {\n return []\n }\n}\n\ninterface SqliteDb {\n prepare(sql: string): {\n run(...args: unknown[]): void\n get(...args: unknown[]): Record<string, unknown> | undefined\n }\n}\n\nasync function openDatabase(path: string): Promise<SqliteDb> {\n try {\n const mod = await import('better-sqlite3')\n const Database = mod.default ?? mod\n return new (Database as new (p: string) => SqliteDb)(path)\n } catch {\n throw new Error('Install better-sqlite3 to use sqliteChatMemory: npm install better-sqlite3')\n }\n}\n\nexport function sqliteChatMemory(config: SqliteChatMemoryConfig): ChatMemory {\n const conversationId = config.conversationId ?? 'default'\n let dbPromise: Promise<SqliteDb> | null = null\n\n const getDb = (): Promise<SqliteDb> => {\n if (!dbPromise) {\n dbPromise = openDatabase(config.path).then(db => {\n db.prepare(`\n CREATE TABLE IF NOT EXISTS conversations (\n id TEXT PRIMARY KEY,\n messages TEXT NOT NULL\n )\n `).run()\n return db\n })\n }\n return dbPromise\n }\n\n return {\n async load() {\n const db = await getDb()\n const row = db.prepare('SELECT messages FROM conversations WHERE id = ?').get(conversationId)\n return deserializeMessages(row?.messages as string | undefined)\n },\n async save(messages) {\n const db = await getDb()\n const json = serializeMessages(messages)\n db.prepare(`\n INSERT INTO conversations (id, messages) VALUES (?, ?)\n ON CONFLICT(id) DO UPDATE SET messages = ?\n `).run(conversationId, json, json)\n },\n async clear() {\n const db = await getDb()\n db.prepare('DELETE FROM conversations WHERE id = ?').run(conversationId)\n },\n }\n}\n","/**\n * Internal Redis client adapter interface.\n * Abstracts the underlying Redis library so it can be swapped\n * (e.g., from `redis` to `ioredis`) without changing consumers.\n */\nexport interface RedisClientAdapter {\n get(key: string): Promise<string | null>\n set(key: string, value: string): Promise<void>\n del(key: string | string[]): Promise<void>\n keys(pattern: string): Promise<string[]>\n disconnect(): Promise<void>\n call(command: string, ...args: (string | number | Buffer)[]): Promise<unknown>\n}\n\nexport interface RedisConnectionConfig {\n url: string\n client?: RedisClientAdapter\n}\n\nexport async function createRedisClientAdapter(url: string): Promise<RedisClientAdapter> {\n let redis: typeof import('redis')\n try {\n redis = await import('redis')\n } catch {\n throw new Error('Install redis to use Redis memory backends: npm install redis')\n }\n\n const client = redis.createClient({ url })\n await client.connect()\n\n return {\n async get(key) {\n return await client.get(key)\n },\n async set(key, value) {\n await client.set(key, value)\n },\n async del(key) {\n const keys = Array.isArray(key) ? key : [key]\n if (keys.length > 0) await client.del(keys)\n },\n async keys(pattern) {\n return await client.keys(pattern)\n },\n async disconnect() {\n await client.disconnect()\n },\n async call(command, ...args) {\n return await client.sendCommand([command, ...args.map(String)])\n },\n }\n}\n","import type { ChatMemory, Message, MemoryRecord } from '@agentskit/core'\nimport type { RedisClientAdapter, RedisConnectionConfig } from './redis-client'\nimport { createRedisClientAdapter } from './redis-client'\n\nexport interface RedisChatMemoryConfig extends RedisConnectionConfig {\n keyPrefix?: string\n conversationId?: string\n}\n\nfunction serializeMessages(messages: Message[]): string {\n const record: MemoryRecord = {\n version: 1,\n messages: messages.map(m => ({\n ...m,\n createdAt: m.createdAt.toISOString(),\n })),\n }\n return JSON.stringify(record)\n}\n\nfunction deserializeMessages(json: string | null): Message[] {\n if (!json) return []\n try {\n const record = JSON.parse(json) as MemoryRecord\n if (!record?.messages) return []\n return record.messages.map(m => ({\n ...m,\n createdAt: new Date(m.createdAt),\n }))\n } catch {\n return []\n }\n}\n\nexport function redisChatMemory(config: RedisChatMemoryConfig): ChatMemory {\n const prefix = config.keyPrefix ?? 'agentskit:chat'\n const convId = config.conversationId ?? 'default'\n const key = `${prefix}:${convId}`\n let clientPromise: Promise<RedisClientAdapter> | null = null\n\n const getClient = (): Promise<RedisClientAdapter> => {\n if (config.client) return Promise.resolve(config.client)\n if (!clientPromise) clientPromise = createRedisClientAdapter(config.url)\n return clientPromise\n }\n\n return {\n async load() {\n const client = await getClient()\n const json = await client.get(key)\n return deserializeMessages(json)\n },\n async save(messages) {\n const client = await getClient()\n await client.set(key, serializeMessages(messages))\n },\n async clear() {\n const client = await getClient()\n await client.del(key)\n },\n }\n}\n","import type { VectorMemory, VectorDocument, RetrievedDocument } from '@agentskit/core'\nimport type { RedisClientAdapter, RedisConnectionConfig } from './redis-client'\nimport { createRedisClientAdapter } from './redis-client'\n\nexport interface RedisVectorMemoryConfig extends RedisConnectionConfig {\n indexName?: string\n keyPrefix?: string\n dimensions?: number\n}\n\nfunction float32Buffer(vector: number[]): Buffer {\n const buffer = Buffer.alloc(vector.length * 4)\n for (let i = 0; i < vector.length; i++) {\n buffer.writeFloatLE(vector[i], i * 4)\n }\n return buffer\n}\n\nexport function redisVectorMemory(config: RedisVectorMemoryConfig): VectorMemory {\n const indexName = config.indexName ?? 'agentskit:vectors:idx'\n const prefix = config.keyPrefix ?? 'agentskit:vec'\n const dimensions = config.dimensions ?? 0\n let clientPromise: Promise<RedisClientAdapter> | null = null\n let indexCreated = false\n\n const getClient = (): Promise<RedisClientAdapter> => {\n if (config.client) return Promise.resolve(config.client)\n if (!clientPromise) clientPromise = createRedisClientAdapter(config.url)\n return clientPromise\n }\n\n const ensureIndex = async (client: RedisClientAdapter, dims: number) => {\n if (indexCreated) return\n try {\n await client.call(\n 'FT.CREATE', indexName,\n 'ON', 'HASH',\n 'PREFIX', '1', `${prefix}:`,\n 'SCHEMA',\n 'content', 'TEXT',\n 'metadata', 'TEXT',\n 'embedding', 'VECTOR', 'HNSW', '6',\n 'TYPE', 'FLOAT32',\n 'DIM', dims,\n 'DISTANCE_METRIC', 'COSINE',\n )\n } catch (err: unknown) {\n const msg = String(err)\n if (!msg.includes('Index already exists')) throw err\n }\n indexCreated = true\n }\n\n return {\n async store(docs: VectorDocument[]) {\n const client = await getClient()\n const dims = dimensions || docs[0]?.embedding.length || 0\n if (dims > 0) await ensureIndex(client, dims)\n\n for (const doc of docs) {\n const key = `${prefix}:${doc.id}`\n await client.call(\n 'HSET', key,\n 'content', doc.content,\n 'metadata', JSON.stringify(doc.metadata ?? {}),\n 'embedding', float32Buffer(doc.embedding),\n )\n }\n },\n async search(embedding, options) {\n const client = await getClient()\n const topK = options?.topK ?? 5\n const threshold = options?.threshold ?? 0\n\n const result = await client.call(\n 'FT.SEARCH', indexName,\n `*=>[KNN ${topK} @embedding $vec AS score]`,\n 'PARAMS', '2', 'vec', float32Buffer(embedding),\n 'SORTBY', 'score',\n 'RETURN', '3', 'content', 'metadata', 'score',\n 'DIALECT', '2',\n ) as unknown[]\n\n if (!Array.isArray(result) || result.length < 2) return []\n\n const docs: RetrievedDocument[] = []\n // FT.SEARCH returns [total, key1, [field, val, ...], key2, [field, val, ...], ...]\n for (let i = 1; i < result.length; i += 2) {\n const key = String(result[i])\n const fields = result[i + 1] as string[]\n if (!Array.isArray(fields)) continue\n\n const fieldMap: Record<string, string> = {}\n for (let j = 0; j < fields.length; j += 2) {\n fieldMap[fields[j]] = fields[j + 1]\n }\n\n const score = 1 - parseFloat(fieldMap.score ?? '1') // COSINE distance → similarity\n if (score < threshold) continue\n\n docs.push({\n id: key.replace(`${prefix}:`, ''),\n content: fieldMap.content ?? '',\n score,\n metadata: fieldMap.metadata ? JSON.parse(fieldMap.metadata) : undefined,\n })\n }\n\n return docs\n },\n async delete(ids) {\n const client = await getClient()\n await client.del(ids.map(id => `${prefix}:${id}`))\n },\n }\n}\n","import type { VectorMemory, VectorDocument, RetrievedDocument } from '@agentskit/core'\nimport type { VectorStore } from './vector-store'\n\nexport interface FileVectorMemoryConfig {\n path: string\n store?: VectorStore\n}\n\nfunction requireVectra(): { LocalIndex: new (path: string) => VectraIndex } {\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n return require('vectra')\n } catch {\n throw new Error(\n 'Install vectra to use fileVectorMemory: npm install vectra'\n )\n }\n}\n\ninterface VectraIndex {\n isIndexCreated(): Promise<boolean>\n createIndex(): Promise<void>\n insertItem(item: { vector: number[]; metadata: Record<string, unknown> }): Promise<unknown>\n queryItems(vector: number[], topK: number): Promise<Array<{ score: number; item: { metadata: Record<string, unknown> } }>>\n listItems(): Promise<Array<{ id: string; metadata: Record<string, unknown> }>>;\n deleteItem(id: string): Promise<void>\n}\n\nfunction createVectraStore(dirPath: string): VectorStore {\n let index: VectraIndex | null = null\n\n const getIndex = async (): Promise<VectraIndex> => {\n if (index) return index\n const { LocalIndex } = requireVectra()\n index = new LocalIndex(dirPath)\n if (!(await index.isIndexCreated())) {\n await index.createIndex()\n }\n return index\n }\n\n return {\n async upsert(docs) {\n const idx = await getIndex()\n for (const doc of docs) {\n await idx.insertItem({\n vector: doc.vector,\n metadata: { _id: doc.id, ...doc.metadata },\n })\n }\n },\n async query(vector, topK) {\n const idx = await getIndex()\n const results = await idx.queryItems(vector, topK)\n return results.map(r => ({\n id: String(r.item.metadata._id ?? ''),\n score: r.score,\n metadata: r.item.metadata,\n }))\n },\n async delete(ids) {\n const idx = await getIndex()\n const items = await idx.listItems()\n for (const item of items) {\n if (ids.includes(String(item.metadata._id ?? item.id))) {\n await idx.deleteItem(item.id)\n }\n }\n },\n }\n}\n\nexport function fileVectorMemory(config: FileVectorMemoryConfig): VectorMemory {\n const store = config.store ?? createVectraStore(config.path)\n const contentCache = new Map<string, string>()\n\n return {\n async store(docs: VectorDocument[]) {\n for (const doc of docs) {\n contentCache.set(doc.id, doc.content)\n }\n await store.upsert(docs.map(doc => ({\n id: doc.id,\n vector: doc.embedding,\n metadata: { content: doc.content, ...doc.metadata },\n })))\n },\n async search(embedding, options) {\n const topK = options?.topK ?? 5\n const threshold = options?.threshold ?? 0\n const results = await store.query(embedding, topK)\n\n return results\n .filter(r => r.score >= threshold)\n .map((r): RetrievedDocument => ({\n id: r.id,\n content: String(r.metadata.content ?? contentCache.get(r.id) ?? ''),\n score: r.score,\n metadata: r.metadata,\n }))\n },\n async delete(ids) {\n for (const id of ids) contentCache.delete(id)\n await store.delete(ids)\n },\n }\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@agentskit/memory",
3
+ "version": "0.4.0",
4
+ "description": "Persistent and vector memory backends for AgentsKit.",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "scripts": {
23
+ "build": "tsup",
24
+ "test": "vitest run",
25
+ "lint": "tsc --noEmit",
26
+ "dev": "tsup --watch"
27
+ },
28
+ "dependencies": {
29
+ "@agentskit/core": "workspace:*"
30
+ },
31
+ "devDependencies": {
32
+ "@types/better-sqlite3": "^7.6.12",
33
+ "@types/node": "^24.0.0",
34
+ "better-sqlite3": "^11.9.1",
35
+ "redis": "^5.11.0",
36
+ "tsup": "^8.5.0",
37
+ "typescript": "^5.9.2",
38
+ "vectra": "^0.9.0",
39
+ "vitest": "^4.1.2"
40
+ }
41
+ }