@mastra/lance 0.0.0-error-handler-fix-20251020202607 → 0.0.0-execa-dynamic-import-20260304221256
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/CHANGELOG.md +1570 -3
- package/LICENSE.md +15 -0
- package/README.md +61 -4
- package/dist/docs/SKILL.md +27 -0
- package/dist/docs/assets/SOURCE_MAP.json +6 -0
- package/dist/docs/references/docs-rag-vector-databases.md +645 -0
- package/dist/docs/references/reference-storage-lance.md +131 -0
- package/dist/docs/references/reference-vectors-lance.md +220 -0
- package/dist/index.cjs +1719 -1786
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1717 -1787
- package/dist/index.js.map +1 -1
- package/dist/storage/{domains/operations → db}/index.d.ts +21 -2
- package/dist/storage/db/index.d.ts.map +1 -0
- package/dist/storage/db/utils.d.ts.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +21 -46
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts +24 -27
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +21 -24
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +103 -246
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/vector/filter.d.ts +5 -5
- package/dist/vector/index.d.ts +29 -11
- package/dist/vector/index.d.ts.map +1 -1
- package/package.json +17 -13
- package/dist/storage/domains/legacy-evals/index.d.ts +0 -25
- package/dist/storage/domains/legacy-evals/index.d.ts.map +0 -1
- package/dist/storage/domains/operations/index.d.ts.map +0 -1
- package/dist/storage/domains/traces/index.d.ts +0 -34
- package/dist/storage/domains/traces/index.d.ts.map +0 -1
- package/dist/storage/domains/utils.d.ts.map +0 -1
- /package/dist/storage/{domains → db}/utils.d.ts +0 -0
package/dist/index.cjs
CHANGED
|
@@ -4,132 +4,17 @@ var lancedb = require('@lancedb/lancedb');
|
|
|
4
4
|
var error = require('@mastra/core/error');
|
|
5
5
|
var storage = require('@mastra/core/storage');
|
|
6
6
|
var agent = require('@mastra/core/agent');
|
|
7
|
+
var base = require('@mastra/core/base');
|
|
7
8
|
var apacheArrow = require('apache-arrow');
|
|
8
|
-
var
|
|
9
|
+
var evals = require('@mastra/core/evals');
|
|
9
10
|
var vector = require('@mastra/core/vector');
|
|
10
11
|
var filter = require('@mastra/core/vector/filter');
|
|
11
12
|
|
|
12
13
|
// src/storage/index.ts
|
|
13
|
-
var StoreLegacyEvalsLance = class extends storage.LegacyEvalsStorage {
|
|
14
|
-
client;
|
|
15
|
-
constructor({ client }) {
|
|
16
|
-
super();
|
|
17
|
-
this.client = client;
|
|
18
|
-
}
|
|
19
|
-
async getEvalsByAgentName(agentName, type) {
|
|
20
|
-
try {
|
|
21
|
-
const table = await this.client.openTable(storage.TABLE_EVALS);
|
|
22
|
-
const query = table.query().where(`agent_name = '${agentName}'`);
|
|
23
|
-
const records = await query.toArray();
|
|
24
|
-
let filteredRecords = records;
|
|
25
|
-
if (type === "live") {
|
|
26
|
-
filteredRecords = records.filter((record) => record.test_info === null);
|
|
27
|
-
} else if (type === "test") {
|
|
28
|
-
filteredRecords = records.filter((record) => record.test_info !== null);
|
|
29
|
-
}
|
|
30
|
-
return filteredRecords.map((record) => {
|
|
31
|
-
return {
|
|
32
|
-
id: record.id,
|
|
33
|
-
input: record.input,
|
|
34
|
-
output: record.output,
|
|
35
|
-
agentName: record.agent_name,
|
|
36
|
-
metricName: record.metric_name,
|
|
37
|
-
result: JSON.parse(record.result),
|
|
38
|
-
instructions: record.instructions,
|
|
39
|
-
testInfo: record.test_info ? JSON.parse(record.test_info) : null,
|
|
40
|
-
globalRunId: record.global_run_id,
|
|
41
|
-
runId: record.run_id,
|
|
42
|
-
createdAt: new Date(record.created_at).toString()
|
|
43
|
-
};
|
|
44
|
-
});
|
|
45
|
-
} catch (error$1) {
|
|
46
|
-
throw new error.MastraError(
|
|
47
|
-
{
|
|
48
|
-
id: "LANCE_STORE_GET_EVALS_BY_AGENT_NAME_FAILED",
|
|
49
|
-
domain: error.ErrorDomain.STORAGE,
|
|
50
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
51
|
-
details: { agentName }
|
|
52
|
-
},
|
|
53
|
-
error$1
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
async getEvals(options) {
|
|
58
|
-
try {
|
|
59
|
-
const table = await this.client.openTable(storage.TABLE_EVALS);
|
|
60
|
-
const conditions = [];
|
|
61
|
-
if (options.agentName) {
|
|
62
|
-
conditions.push(`agent_name = '${options.agentName}'`);
|
|
63
|
-
}
|
|
64
|
-
if (options.type === "live") {
|
|
65
|
-
conditions.push("length(test_info) = 0");
|
|
66
|
-
} else if (options.type === "test") {
|
|
67
|
-
conditions.push("length(test_info) > 0");
|
|
68
|
-
}
|
|
69
|
-
const startDate = options.dateRange?.start || options.fromDate;
|
|
70
|
-
const endDate = options.dateRange?.end || options.toDate;
|
|
71
|
-
if (startDate) {
|
|
72
|
-
conditions.push(`\`created_at\` >= ${startDate.getTime()}`);
|
|
73
|
-
}
|
|
74
|
-
if (endDate) {
|
|
75
|
-
conditions.push(`\`created_at\` <= ${endDate.getTime()}`);
|
|
76
|
-
}
|
|
77
|
-
let total = 0;
|
|
78
|
-
if (conditions.length > 0) {
|
|
79
|
-
total = await table.countRows(conditions.join(" AND "));
|
|
80
|
-
} else {
|
|
81
|
-
total = await table.countRows();
|
|
82
|
-
}
|
|
83
|
-
const query = table.query();
|
|
84
|
-
if (conditions.length > 0) {
|
|
85
|
-
const whereClause = conditions.join(" AND ");
|
|
86
|
-
query.where(whereClause);
|
|
87
|
-
}
|
|
88
|
-
const records = await query.toArray();
|
|
89
|
-
const evals = records.sort((a, b) => b.created_at - a.created_at).map((record) => {
|
|
90
|
-
return {
|
|
91
|
-
id: record.id,
|
|
92
|
-
input: record.input,
|
|
93
|
-
output: record.output,
|
|
94
|
-
agentName: record.agent_name,
|
|
95
|
-
metricName: record.metric_name,
|
|
96
|
-
result: JSON.parse(record.result),
|
|
97
|
-
instructions: record.instructions,
|
|
98
|
-
testInfo: record.test_info ? JSON.parse(record.test_info) : null,
|
|
99
|
-
globalRunId: record.global_run_id,
|
|
100
|
-
runId: record.run_id,
|
|
101
|
-
createdAt: new Date(record.created_at).toISOString()
|
|
102
|
-
};
|
|
103
|
-
});
|
|
104
|
-
const page = options.page || 0;
|
|
105
|
-
const perPage = options.perPage || 10;
|
|
106
|
-
const pagedEvals = evals.slice(page * perPage, (page + 1) * perPage);
|
|
107
|
-
return {
|
|
108
|
-
evals: pagedEvals,
|
|
109
|
-
total,
|
|
110
|
-
page,
|
|
111
|
-
perPage,
|
|
112
|
-
hasMore: total > (page + 1) * perPage
|
|
113
|
-
};
|
|
114
|
-
} catch (error$1) {
|
|
115
|
-
throw new error.MastraError(
|
|
116
|
-
{
|
|
117
|
-
id: "LANCE_STORE_GET_EVALS_FAILED",
|
|
118
|
-
domain: error.ErrorDomain.STORAGE,
|
|
119
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
120
|
-
details: { agentName: options.agentName ?? "" }
|
|
121
|
-
},
|
|
122
|
-
error$1
|
|
123
|
-
);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
14
|
function getPrimaryKeys(tableName) {
|
|
128
15
|
let primaryId = ["id"];
|
|
129
16
|
if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
|
|
130
17
|
primaryId = ["workflow_name", "run_id"];
|
|
131
|
-
} else if (tableName === storage.TABLE_EVALS) {
|
|
132
|
-
primaryId = ["agent_name", "metric_name", "run_id"];
|
|
133
18
|
}
|
|
134
19
|
return primaryId;
|
|
135
20
|
}
|
|
@@ -207,7 +92,7 @@ async function getTableSchema({
|
|
|
207
92
|
} catch (validationError) {
|
|
208
93
|
throw new error.MastraError(
|
|
209
94
|
{
|
|
210
|
-
id: "
|
|
95
|
+
id: storage.createStorageErrorId("LANCE", "GET_TABLE_SCHEMA", "INVALID_ARGS"),
|
|
211
96
|
domain: error.ErrorDomain.STORAGE,
|
|
212
97
|
category: error.ErrorCategory.USER,
|
|
213
98
|
text: validationError.message,
|
|
@@ -230,7 +115,7 @@ async function getTableSchema({
|
|
|
230
115
|
} catch (error$1) {
|
|
231
116
|
throw new error.MastraError(
|
|
232
117
|
{
|
|
233
|
-
id: "
|
|
118
|
+
id: storage.createStorageErrorId("LANCE", "GET_TABLE_SCHEMA", "FAILED"),
|
|
234
119
|
domain: error.ErrorDomain.STORAGE,
|
|
235
120
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
236
121
|
details: { tableName }
|
|
@@ -240,1202 +125,1285 @@ async function getTableSchema({
|
|
|
240
125
|
}
|
|
241
126
|
}
|
|
242
127
|
|
|
243
|
-
// src/storage/
|
|
244
|
-
|
|
128
|
+
// src/storage/db/index.ts
|
|
129
|
+
function resolveLanceConfig(config) {
|
|
130
|
+
return config.client;
|
|
131
|
+
}
|
|
132
|
+
var LanceDB = class extends base.MastraBase {
|
|
245
133
|
client;
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
super();
|
|
134
|
+
constructor({ client }) {
|
|
135
|
+
super({ name: "lance-db" });
|
|
249
136
|
this.client = client;
|
|
250
|
-
this.operations = operations;
|
|
251
137
|
}
|
|
252
|
-
|
|
138
|
+
getDefaultValue(type) {
|
|
139
|
+
switch (type) {
|
|
140
|
+
case "text":
|
|
141
|
+
return "''";
|
|
142
|
+
case "timestamp":
|
|
143
|
+
return "CURRENT_TIMESTAMP";
|
|
144
|
+
case "integer":
|
|
145
|
+
case "bigint":
|
|
146
|
+
return "0";
|
|
147
|
+
case "jsonb":
|
|
148
|
+
return "'{}'";
|
|
149
|
+
case "uuid":
|
|
150
|
+
return "''";
|
|
151
|
+
default:
|
|
152
|
+
return storage.getDefaultValue(type);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async hasColumn(tableName, columnName) {
|
|
156
|
+
const table = await this.client.openTable(tableName);
|
|
157
|
+
const schema = await table.schema();
|
|
158
|
+
return schema.fields.some((field) => field.name === columnName);
|
|
159
|
+
}
|
|
160
|
+
translateSchema(schema) {
|
|
161
|
+
const fields = Object.entries(schema).map(([name, column]) => {
|
|
162
|
+
let arrowType;
|
|
163
|
+
switch (column.type.toLowerCase()) {
|
|
164
|
+
case "text":
|
|
165
|
+
case "uuid":
|
|
166
|
+
arrowType = new apacheArrow.Utf8();
|
|
167
|
+
break;
|
|
168
|
+
case "int":
|
|
169
|
+
case "integer":
|
|
170
|
+
arrowType = new apacheArrow.Int32();
|
|
171
|
+
break;
|
|
172
|
+
case "bigint":
|
|
173
|
+
arrowType = new apacheArrow.Float64();
|
|
174
|
+
break;
|
|
175
|
+
case "float":
|
|
176
|
+
arrowType = new apacheArrow.Float32();
|
|
177
|
+
break;
|
|
178
|
+
case "jsonb":
|
|
179
|
+
case "json":
|
|
180
|
+
arrowType = new apacheArrow.Utf8();
|
|
181
|
+
break;
|
|
182
|
+
case "binary":
|
|
183
|
+
arrowType = new apacheArrow.Binary();
|
|
184
|
+
break;
|
|
185
|
+
case "timestamp":
|
|
186
|
+
arrowType = new apacheArrow.Float64();
|
|
187
|
+
break;
|
|
188
|
+
default:
|
|
189
|
+
arrowType = new apacheArrow.Utf8();
|
|
190
|
+
}
|
|
191
|
+
return new apacheArrow.Field(name, arrowType, column.nullable ?? true);
|
|
192
|
+
});
|
|
193
|
+
return new apacheArrow.Schema(fields);
|
|
194
|
+
}
|
|
195
|
+
async createTable({
|
|
196
|
+
tableName,
|
|
197
|
+
schema
|
|
198
|
+
}) {
|
|
253
199
|
try {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
200
|
+
if (!this.client) {
|
|
201
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
202
|
+
}
|
|
203
|
+
if (!tableName) {
|
|
204
|
+
throw new Error("tableName is required for createTable.");
|
|
205
|
+
}
|
|
206
|
+
if (!schema) {
|
|
207
|
+
throw new Error("schema is required for createTable.");
|
|
257
208
|
}
|
|
258
|
-
return {
|
|
259
|
-
...thread,
|
|
260
|
-
createdAt: new Date(thread.createdAt),
|
|
261
|
-
updatedAt: new Date(thread.updatedAt)
|
|
262
|
-
};
|
|
263
209
|
} catch (error$1) {
|
|
264
210
|
throw new error.MastraError(
|
|
265
211
|
{
|
|
266
|
-
id: "
|
|
212
|
+
id: storage.createStorageErrorId("LANCE", "CREATE_TABLE", "INVALID_ARGS"),
|
|
267
213
|
domain: error.ErrorDomain.STORAGE,
|
|
268
|
-
category: error.ErrorCategory.
|
|
214
|
+
category: error.ErrorCategory.USER,
|
|
215
|
+
details: { tableName }
|
|
269
216
|
},
|
|
270
217
|
error$1
|
|
271
218
|
);
|
|
272
219
|
}
|
|
273
|
-
}
|
|
274
|
-
async getThreadsByResourceId({ resourceId }) {
|
|
275
220
|
try {
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
const records = await query.toArray();
|
|
279
|
-
return processResultWithTypeConversion(
|
|
280
|
-
records,
|
|
281
|
-
await getTableSchema({ tableName: storage.TABLE_THREADS, client: this.client })
|
|
282
|
-
);
|
|
221
|
+
const arrowSchema = this.translateSchema(schema);
|
|
222
|
+
await this.client.createEmptyTable(tableName, arrowSchema);
|
|
283
223
|
} catch (error$1) {
|
|
224
|
+
if (error$1.message?.includes("already exists")) {
|
|
225
|
+
this.logger.debug(`Table '${tableName}' already exists, skipping create`);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
284
228
|
throw new error.MastraError(
|
|
285
229
|
{
|
|
286
|
-
id: "
|
|
230
|
+
id: storage.createStorageErrorId("LANCE", "CREATE_TABLE", "FAILED"),
|
|
287
231
|
domain: error.ErrorDomain.STORAGE,
|
|
288
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
232
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
233
|
+
details: { tableName }
|
|
289
234
|
},
|
|
290
235
|
error$1
|
|
291
236
|
);
|
|
292
237
|
}
|
|
293
238
|
}
|
|
294
|
-
|
|
295
|
-
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
296
|
-
* @param thread - The thread to save
|
|
297
|
-
* @returns The saved thread
|
|
298
|
-
*/
|
|
299
|
-
async saveThread({ thread }) {
|
|
239
|
+
async dropTable({ tableName }) {
|
|
300
240
|
try {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
241
|
+
if (!this.client) {
|
|
242
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
243
|
+
}
|
|
244
|
+
if (!tableName) {
|
|
245
|
+
throw new Error("tableName is required for dropTable.");
|
|
246
|
+
}
|
|
247
|
+
} catch (validationError) {
|
|
306
248
|
throw new error.MastraError(
|
|
307
249
|
{
|
|
308
|
-
id: "
|
|
250
|
+
id: storage.createStorageErrorId("LANCE", "DROP_TABLE", "INVALID_ARGS"),
|
|
309
251
|
domain: error.ErrorDomain.STORAGE,
|
|
310
|
-
category: error.ErrorCategory.
|
|
252
|
+
category: error.ErrorCategory.USER,
|
|
253
|
+
text: validationError.message,
|
|
254
|
+
details: { tableName }
|
|
311
255
|
},
|
|
312
|
-
|
|
256
|
+
validationError
|
|
313
257
|
);
|
|
314
258
|
}
|
|
315
|
-
}
|
|
316
|
-
async updateThread({
|
|
317
|
-
id,
|
|
318
|
-
title,
|
|
319
|
-
metadata
|
|
320
|
-
}) {
|
|
321
|
-
const maxRetries = 5;
|
|
322
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
323
|
-
try {
|
|
324
|
-
const current = await this.getThreadById({ threadId: id });
|
|
325
|
-
if (!current) {
|
|
326
|
-
throw new Error(`Thread with id ${id} not found`);
|
|
327
|
-
}
|
|
328
|
-
const mergedMetadata = { ...current.metadata, ...metadata };
|
|
329
|
-
const record = {
|
|
330
|
-
id,
|
|
331
|
-
title,
|
|
332
|
-
metadata: JSON.stringify(mergedMetadata),
|
|
333
|
-
updatedAt: (/* @__PURE__ */ new Date()).getTime()
|
|
334
|
-
};
|
|
335
|
-
const table = await this.client.openTable(storage.TABLE_THREADS);
|
|
336
|
-
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
337
|
-
const updatedThread = await this.getThreadById({ threadId: id });
|
|
338
|
-
if (!updatedThread) {
|
|
339
|
-
throw new Error(`Failed to retrieve updated thread ${id}`);
|
|
340
|
-
}
|
|
341
|
-
return updatedThread;
|
|
342
|
-
} catch (error$1) {
|
|
343
|
-
if (error$1.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
344
|
-
const delay = Math.pow(2, attempt) * 10;
|
|
345
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
346
|
-
continue;
|
|
347
|
-
}
|
|
348
|
-
throw new error.MastraError(
|
|
349
|
-
{
|
|
350
|
-
id: "LANCE_STORE_UPDATE_THREAD_FAILED",
|
|
351
|
-
domain: error.ErrorDomain.STORAGE,
|
|
352
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
353
|
-
},
|
|
354
|
-
error$1
|
|
355
|
-
);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
throw new error.MastraError(
|
|
359
|
-
{
|
|
360
|
-
id: "LANCE_STORE_UPDATE_THREAD_FAILED",
|
|
361
|
-
domain: error.ErrorDomain.STORAGE,
|
|
362
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
363
|
-
},
|
|
364
|
-
new Error("All retries exhausted")
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
async deleteThread({ threadId }) {
|
|
368
259
|
try {
|
|
369
|
-
|
|
370
|
-
await table.delete(`id = '${threadId}'`);
|
|
371
|
-
const messagesTable = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
372
|
-
await messagesTable.delete(`thread_id = '${threadId}'`);
|
|
260
|
+
await this.client.dropTable(tableName);
|
|
373
261
|
} catch (error$1) {
|
|
262
|
+
if (error$1.toString().includes("was not found") || error$1.message?.includes("Table not found")) {
|
|
263
|
+
this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
374
266
|
throw new error.MastraError(
|
|
375
267
|
{
|
|
376
|
-
id: "
|
|
268
|
+
id: storage.createStorageErrorId("LANCE", "DROP_TABLE", "FAILED"),
|
|
377
269
|
domain: error.ErrorDomain.STORAGE,
|
|
378
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
270
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
271
|
+
details: { tableName }
|
|
379
272
|
},
|
|
380
273
|
error$1
|
|
381
274
|
);
|
|
382
275
|
}
|
|
383
276
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
content: typeof message.content === "string" ? (() => {
|
|
390
|
-
try {
|
|
391
|
-
return JSON.parse(message.content);
|
|
392
|
-
} catch {
|
|
393
|
-
return message.content;
|
|
394
|
-
}
|
|
395
|
-
})() : message.content
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
async getMessages({
|
|
399
|
-
threadId,
|
|
400
|
-
resourceId,
|
|
401
|
-
selectBy,
|
|
402
|
-
format,
|
|
403
|
-
threadConfig
|
|
404
|
-
}) {
|
|
277
|
+
async alterTable({
|
|
278
|
+
tableName,
|
|
279
|
+
schema,
|
|
280
|
+
ifNotExists
|
|
281
|
+
}) {
|
|
405
282
|
try {
|
|
406
|
-
if (!
|
|
407
|
-
|
|
408
|
-
throw new Error("ThreadConfig is not supported by LanceDB storage");
|
|
283
|
+
if (!this.client) {
|
|
284
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
409
285
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
let allRecords = [];
|
|
413
|
-
if (selectBy?.include && selectBy.include.length > 0) {
|
|
414
|
-
const threadIds = [...new Set(selectBy.include.map((item) => item.threadId))];
|
|
415
|
-
for (const threadId2 of threadIds) {
|
|
416
|
-
const threadQuery = table.query().where(`thread_id = '${threadId2}'`);
|
|
417
|
-
let threadRecords = await threadQuery.toArray();
|
|
418
|
-
allRecords.push(...threadRecords);
|
|
419
|
-
}
|
|
420
|
-
} else {
|
|
421
|
-
let query = table.query().where(`\`thread_id\` = '${threadId}'`);
|
|
422
|
-
allRecords = await query.toArray();
|
|
286
|
+
if (!tableName) {
|
|
287
|
+
throw new Error("tableName is required for alterTable.");
|
|
423
288
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
const dateB = new Date(b.createdAt).getTime();
|
|
427
|
-
return dateA - dateB;
|
|
428
|
-
});
|
|
429
|
-
if (selectBy?.include && selectBy.include.length > 0) {
|
|
430
|
-
allRecords = this.processMessagesWithContext(allRecords, selectBy.include);
|
|
289
|
+
if (!schema) {
|
|
290
|
+
throw new Error("schema is required for alterTable.");
|
|
431
291
|
}
|
|
432
|
-
if (
|
|
433
|
-
|
|
292
|
+
if (!ifNotExists || ifNotExists.length === 0) {
|
|
293
|
+
this.logger.debug("No columns specified to add in alterTable, skipping.");
|
|
294
|
+
return;
|
|
434
295
|
}
|
|
435
|
-
|
|
436
|
-
allRecords,
|
|
437
|
-
await getTableSchema({ tableName: storage.TABLE_MESSAGES, client: this.client })
|
|
438
|
-
);
|
|
439
|
-
const list = new agent.MessageList({ threadId, resourceId }).add(messages.map(this.normalizeMessage), "memory");
|
|
440
|
-
if (format === "v2") return list.get.all.v2();
|
|
441
|
-
return list.get.all.v1();
|
|
442
|
-
} catch (error$1) {
|
|
296
|
+
} catch (validationError) {
|
|
443
297
|
throw new error.MastraError(
|
|
444
298
|
{
|
|
445
|
-
id: "
|
|
299
|
+
id: storage.createStorageErrorId("LANCE", "ALTER_TABLE", "INVALID_ARGS"),
|
|
446
300
|
domain: error.ErrorDomain.STORAGE,
|
|
447
|
-
category: error.ErrorCategory.
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
resourceId: resourceId ?? ""
|
|
451
|
-
}
|
|
301
|
+
category: error.ErrorCategory.USER,
|
|
302
|
+
text: validationError.message,
|
|
303
|
+
details: { tableName }
|
|
452
304
|
},
|
|
453
|
-
|
|
305
|
+
validationError
|
|
454
306
|
);
|
|
455
307
|
}
|
|
456
|
-
}
|
|
457
|
-
async getMessagesById({
|
|
458
|
-
messageIds,
|
|
459
|
-
format
|
|
460
|
-
}) {
|
|
461
|
-
if (messageIds.length === 0) return [];
|
|
462
308
|
try {
|
|
463
|
-
const table = await this.client.openTable(
|
|
464
|
-
const
|
|
465
|
-
const
|
|
466
|
-
const
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
309
|
+
const table = await this.client.openTable(tableName);
|
|
310
|
+
const currentSchema = await table.schema();
|
|
311
|
+
const existingFields = new Set(currentSchema.fields.map((f) => f.name));
|
|
312
|
+
const typeMap = {
|
|
313
|
+
text: "string",
|
|
314
|
+
integer: "int",
|
|
315
|
+
bigint: "bigint",
|
|
316
|
+
timestamp: "timestamp",
|
|
317
|
+
jsonb: "string",
|
|
318
|
+
uuid: "string"
|
|
319
|
+
};
|
|
320
|
+
const columnsToAdd = ifNotExists.filter((col) => schema[col] && !existingFields.has(col)).map((col) => {
|
|
321
|
+
const colDef = schema[col];
|
|
322
|
+
return {
|
|
323
|
+
name: col,
|
|
324
|
+
valueSql: colDef?.nullable ? `cast(NULL as ${typeMap[colDef.type ?? "text"]})` : `cast(${this.getDefaultValue(colDef?.type ?? "text")} as ${typeMap[colDef?.type ?? "text"]})`
|
|
325
|
+
};
|
|
326
|
+
});
|
|
327
|
+
if (columnsToAdd.length > 0) {
|
|
328
|
+
await table.addColumns(columnsToAdd);
|
|
329
|
+
this.logger?.info?.(`Added columns [${columnsToAdd.map((c) => c.name).join(", ")}] to table ${tableName}`);
|
|
330
|
+
}
|
|
473
331
|
} catch (error$1) {
|
|
474
332
|
throw new error.MastraError(
|
|
475
333
|
{
|
|
476
|
-
id: "
|
|
334
|
+
id: storage.createStorageErrorId("LANCE", "ALTER_TABLE", "FAILED"),
|
|
477
335
|
domain: error.ErrorDomain.STORAGE,
|
|
478
336
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
479
|
-
details: {
|
|
480
|
-
messageIds: JSON.stringify(messageIds)
|
|
481
|
-
}
|
|
337
|
+
details: { tableName }
|
|
482
338
|
},
|
|
483
339
|
error$1
|
|
484
340
|
);
|
|
485
341
|
}
|
|
486
342
|
}
|
|
487
|
-
async
|
|
343
|
+
async clearTable({ tableName }) {
|
|
488
344
|
try {
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
return [];
|
|
492
|
-
}
|
|
493
|
-
const threadId = messages[0]?.threadId;
|
|
494
|
-
if (!threadId) {
|
|
495
|
-
throw new Error("Thread ID is required");
|
|
345
|
+
if (!this.client) {
|
|
346
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
496
347
|
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
throw new Error("Message ID is required");
|
|
500
|
-
}
|
|
501
|
-
if (!message.threadId) {
|
|
502
|
-
throw new Error("Thread ID is required for all messages");
|
|
503
|
-
}
|
|
504
|
-
if (message.resourceId === null || message.resourceId === void 0) {
|
|
505
|
-
throw new Error("Resource ID cannot be null or undefined");
|
|
506
|
-
}
|
|
507
|
-
if (!message.content) {
|
|
508
|
-
throw new Error("Message content is required");
|
|
509
|
-
}
|
|
348
|
+
if (!tableName) {
|
|
349
|
+
throw new Error("tableName is required for clearTable.");
|
|
510
350
|
}
|
|
511
|
-
|
|
512
|
-
const { threadId: threadId2, type, ...rest } = message;
|
|
513
|
-
return {
|
|
514
|
-
...rest,
|
|
515
|
-
thread_id: threadId2,
|
|
516
|
-
type: type ?? "v2",
|
|
517
|
-
content: JSON.stringify(message.content)
|
|
518
|
-
};
|
|
519
|
-
});
|
|
520
|
-
const table = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
521
|
-
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
|
|
522
|
-
const threadsTable = await this.client.openTable(storage.TABLE_THREADS);
|
|
523
|
-
const currentTime = (/* @__PURE__ */ new Date()).getTime();
|
|
524
|
-
const updateRecord = { id: threadId, updatedAt: currentTime };
|
|
525
|
-
await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([updateRecord]);
|
|
526
|
-
const list = new agent.MessageList().add(messages, "memory");
|
|
527
|
-
if (format === `v2`) return list.get.all.v2();
|
|
528
|
-
return list.get.all.v1();
|
|
529
|
-
} catch (error$1) {
|
|
351
|
+
} catch (validationError) {
|
|
530
352
|
throw new error.MastraError(
|
|
531
353
|
{
|
|
532
|
-
id: "
|
|
354
|
+
id: storage.createStorageErrorId("LANCE", "CLEAR_TABLE", "INVALID_ARGS"),
|
|
533
355
|
domain: error.ErrorDomain.STORAGE,
|
|
534
|
-
category: error.ErrorCategory.
|
|
356
|
+
category: error.ErrorCategory.USER,
|
|
357
|
+
text: validationError.message,
|
|
358
|
+
details: { tableName }
|
|
535
359
|
},
|
|
536
|
-
|
|
360
|
+
validationError
|
|
537
361
|
);
|
|
538
362
|
}
|
|
539
|
-
}
|
|
540
|
-
async getThreadsByResourceIdPaginated(args) {
|
|
541
363
|
try {
|
|
542
|
-
const
|
|
543
|
-
|
|
544
|
-
const total = await table.countRows(`\`resourceId\` = '${resourceId}'`);
|
|
545
|
-
const query = table.query().where(`\`resourceId\` = '${resourceId}'`);
|
|
546
|
-
const offset = page * perPage;
|
|
547
|
-
query.limit(perPage);
|
|
548
|
-
if (offset > 0) {
|
|
549
|
-
query.offset(offset);
|
|
550
|
-
}
|
|
551
|
-
const records = await query.toArray();
|
|
552
|
-
records.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
|
|
553
|
-
const schema = await getTableSchema({ tableName: storage.TABLE_THREADS, client: this.client });
|
|
554
|
-
const threads = records.map((record) => processResultWithTypeConversion(record, schema));
|
|
555
|
-
return {
|
|
556
|
-
threads,
|
|
557
|
-
total,
|
|
558
|
-
page,
|
|
559
|
-
perPage,
|
|
560
|
-
hasMore: total > (page + 1) * perPage
|
|
561
|
-
};
|
|
364
|
+
const table = await this.client.openTable(tableName);
|
|
365
|
+
await table.delete("1=1");
|
|
562
366
|
} catch (error$1) {
|
|
563
367
|
throw new error.MastraError(
|
|
564
368
|
{
|
|
565
|
-
id: "
|
|
369
|
+
id: storage.createStorageErrorId("LANCE", "CLEAR_TABLE", "FAILED"),
|
|
566
370
|
domain: error.ErrorDomain.STORAGE,
|
|
567
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
371
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
372
|
+
details: { tableName }
|
|
568
373
|
},
|
|
569
374
|
error$1
|
|
570
375
|
);
|
|
571
376
|
}
|
|
572
377
|
}
|
|
573
|
-
|
|
574
|
-
* Processes messages to include context messages based on withPreviousMessages and withNextMessages
|
|
575
|
-
* @param records - The sorted array of records to process
|
|
576
|
-
* @param include - The array of include specifications with context parameters
|
|
577
|
-
* @returns The processed array with context messages included
|
|
578
|
-
*/
|
|
579
|
-
processMessagesWithContext(records, include) {
|
|
580
|
-
const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
|
|
581
|
-
if (messagesWithContext.length === 0) {
|
|
582
|
-
return records;
|
|
583
|
-
}
|
|
584
|
-
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
585
|
-
records.forEach((message, index) => {
|
|
586
|
-
messageIndexMap.set(message.id, index);
|
|
587
|
-
});
|
|
588
|
-
const additionalIndices = /* @__PURE__ */ new Set();
|
|
589
|
-
for (const item of messagesWithContext) {
|
|
590
|
-
const messageIndex = messageIndexMap.get(item.id);
|
|
591
|
-
if (messageIndex !== void 0) {
|
|
592
|
-
if (item.withPreviousMessages) {
|
|
593
|
-
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
594
|
-
for (let i = startIdx; i < messageIndex; i++) {
|
|
595
|
-
additionalIndices.add(i);
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
if (item.withNextMessages) {
|
|
599
|
-
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
600
|
-
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
601
|
-
additionalIndices.add(i);
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
if (additionalIndices.size === 0) {
|
|
607
|
-
return records;
|
|
608
|
-
}
|
|
609
|
-
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
610
|
-
const allIndices = /* @__PURE__ */ new Set();
|
|
611
|
-
records.forEach((record, index) => {
|
|
612
|
-
if (originalMatchIds.has(record.id)) {
|
|
613
|
-
allIndices.add(index);
|
|
614
|
-
}
|
|
615
|
-
});
|
|
616
|
-
additionalIndices.forEach((index) => {
|
|
617
|
-
allIndices.add(index);
|
|
618
|
-
});
|
|
619
|
-
return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
|
|
620
|
-
}
|
|
621
|
-
async getMessagesPaginated(args) {
|
|
622
|
-
const { threadId, resourceId, selectBy, format = "v1" } = args;
|
|
623
|
-
const page = selectBy?.pagination?.page ?? 0;
|
|
624
|
-
const perPage = selectBy?.pagination?.perPage ?? 10;
|
|
378
|
+
async insert({ tableName, record }) {
|
|
625
379
|
try {
|
|
626
|
-
if (!
|
|
627
|
-
|
|
628
|
-
const fromDate = dateRange?.start;
|
|
629
|
-
const toDate = dateRange?.end;
|
|
630
|
-
const table = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
631
|
-
const messages = [];
|
|
632
|
-
if (selectBy?.include && Array.isArray(selectBy.include)) {
|
|
633
|
-
const threadIds = [...new Set(selectBy.include.map((item) => item.threadId))];
|
|
634
|
-
const allThreadMessages = [];
|
|
635
|
-
for (const threadId2 of threadIds) {
|
|
636
|
-
const threadQuery = table.query().where(`thread_id = '${threadId2}'`);
|
|
637
|
-
let threadRecords = await threadQuery.toArray();
|
|
638
|
-
if (fromDate) threadRecords = threadRecords.filter((m) => m.createdAt >= fromDate.getTime());
|
|
639
|
-
if (toDate) threadRecords = threadRecords.filter((m) => m.createdAt <= toDate.getTime());
|
|
640
|
-
allThreadMessages.push(...threadRecords);
|
|
641
|
-
}
|
|
642
|
-
allThreadMessages.sort((a, b) => a.createdAt - b.createdAt);
|
|
643
|
-
const contextMessages = this.processMessagesWithContext(allThreadMessages, selectBy.include);
|
|
644
|
-
messages.push(...contextMessages);
|
|
645
|
-
}
|
|
646
|
-
const conditions = [`thread_id = '${threadId}'`];
|
|
647
|
-
if (resourceId) {
|
|
648
|
-
conditions.push(`\`resourceId\` = '${resourceId}'`);
|
|
649
|
-
}
|
|
650
|
-
if (fromDate) {
|
|
651
|
-
conditions.push(`\`createdAt\` >= ${fromDate.getTime()}`);
|
|
652
|
-
}
|
|
653
|
-
if (toDate) {
|
|
654
|
-
conditions.push(`\`createdAt\` <= ${toDate.getTime()}`);
|
|
380
|
+
if (!this.client) {
|
|
381
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
655
382
|
}
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
total = await table.countRows(conditions.join(" AND "));
|
|
659
|
-
} else {
|
|
660
|
-
total = await table.countRows();
|
|
383
|
+
if (!tableName) {
|
|
384
|
+
throw new Error("tableName is required for insert.");
|
|
661
385
|
}
|
|
662
|
-
if (
|
|
663
|
-
|
|
664
|
-
messages: [],
|
|
665
|
-
total: 0,
|
|
666
|
-
page,
|
|
667
|
-
perPage,
|
|
668
|
-
hasMore: false
|
|
669
|
-
};
|
|
386
|
+
if (!record || Object.keys(record).length === 0) {
|
|
387
|
+
throw new Error("record is required and cannot be empty for insert.");
|
|
670
388
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
if (excludeIds.length > 0) {
|
|
692
|
-
records = records.filter((m) => !excludeIds.includes(m.id));
|
|
389
|
+
} catch (validationError) {
|
|
390
|
+
throw new error.MastraError(
|
|
391
|
+
{
|
|
392
|
+
id: storage.createStorageErrorId("LANCE", "INSERT", "INVALID_ARGS"),
|
|
393
|
+
domain: error.ErrorDomain.STORAGE,
|
|
394
|
+
category: error.ErrorCategory.USER,
|
|
395
|
+
text: validationError.message,
|
|
396
|
+
details: { tableName }
|
|
397
|
+
},
|
|
398
|
+
validationError
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
try {
|
|
402
|
+
const table = await this.client.openTable(tableName);
|
|
403
|
+
const primaryId = getPrimaryKeys(tableName);
|
|
404
|
+
const processedRecord = { ...record };
|
|
405
|
+
for (const key in processedRecord) {
|
|
406
|
+
if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
|
|
407
|
+
this.logger.debug("Converting object to JSON string: ", processedRecord[key]);
|
|
408
|
+
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
693
409
|
}
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
const allMessages = [...messages, ...selectedMessages];
|
|
697
|
-
const seen = /* @__PURE__ */ new Set();
|
|
698
|
-
const dedupedMessages = allMessages.filter((m) => {
|
|
699
|
-
const key = `${m.id}:${m.thread_id}`;
|
|
700
|
-
if (seen.has(key)) return false;
|
|
701
|
-
seen.add(key);
|
|
702
|
-
return true;
|
|
703
|
-
});
|
|
704
|
-
const formattedMessages = dedupedMessages.map((msg) => {
|
|
705
|
-
const { thread_id, ...rest } = msg;
|
|
706
|
-
return {
|
|
707
|
-
...rest,
|
|
708
|
-
threadId: thread_id,
|
|
709
|
-
content: typeof msg.content === "string" ? (() => {
|
|
710
|
-
try {
|
|
711
|
-
return JSON.parse(msg.content);
|
|
712
|
-
} catch {
|
|
713
|
-
return msg.content;
|
|
714
|
-
}
|
|
715
|
-
})() : msg.content
|
|
716
|
-
};
|
|
717
|
-
});
|
|
718
|
-
const list = new agent.MessageList().add(formattedMessages, "memory");
|
|
719
|
-
return {
|
|
720
|
-
messages: format === "v2" ? list.get.all.v2() : list.get.all.v1(),
|
|
721
|
-
total,
|
|
722
|
-
// Total should be the count of messages matching the filters
|
|
723
|
-
page,
|
|
724
|
-
perPage,
|
|
725
|
-
hasMore: total > (page + 1) * perPage
|
|
726
|
-
};
|
|
410
|
+
}
|
|
411
|
+
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([processedRecord]);
|
|
727
412
|
} catch (error$1) {
|
|
728
|
-
|
|
413
|
+
throw new error.MastraError(
|
|
729
414
|
{
|
|
730
|
-
id: "
|
|
415
|
+
id: storage.createStorageErrorId("LANCE", "INSERT", "FAILED"),
|
|
731
416
|
domain: error.ErrorDomain.STORAGE,
|
|
732
417
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
733
|
-
details: {
|
|
734
|
-
threadId,
|
|
735
|
-
resourceId: resourceId ?? ""
|
|
736
|
-
}
|
|
418
|
+
details: { tableName }
|
|
737
419
|
},
|
|
738
420
|
error$1
|
|
739
421
|
);
|
|
740
|
-
this.logger?.trackException?.(mastraError);
|
|
741
|
-
this.logger?.error?.(mastraError.toString());
|
|
742
|
-
return { messages: [], total: 0, page, perPage, hasMore: false };
|
|
743
422
|
}
|
|
744
423
|
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
if (!messages.length) {
|
|
768
|
-
return [];
|
|
424
|
+
async batchInsert({ tableName, records }) {
|
|
425
|
+
try {
|
|
426
|
+
if (!this.client) {
|
|
427
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
428
|
+
}
|
|
429
|
+
if (!tableName) {
|
|
430
|
+
throw new Error("tableName is required for batchInsert.");
|
|
431
|
+
}
|
|
432
|
+
if (!records || records.length === 0) {
|
|
433
|
+
throw new Error("records array is required and cannot be empty for batchInsert.");
|
|
434
|
+
}
|
|
435
|
+
} catch (validationError) {
|
|
436
|
+
throw new error.MastraError(
|
|
437
|
+
{
|
|
438
|
+
id: storage.createStorageErrorId("LANCE", "BATCH_INSERT", "INVALID_ARGS"),
|
|
439
|
+
domain: error.ErrorDomain.STORAGE,
|
|
440
|
+
category: error.ErrorCategory.USER,
|
|
441
|
+
text: validationError.message,
|
|
442
|
+
details: { tableName }
|
|
443
|
+
},
|
|
444
|
+
validationError
|
|
445
|
+
);
|
|
769
446
|
}
|
|
770
|
-
const updatedMessages = [];
|
|
771
|
-
const affectedThreadIds = /* @__PURE__ */ new Set();
|
|
772
447
|
try {
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
continue;
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
const originalThreadId = existingMsg.threadId;
|
|
782
|
-
affectedThreadIds.add(originalThreadId);
|
|
783
|
-
const updatePayload = {};
|
|
784
|
-
if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
|
|
785
|
-
if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
|
|
786
|
-
if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
|
|
787
|
-
if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
|
|
788
|
-
updatePayload.thread_id = updates.threadId;
|
|
789
|
-
affectedThreadIds.add(updates.threadId);
|
|
790
|
-
}
|
|
791
|
-
if (updates.content) {
|
|
792
|
-
const existingContent = existingMsg.content;
|
|
793
|
-
let newContent = { ...existingContent };
|
|
794
|
-
if (updates.content.metadata !== void 0) {
|
|
795
|
-
newContent.metadata = {
|
|
796
|
-
...existingContent.metadata || {},
|
|
797
|
-
...updates.content.metadata || {}
|
|
798
|
-
};
|
|
799
|
-
}
|
|
800
|
-
if (updates.content.content !== void 0) {
|
|
801
|
-
newContent.content = updates.content.content;
|
|
802
|
-
}
|
|
803
|
-
if ("parts" in updates.content && updates.content.parts !== void 0) {
|
|
804
|
-
newContent.parts = updates.content.parts;
|
|
448
|
+
const table = await this.client.openTable(tableName);
|
|
449
|
+
const primaryId = getPrimaryKeys(tableName);
|
|
450
|
+
const processedRecords = records.map((record) => {
|
|
451
|
+
const processedRecord = { ...record };
|
|
452
|
+
for (const key in processedRecord) {
|
|
453
|
+
if (processedRecord[key] == null) continue;
|
|
454
|
+
if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
|
|
455
|
+
processedRecord[key] = JSON.stringify(processedRecord[key]);
|
|
805
456
|
}
|
|
806
|
-
updatePayload.content = JSON.stringify(newContent);
|
|
807
457
|
}
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
updatedMessages.push(this.parseMessageData(updatedMessage));
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
for (const threadId of affectedThreadIds) {
|
|
815
|
-
await this.operations.insert({
|
|
816
|
-
tableName: storage.TABLE_THREADS,
|
|
817
|
-
record: { id: threadId, updatedAt: Date.now() }
|
|
818
|
-
});
|
|
819
|
-
}
|
|
820
|
-
return updatedMessages;
|
|
458
|
+
return processedRecord;
|
|
459
|
+
});
|
|
460
|
+
await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(processedRecords);
|
|
821
461
|
} catch (error$1) {
|
|
822
462
|
throw new error.MastraError(
|
|
823
463
|
{
|
|
824
|
-
id: "
|
|
464
|
+
id: storage.createStorageErrorId("LANCE", "BATCH_INSERT", "FAILED"),
|
|
825
465
|
domain: error.ErrorDomain.STORAGE,
|
|
826
466
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
827
|
-
details: {
|
|
467
|
+
details: { tableName }
|
|
828
468
|
},
|
|
829
469
|
error$1
|
|
830
470
|
);
|
|
831
471
|
}
|
|
832
472
|
}
|
|
833
|
-
async
|
|
473
|
+
async load({ tableName, keys }) {
|
|
834
474
|
try {
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
return null;
|
|
838
|
-
}
|
|
839
|
-
let createdAt;
|
|
840
|
-
let updatedAt;
|
|
841
|
-
try {
|
|
842
|
-
if (resource.createdAt instanceof Date) {
|
|
843
|
-
createdAt = resource.createdAt;
|
|
844
|
-
} else if (typeof resource.createdAt === "string") {
|
|
845
|
-
createdAt = new Date(resource.createdAt);
|
|
846
|
-
} else if (typeof resource.createdAt === "number") {
|
|
847
|
-
createdAt = new Date(resource.createdAt);
|
|
848
|
-
} else {
|
|
849
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
850
|
-
}
|
|
851
|
-
if (isNaN(createdAt.getTime())) {
|
|
852
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
853
|
-
}
|
|
854
|
-
} catch {
|
|
855
|
-
createdAt = /* @__PURE__ */ new Date();
|
|
856
|
-
}
|
|
857
|
-
try {
|
|
858
|
-
if (resource.updatedAt instanceof Date) {
|
|
859
|
-
updatedAt = resource.updatedAt;
|
|
860
|
-
} else if (typeof resource.updatedAt === "string") {
|
|
861
|
-
updatedAt = new Date(resource.updatedAt);
|
|
862
|
-
} else if (typeof resource.updatedAt === "number") {
|
|
863
|
-
updatedAt = new Date(resource.updatedAt);
|
|
864
|
-
} else {
|
|
865
|
-
updatedAt = /* @__PURE__ */ new Date();
|
|
866
|
-
}
|
|
867
|
-
if (isNaN(updatedAt.getTime())) {
|
|
868
|
-
updatedAt = /* @__PURE__ */ new Date();
|
|
869
|
-
}
|
|
870
|
-
} catch {
|
|
871
|
-
updatedAt = /* @__PURE__ */ new Date();
|
|
475
|
+
if (!this.client) {
|
|
476
|
+
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
872
477
|
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
workingMemory = void 0;
|
|
876
|
-
} else if (workingMemory === "") {
|
|
877
|
-
workingMemory = "";
|
|
878
|
-
} else if (typeof workingMemory === "object") {
|
|
879
|
-
workingMemory = JSON.stringify(workingMemory);
|
|
478
|
+
if (!tableName) {
|
|
479
|
+
throw new Error("tableName is required for load.");
|
|
880
480
|
}
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
metadata = void 0;
|
|
884
|
-
} else if (typeof metadata === "string") {
|
|
885
|
-
try {
|
|
886
|
-
metadata = JSON.parse(metadata);
|
|
887
|
-
} catch {
|
|
888
|
-
metadata = metadata;
|
|
889
|
-
}
|
|
481
|
+
if (!keys || Object.keys(keys).length === 0) {
|
|
482
|
+
throw new Error("keys are required and cannot be empty for load.");
|
|
890
483
|
}
|
|
891
|
-
|
|
892
|
-
...resource,
|
|
893
|
-
createdAt,
|
|
894
|
-
updatedAt,
|
|
895
|
-
workingMemory,
|
|
896
|
-
metadata
|
|
897
|
-
};
|
|
898
|
-
} catch (error$1) {
|
|
484
|
+
} catch (validationError) {
|
|
899
485
|
throw new error.MastraError(
|
|
900
486
|
{
|
|
901
|
-
id: "
|
|
487
|
+
id: storage.createStorageErrorId("LANCE", "LOAD", "INVALID_ARGS"),
|
|
902
488
|
domain: error.ErrorDomain.STORAGE,
|
|
903
|
-
category: error.ErrorCategory.
|
|
489
|
+
category: error.ErrorCategory.USER,
|
|
490
|
+
text: validationError.message,
|
|
491
|
+
details: { tableName }
|
|
904
492
|
},
|
|
905
|
-
|
|
493
|
+
validationError
|
|
906
494
|
);
|
|
907
495
|
}
|
|
908
|
-
}
|
|
909
|
-
async saveResource({ resource }) {
|
|
910
496
|
try {
|
|
911
|
-
const
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
497
|
+
const table = await this.client.openTable(tableName);
|
|
498
|
+
const tableSchema = await getTableSchema({ tableName, client: this.client });
|
|
499
|
+
const query = table.query();
|
|
500
|
+
if (Object.keys(keys).length > 0) {
|
|
501
|
+
validateKeyTypes(keys, tableSchema);
|
|
502
|
+
const filterConditions = Object.entries(keys).map(([key, value]) => {
|
|
503
|
+
const isCamelCase = /^[a-z][a-zA-Z]*$/.test(key) && /[A-Z]/.test(key);
|
|
504
|
+
const quotedKey = isCamelCase ? `\`${key}\`` : key;
|
|
505
|
+
if (typeof value === "string") {
|
|
506
|
+
return `${quotedKey} = '${value}'`;
|
|
507
|
+
} else if (value === null) {
|
|
508
|
+
return `${quotedKey} IS NULL`;
|
|
509
|
+
} else {
|
|
510
|
+
return `${quotedKey} = ${value}`;
|
|
511
|
+
}
|
|
512
|
+
}).join(" AND ");
|
|
513
|
+
this.logger.debug("where clause generated: " + filterConditions);
|
|
514
|
+
query.where(filterConditions);
|
|
515
|
+
}
|
|
516
|
+
const result = await query.limit(1).toArray();
|
|
517
|
+
if (result.length === 0) {
|
|
518
|
+
this.logger.debug("No record found");
|
|
519
|
+
return null;
|
|
520
|
+
}
|
|
521
|
+
return processResultWithTypeConversion(result[0], tableSchema);
|
|
922
522
|
} catch (error$1) {
|
|
523
|
+
if (error$1 instanceof error.MastraError) throw error$1;
|
|
923
524
|
throw new error.MastraError(
|
|
924
525
|
{
|
|
925
|
-
id: "
|
|
526
|
+
id: storage.createStorageErrorId("LANCE", "LOAD", "FAILED"),
|
|
926
527
|
domain: error.ErrorDomain.STORAGE,
|
|
927
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
528
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
529
|
+
details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
|
|
928
530
|
},
|
|
929
531
|
error$1
|
|
930
532
|
);
|
|
931
533
|
}
|
|
932
534
|
}
|
|
933
|
-
async updateResource({
|
|
934
|
-
resourceId,
|
|
935
|
-
workingMemory,
|
|
936
|
-
metadata
|
|
937
|
-
}) {
|
|
938
|
-
const maxRetries = 3;
|
|
939
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
940
|
-
try {
|
|
941
|
-
const existingResource = await this.getResourceById({ resourceId });
|
|
942
|
-
if (!existingResource) {
|
|
943
|
-
const newResource = {
|
|
944
|
-
id: resourceId,
|
|
945
|
-
workingMemory,
|
|
946
|
-
metadata: metadata || {},
|
|
947
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
948
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
949
|
-
};
|
|
950
|
-
return this.saveResource({ resource: newResource });
|
|
951
|
-
}
|
|
952
|
-
const updatedResource = {
|
|
953
|
-
...existingResource,
|
|
954
|
-
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
955
|
-
metadata: {
|
|
956
|
-
...existingResource.metadata,
|
|
957
|
-
...metadata
|
|
958
|
-
},
|
|
959
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
960
|
-
};
|
|
961
|
-
const record = {
|
|
962
|
-
id: resourceId,
|
|
963
|
-
workingMemory: updatedResource.workingMemory || "",
|
|
964
|
-
metadata: updatedResource.metadata ? JSON.stringify(updatedResource.metadata) : "",
|
|
965
|
-
updatedAt: updatedResource.updatedAt.getTime()
|
|
966
|
-
// Store as timestamp (milliseconds)
|
|
967
|
-
};
|
|
968
|
-
const table = await this.client.openTable(storage.TABLE_RESOURCES);
|
|
969
|
-
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
970
|
-
return updatedResource;
|
|
971
|
-
} catch (error$1) {
|
|
972
|
-
if (error$1.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
973
|
-
const delay = Math.pow(2, attempt) * 10;
|
|
974
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
975
|
-
continue;
|
|
976
|
-
}
|
|
977
|
-
throw new error.MastraError(
|
|
978
|
-
{
|
|
979
|
-
id: "LANCE_STORE_UPDATE_RESOURCE_FAILED",
|
|
980
|
-
domain: error.ErrorDomain.STORAGE,
|
|
981
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
982
|
-
},
|
|
983
|
-
error$1
|
|
984
|
-
);
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
throw new Error("Unexpected end of retry loop");
|
|
988
|
-
}
|
|
989
535
|
};
|
|
990
|
-
|
|
536
|
+
|
|
537
|
+
// src/storage/domains/memory/index.ts
|
|
538
|
+
var StoreMemoryLance = class extends storage.MemoryStorage {
|
|
991
539
|
client;
|
|
992
|
-
|
|
540
|
+
#db;
|
|
541
|
+
constructor(config) {
|
|
993
542
|
super();
|
|
543
|
+
const client = resolveLanceConfig(config);
|
|
994
544
|
this.client = client;
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
case "jsonb":
|
|
1006
|
-
return "'{}'";
|
|
1007
|
-
case "uuid":
|
|
1008
|
-
return "''";
|
|
1009
|
-
default:
|
|
1010
|
-
return super.getDefaultValue(type);
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
async hasColumn(tableName, columnName) {
|
|
1014
|
-
const table = await this.client.openTable(tableName);
|
|
1015
|
-
const schema = await table.schema();
|
|
1016
|
-
return schema.fields.some((field) => field.name === columnName);
|
|
1017
|
-
}
|
|
1018
|
-
translateSchema(schema) {
|
|
1019
|
-
const fields = Object.entries(schema).map(([name, column]) => {
|
|
1020
|
-
let arrowType;
|
|
1021
|
-
switch (column.type.toLowerCase()) {
|
|
1022
|
-
case "text":
|
|
1023
|
-
case "uuid":
|
|
1024
|
-
arrowType = new apacheArrow.Utf8();
|
|
1025
|
-
break;
|
|
1026
|
-
case "int":
|
|
1027
|
-
case "integer":
|
|
1028
|
-
arrowType = new apacheArrow.Int32();
|
|
1029
|
-
break;
|
|
1030
|
-
case "bigint":
|
|
1031
|
-
arrowType = new apacheArrow.Float64();
|
|
1032
|
-
break;
|
|
1033
|
-
case "float":
|
|
1034
|
-
arrowType = new apacheArrow.Float32();
|
|
1035
|
-
break;
|
|
1036
|
-
case "jsonb":
|
|
1037
|
-
case "json":
|
|
1038
|
-
arrowType = new apacheArrow.Utf8();
|
|
1039
|
-
break;
|
|
1040
|
-
case "binary":
|
|
1041
|
-
arrowType = new apacheArrow.Binary();
|
|
1042
|
-
break;
|
|
1043
|
-
case "timestamp":
|
|
1044
|
-
arrowType = new apacheArrow.Float64();
|
|
1045
|
-
break;
|
|
1046
|
-
default:
|
|
1047
|
-
arrowType = new apacheArrow.Utf8();
|
|
1048
|
-
}
|
|
1049
|
-
return new apacheArrow.Field(name, arrowType, column.nullable ?? true);
|
|
545
|
+
this.#db = new LanceDB({ client });
|
|
546
|
+
}
|
|
547
|
+
async init() {
|
|
548
|
+
await this.#db.createTable({ tableName: storage.TABLE_THREADS, schema: storage.TABLE_SCHEMAS[storage.TABLE_THREADS] });
|
|
549
|
+
await this.#db.createTable({ tableName: storage.TABLE_MESSAGES, schema: storage.TABLE_SCHEMAS[storage.TABLE_MESSAGES] });
|
|
550
|
+
await this.#db.createTable({ tableName: storage.TABLE_RESOURCES, schema: storage.TABLE_SCHEMAS[storage.TABLE_RESOURCES] });
|
|
551
|
+
await this.#db.alterTable({
|
|
552
|
+
tableName: storage.TABLE_MESSAGES,
|
|
553
|
+
schema: storage.TABLE_SCHEMAS[storage.TABLE_MESSAGES],
|
|
554
|
+
ifNotExists: ["resourceId"]
|
|
1050
555
|
});
|
|
1051
|
-
return new apacheArrow.Schema(fields);
|
|
1052
556
|
}
|
|
1053
|
-
async
|
|
1054
|
-
tableName
|
|
1055
|
-
|
|
1056
|
-
|
|
557
|
+
async dangerouslyClearAll() {
|
|
558
|
+
await this.#db.clearTable({ tableName: storage.TABLE_THREADS });
|
|
559
|
+
await this.#db.clearTable({ tableName: storage.TABLE_MESSAGES });
|
|
560
|
+
await this.#db.clearTable({ tableName: storage.TABLE_RESOURCES });
|
|
561
|
+
}
|
|
562
|
+
async deleteMessages(messageIds) {
|
|
563
|
+
if (!messageIds || messageIds.length === 0) {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
this.logger.debug("Deleting messages", { count: messageIds.length });
|
|
1057
567
|
try {
|
|
1058
|
-
|
|
1059
|
-
|
|
568
|
+
const threadIds = /* @__PURE__ */ new Set();
|
|
569
|
+
for (const messageId of messageIds) {
|
|
570
|
+
const message = await this.#db.load({ tableName: storage.TABLE_MESSAGES, keys: { id: messageId } });
|
|
571
|
+
if (message?.thread_id) {
|
|
572
|
+
threadIds.add(message.thread_id);
|
|
573
|
+
}
|
|
1060
574
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
575
|
+
const messagesTable = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
576
|
+
const idConditions = messageIds.map((id) => `id = '${this.escapeSql(id)}'`).join(" OR ");
|
|
577
|
+
await messagesTable.delete(idConditions);
|
|
578
|
+
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
579
|
+
const threadsTable = await this.client.openTable(storage.TABLE_THREADS);
|
|
580
|
+
for (const threadId of threadIds) {
|
|
581
|
+
const thread = await this.getThreadById({ threadId });
|
|
582
|
+
if (thread) {
|
|
583
|
+
const record = {
|
|
584
|
+
id: threadId,
|
|
585
|
+
resourceId: thread.resourceId,
|
|
586
|
+
title: thread.title,
|
|
587
|
+
metadata: JSON.stringify(thread.metadata),
|
|
588
|
+
createdAt: new Date(thread.createdAt).getTime(),
|
|
589
|
+
updatedAt: now
|
|
590
|
+
};
|
|
591
|
+
await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
592
|
+
}
|
|
1063
593
|
}
|
|
1064
|
-
|
|
1065
|
-
|
|
594
|
+
} catch (error$1) {
|
|
595
|
+
throw new error.MastraError(
|
|
596
|
+
{
|
|
597
|
+
id: storage.createStorageErrorId("LANCE", "DELETE_MESSAGES", "FAILED"),
|
|
598
|
+
domain: error.ErrorDomain.STORAGE,
|
|
599
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
600
|
+
details: { count: messageIds.length }
|
|
601
|
+
},
|
|
602
|
+
error$1
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
// Utility to escape single quotes in SQL strings
|
|
607
|
+
escapeSql(str) {
|
|
608
|
+
return str.replace(/'/g, "''");
|
|
609
|
+
}
|
|
610
|
+
async getThreadById({ threadId }) {
|
|
611
|
+
try {
|
|
612
|
+
const thread = await this.#db.load({ tableName: storage.TABLE_THREADS, keys: { id: threadId } });
|
|
613
|
+
if (!thread) {
|
|
614
|
+
return null;
|
|
1066
615
|
}
|
|
616
|
+
return {
|
|
617
|
+
...thread,
|
|
618
|
+
createdAt: new Date(thread.createdAt),
|
|
619
|
+
updatedAt: new Date(thread.updatedAt)
|
|
620
|
+
};
|
|
1067
621
|
} catch (error$1) {
|
|
1068
622
|
throw new error.MastraError(
|
|
1069
623
|
{
|
|
1070
|
-
id: "
|
|
624
|
+
id: storage.createStorageErrorId("LANCE", "GET_THREAD_BY_ID", "FAILED"),
|
|
1071
625
|
domain: error.ErrorDomain.STORAGE,
|
|
1072
|
-
category: error.ErrorCategory.
|
|
1073
|
-
details: { tableName }
|
|
626
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1074
627
|
},
|
|
1075
628
|
error$1
|
|
1076
629
|
);
|
|
1077
630
|
}
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
634
|
+
* @param thread - The thread to save
|
|
635
|
+
* @returns The saved thread
|
|
636
|
+
*/
|
|
637
|
+
async saveThread({ thread }) {
|
|
1078
638
|
try {
|
|
1079
|
-
const
|
|
1080
|
-
await this.client.
|
|
639
|
+
const record = { ...thread, metadata: JSON.stringify(thread.metadata) };
|
|
640
|
+
const table = await this.client.openTable(storage.TABLE_THREADS);
|
|
641
|
+
await table.add([record], { mode: "append" });
|
|
642
|
+
return thread;
|
|
1081
643
|
} catch (error$1) {
|
|
1082
|
-
if (error$1.message?.includes("already exists")) {
|
|
1083
|
-
this.logger.debug(`Table '${tableName}' already exists, skipping create`);
|
|
1084
|
-
return;
|
|
1085
|
-
}
|
|
1086
644
|
throw new error.MastraError(
|
|
1087
645
|
{
|
|
1088
|
-
id: "
|
|
646
|
+
id: storage.createStorageErrorId("LANCE", "SAVE_THREAD", "FAILED"),
|
|
1089
647
|
domain: error.ErrorDomain.STORAGE,
|
|
1090
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1091
|
-
details: { tableName }
|
|
648
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1092
649
|
},
|
|
1093
650
|
error$1
|
|
1094
651
|
);
|
|
1095
652
|
}
|
|
1096
653
|
}
|
|
1097
|
-
async
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
654
|
+
async updateThread({
|
|
655
|
+
id,
|
|
656
|
+
title,
|
|
657
|
+
metadata
|
|
658
|
+
}) {
|
|
659
|
+
const maxRetries = 5;
|
|
660
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
661
|
+
try {
|
|
662
|
+
const current = await this.getThreadById({ threadId: id });
|
|
663
|
+
if (!current) {
|
|
664
|
+
throw new Error(`Thread with id ${id} not found`);
|
|
665
|
+
}
|
|
666
|
+
const mergedMetadata = { ...current.metadata, ...metadata };
|
|
667
|
+
const record = {
|
|
668
|
+
id,
|
|
669
|
+
title,
|
|
670
|
+
metadata: JSON.stringify(mergedMetadata),
|
|
671
|
+
updatedAt: (/* @__PURE__ */ new Date()).getTime()
|
|
672
|
+
};
|
|
673
|
+
const table = await this.client.openTable(storage.TABLE_THREADS);
|
|
674
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
675
|
+
const updatedThread = await this.getThreadById({ threadId: id });
|
|
676
|
+
if (!updatedThread) {
|
|
677
|
+
throw new Error(`Failed to retrieve updated thread ${id}`);
|
|
678
|
+
}
|
|
679
|
+
return updatedThread;
|
|
680
|
+
} catch (error$1) {
|
|
681
|
+
if (error$1.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
682
|
+
const delay = Math.pow(2, attempt) * 10;
|
|
683
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
684
|
+
continue;
|
|
685
|
+
}
|
|
686
|
+
throw new error.MastraError(
|
|
687
|
+
{
|
|
688
|
+
id: storage.createStorageErrorId("LANCE", "UPDATE_THREAD", "FAILED"),
|
|
689
|
+
domain: error.ErrorDomain.STORAGE,
|
|
690
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
691
|
+
},
|
|
692
|
+
error$1
|
|
693
|
+
);
|
|
1104
694
|
}
|
|
1105
|
-
}
|
|
695
|
+
}
|
|
696
|
+
throw new error.MastraError(
|
|
697
|
+
{
|
|
698
|
+
id: storage.createStorageErrorId("LANCE", "UPDATE_THREAD", "FAILED"),
|
|
699
|
+
domain: error.ErrorDomain.STORAGE,
|
|
700
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
701
|
+
},
|
|
702
|
+
new Error("All retries exhausted")
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
async deleteThread({ threadId }) {
|
|
706
|
+
try {
|
|
707
|
+
const table = await this.client.openTable(storage.TABLE_THREADS);
|
|
708
|
+
await table.delete(`id = '${threadId}'`);
|
|
709
|
+
const messagesTable = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
710
|
+
await messagesTable.delete(`thread_id = '${threadId}'`);
|
|
711
|
+
} catch (error$1) {
|
|
1106
712
|
throw new error.MastraError(
|
|
1107
713
|
{
|
|
1108
|
-
id: "
|
|
714
|
+
id: storage.createStorageErrorId("LANCE", "DELETE_THREAD", "FAILED"),
|
|
1109
715
|
domain: error.ErrorDomain.STORAGE,
|
|
1110
|
-
category: error.ErrorCategory.
|
|
1111
|
-
text: validationError.message,
|
|
1112
|
-
details: { tableName }
|
|
716
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1113
717
|
},
|
|
1114
|
-
|
|
718
|
+
error$1
|
|
1115
719
|
);
|
|
1116
720
|
}
|
|
721
|
+
}
|
|
722
|
+
normalizeMessage(message) {
|
|
723
|
+
const { thread_id, ...rest } = message;
|
|
724
|
+
return {
|
|
725
|
+
...rest,
|
|
726
|
+
threadId: thread_id,
|
|
727
|
+
content: typeof message.content === "string" ? (() => {
|
|
728
|
+
try {
|
|
729
|
+
return JSON.parse(message.content);
|
|
730
|
+
} catch {
|
|
731
|
+
return message.content;
|
|
732
|
+
}
|
|
733
|
+
})() : message.content
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
async listMessagesById({ messageIds }) {
|
|
737
|
+
if (messageIds.length === 0) return { messages: [] };
|
|
1117
738
|
try {
|
|
1118
|
-
await this.client.
|
|
739
|
+
const table = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
740
|
+
const quotedIds = messageIds.map((id) => `'${id}'`).join(", ");
|
|
741
|
+
const allRecords = await table.query().where(`id IN (${quotedIds})`).toArray();
|
|
742
|
+
const messages = processResultWithTypeConversion(
|
|
743
|
+
allRecords,
|
|
744
|
+
await getTableSchema({ tableName: storage.TABLE_MESSAGES, client: this.client })
|
|
745
|
+
);
|
|
746
|
+
const list = new agent.MessageList().add(
|
|
747
|
+
messages.map(this.normalizeMessage),
|
|
748
|
+
"memory"
|
|
749
|
+
);
|
|
750
|
+
return { messages: list.get.all.db() };
|
|
1119
751
|
} catch (error$1) {
|
|
1120
|
-
if (error$1.toString().includes("was not found") || error$1.message?.includes("Table not found")) {
|
|
1121
|
-
this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
|
|
1122
|
-
return;
|
|
1123
|
-
}
|
|
1124
752
|
throw new error.MastraError(
|
|
1125
753
|
{
|
|
1126
|
-
id: "
|
|
754
|
+
id: storage.createStorageErrorId("LANCE", "LIST_MESSAGES_BY_ID", "FAILED"),
|
|
1127
755
|
domain: error.ErrorDomain.STORAGE,
|
|
1128
756
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1129
|
-
details: {
|
|
757
|
+
details: {
|
|
758
|
+
messageIds: JSON.stringify(messageIds)
|
|
759
|
+
}
|
|
1130
760
|
},
|
|
1131
761
|
error$1
|
|
1132
762
|
);
|
|
1133
763
|
}
|
|
1134
764
|
}
|
|
1135
|
-
async
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
}) {
|
|
1140
|
-
try {
|
|
1141
|
-
if (!this.client) {
|
|
1142
|
-
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
1143
|
-
}
|
|
1144
|
-
if (!tableName) {
|
|
1145
|
-
throw new Error("tableName is required for alterTable.");
|
|
1146
|
-
}
|
|
1147
|
-
if (!schema) {
|
|
1148
|
-
throw new Error("schema is required for alterTable.");
|
|
1149
|
-
}
|
|
1150
|
-
if (!ifNotExists || ifNotExists.length === 0) {
|
|
1151
|
-
this.logger.debug("No columns specified to add in alterTable, skipping.");
|
|
1152
|
-
return;
|
|
1153
|
-
}
|
|
1154
|
-
} catch (validationError) {
|
|
765
|
+
async listMessages(args) {
|
|
766
|
+
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
767
|
+
const threadIds = Array.isArray(threadId) ? threadId : [threadId];
|
|
768
|
+
if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) {
|
|
1155
769
|
throw new error.MastraError(
|
|
1156
770
|
{
|
|
1157
|
-
id: "
|
|
771
|
+
id: storage.createStorageErrorId("LANCE", "LIST_MESSAGES", "INVALID_THREAD_ID"),
|
|
1158
772
|
domain: error.ErrorDomain.STORAGE,
|
|
1159
|
-
category: error.ErrorCategory.
|
|
1160
|
-
|
|
1161
|
-
details: { tableName }
|
|
773
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
774
|
+
details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
|
|
1162
775
|
},
|
|
1163
|
-
|
|
776
|
+
new Error("threadId must be a non-empty string or array of non-empty strings")
|
|
1164
777
|
);
|
|
1165
778
|
}
|
|
779
|
+
const perPage = storage.normalizePerPage(perPageInput, 40);
|
|
780
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1166
781
|
try {
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
}
|
|
1178
|
-
const
|
|
1179
|
-
|
|
782
|
+
if (page < 0) {
|
|
783
|
+
throw new error.MastraError(
|
|
784
|
+
{
|
|
785
|
+
id: storage.createStorageErrorId("LANCE", "LIST_MESSAGES", "INVALID_PAGE"),
|
|
786
|
+
domain: error.ErrorDomain.STORAGE,
|
|
787
|
+
category: error.ErrorCategory.USER,
|
|
788
|
+
details: { page }
|
|
789
|
+
},
|
|
790
|
+
new Error("page must be >= 0")
|
|
791
|
+
);
|
|
792
|
+
}
|
|
793
|
+
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
794
|
+
const table = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
795
|
+
const threadCondition = threadIds.length === 1 ? `thread_id = '${this.escapeSql(threadIds[0])}'` : `thread_id IN (${threadIds.map((t) => `'${this.escapeSql(t)}'`).join(", ")})`;
|
|
796
|
+
const conditions = [threadCondition];
|
|
797
|
+
if (resourceId) {
|
|
798
|
+
conditions.push(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
|
|
799
|
+
}
|
|
800
|
+
if (filter?.dateRange?.start) {
|
|
801
|
+
const startTime = filter.dateRange.start instanceof Date ? filter.dateRange.start.getTime() : new Date(filter.dateRange.start).getTime();
|
|
802
|
+
const startOp = filter.dateRange.startExclusive ? ">" : ">=";
|
|
803
|
+
conditions.push(`\`createdAt\` ${startOp} ${startTime}`);
|
|
804
|
+
}
|
|
805
|
+
if (filter?.dateRange?.end) {
|
|
806
|
+
const endTime = filter.dateRange.end instanceof Date ? filter.dateRange.end.getTime() : new Date(filter.dateRange.end).getTime();
|
|
807
|
+
const endOp = filter.dateRange.endExclusive ? "<" : "<=";
|
|
808
|
+
conditions.push(`\`createdAt\` ${endOp} ${endTime}`);
|
|
809
|
+
}
|
|
810
|
+
const whereClause = conditions.join(" AND ");
|
|
811
|
+
const total = await table.countRows(whereClause);
|
|
812
|
+
const query = table.query().where(whereClause);
|
|
813
|
+
let allRecords = await query.toArray();
|
|
814
|
+
allRecords.sort((a, b) => {
|
|
815
|
+
const aValue = field === "createdAt" ? a.createdAt : a[field];
|
|
816
|
+
const bValue = field === "createdAt" ? b.createdAt : b[field];
|
|
817
|
+
if (aValue == null && bValue == null) return 0;
|
|
818
|
+
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
819
|
+
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
820
|
+
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
821
|
+
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
822
|
+
}
|
|
823
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
824
|
+
});
|
|
825
|
+
const paginatedRecords = allRecords.slice(offset, offset + perPage);
|
|
826
|
+
const messages = paginatedRecords.map((row) => this.normalizeMessage(row));
|
|
827
|
+
if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
|
|
1180
828
|
return {
|
|
1181
|
-
|
|
1182
|
-
|
|
829
|
+
messages: [],
|
|
830
|
+
total: 0,
|
|
831
|
+
page,
|
|
832
|
+
perPage: perPageForResponse,
|
|
833
|
+
hasMore: false
|
|
1183
834
|
};
|
|
1184
|
-
});
|
|
1185
|
-
if (columnsToAdd.length > 0) {
|
|
1186
|
-
await table.addColumns(columnsToAdd);
|
|
1187
|
-
this.logger?.info?.(`Added columns [${columnsToAdd.map((c) => c.name).join(", ")}] to table ${tableName}`);
|
|
1188
835
|
}
|
|
836
|
+
const messageIds = new Set(messages.map((m) => m.id));
|
|
837
|
+
if (include && include.length > 0) {
|
|
838
|
+
const threadIds2 = [...new Set(include.map((item) => item.threadId || threadId))];
|
|
839
|
+
const allThreadMessages = [];
|
|
840
|
+
for (const tid of threadIds2) {
|
|
841
|
+
const threadQuery = table.query().where(`thread_id = '${tid}'`);
|
|
842
|
+
let threadRecords = await threadQuery.toArray();
|
|
843
|
+
allThreadMessages.push(...threadRecords);
|
|
844
|
+
}
|
|
845
|
+
allThreadMessages.sort((a, b) => a.createdAt - b.createdAt);
|
|
846
|
+
const contextMessages = this.processMessagesWithContext(allThreadMessages, include);
|
|
847
|
+
const includedMessages = contextMessages.map((row) => this.normalizeMessage(row));
|
|
848
|
+
for (const includeMsg of includedMessages) {
|
|
849
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
850
|
+
messages.push(includeMsg);
|
|
851
|
+
messageIds.add(includeMsg.id);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
const list = new agent.MessageList().add(messages, "memory");
|
|
856
|
+
let finalMessages = list.get.all.db();
|
|
857
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
858
|
+
const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
|
|
859
|
+
const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
|
|
860
|
+
if (aValue == null && bValue == null) return 0;
|
|
861
|
+
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
862
|
+
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
863
|
+
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
864
|
+
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
865
|
+
}
|
|
866
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
867
|
+
});
|
|
868
|
+
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
869
|
+
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
870
|
+
const fetchedAll = perPageInput === false || allThreadMessagesReturned;
|
|
871
|
+
const hasMore = !fetchedAll && offset + perPage < total;
|
|
872
|
+
return {
|
|
873
|
+
messages: finalMessages,
|
|
874
|
+
total,
|
|
875
|
+
page,
|
|
876
|
+
perPage: perPageForResponse,
|
|
877
|
+
hasMore
|
|
878
|
+
};
|
|
1189
879
|
} catch (error$1) {
|
|
1190
|
-
|
|
880
|
+
const mastraError = new error.MastraError(
|
|
1191
881
|
{
|
|
1192
|
-
id: "
|
|
882
|
+
id: storage.createStorageErrorId("LANCE", "LIST_MESSAGES", "FAILED"),
|
|
1193
883
|
domain: error.ErrorDomain.STORAGE,
|
|
1194
884
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1195
|
-
details: {
|
|
885
|
+
details: {
|
|
886
|
+
threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
|
|
887
|
+
resourceId: resourceId ?? ""
|
|
888
|
+
}
|
|
1196
889
|
},
|
|
1197
890
|
error$1
|
|
1198
891
|
);
|
|
892
|
+
this.logger?.error?.(mastraError.toString());
|
|
893
|
+
this.logger?.trackException?.(mastraError);
|
|
894
|
+
return {
|
|
895
|
+
messages: [],
|
|
896
|
+
total: 0,
|
|
897
|
+
page,
|
|
898
|
+
perPage: perPageForResponse,
|
|
899
|
+
hasMore: false
|
|
900
|
+
};
|
|
1199
901
|
}
|
|
1200
902
|
}
|
|
1201
|
-
async
|
|
903
|
+
async saveMessages(args) {
|
|
1202
904
|
try {
|
|
1203
|
-
|
|
1204
|
-
|
|
905
|
+
const { messages } = args;
|
|
906
|
+
if (messages.length === 0) {
|
|
907
|
+
return { messages: [] };
|
|
1205
908
|
}
|
|
1206
|
-
|
|
1207
|
-
|
|
909
|
+
const threadId = messages[0]?.threadId;
|
|
910
|
+
if (!threadId) {
|
|
911
|
+
throw new Error("Thread ID is required");
|
|
1208
912
|
}
|
|
1209
|
-
|
|
913
|
+
for (const message of messages) {
|
|
914
|
+
if (!message.id) {
|
|
915
|
+
throw new Error("Message ID is required");
|
|
916
|
+
}
|
|
917
|
+
if (!message.threadId) {
|
|
918
|
+
throw new Error("Thread ID is required for all messages");
|
|
919
|
+
}
|
|
920
|
+
if (message.resourceId === null || message.resourceId === void 0) {
|
|
921
|
+
throw new Error("Resource ID cannot be null or undefined");
|
|
922
|
+
}
|
|
923
|
+
if (!message.content) {
|
|
924
|
+
throw new Error("Message content is required");
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
const transformedMessages = messages.map((message) => {
|
|
928
|
+
const { threadId: threadId2, type, ...rest } = message;
|
|
929
|
+
return {
|
|
930
|
+
...rest,
|
|
931
|
+
thread_id: threadId2,
|
|
932
|
+
type: type ?? "v2",
|
|
933
|
+
content: JSON.stringify(message.content)
|
|
934
|
+
};
|
|
935
|
+
});
|
|
936
|
+
const table = await this.client.openTable(storage.TABLE_MESSAGES);
|
|
937
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
|
|
938
|
+
const threadsTable = await this.client.openTable(storage.TABLE_THREADS);
|
|
939
|
+
const currentTime = (/* @__PURE__ */ new Date()).getTime();
|
|
940
|
+
const updateRecord = { id: threadId, updatedAt: currentTime };
|
|
941
|
+
await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([updateRecord]);
|
|
942
|
+
const list = new agent.MessageList().add(messages, "memory");
|
|
943
|
+
return { messages: list.get.all.db() };
|
|
944
|
+
} catch (error$1) {
|
|
1210
945
|
throw new error.MastraError(
|
|
1211
946
|
{
|
|
1212
|
-
id: "
|
|
947
|
+
id: storage.createStorageErrorId("LANCE", "SAVE_MESSAGES", "FAILED"),
|
|
1213
948
|
domain: error.ErrorDomain.STORAGE,
|
|
1214
|
-
category: error.ErrorCategory.
|
|
1215
|
-
text: validationError.message,
|
|
1216
|
-
details: { tableName }
|
|
949
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1217
950
|
},
|
|
1218
|
-
|
|
951
|
+
error$1
|
|
1219
952
|
);
|
|
1220
953
|
}
|
|
954
|
+
}
|
|
955
|
+
async listThreads(args) {
|
|
956
|
+
const { page = 0, perPage: perPageInput, orderBy, filter } = args;
|
|
1221
957
|
try {
|
|
1222
|
-
|
|
1223
|
-
await table.delete("1=1");
|
|
958
|
+
this.validatePaginationInput(page, perPageInput ?? 100);
|
|
1224
959
|
} catch (error$1) {
|
|
1225
960
|
throw new error.MastraError(
|
|
1226
961
|
{
|
|
1227
|
-
id: "
|
|
962
|
+
id: storage.createStorageErrorId("LANCE", "LIST_THREADS", "INVALID_PAGE"),
|
|
1228
963
|
domain: error.ErrorDomain.STORAGE,
|
|
1229
|
-
category: error.ErrorCategory.
|
|
1230
|
-
details: {
|
|
964
|
+
category: error.ErrorCategory.USER,
|
|
965
|
+
details: { page, ...perPageInput !== void 0 && { perPage: perPageInput } }
|
|
1231
966
|
},
|
|
1232
|
-
error$1
|
|
967
|
+
error$1 instanceof Error ? error$1 : new Error("Invalid pagination parameters")
|
|
1233
968
|
);
|
|
1234
969
|
}
|
|
1235
|
-
|
|
1236
|
-
async insert({ tableName, record }) {
|
|
970
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
1237
971
|
try {
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
}
|
|
1241
|
-
if (!tableName) {
|
|
1242
|
-
throw new Error("tableName is required for insert.");
|
|
1243
|
-
}
|
|
1244
|
-
if (!record || Object.keys(record).length === 0) {
|
|
1245
|
-
throw new Error("record is required and cannot be empty for insert.");
|
|
1246
|
-
}
|
|
1247
|
-
} catch (validationError) {
|
|
972
|
+
this.validateMetadataKeys(filter?.metadata);
|
|
973
|
+
} catch (error$1) {
|
|
1248
974
|
throw new error.MastraError(
|
|
1249
975
|
{
|
|
1250
|
-
id: "
|
|
976
|
+
id: storage.createStorageErrorId("LANCE", "LIST_THREADS", "INVALID_METADATA_KEY"),
|
|
1251
977
|
domain: error.ErrorDomain.STORAGE,
|
|
1252
978
|
category: error.ErrorCategory.USER,
|
|
1253
|
-
|
|
1254
|
-
details: { tableName }
|
|
979
|
+
details: { metadataKeys: filter?.metadata ? Object.keys(filter.metadata).join(", ") : "" }
|
|
1255
980
|
},
|
|
1256
|
-
|
|
981
|
+
error$1 instanceof Error ? error$1 : new Error("Invalid metadata key")
|
|
1257
982
|
);
|
|
1258
983
|
}
|
|
1259
984
|
try {
|
|
1260
|
-
const
|
|
1261
|
-
const
|
|
1262
|
-
const
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
985
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
986
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
987
|
+
const table = await this.client.openTable(storage.TABLE_THREADS);
|
|
988
|
+
const whereClauses = [];
|
|
989
|
+
if (filter?.resourceId) {
|
|
990
|
+
whereClauses.push(`\`resourceId\` = '${this.escapeSql(filter.resourceId)}'`);
|
|
991
|
+
}
|
|
992
|
+
const whereClause = whereClauses.length > 0 ? whereClauses.join(" AND ") : "";
|
|
993
|
+
const query = whereClause ? table.query().where(whereClause) : table.query();
|
|
994
|
+
let records = await query.toArray();
|
|
995
|
+
if (filter?.metadata && Object.keys(filter.metadata).length > 0) {
|
|
996
|
+
records = records.filter((record) => {
|
|
997
|
+
if (!record.metadata) return false;
|
|
998
|
+
let recordMeta;
|
|
999
|
+
if (typeof record.metadata === "string") {
|
|
1000
|
+
try {
|
|
1001
|
+
recordMeta = JSON.parse(record.metadata);
|
|
1002
|
+
} catch {
|
|
1003
|
+
return false;
|
|
1004
|
+
}
|
|
1005
|
+
} else {
|
|
1006
|
+
recordMeta = record.metadata;
|
|
1007
|
+
}
|
|
1008
|
+
return Object.entries(filter.metadata).every(([key, value]) => recordMeta[key] === value);
|
|
1009
|
+
});
|
|
1268
1010
|
}
|
|
1269
|
-
|
|
1270
|
-
|
|
1011
|
+
const total = records.length;
|
|
1012
|
+
records.sort((a, b) => {
|
|
1013
|
+
const aValue = ["createdAt", "updatedAt"].includes(field) ? new Date(a[field]).getTime() : a[field];
|
|
1014
|
+
const bValue = ["createdAt", "updatedAt"].includes(field) ? new Date(b[field]).getTime() : b[field];
|
|
1015
|
+
if (aValue == null && bValue == null) return 0;
|
|
1016
|
+
if (aValue == null) return direction === "ASC" ? -1 : 1;
|
|
1017
|
+
if (bValue == null) return direction === "ASC" ? 1 : -1;
|
|
1018
|
+
if (typeof aValue === "string" && typeof bValue === "string") {
|
|
1019
|
+
return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
|
|
1020
|
+
}
|
|
1021
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
1022
|
+
});
|
|
1023
|
+
const paginatedRecords = records.slice(offset, offset + perPage);
|
|
1024
|
+
const schema = await getTableSchema({ tableName: storage.TABLE_THREADS, client: this.client });
|
|
1025
|
+
const threads = paginatedRecords.map(
|
|
1026
|
+
(record) => processResultWithTypeConversion(record, schema)
|
|
1027
|
+
);
|
|
1028
|
+
return {
|
|
1029
|
+
threads,
|
|
1030
|
+
total,
|
|
1031
|
+
page,
|
|
1032
|
+
perPage: perPageForResponse,
|
|
1033
|
+
hasMore: offset + perPage < total
|
|
1034
|
+
};
|
|
1271
1035
|
} catch (error$1) {
|
|
1272
1036
|
throw new error.MastraError(
|
|
1273
1037
|
{
|
|
1274
|
-
id: "
|
|
1038
|
+
id: storage.createStorageErrorId("LANCE", "LIST_THREADS", "FAILED"),
|
|
1275
1039
|
domain: error.ErrorDomain.STORAGE,
|
|
1276
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1277
|
-
details: { tableName }
|
|
1040
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1278
1041
|
},
|
|
1279
1042
|
error$1
|
|
1280
1043
|
);
|
|
1281
1044
|
}
|
|
1282
1045
|
}
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1046
|
+
/**
|
|
1047
|
+
* Processes messages to include context messages based on withPreviousMessages and withNextMessages
|
|
1048
|
+
* @param records - The sorted array of records to process
|
|
1049
|
+
* @param include - The array of include specifications with context parameters
|
|
1050
|
+
* @returns The processed array with context messages included
|
|
1051
|
+
*/
|
|
1052
|
+
processMessagesWithContext(records, include) {
|
|
1053
|
+
const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
|
|
1054
|
+
if (messagesWithContext.length === 0) {
|
|
1055
|
+
return records;
|
|
1056
|
+
}
|
|
1057
|
+
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
1058
|
+
records.forEach((message, index) => {
|
|
1059
|
+
messageIndexMap.set(message.id, index);
|
|
1060
|
+
});
|
|
1061
|
+
const additionalIndices = /* @__PURE__ */ new Set();
|
|
1062
|
+
for (const item of messagesWithContext) {
|
|
1063
|
+
const messageIndex = messageIndexMap.get(item.id);
|
|
1064
|
+
if (messageIndex !== void 0) {
|
|
1065
|
+
if (item.withPreviousMessages) {
|
|
1066
|
+
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
1067
|
+
for (let i = startIdx; i < messageIndex; i++) {
|
|
1068
|
+
additionalIndices.add(i);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
if (item.withNextMessages) {
|
|
1072
|
+
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
1073
|
+
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
1074
|
+
additionalIndices.add(i);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1287
1077
|
}
|
|
1288
|
-
|
|
1289
|
-
|
|
1078
|
+
}
|
|
1079
|
+
if (additionalIndices.size === 0) {
|
|
1080
|
+
return records;
|
|
1081
|
+
}
|
|
1082
|
+
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
1083
|
+
const allIndices = /* @__PURE__ */ new Set();
|
|
1084
|
+
records.forEach((record, index) => {
|
|
1085
|
+
if (originalMatchIds.has(record.id)) {
|
|
1086
|
+
allIndices.add(index);
|
|
1290
1087
|
}
|
|
1291
|
-
|
|
1292
|
-
|
|
1088
|
+
});
|
|
1089
|
+
additionalIndices.forEach((index) => {
|
|
1090
|
+
allIndices.add(index);
|
|
1091
|
+
});
|
|
1092
|
+
return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
|
|
1093
|
+
}
|
|
1094
|
+
/**
|
|
1095
|
+
* Parse message data from LanceDB record format to MastraDBMessage format
|
|
1096
|
+
*/
|
|
1097
|
+
parseMessageData(data) {
|
|
1098
|
+
const { thread_id, ...rest } = data;
|
|
1099
|
+
return {
|
|
1100
|
+
...rest,
|
|
1101
|
+
threadId: thread_id,
|
|
1102
|
+
content: typeof data.content === "string" ? (() => {
|
|
1103
|
+
try {
|
|
1104
|
+
return JSON.parse(data.content);
|
|
1105
|
+
} catch {
|
|
1106
|
+
return data.content;
|
|
1107
|
+
}
|
|
1108
|
+
})() : data.content,
|
|
1109
|
+
createdAt: new Date(data.createdAt),
|
|
1110
|
+
updatedAt: new Date(data.updatedAt)
|
|
1111
|
+
};
|
|
1112
|
+
}
|
|
1113
|
+
async updateMessages(args) {
|
|
1114
|
+
const { messages } = args;
|
|
1115
|
+
this.logger.debug("Updating messages", { count: messages.length });
|
|
1116
|
+
if (!messages.length) {
|
|
1117
|
+
return [];
|
|
1118
|
+
}
|
|
1119
|
+
const updatedMessages = [];
|
|
1120
|
+
const affectedThreadIds = /* @__PURE__ */ new Set();
|
|
1121
|
+
try {
|
|
1122
|
+
for (const updateData of messages) {
|
|
1123
|
+
const { id, ...updates } = updateData;
|
|
1124
|
+
const existingMessage = await this.#db.load({ tableName: storage.TABLE_MESSAGES, keys: { id } });
|
|
1125
|
+
if (!existingMessage) {
|
|
1126
|
+
this.logger.warn("Message not found for update", { id });
|
|
1127
|
+
continue;
|
|
1128
|
+
}
|
|
1129
|
+
const existingMsg = this.parseMessageData(existingMessage);
|
|
1130
|
+
const originalThreadId = existingMsg.threadId;
|
|
1131
|
+
affectedThreadIds.add(originalThreadId);
|
|
1132
|
+
const updatePayload = {};
|
|
1133
|
+
if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
|
|
1134
|
+
if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
|
|
1135
|
+
if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
|
|
1136
|
+
if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
|
|
1137
|
+
updatePayload.thread_id = updates.threadId;
|
|
1138
|
+
affectedThreadIds.add(updates.threadId);
|
|
1139
|
+
}
|
|
1140
|
+
if (updates.content) {
|
|
1141
|
+
const existingContent = existingMsg.content;
|
|
1142
|
+
let newContent = { ...existingContent };
|
|
1143
|
+
if (updates.content.metadata !== void 0) {
|
|
1144
|
+
newContent.metadata = {
|
|
1145
|
+
...existingContent.metadata || {},
|
|
1146
|
+
...updates.content.metadata || {}
|
|
1147
|
+
};
|
|
1148
|
+
}
|
|
1149
|
+
if (updates.content.content !== void 0) {
|
|
1150
|
+
newContent.content = updates.content.content;
|
|
1151
|
+
}
|
|
1152
|
+
if ("parts" in updates.content && updates.content.parts !== void 0) {
|
|
1153
|
+
newContent.parts = updates.content.parts;
|
|
1154
|
+
}
|
|
1155
|
+
updatePayload.content = JSON.stringify(newContent);
|
|
1156
|
+
}
|
|
1157
|
+
await this.#db.insert({ tableName: storage.TABLE_MESSAGES, record: { id, ...updatePayload } });
|
|
1158
|
+
const updatedMessage = await this.#db.load({ tableName: storage.TABLE_MESSAGES, keys: { id } });
|
|
1159
|
+
if (updatedMessage) {
|
|
1160
|
+
updatedMessages.push(this.parseMessageData(updatedMessage));
|
|
1161
|
+
}
|
|
1293
1162
|
}
|
|
1294
|
-
|
|
1163
|
+
for (const threadId of affectedThreadIds) {
|
|
1164
|
+
await this.#db.insert({
|
|
1165
|
+
tableName: storage.TABLE_THREADS,
|
|
1166
|
+
record: { id: threadId, updatedAt: Date.now() }
|
|
1167
|
+
});
|
|
1168
|
+
}
|
|
1169
|
+
return updatedMessages;
|
|
1170
|
+
} catch (error$1) {
|
|
1295
1171
|
throw new error.MastraError(
|
|
1296
1172
|
{
|
|
1297
|
-
id: "
|
|
1173
|
+
id: storage.createStorageErrorId("LANCE", "UPDATE_MESSAGES", "FAILED"),
|
|
1298
1174
|
domain: error.ErrorDomain.STORAGE,
|
|
1299
|
-
category: error.ErrorCategory.
|
|
1300
|
-
|
|
1301
|
-
details: { tableName }
|
|
1175
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1176
|
+
details: { count: messages.length }
|
|
1302
1177
|
},
|
|
1303
|
-
|
|
1178
|
+
error$1
|
|
1304
1179
|
);
|
|
1305
1180
|
}
|
|
1181
|
+
}
|
|
1182
|
+
async getResourceById({ resourceId }) {
|
|
1306
1183
|
try {
|
|
1307
|
-
const
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1184
|
+
const resource = await this.#db.load({ tableName: storage.TABLE_RESOURCES, keys: { id: resourceId } });
|
|
1185
|
+
if (!resource) {
|
|
1186
|
+
return null;
|
|
1187
|
+
}
|
|
1188
|
+
let createdAt;
|
|
1189
|
+
let updatedAt;
|
|
1190
|
+
try {
|
|
1191
|
+
if (resource.createdAt instanceof Date) {
|
|
1192
|
+
createdAt = resource.createdAt;
|
|
1193
|
+
} else if (typeof resource.createdAt === "string") {
|
|
1194
|
+
createdAt = new Date(resource.createdAt);
|
|
1195
|
+
} else if (typeof resource.createdAt === "number") {
|
|
1196
|
+
createdAt = new Date(resource.createdAt);
|
|
1197
|
+
} else {
|
|
1198
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
1316
1199
|
}
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1200
|
+
if (isNaN(createdAt.getTime())) {
|
|
1201
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
1202
|
+
}
|
|
1203
|
+
} catch {
|
|
1204
|
+
createdAt = /* @__PURE__ */ new Date();
|
|
1205
|
+
}
|
|
1206
|
+
try {
|
|
1207
|
+
if (resource.updatedAt instanceof Date) {
|
|
1208
|
+
updatedAt = resource.updatedAt;
|
|
1209
|
+
} else if (typeof resource.updatedAt === "string") {
|
|
1210
|
+
updatedAt = new Date(resource.updatedAt);
|
|
1211
|
+
} else if (typeof resource.updatedAt === "number") {
|
|
1212
|
+
updatedAt = new Date(resource.updatedAt);
|
|
1213
|
+
} else {
|
|
1214
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
1215
|
+
}
|
|
1216
|
+
if (isNaN(updatedAt.getTime())) {
|
|
1217
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
1218
|
+
}
|
|
1219
|
+
} catch {
|
|
1220
|
+
updatedAt = /* @__PURE__ */ new Date();
|
|
1221
|
+
}
|
|
1222
|
+
let workingMemory = resource.workingMemory;
|
|
1223
|
+
if (workingMemory === null || workingMemory === void 0) {
|
|
1224
|
+
workingMemory = void 0;
|
|
1225
|
+
} else if (workingMemory === "") {
|
|
1226
|
+
workingMemory = "";
|
|
1227
|
+
} else if (typeof workingMemory === "object") {
|
|
1228
|
+
workingMemory = JSON.stringify(workingMemory);
|
|
1229
|
+
}
|
|
1230
|
+
let metadata = resource.metadata;
|
|
1231
|
+
if (metadata === "" || metadata === null || metadata === void 0) {
|
|
1232
|
+
metadata = void 0;
|
|
1233
|
+
} else if (typeof metadata === "string") {
|
|
1234
|
+
try {
|
|
1235
|
+
metadata = JSON.parse(metadata);
|
|
1236
|
+
} catch {
|
|
1237
|
+
metadata = metadata;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
return {
|
|
1241
|
+
...resource,
|
|
1242
|
+
createdAt,
|
|
1243
|
+
updatedAt,
|
|
1244
|
+
workingMemory,
|
|
1245
|
+
metadata
|
|
1246
|
+
};
|
|
1320
1247
|
} catch (error$1) {
|
|
1321
1248
|
throw new error.MastraError(
|
|
1322
1249
|
{
|
|
1323
|
-
id: "
|
|
1250
|
+
id: storage.createStorageErrorId("LANCE", "GET_RESOURCE_BY_ID", "FAILED"),
|
|
1324
1251
|
domain: error.ErrorDomain.STORAGE,
|
|
1325
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1326
|
-
details: { tableName }
|
|
1252
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1327
1253
|
},
|
|
1328
1254
|
error$1
|
|
1329
1255
|
);
|
|
1330
1256
|
}
|
|
1331
1257
|
}
|
|
1332
|
-
async
|
|
1333
|
-
try {
|
|
1334
|
-
if (!this.client) {
|
|
1335
|
-
throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
|
|
1336
|
-
}
|
|
1337
|
-
if (!tableName) {
|
|
1338
|
-
throw new Error("tableName is required for load.");
|
|
1339
|
-
}
|
|
1340
|
-
if (!keys || Object.keys(keys).length === 0) {
|
|
1341
|
-
throw new Error("keys are required and cannot be empty for load.");
|
|
1342
|
-
}
|
|
1343
|
-
} catch (validationError) {
|
|
1344
|
-
throw new error.MastraError(
|
|
1345
|
-
{
|
|
1346
|
-
id: "STORAGE_LANCE_STORAGE_LOAD_INVALID_ARGS",
|
|
1347
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1348
|
-
category: error.ErrorCategory.USER,
|
|
1349
|
-
text: validationError.message,
|
|
1350
|
-
details: { tableName }
|
|
1351
|
-
},
|
|
1352
|
-
validationError
|
|
1353
|
-
);
|
|
1354
|
-
}
|
|
1258
|
+
async saveResource({ resource }) {
|
|
1355
1259
|
try {
|
|
1356
|
-
const
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
return `${quotedKey} IS NULL`;
|
|
1368
|
-
} else {
|
|
1369
|
-
return `${quotedKey} = ${value}`;
|
|
1370
|
-
}
|
|
1371
|
-
}).join(" AND ");
|
|
1372
|
-
this.logger.debug("where clause generated: " + filterConditions);
|
|
1373
|
-
query.where(filterConditions);
|
|
1374
|
-
}
|
|
1375
|
-
const result = await query.limit(1).toArray();
|
|
1376
|
-
if (result.length === 0) {
|
|
1377
|
-
this.logger.debug("No record found");
|
|
1378
|
-
return null;
|
|
1379
|
-
}
|
|
1380
|
-
return processResultWithTypeConversion(result[0], tableSchema);
|
|
1260
|
+
const record = {
|
|
1261
|
+
...resource,
|
|
1262
|
+
metadata: resource.metadata ? JSON.stringify(resource.metadata) : "",
|
|
1263
|
+
createdAt: resource.createdAt.getTime(),
|
|
1264
|
+
// Store as timestamp (milliseconds)
|
|
1265
|
+
updatedAt: resource.updatedAt.getTime()
|
|
1266
|
+
// Store as timestamp (milliseconds)
|
|
1267
|
+
};
|
|
1268
|
+
const table = await this.client.openTable(storage.TABLE_RESOURCES);
|
|
1269
|
+
await table.add([record], { mode: "append" });
|
|
1270
|
+
return resource;
|
|
1381
1271
|
} catch (error$1) {
|
|
1382
|
-
if (error$1 instanceof error.MastraError) throw error$1;
|
|
1383
1272
|
throw new error.MastraError(
|
|
1384
1273
|
{
|
|
1385
|
-
id: "
|
|
1274
|
+
id: storage.createStorageErrorId("LANCE", "SAVE_RESOURCE", "FAILED"),
|
|
1386
1275
|
domain: error.ErrorDomain.STORAGE,
|
|
1387
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1388
|
-
details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
|
|
1276
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1389
1277
|
},
|
|
1390
1278
|
error$1
|
|
1391
1279
|
);
|
|
1392
1280
|
}
|
|
1393
1281
|
}
|
|
1282
|
+
async updateResource({
|
|
1283
|
+
resourceId,
|
|
1284
|
+
workingMemory,
|
|
1285
|
+
metadata
|
|
1286
|
+
}) {
|
|
1287
|
+
const maxRetries = 3;
|
|
1288
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
1289
|
+
try {
|
|
1290
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
1291
|
+
if (!existingResource) {
|
|
1292
|
+
const newResource = {
|
|
1293
|
+
id: resourceId,
|
|
1294
|
+
workingMemory,
|
|
1295
|
+
metadata: metadata || {},
|
|
1296
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1297
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1298
|
+
};
|
|
1299
|
+
return this.saveResource({ resource: newResource });
|
|
1300
|
+
}
|
|
1301
|
+
const updatedResource = {
|
|
1302
|
+
...existingResource,
|
|
1303
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
1304
|
+
metadata: {
|
|
1305
|
+
...existingResource.metadata,
|
|
1306
|
+
...metadata
|
|
1307
|
+
},
|
|
1308
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1309
|
+
};
|
|
1310
|
+
const record = {
|
|
1311
|
+
id: resourceId,
|
|
1312
|
+
workingMemory: updatedResource.workingMemory || "",
|
|
1313
|
+
metadata: updatedResource.metadata ? JSON.stringify(updatedResource.metadata) : "",
|
|
1314
|
+
updatedAt: updatedResource.updatedAt.getTime()
|
|
1315
|
+
// Store as timestamp (milliseconds)
|
|
1316
|
+
};
|
|
1317
|
+
const table = await this.client.openTable(storage.TABLE_RESOURCES);
|
|
1318
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
1319
|
+
return updatedResource;
|
|
1320
|
+
} catch (error$1) {
|
|
1321
|
+
if (error$1.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
|
|
1322
|
+
const delay = Math.pow(2, attempt) * 10;
|
|
1323
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
1324
|
+
continue;
|
|
1325
|
+
}
|
|
1326
|
+
throw new error.MastraError(
|
|
1327
|
+
{
|
|
1328
|
+
id: storage.createStorageErrorId("LANCE", "UPDATE_RESOURCE", "FAILED"),
|
|
1329
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1330
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1331
|
+
},
|
|
1332
|
+
error$1
|
|
1333
|
+
);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
throw new Error("Unexpected end of retry loop");
|
|
1337
|
+
}
|
|
1394
1338
|
};
|
|
1395
1339
|
var StoreScoresLance = class extends storage.ScoresStorage {
|
|
1396
1340
|
client;
|
|
1397
|
-
|
|
1341
|
+
#db;
|
|
1342
|
+
constructor(config) {
|
|
1398
1343
|
super();
|
|
1344
|
+
const client = resolveLanceConfig(config);
|
|
1399
1345
|
this.client = client;
|
|
1346
|
+
this.#db = new LanceDB({ client });
|
|
1347
|
+
}
|
|
1348
|
+
async init() {
|
|
1349
|
+
await this.#db.createTable({ tableName: storage.TABLE_SCORERS, schema: storage.SCORERS_SCHEMA });
|
|
1350
|
+
await this.#db.alterTable({
|
|
1351
|
+
tableName: storage.TABLE_SCORERS,
|
|
1352
|
+
schema: storage.SCORERS_SCHEMA,
|
|
1353
|
+
ifNotExists: ["spanId", "requestContext"]
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
async dangerouslyClearAll() {
|
|
1357
|
+
await this.#db.clearTable({ tableName: storage.TABLE_SCORERS });
|
|
1400
1358
|
}
|
|
1401
1359
|
async saveScore(score) {
|
|
1402
1360
|
let validatedScore;
|
|
1403
1361
|
try {
|
|
1404
|
-
validatedScore =
|
|
1362
|
+
validatedScore = evals.saveScorePayloadSchema.parse(score);
|
|
1405
1363
|
} catch (error$1) {
|
|
1406
1364
|
throw new error.MastraError(
|
|
1407
1365
|
{
|
|
1408
|
-
id: "
|
|
1366
|
+
id: storage.createStorageErrorId("LANCE", "SAVE_SCORE", "VALIDATION_FAILED"),
|
|
1409
1367
|
text: "Failed to save score in LanceStorage",
|
|
1410
1368
|
domain: error.ErrorDomain.STORAGE,
|
|
1411
|
-
category: error.ErrorCategory.
|
|
1369
|
+
category: error.ErrorCategory.USER,
|
|
1370
|
+
details: {
|
|
1371
|
+
scorer: typeof score.scorer?.id === "string" ? score.scorer.id : String(score.scorer?.id ?? "unknown"),
|
|
1372
|
+
entityId: score.entityId ?? "unknown",
|
|
1373
|
+
entityType: score.entityType ?? "unknown",
|
|
1374
|
+
traceId: score.traceId ?? "",
|
|
1375
|
+
spanId: score.spanId ?? ""
|
|
1376
|
+
}
|
|
1412
1377
|
},
|
|
1413
1378
|
error$1
|
|
1414
1379
|
);
|
|
1415
1380
|
}
|
|
1381
|
+
const id = crypto.randomUUID();
|
|
1382
|
+
const now = /* @__PURE__ */ new Date();
|
|
1416
1383
|
try {
|
|
1417
|
-
const id = crypto.randomUUID();
|
|
1418
1384
|
const table = await this.client.openTable(storage.TABLE_SCORERS);
|
|
1419
1385
|
const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
|
|
1420
1386
|
const allowedFields = new Set(schema.fields.map((f) => f.name));
|
|
1421
1387
|
const filteredScore = {};
|
|
1422
|
-
Object.keys(validatedScore)
|
|
1388
|
+
for (const key of Object.keys(validatedScore)) {
|
|
1423
1389
|
if (allowedFields.has(key)) {
|
|
1424
|
-
filteredScore[key] =
|
|
1390
|
+
filteredScore[key] = validatedScore[key];
|
|
1425
1391
|
}
|
|
1426
|
-
}
|
|
1392
|
+
}
|
|
1427
1393
|
for (const key in filteredScore) {
|
|
1428
1394
|
if (filteredScore[key] !== null && typeof filteredScore[key] === "object" && !(filteredScore[key] instanceof Date)) {
|
|
1429
1395
|
filteredScore[key] = JSON.stringify(filteredScore[key]);
|
|
1430
1396
|
}
|
|
1431
1397
|
}
|
|
1432
1398
|
filteredScore.id = id;
|
|
1399
|
+
filteredScore.createdAt = now;
|
|
1400
|
+
filteredScore.updatedAt = now;
|
|
1433
1401
|
await table.add([filteredScore], { mode: "append" });
|
|
1434
|
-
return { score };
|
|
1402
|
+
return { score: { ...validatedScore, id, createdAt: now, updatedAt: now } };
|
|
1435
1403
|
} catch (error$1) {
|
|
1436
1404
|
throw new error.MastraError(
|
|
1437
1405
|
{
|
|
1438
|
-
id: "
|
|
1406
|
+
id: storage.createStorageErrorId("LANCE", "SAVE_SCORE", "FAILED"),
|
|
1439
1407
|
text: "Failed to save score in LanceStorage",
|
|
1440
1408
|
domain: error.ErrorDomain.STORAGE,
|
|
1441
1409
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
@@ -1451,12 +1419,11 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1451
1419
|
const query = table.query().where(`id = '${id}'`).limit(1);
|
|
1452
1420
|
const records = await query.toArray();
|
|
1453
1421
|
if (records.length === 0) return null;
|
|
1454
|
-
|
|
1455
|
-
return processResultWithTypeConversion(records[0], schema);
|
|
1422
|
+
return await this.transformScoreRow(records[0]);
|
|
1456
1423
|
} catch (error$1) {
|
|
1457
1424
|
throw new error.MastraError(
|
|
1458
1425
|
{
|
|
1459
|
-
id: "
|
|
1426
|
+
id: storage.createStorageErrorId("LANCE", "GET_SCORE_BY_ID", "FAILED"),
|
|
1460
1427
|
text: "Failed to get score by id in LanceStorage",
|
|
1461
1428
|
domain: error.ErrorDomain.STORAGE,
|
|
1462
1429
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
@@ -1466,7 +1433,23 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1466
1433
|
);
|
|
1467
1434
|
}
|
|
1468
1435
|
}
|
|
1469
|
-
|
|
1436
|
+
/**
|
|
1437
|
+
* LanceDB-specific score row transformation.
|
|
1438
|
+
*
|
|
1439
|
+
* Note: This implementation does NOT use coreTransformScoreRow because:
|
|
1440
|
+
* 1. LanceDB stores schema information in the table itself (requires async fetch)
|
|
1441
|
+
* 2. Uses processResultWithTypeConversion utility for LanceDB-specific type handling
|
|
1442
|
+
*/
|
|
1443
|
+
async transformScoreRow(row) {
|
|
1444
|
+
const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
|
|
1445
|
+
const transformed = processResultWithTypeConversion(row, schema);
|
|
1446
|
+
return {
|
|
1447
|
+
...transformed,
|
|
1448
|
+
createdAt: row.createdAt,
|
|
1449
|
+
updatedAt: row.updatedAt
|
|
1450
|
+
};
|
|
1451
|
+
}
|
|
1452
|
+
async listScoresByScorerId({
|
|
1470
1453
|
scorerId,
|
|
1471
1454
|
pagination,
|
|
1472
1455
|
entityId,
|
|
@@ -1474,9 +1457,10 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1474
1457
|
source
|
|
1475
1458
|
}) {
|
|
1476
1459
|
try {
|
|
1460
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1461
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
1462
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1477
1463
|
const table = await this.client.openTable(storage.TABLE_SCORERS);
|
|
1478
|
-
const { page = 0, perPage = 10 } = pagination || {};
|
|
1479
|
-
const offset = page * perPage;
|
|
1480
1464
|
let query = table.query().where(`\`scorerId\` = '${scorerId}'`);
|
|
1481
1465
|
if (source) {
|
|
1482
1466
|
query = query.where(`\`source\` = '${source}'`);
|
|
@@ -1487,30 +1471,38 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1487
1471
|
if (entityType) {
|
|
1488
1472
|
query = query.where(`\`entityType\` = '${entityType}'`);
|
|
1489
1473
|
}
|
|
1490
|
-
query = query.limit(perPage);
|
|
1491
|
-
if (offset > 0) query.offset(offset);
|
|
1492
|
-
const records = await query.toArray();
|
|
1493
|
-
const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
|
|
1494
|
-
const scores = processResultWithTypeConversion(records, schema);
|
|
1495
1474
|
let totalQuery = table.query().where(`\`scorerId\` = '${scorerId}'`);
|
|
1496
1475
|
if (source) {
|
|
1497
1476
|
totalQuery = totalQuery.where(`\`source\` = '${source}'`);
|
|
1498
1477
|
}
|
|
1478
|
+
if (entityId) {
|
|
1479
|
+
totalQuery = totalQuery.where(`\`entityId\` = '${entityId}'`);
|
|
1480
|
+
}
|
|
1481
|
+
if (entityType) {
|
|
1482
|
+
totalQuery = totalQuery.where(`\`entityType\` = '${entityType}'`);
|
|
1483
|
+
}
|
|
1499
1484
|
const allRecords = await totalQuery.toArray();
|
|
1500
1485
|
const total = allRecords.length;
|
|
1486
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1487
|
+
if (perPageInput !== false) {
|
|
1488
|
+
query = query.limit(perPage);
|
|
1489
|
+
if (start > 0) query = query.offset(start);
|
|
1490
|
+
}
|
|
1491
|
+
const records = await query.toArray();
|
|
1492
|
+
const scores = await Promise.all(records.map(async (record) => await this.transformScoreRow(record)));
|
|
1501
1493
|
return {
|
|
1502
1494
|
pagination: {
|
|
1503
1495
|
page,
|
|
1504
|
-
perPage,
|
|
1496
|
+
perPage: perPageForResponse,
|
|
1505
1497
|
total,
|
|
1506
|
-
hasMore:
|
|
1498
|
+
hasMore: end < total
|
|
1507
1499
|
},
|
|
1508
1500
|
scores
|
|
1509
1501
|
};
|
|
1510
1502
|
} catch (error$1) {
|
|
1511
1503
|
throw new error.MastraError(
|
|
1512
1504
|
{
|
|
1513
|
-
id: "
|
|
1505
|
+
id: storage.createStorageErrorId("LANCE", "LIST_SCORES_BY_SCORER_ID", "FAILED"),
|
|
1514
1506
|
text: "Failed to get scores by scorerId in LanceStorage",
|
|
1515
1507
|
domain: error.ErrorDomain.STORAGE,
|
|
1516
1508
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
@@ -1520,34 +1512,38 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1520
1512
|
);
|
|
1521
1513
|
}
|
|
1522
1514
|
}
|
|
1523
|
-
async
|
|
1515
|
+
async listScoresByRunId({
|
|
1524
1516
|
runId,
|
|
1525
1517
|
pagination
|
|
1526
1518
|
}) {
|
|
1527
1519
|
try {
|
|
1520
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1521
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
1522
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1528
1523
|
const table = await this.client.openTable(storage.TABLE_SCORERS);
|
|
1529
|
-
const { page = 0, perPage = 10 } = pagination || {};
|
|
1530
|
-
const offset = page * perPage;
|
|
1531
|
-
const query = table.query().where(`\`runId\` = '${runId}'`).limit(perPage);
|
|
1532
|
-
if (offset > 0) query.offset(offset);
|
|
1533
|
-
const records = await query.toArray();
|
|
1534
|
-
const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
|
|
1535
|
-
const scores = processResultWithTypeConversion(records, schema);
|
|
1536
1524
|
const allRecords = await table.query().where(`\`runId\` = '${runId}'`).toArray();
|
|
1537
1525
|
const total = allRecords.length;
|
|
1526
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1527
|
+
let query = table.query().where(`\`runId\` = '${runId}'`);
|
|
1528
|
+
if (perPageInput !== false) {
|
|
1529
|
+
query = query.limit(perPage);
|
|
1530
|
+
if (start > 0) query = query.offset(start);
|
|
1531
|
+
}
|
|
1532
|
+
const records = await query.toArray();
|
|
1533
|
+
const scores = await Promise.all(records.map(async (record) => await this.transformScoreRow(record)));
|
|
1538
1534
|
return {
|
|
1539
1535
|
pagination: {
|
|
1540
1536
|
page,
|
|
1541
|
-
perPage,
|
|
1537
|
+
perPage: perPageForResponse,
|
|
1542
1538
|
total,
|
|
1543
|
-
hasMore:
|
|
1539
|
+
hasMore: end < total
|
|
1544
1540
|
},
|
|
1545
1541
|
scores
|
|
1546
1542
|
};
|
|
1547
1543
|
} catch (error$1) {
|
|
1548
1544
|
throw new error.MastraError(
|
|
1549
1545
|
{
|
|
1550
|
-
id: "
|
|
1546
|
+
id: storage.createStorageErrorId("LANCE", "LIST_SCORES_BY_RUN_ID", "FAILED"),
|
|
1551
1547
|
text: "Failed to get scores by runId in LanceStorage",
|
|
1552
1548
|
domain: error.ErrorDomain.STORAGE,
|
|
1553
1549
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
@@ -1557,35 +1553,39 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1557
1553
|
);
|
|
1558
1554
|
}
|
|
1559
1555
|
}
|
|
1560
|
-
async
|
|
1556
|
+
async listScoresByEntityId({
|
|
1561
1557
|
entityId,
|
|
1562
1558
|
entityType,
|
|
1563
1559
|
pagination
|
|
1564
1560
|
}) {
|
|
1565
1561
|
try {
|
|
1562
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1563
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
1564
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1566
1565
|
const table = await this.client.openTable(storage.TABLE_SCORERS);
|
|
1567
|
-
const { page = 0, perPage = 10 } = pagination || {};
|
|
1568
|
-
const offset = page * perPage;
|
|
1569
|
-
const query = table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).limit(perPage);
|
|
1570
|
-
if (offset > 0) query.offset(offset);
|
|
1571
|
-
const records = await query.toArray();
|
|
1572
|
-
const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
|
|
1573
|
-
const scores = processResultWithTypeConversion(records, schema);
|
|
1574
1566
|
const allRecords = await table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).toArray();
|
|
1575
1567
|
const total = allRecords.length;
|
|
1568
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1569
|
+
let query = table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`);
|
|
1570
|
+
if (perPageInput !== false) {
|
|
1571
|
+
query = query.limit(perPage);
|
|
1572
|
+
if (start > 0) query = query.offset(start);
|
|
1573
|
+
}
|
|
1574
|
+
const records = await query.toArray();
|
|
1575
|
+
const scores = await Promise.all(records.map(async (record) => await this.transformScoreRow(record)));
|
|
1576
1576
|
return {
|
|
1577
1577
|
pagination: {
|
|
1578
1578
|
page,
|
|
1579
|
-
perPage,
|
|
1579
|
+
perPage: perPageForResponse,
|
|
1580
1580
|
total,
|
|
1581
|
-
hasMore:
|
|
1581
|
+
hasMore: end < total
|
|
1582
1582
|
},
|
|
1583
1583
|
scores
|
|
1584
1584
|
};
|
|
1585
1585
|
} catch (error$1) {
|
|
1586
1586
|
throw new error.MastraError(
|
|
1587
1587
|
{
|
|
1588
|
-
id: "
|
|
1588
|
+
id: storage.createStorageErrorId("LANCE", "LIST_SCORES_BY_ENTITY_ID", "FAILED"),
|
|
1589
1589
|
text: "Failed to get scores by entityId and entityType in LanceStorage",
|
|
1590
1590
|
domain: error.ErrorDomain.STORAGE,
|
|
1591
1591
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
@@ -1595,307 +1595,138 @@ var StoreScoresLance = class extends storage.ScoresStorage {
|
|
|
1595
1595
|
);
|
|
1596
1596
|
}
|
|
1597
1597
|
}
|
|
1598
|
-
async
|
|
1598
|
+
async listScoresBySpan({
|
|
1599
1599
|
traceId,
|
|
1600
1600
|
spanId,
|
|
1601
1601
|
pagination
|
|
1602
1602
|
}) {
|
|
1603
1603
|
try {
|
|
1604
|
+
const { page, perPage: perPageInput } = pagination;
|
|
1605
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
1606
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1604
1607
|
const table = await this.client.openTable(storage.TABLE_SCORERS);
|
|
1605
|
-
const
|
|
1606
|
-
const
|
|
1607
|
-
const
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
const allRecords = await table.query().where(`\`traceId\` = '${traceId}' AND \`spanId\` = '${spanId}'`).toArray();
|
|
1613
|
-
const total = allRecords.length;
|
|
1614
|
-
return {
|
|
1615
|
-
pagination: {
|
|
1616
|
-
page,
|
|
1617
|
-
perPage,
|
|
1618
|
-
total,
|
|
1619
|
-
hasMore: offset + scores.length < total
|
|
1620
|
-
},
|
|
1621
|
-
scores
|
|
1622
|
-
};
|
|
1623
|
-
} catch (error$1) {
|
|
1624
|
-
throw new error.MastraError(
|
|
1625
|
-
{
|
|
1626
|
-
id: "LANCE_STORAGE_GET_SCORES_BY_SPAN_FAILED",
|
|
1627
|
-
text: "Failed to get scores by traceId and spanId in LanceStorage",
|
|
1628
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1629
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
1630
|
-
details: { error: error$1?.message }
|
|
1631
|
-
},
|
|
1632
|
-
error$1
|
|
1633
|
-
);
|
|
1634
|
-
}
|
|
1635
|
-
}
|
|
1636
|
-
};
|
|
1637
|
-
var StoreTracesLance = class extends storage.TracesStorage {
|
|
1638
|
-
client;
|
|
1639
|
-
operations;
|
|
1640
|
-
constructor({ client, operations }) {
|
|
1641
|
-
super();
|
|
1642
|
-
this.client = client;
|
|
1643
|
-
this.operations = operations;
|
|
1644
|
-
}
|
|
1645
|
-
async saveTrace({ trace }) {
|
|
1646
|
-
try {
|
|
1647
|
-
const table = await this.client.openTable(storage.TABLE_TRACES);
|
|
1648
|
-
const record = {
|
|
1649
|
-
...trace,
|
|
1650
|
-
attributes: JSON.stringify(trace.attributes),
|
|
1651
|
-
status: JSON.stringify(trace.status),
|
|
1652
|
-
events: JSON.stringify(trace.events),
|
|
1653
|
-
links: JSON.stringify(trace.links),
|
|
1654
|
-
other: JSON.stringify(trace.other)
|
|
1655
|
-
};
|
|
1656
|
-
await table.add([record], { mode: "append" });
|
|
1657
|
-
return trace;
|
|
1658
|
-
} catch (error$1) {
|
|
1659
|
-
throw new error.MastraError(
|
|
1660
|
-
{
|
|
1661
|
-
id: "LANCE_STORE_SAVE_TRACE_FAILED",
|
|
1662
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1663
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1664
|
-
},
|
|
1665
|
-
error$1
|
|
1666
|
-
);
|
|
1667
|
-
}
|
|
1668
|
-
}
|
|
1669
|
-
async getTraceById({ traceId }) {
|
|
1670
|
-
try {
|
|
1671
|
-
const table = await this.client.openTable(storage.TABLE_TRACES);
|
|
1672
|
-
const query = table.query().where(`id = '${traceId}'`);
|
|
1673
|
-
const records = await query.toArray();
|
|
1674
|
-
return records[0];
|
|
1675
|
-
} catch (error$1) {
|
|
1676
|
-
throw new error.MastraError(
|
|
1677
|
-
{
|
|
1678
|
-
id: "LANCE_STORE_GET_TRACE_BY_ID_FAILED",
|
|
1679
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1680
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1681
|
-
},
|
|
1682
|
-
error$1
|
|
1683
|
-
);
|
|
1684
|
-
}
|
|
1685
|
-
}
|
|
1686
|
-
async getTraces({
|
|
1687
|
-
name,
|
|
1688
|
-
scope,
|
|
1689
|
-
page = 1,
|
|
1690
|
-
perPage = 10,
|
|
1691
|
-
attributes
|
|
1692
|
-
}) {
|
|
1693
|
-
try {
|
|
1694
|
-
const table = await this.client.openTable(storage.TABLE_TRACES);
|
|
1695
|
-
const query = table.query();
|
|
1696
|
-
if (name) {
|
|
1697
|
-
query.where(`name = '${name}'`);
|
|
1698
|
-
}
|
|
1699
|
-
if (scope) {
|
|
1700
|
-
query.where(`scope = '${scope}'`);
|
|
1701
|
-
}
|
|
1702
|
-
if (attributes) {
|
|
1703
|
-
query.where(`attributes = '${JSON.stringify(attributes)}'`);
|
|
1704
|
-
}
|
|
1705
|
-
const offset = (page - 1) * perPage;
|
|
1706
|
-
query.limit(perPage);
|
|
1707
|
-
if (offset > 0) {
|
|
1708
|
-
query.offset(offset);
|
|
1709
|
-
}
|
|
1710
|
-
const records = await query.toArray();
|
|
1711
|
-
return records.map((record) => {
|
|
1712
|
-
const processed = {
|
|
1713
|
-
...record,
|
|
1714
|
-
attributes: record.attributes ? JSON.parse(record.attributes) : {},
|
|
1715
|
-
status: record.status ? JSON.parse(record.status) : {},
|
|
1716
|
-
events: record.events ? JSON.parse(record.events) : [],
|
|
1717
|
-
links: record.links ? JSON.parse(record.links) : [],
|
|
1718
|
-
other: record.other ? JSON.parse(record.other) : {},
|
|
1719
|
-
startTime: new Date(record.startTime),
|
|
1720
|
-
endTime: new Date(record.endTime),
|
|
1721
|
-
createdAt: new Date(record.createdAt)
|
|
1722
|
-
};
|
|
1723
|
-
if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
|
|
1724
|
-
processed.parentSpanId = "";
|
|
1725
|
-
} else {
|
|
1726
|
-
processed.parentSpanId = String(processed.parentSpanId);
|
|
1727
|
-
}
|
|
1728
|
-
return processed;
|
|
1729
|
-
});
|
|
1730
|
-
} catch (error$1) {
|
|
1731
|
-
throw new error.MastraError(
|
|
1732
|
-
{
|
|
1733
|
-
id: "LANCE_STORE_GET_TRACES_FAILED",
|
|
1734
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1735
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
1736
|
-
details: { name: name ?? "", scope: scope ?? "" }
|
|
1737
|
-
},
|
|
1738
|
-
error$1
|
|
1739
|
-
);
|
|
1740
|
-
}
|
|
1741
|
-
}
|
|
1742
|
-
async getTracesPaginated(args) {
|
|
1743
|
-
try {
|
|
1744
|
-
const table = await this.client.openTable(storage.TABLE_TRACES);
|
|
1745
|
-
const query = table.query();
|
|
1746
|
-
const conditions = [];
|
|
1747
|
-
if (args.name) {
|
|
1748
|
-
conditions.push(`name = '${args.name}'`);
|
|
1749
|
-
}
|
|
1750
|
-
if (args.scope) {
|
|
1751
|
-
conditions.push(`scope = '${args.scope}'`);
|
|
1752
|
-
}
|
|
1753
|
-
if (args.attributes) {
|
|
1754
|
-
const attributesStr = JSON.stringify(args.attributes);
|
|
1755
|
-
conditions.push(`attributes LIKE '%${attributesStr.replace(/"/g, '\\"')}%'`);
|
|
1756
|
-
}
|
|
1757
|
-
if (args.dateRange?.start) {
|
|
1758
|
-
conditions.push(`\`createdAt\` >= ${args.dateRange.start.getTime()}`);
|
|
1759
|
-
}
|
|
1760
|
-
if (args.dateRange?.end) {
|
|
1761
|
-
conditions.push(`\`createdAt\` <= ${args.dateRange.end.getTime()}`);
|
|
1762
|
-
}
|
|
1763
|
-
if (conditions.length > 0) {
|
|
1764
|
-
const whereClause = conditions.join(" AND ");
|
|
1765
|
-
query.where(whereClause);
|
|
1766
|
-
}
|
|
1767
|
-
let total = 0;
|
|
1768
|
-
if (conditions.length > 0) {
|
|
1769
|
-
const countQuery = table.query().where(conditions.join(" AND "));
|
|
1770
|
-
const allRecords = await countQuery.toArray();
|
|
1771
|
-
total = allRecords.length;
|
|
1772
|
-
} else {
|
|
1773
|
-
total = await table.countRows();
|
|
1774
|
-
}
|
|
1775
|
-
const page = args.page || 0;
|
|
1776
|
-
const perPage = args.perPage || 10;
|
|
1777
|
-
const offset = page * perPage;
|
|
1778
|
-
query.limit(perPage);
|
|
1779
|
-
if (offset > 0) {
|
|
1780
|
-
query.offset(offset);
|
|
1608
|
+
const allRecords = await table.query().where(`\`traceId\` = '${traceId}' AND \`spanId\` = '${spanId}'`).toArray();
|
|
1609
|
+
const total = allRecords.length;
|
|
1610
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
1611
|
+
let query = table.query().where(`\`traceId\` = '${traceId}' AND \`spanId\` = '${spanId}'`);
|
|
1612
|
+
if (perPageInput !== false) {
|
|
1613
|
+
query = query.limit(perPage);
|
|
1614
|
+
if (start > 0) query = query.offset(start);
|
|
1781
1615
|
}
|
|
1782
1616
|
const records = await query.toArray();
|
|
1783
|
-
const
|
|
1784
|
-
const processed = {
|
|
1785
|
-
...record,
|
|
1786
|
-
attributes: record.attributes ? JSON.parse(record.attributes) : {},
|
|
1787
|
-
status: record.status ? JSON.parse(record.status) : {},
|
|
1788
|
-
events: record.events ? JSON.parse(record.events) : [],
|
|
1789
|
-
links: record.links ? JSON.parse(record.links) : [],
|
|
1790
|
-
other: record.other ? JSON.parse(record.other) : {},
|
|
1791
|
-
startTime: new Date(record.startTime),
|
|
1792
|
-
endTime: new Date(record.endTime),
|
|
1793
|
-
createdAt: new Date(record.createdAt)
|
|
1794
|
-
};
|
|
1795
|
-
if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
|
|
1796
|
-
processed.parentSpanId = "";
|
|
1797
|
-
} else {
|
|
1798
|
-
processed.parentSpanId = String(processed.parentSpanId);
|
|
1799
|
-
}
|
|
1800
|
-
return processed;
|
|
1801
|
-
});
|
|
1617
|
+
const scores = await Promise.all(records.map(async (record) => await this.transformScoreRow(record)));
|
|
1802
1618
|
return {
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1619
|
+
pagination: {
|
|
1620
|
+
page,
|
|
1621
|
+
perPage: perPageForResponse,
|
|
1622
|
+
total,
|
|
1623
|
+
hasMore: end < total
|
|
1624
|
+
},
|
|
1625
|
+
scores
|
|
1808
1626
|
};
|
|
1809
1627
|
} catch (error$1) {
|
|
1810
1628
|
throw new error.MastraError(
|
|
1811
1629
|
{
|
|
1812
|
-
id: "
|
|
1630
|
+
id: storage.createStorageErrorId("LANCE", "LIST_SCORES_BY_SPAN", "FAILED"),
|
|
1631
|
+
text: "Failed to get scores by traceId and spanId in LanceStorage",
|
|
1813
1632
|
domain: error.ErrorDomain.STORAGE,
|
|
1814
1633
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1815
|
-
details: {
|
|
1634
|
+
details: { error: error$1?.message }
|
|
1816
1635
|
},
|
|
1817
1636
|
error$1
|
|
1818
1637
|
);
|
|
1819
1638
|
}
|
|
1820
1639
|
}
|
|
1821
|
-
async batchTraceInsert({ records }) {
|
|
1822
|
-
this.logger.debug("Batch inserting traces", { count: records.length });
|
|
1823
|
-
await this.operations.batchInsert({
|
|
1824
|
-
tableName: storage.TABLE_TRACES,
|
|
1825
|
-
records
|
|
1826
|
-
});
|
|
1827
|
-
}
|
|
1828
1640
|
};
|
|
1829
|
-
function
|
|
1830
|
-
|
|
1831
|
-
if (typeof parsedSnapshot === "string") {
|
|
1832
|
-
try {
|
|
1833
|
-
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1834
|
-
} catch (e) {
|
|
1835
|
-
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1836
|
-
}
|
|
1837
|
-
}
|
|
1838
|
-
return {
|
|
1839
|
-
workflowName: row.workflow_name,
|
|
1840
|
-
runId: row.run_id,
|
|
1841
|
-
snapshot: parsedSnapshot,
|
|
1842
|
-
createdAt: storage.ensureDate(row.createdAt),
|
|
1843
|
-
updatedAt: storage.ensureDate(row.updatedAt),
|
|
1844
|
-
resourceId: row.resourceId
|
|
1845
|
-
};
|
|
1641
|
+
function escapeSql(str) {
|
|
1642
|
+
return str.replace(/'/g, "''");
|
|
1846
1643
|
}
|
|
1847
1644
|
var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
1848
1645
|
client;
|
|
1849
|
-
|
|
1646
|
+
#db;
|
|
1647
|
+
constructor(config) {
|
|
1850
1648
|
super();
|
|
1649
|
+
const client = resolveLanceConfig(config);
|
|
1851
1650
|
this.client = client;
|
|
1651
|
+
this.#db = new LanceDB({ client });
|
|
1852
1652
|
}
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
// runId,
|
|
1856
|
-
// stepId,
|
|
1857
|
-
// result,
|
|
1858
|
-
// runtimeContext,
|
|
1859
|
-
}) {
|
|
1860
|
-
throw new Error("Method not implemented.");
|
|
1653
|
+
supportsConcurrentUpdates() {
|
|
1654
|
+
return false;
|
|
1861
1655
|
}
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1656
|
+
parseWorkflowRun(row) {
|
|
1657
|
+
let parsedSnapshot = row.snapshot;
|
|
1658
|
+
if (typeof parsedSnapshot === "string") {
|
|
1659
|
+
try {
|
|
1660
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
1661
|
+
} catch (e) {
|
|
1662
|
+
this.logger.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
return {
|
|
1666
|
+
workflowName: row.workflow_name,
|
|
1667
|
+
runId: row.run_id,
|
|
1668
|
+
snapshot: parsedSnapshot,
|
|
1669
|
+
createdAt: storage.ensureDate(row.createdAt),
|
|
1670
|
+
updatedAt: storage.ensureDate(row.updatedAt),
|
|
1671
|
+
resourceId: row.resourceId
|
|
1672
|
+
};
|
|
1673
|
+
}
|
|
1674
|
+
async init() {
|
|
1675
|
+
const schema = storage.TABLE_SCHEMAS[storage.TABLE_WORKFLOW_SNAPSHOT];
|
|
1676
|
+
await this.#db.createTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT, schema });
|
|
1677
|
+
await this.#db.alterTable({
|
|
1678
|
+
tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
1679
|
+
schema,
|
|
1680
|
+
ifNotExists: ["resourceId"]
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
async dangerouslyClearAll() {
|
|
1684
|
+
await this.#db.clearTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT });
|
|
1685
|
+
}
|
|
1686
|
+
async updateWorkflowResults(_args) {
|
|
1687
|
+
throw new Error(
|
|
1688
|
+
"updateWorkflowResults is not implemented for LanceDB storage. LanceDB does not support atomic read-modify-write operations needed for concurrent workflow updates."
|
|
1689
|
+
);
|
|
1690
|
+
}
|
|
1691
|
+
async updateWorkflowState(_args) {
|
|
1692
|
+
throw new Error(
|
|
1693
|
+
"updateWorkflowState is not implemented for LanceDB storage. LanceDB does not support atomic read-modify-write operations needed for concurrent workflow updates."
|
|
1694
|
+
);
|
|
1868
1695
|
}
|
|
1869
1696
|
async persistWorkflowSnapshot({
|
|
1870
1697
|
workflowName,
|
|
1871
1698
|
runId,
|
|
1872
1699
|
resourceId,
|
|
1873
|
-
snapshot
|
|
1700
|
+
snapshot,
|
|
1701
|
+
createdAt,
|
|
1702
|
+
updatedAt
|
|
1874
1703
|
}) {
|
|
1875
1704
|
try {
|
|
1876
1705
|
const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1877
|
-
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1706
|
+
const query = table.query().where(`workflow_name = '${escapeSql(workflowName)}' AND run_id = '${escapeSql(runId)}'`);
|
|
1878
1707
|
const records = await query.toArray();
|
|
1879
|
-
let
|
|
1880
|
-
const now = Date.now();
|
|
1708
|
+
let createdAtValue;
|
|
1709
|
+
const now = createdAt?.getTime() ?? Date.now();
|
|
1881
1710
|
if (records.length > 0) {
|
|
1882
|
-
|
|
1711
|
+
createdAtValue = records[0].createdAt ?? now;
|
|
1883
1712
|
} else {
|
|
1884
|
-
|
|
1713
|
+
createdAtValue = now;
|
|
1885
1714
|
}
|
|
1715
|
+
const { status, value, ...rest } = snapshot;
|
|
1886
1716
|
const record = {
|
|
1887
1717
|
workflow_name: workflowName,
|
|
1888
1718
|
run_id: runId,
|
|
1889
1719
|
resourceId,
|
|
1890
|
-
snapshot: JSON.stringify(
|
|
1891
|
-
|
|
1892
|
-
|
|
1720
|
+
snapshot: JSON.stringify({ status, value, ...rest }),
|
|
1721
|
+
// this is to ensure status is always just before value, for when querying the db by status
|
|
1722
|
+
createdAt: createdAtValue,
|
|
1723
|
+
updatedAt: updatedAt ?? now
|
|
1893
1724
|
};
|
|
1894
1725
|
await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
|
|
1895
1726
|
} catch (error$1) {
|
|
1896
1727
|
throw new error.MastraError(
|
|
1897
1728
|
{
|
|
1898
|
-
id: "
|
|
1729
|
+
id: storage.createStorageErrorId("LANCE", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
1899
1730
|
domain: error.ErrorDomain.STORAGE,
|
|
1900
1731
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1901
1732
|
details: { workflowName, runId }
|
|
@@ -1910,13 +1741,13 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
|
1910
1741
|
}) {
|
|
1911
1742
|
try {
|
|
1912
1743
|
const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1913
|
-
const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
|
|
1744
|
+
const query = table.query().where(`workflow_name = '${escapeSql(workflowName)}' AND run_id = '${escapeSql(runId)}'`);
|
|
1914
1745
|
const records = await query.toArray();
|
|
1915
1746
|
return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
|
|
1916
1747
|
} catch (error$1) {
|
|
1917
1748
|
throw new error.MastraError(
|
|
1918
1749
|
{
|
|
1919
|
-
id: "
|
|
1750
|
+
id: storage.createStorageErrorId("LANCE", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
1920
1751
|
domain: error.ErrorDomain.STORAGE,
|
|
1921
1752
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1922
1753
|
details: { workflowName, runId }
|
|
@@ -1928,19 +1759,19 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
|
1928
1759
|
async getWorkflowRunById(args) {
|
|
1929
1760
|
try {
|
|
1930
1761
|
const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1931
|
-
let whereClause = `run_id = '${args.runId}'`;
|
|
1762
|
+
let whereClause = `run_id = '${escapeSql(args.runId)}'`;
|
|
1932
1763
|
if (args.workflowName) {
|
|
1933
|
-
whereClause += ` AND workflow_name = '${args.workflowName}'`;
|
|
1764
|
+
whereClause += ` AND workflow_name = '${escapeSql(args.workflowName)}'`;
|
|
1934
1765
|
}
|
|
1935
1766
|
const query = table.query().where(whereClause);
|
|
1936
1767
|
const records = await query.toArray();
|
|
1937
1768
|
if (records.length === 0) return null;
|
|
1938
1769
|
const record = records[0];
|
|
1939
|
-
return parseWorkflowRun(record);
|
|
1770
|
+
return this.parseWorkflowRun(record);
|
|
1940
1771
|
} catch (error$1) {
|
|
1941
1772
|
throw new error.MastraError(
|
|
1942
1773
|
{
|
|
1943
|
-
id: "
|
|
1774
|
+
id: storage.createStorageErrorId("LANCE", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
1944
1775
|
domain: error.ErrorDomain.STORAGE,
|
|
1945
1776
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1946
1777
|
details: { runId: args.runId, workflowName: args.workflowName ?? "" }
|
|
@@ -1949,359 +1780,182 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
|
|
|
1949
1780
|
);
|
|
1950
1781
|
}
|
|
1951
1782
|
}
|
|
1952
|
-
async
|
|
1783
|
+
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
1953
1784
|
try {
|
|
1954
1785
|
const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
if (args?.workflowName) {
|
|
1958
|
-
conditions.push(`workflow_name = '${args.workflowName.replace(/'/g, "''")}'`);
|
|
1959
|
-
}
|
|
1960
|
-
if (args?.resourceId) {
|
|
1961
|
-
conditions.push(`\`resourceId\` = '${args.resourceId}'`);
|
|
1962
|
-
}
|
|
1963
|
-
if (args?.fromDate instanceof Date) {
|
|
1964
|
-
conditions.push(`\`createdAt\` >= ${args.fromDate.getTime()}`);
|
|
1965
|
-
}
|
|
1966
|
-
if (args?.toDate instanceof Date) {
|
|
1967
|
-
conditions.push(`\`createdAt\` <= ${args.toDate.getTime()}`);
|
|
1968
|
-
}
|
|
1969
|
-
let total = 0;
|
|
1970
|
-
if (conditions.length > 0) {
|
|
1971
|
-
query = query.where(conditions.join(" AND "));
|
|
1972
|
-
total = await table.countRows(conditions.join(" AND "));
|
|
1973
|
-
} else {
|
|
1974
|
-
total = await table.countRows();
|
|
1975
|
-
}
|
|
1976
|
-
if (args?.limit) {
|
|
1977
|
-
query.limit(args.limit);
|
|
1978
|
-
}
|
|
1979
|
-
if (args?.offset) {
|
|
1980
|
-
query.offset(args.offset);
|
|
1981
|
-
}
|
|
1982
|
-
const records = await query.toArray();
|
|
1983
|
-
return {
|
|
1984
|
-
runs: records.map((record) => parseWorkflowRun(record)),
|
|
1985
|
-
total: total || records.length
|
|
1986
|
-
};
|
|
1786
|
+
const whereClause = `run_id = '${escapeSql(runId)}' AND workflow_name = '${escapeSql(workflowName)}'`;
|
|
1787
|
+
await table.delete(whereClause);
|
|
1987
1788
|
} catch (error$1) {
|
|
1988
1789
|
throw new error.MastraError(
|
|
1989
1790
|
{
|
|
1990
|
-
id: "
|
|
1791
|
+
id: storage.createStorageErrorId("LANCE", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
1991
1792
|
domain: error.ErrorDomain.STORAGE,
|
|
1992
1793
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1993
|
-
details: {
|
|
1794
|
+
details: { runId, workflowName }
|
|
1994
1795
|
},
|
|
1995
1796
|
error$1
|
|
1996
1797
|
);
|
|
1997
1798
|
}
|
|
1998
1799
|
}
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
// src/storage/index.ts
|
|
2002
|
-
var LanceStorage = class _LanceStorage extends storage.MastraStorage {
|
|
2003
|
-
stores;
|
|
2004
|
-
lanceClient;
|
|
2005
|
-
/**
|
|
2006
|
-
* Creates a new instance of LanceStorage
|
|
2007
|
-
* @param uri The URI to connect to LanceDB
|
|
2008
|
-
* @param options connection options
|
|
2009
|
-
*
|
|
2010
|
-
* Usage:
|
|
2011
|
-
*
|
|
2012
|
-
* Connect to a local database
|
|
2013
|
-
* ```ts
|
|
2014
|
-
* const store = await LanceStorage.create('/path/to/db');
|
|
2015
|
-
* ```
|
|
2016
|
-
*
|
|
2017
|
-
* Connect to a LanceDB cloud database
|
|
2018
|
-
* ```ts
|
|
2019
|
-
* const store = await LanceStorage.create('db://host:port');
|
|
2020
|
-
* ```
|
|
2021
|
-
*
|
|
2022
|
-
* Connect to a cloud database
|
|
2023
|
-
* ```ts
|
|
2024
|
-
* const store = await LanceStorage.create('s3://bucket/db', { storageOptions: { timeout: '60s' } });
|
|
2025
|
-
* ```
|
|
2026
|
-
*/
|
|
2027
|
-
static async create(name, uri, options) {
|
|
2028
|
-
const instance = new _LanceStorage(name);
|
|
1800
|
+
async listWorkflowRuns(args) {
|
|
2029
1801
|
try {
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
traces: new StoreTracesLance({ client: instance.lanceClient, operations }),
|
|
2036
|
-
scores: new StoreScoresLance({ client: instance.lanceClient }),
|
|
2037
|
-
memory: new StoreMemoryLance({ client: instance.lanceClient, operations }),
|
|
2038
|
-
legacyEvals: new StoreLegacyEvalsLance({ client: instance.lanceClient })
|
|
2039
|
-
};
|
|
2040
|
-
return instance;
|
|
2041
|
-
} catch (e) {
|
|
2042
|
-
throw new error.MastraError(
|
|
2043
|
-
{
|
|
2044
|
-
id: "STORAGE_LANCE_STORAGE_CONNECT_FAILED",
|
|
2045
|
-
domain: error.ErrorDomain.STORAGE,
|
|
2046
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
2047
|
-
text: `Failed to connect to LanceDB: ${e.message || e}`,
|
|
2048
|
-
details: { uri, optionsProvided: !!options }
|
|
2049
|
-
},
|
|
2050
|
-
e
|
|
2051
|
-
);
|
|
2052
|
-
}
|
|
2053
|
-
}
|
|
2054
|
-
/**
|
|
2055
|
-
* @internal
|
|
2056
|
-
* Private constructor to enforce using the create factory method
|
|
2057
|
-
*/
|
|
2058
|
-
constructor(name) {
|
|
2059
|
-
super({ name });
|
|
2060
|
-
const operations = new StoreOperationsLance({ client: this.lanceClient });
|
|
2061
|
-
this.stores = {
|
|
2062
|
-
operations: new StoreOperationsLance({ client: this.lanceClient }),
|
|
2063
|
-
workflows: new StoreWorkflowsLance({ client: this.lanceClient }),
|
|
2064
|
-
traces: new StoreTracesLance({ client: this.lanceClient, operations }),
|
|
2065
|
-
scores: new StoreScoresLance({ client: this.lanceClient }),
|
|
2066
|
-
legacyEvals: new StoreLegacyEvalsLance({ client: this.lanceClient }),
|
|
2067
|
-
memory: new StoreMemoryLance({ client: this.lanceClient, operations })
|
|
2068
|
-
};
|
|
2069
|
-
}
|
|
2070
|
-
async createTable({
|
|
2071
|
-
tableName,
|
|
2072
|
-
schema
|
|
2073
|
-
}) {
|
|
2074
|
-
return this.stores.operations.createTable({ tableName, schema });
|
|
2075
|
-
}
|
|
2076
|
-
async dropTable({ tableName }) {
|
|
2077
|
-
return this.stores.operations.dropTable({ tableName });
|
|
2078
|
-
}
|
|
2079
|
-
async alterTable({
|
|
2080
|
-
tableName,
|
|
2081
|
-
schema,
|
|
2082
|
-
ifNotExists
|
|
2083
|
-
}) {
|
|
2084
|
-
return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
2085
|
-
}
|
|
2086
|
-
async clearTable({ tableName }) {
|
|
2087
|
-
return this.stores.operations.clearTable({ tableName });
|
|
2088
|
-
}
|
|
2089
|
-
async insert({ tableName, record }) {
|
|
2090
|
-
return this.stores.operations.insert({ tableName, record });
|
|
2091
|
-
}
|
|
2092
|
-
async batchInsert({ tableName, records }) {
|
|
2093
|
-
return this.stores.operations.batchInsert({ tableName, records });
|
|
2094
|
-
}
|
|
2095
|
-
async load({ tableName, keys }) {
|
|
2096
|
-
return this.stores.operations.load({ tableName, keys });
|
|
2097
|
-
}
|
|
2098
|
-
async getThreadById({ threadId }) {
|
|
2099
|
-
return this.stores.memory.getThreadById({ threadId });
|
|
2100
|
-
}
|
|
2101
|
-
async getThreadsByResourceId({ resourceId }) {
|
|
2102
|
-
return this.stores.memory.getThreadsByResourceId({ resourceId });
|
|
2103
|
-
}
|
|
2104
|
-
/**
|
|
2105
|
-
* Saves a thread to the database. This function doesn't overwrite existing threads.
|
|
2106
|
-
* @param thread - The thread to save
|
|
2107
|
-
* @returns The saved thread
|
|
2108
|
-
*/
|
|
2109
|
-
async saveThread({ thread }) {
|
|
2110
|
-
return this.stores.memory.saveThread({ thread });
|
|
2111
|
-
}
|
|
2112
|
-
async updateThread({
|
|
2113
|
-
id,
|
|
2114
|
-
title,
|
|
2115
|
-
metadata
|
|
2116
|
-
}) {
|
|
2117
|
-
return this.stores.memory.updateThread({ id, title, metadata });
|
|
2118
|
-
}
|
|
2119
|
-
async deleteThread({ threadId }) {
|
|
2120
|
-
return this.stores.memory.deleteThread({ threadId });
|
|
2121
|
-
}
|
|
2122
|
-
get supports() {
|
|
2123
|
-
return {
|
|
2124
|
-
selectByIncludeResourceScope: true,
|
|
2125
|
-
resourceWorkingMemory: true,
|
|
2126
|
-
hasColumn: true,
|
|
2127
|
-
createTable: true,
|
|
2128
|
-
deleteMessages: false,
|
|
2129
|
-
getScoresBySpan: true
|
|
2130
|
-
};
|
|
2131
|
-
}
|
|
2132
|
-
async getResourceById({ resourceId }) {
|
|
2133
|
-
return this.stores.memory.getResourceById({ resourceId });
|
|
2134
|
-
}
|
|
2135
|
-
async saveResource({ resource }) {
|
|
2136
|
-
return this.stores.memory.saveResource({ resource });
|
|
2137
|
-
}
|
|
2138
|
-
async updateResource({
|
|
2139
|
-
resourceId,
|
|
2140
|
-
workingMemory,
|
|
2141
|
-
metadata
|
|
2142
|
-
}) {
|
|
2143
|
-
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
2144
|
-
}
|
|
2145
|
-
/**
|
|
2146
|
-
* Processes messages to include context messages based on withPreviousMessages and withNextMessages
|
|
2147
|
-
* @param records - The sorted array of records to process
|
|
2148
|
-
* @param include - The array of include specifications with context parameters
|
|
2149
|
-
* @returns The processed array with context messages included
|
|
2150
|
-
*/
|
|
2151
|
-
processMessagesWithContext(records, include) {
|
|
2152
|
-
const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
|
|
2153
|
-
if (messagesWithContext.length === 0) {
|
|
2154
|
-
return records;
|
|
2155
|
-
}
|
|
2156
|
-
const messageIndexMap = /* @__PURE__ */ new Map();
|
|
2157
|
-
records.forEach((message, index) => {
|
|
2158
|
-
messageIndexMap.set(message.id, index);
|
|
2159
|
-
});
|
|
2160
|
-
const additionalIndices = /* @__PURE__ */ new Set();
|
|
2161
|
-
for (const item of messagesWithContext) {
|
|
2162
|
-
const messageIndex = messageIndexMap.get(item.id);
|
|
2163
|
-
if (messageIndex !== void 0) {
|
|
2164
|
-
if (item.withPreviousMessages) {
|
|
2165
|
-
const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
|
|
2166
|
-
for (let i = startIdx; i < messageIndex; i++) {
|
|
2167
|
-
additionalIndices.add(i);
|
|
2168
|
-
}
|
|
2169
|
-
}
|
|
2170
|
-
if (item.withNextMessages) {
|
|
2171
|
-
const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
|
|
2172
|
-
for (let i = messageIndex + 1; i <= endIdx; i++) {
|
|
2173
|
-
additionalIndices.add(i);
|
|
2174
|
-
}
|
|
2175
|
-
}
|
|
1802
|
+
const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
1803
|
+
let query = table.query();
|
|
1804
|
+
const conditions = [];
|
|
1805
|
+
if (args?.workflowName) {
|
|
1806
|
+
conditions.push(`workflow_name = '${escapeSql(args.workflowName)}'`);
|
|
2176
1807
|
}
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
}
|
|
2181
|
-
const originalMatchIds = new Set(include.map((item) => item.id));
|
|
2182
|
-
const allIndices = /* @__PURE__ */ new Set();
|
|
2183
|
-
records.forEach((record, index) => {
|
|
2184
|
-
if (originalMatchIds.has(record.id)) {
|
|
2185
|
-
allIndices.add(index);
|
|
1808
|
+
if (args?.status) {
|
|
1809
|
+
const escapedStatus = args.status.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
1810
|
+
conditions.push(`\`snapshot\` LIKE '%"status":"${escapedStatus}","value"%'`);
|
|
2186
1811
|
}
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
return this.stores.workflows.getWorkflowRuns(args);
|
|
2237
|
-
}
|
|
2238
|
-
async getWorkflowRunById(args) {
|
|
2239
|
-
return this.stores.workflows.getWorkflowRunById(args);
|
|
2240
|
-
}
|
|
2241
|
-
async updateWorkflowResults({
|
|
2242
|
-
workflowName,
|
|
2243
|
-
runId,
|
|
2244
|
-
stepId,
|
|
2245
|
-
result,
|
|
2246
|
-
runtimeContext
|
|
2247
|
-
}) {
|
|
2248
|
-
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, runtimeContext });
|
|
2249
|
-
}
|
|
2250
|
-
async updateWorkflowState({
|
|
2251
|
-
workflowName,
|
|
2252
|
-
runId,
|
|
2253
|
-
opts
|
|
2254
|
-
}) {
|
|
2255
|
-
return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
|
|
2256
|
-
}
|
|
2257
|
-
async persistWorkflowSnapshot({
|
|
2258
|
-
workflowName,
|
|
2259
|
-
runId,
|
|
2260
|
-
resourceId,
|
|
2261
|
-
snapshot
|
|
2262
|
-
}) {
|
|
2263
|
-
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
2264
|
-
}
|
|
2265
|
-
async loadWorkflowSnapshot({
|
|
2266
|
-
workflowName,
|
|
2267
|
-
runId
|
|
2268
|
-
}) {
|
|
2269
|
-
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2270
|
-
}
|
|
2271
|
-
async getScoreById({ id: _id }) {
|
|
2272
|
-
return this.stores.scores.getScoreById({ id: _id });
|
|
2273
|
-
}
|
|
2274
|
-
async getScoresByScorerId({
|
|
2275
|
-
scorerId,
|
|
2276
|
-
source,
|
|
2277
|
-
entityId,
|
|
2278
|
-
entityType,
|
|
2279
|
-
pagination
|
|
2280
|
-
}) {
|
|
2281
|
-
return this.stores.scores.getScoresByScorerId({ scorerId, source, pagination, entityId, entityType });
|
|
2282
|
-
}
|
|
2283
|
-
async saveScore(_score) {
|
|
2284
|
-
return this.stores.scores.saveScore(_score);
|
|
1812
|
+
if (args?.resourceId) {
|
|
1813
|
+
conditions.push(`\`resourceId\` = '${escapeSql(args.resourceId)}'`);
|
|
1814
|
+
}
|
|
1815
|
+
if (args?.fromDate instanceof Date) {
|
|
1816
|
+
conditions.push(`\`createdAt\` >= ${args.fromDate.getTime()}`);
|
|
1817
|
+
}
|
|
1818
|
+
if (args?.toDate instanceof Date) {
|
|
1819
|
+
conditions.push(`\`createdAt\` <= ${args.toDate.getTime()}`);
|
|
1820
|
+
}
|
|
1821
|
+
let total = 0;
|
|
1822
|
+
if (conditions.length > 0) {
|
|
1823
|
+
query = query.where(conditions.join(" AND "));
|
|
1824
|
+
total = await table.countRows(conditions.join(" AND "));
|
|
1825
|
+
} else {
|
|
1826
|
+
total = await table.countRows();
|
|
1827
|
+
}
|
|
1828
|
+
if (args?.perPage !== void 0 && args?.page !== void 0) {
|
|
1829
|
+
const normalizedPerPage = storage.normalizePerPage(args.perPage, Number.MAX_SAFE_INTEGER);
|
|
1830
|
+
if (args.page < 0 || !Number.isInteger(args.page)) {
|
|
1831
|
+
throw new error.MastraError(
|
|
1832
|
+
{
|
|
1833
|
+
id: storage.createStorageErrorId("LANCE", "LIST_WORKFLOW_RUNS", "INVALID_PAGINATION"),
|
|
1834
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1835
|
+
category: error.ErrorCategory.USER,
|
|
1836
|
+
details: { page: args.page, perPage: args.perPage }
|
|
1837
|
+
},
|
|
1838
|
+
new Error(`Invalid pagination parameters: page=${args.page}, perPage=${args.perPage}`)
|
|
1839
|
+
);
|
|
1840
|
+
}
|
|
1841
|
+
const offset = args.page * normalizedPerPage;
|
|
1842
|
+
query.limit(normalizedPerPage);
|
|
1843
|
+
query.offset(offset);
|
|
1844
|
+
}
|
|
1845
|
+
const records = await query.toArray();
|
|
1846
|
+
return {
|
|
1847
|
+
runs: records.map((record) => this.parseWorkflowRun(record)),
|
|
1848
|
+
total: total || records.length
|
|
1849
|
+
};
|
|
1850
|
+
} catch (error$1) {
|
|
1851
|
+
throw new error.MastraError(
|
|
1852
|
+
{
|
|
1853
|
+
id: storage.createStorageErrorId("LANCE", "LIST_WORKFLOW_RUNS", "FAILED"),
|
|
1854
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1855
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1856
|
+
details: { resourceId: args?.resourceId ?? "", workflowName: args?.workflowName ?? "" }
|
|
1857
|
+
},
|
|
1858
|
+
error$1
|
|
1859
|
+
);
|
|
1860
|
+
}
|
|
2285
1861
|
}
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
1862
|
+
};
|
|
1863
|
+
|
|
1864
|
+
// src/storage/index.ts
|
|
1865
|
+
var LanceStorage = class _LanceStorage extends storage.MastraCompositeStore {
|
|
1866
|
+
stores;
|
|
1867
|
+
lanceClient;
|
|
1868
|
+
/**
|
|
1869
|
+
* Creates a new instance of LanceStorage
|
|
1870
|
+
* @param id The unique identifier for this storage instance
|
|
1871
|
+
* @param name The name for this storage instance
|
|
1872
|
+
* @param uri The URI to connect to LanceDB
|
|
1873
|
+
* @param connectionOptions connection options for LanceDB
|
|
1874
|
+
* @param storageOptions storage options including disableInit
|
|
1875
|
+
*
|
|
1876
|
+
* Usage:
|
|
1877
|
+
*
|
|
1878
|
+
* Connect to a local database
|
|
1879
|
+
* ```ts
|
|
1880
|
+
* const store = await LanceStorage.create('my-storage-id', 'MyStorage', '/path/to/db');
|
|
1881
|
+
* ```
|
|
1882
|
+
*
|
|
1883
|
+
* Connect to a LanceDB cloud database
|
|
1884
|
+
* ```ts
|
|
1885
|
+
* const store = await LanceStorage.create('my-storage-id', 'MyStorage', 'db://host:port');
|
|
1886
|
+
* ```
|
|
1887
|
+
*
|
|
1888
|
+
* Connect to a cloud database
|
|
1889
|
+
* ```ts
|
|
1890
|
+
* const store = await LanceStorage.create('my-storage-id', 'MyStorage', 's3://bucket/db', { storageOptions: { timeout: '60s' } });
|
|
1891
|
+
* ```
|
|
1892
|
+
*
|
|
1893
|
+
* Disable auto-init for runtime (after CI/CD has run migrations)
|
|
1894
|
+
* ```ts
|
|
1895
|
+
* const store = await LanceStorage.create('my-storage-id', 'MyStorage', '/path/to/db', undefined, { disableInit: true });
|
|
1896
|
+
* ```
|
|
1897
|
+
*/
|
|
1898
|
+
static async create(id, name, uri, connectionOptions, storageOptions) {
|
|
1899
|
+
const instance = new _LanceStorage(id, name, storageOptions?.disableInit);
|
|
1900
|
+
try {
|
|
1901
|
+
instance.lanceClient = await lancedb.connect(uri, connectionOptions);
|
|
1902
|
+
instance.stores = {
|
|
1903
|
+
workflows: new StoreWorkflowsLance({ client: instance.lanceClient }),
|
|
1904
|
+
scores: new StoreScoresLance({ client: instance.lanceClient }),
|
|
1905
|
+
memory: new StoreMemoryLance({ client: instance.lanceClient })
|
|
1906
|
+
};
|
|
1907
|
+
return instance;
|
|
1908
|
+
} catch (e) {
|
|
1909
|
+
throw new error.MastraError(
|
|
1910
|
+
{
|
|
1911
|
+
id: storage.createStorageErrorId("LANCE", "CONNECT", "FAILED"),
|
|
1912
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1913
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1914
|
+
text: `Failed to connect to LanceDB: ${e.message || e}`,
|
|
1915
|
+
details: { uri, optionsProvided: !!connectionOptions }
|
|
1916
|
+
},
|
|
1917
|
+
e
|
|
1918
|
+
);
|
|
1919
|
+
}
|
|
2291
1920
|
}
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
1921
|
+
/**
|
|
1922
|
+
* Creates a new instance of LanceStorage from a pre-configured LanceDB connection.
|
|
1923
|
+
* Use this when you need to configure the connection before initialization.
|
|
1924
|
+
*
|
|
1925
|
+
* @param id The unique identifier for this storage instance
|
|
1926
|
+
* @param name The name for this storage instance
|
|
1927
|
+
* @param client Pre-configured LanceDB connection
|
|
1928
|
+
* @param options Storage options including disableInit
|
|
1929
|
+
*
|
|
1930
|
+
* @example
|
|
1931
|
+
* ```typescript
|
|
1932
|
+
* import { connect } from '@lancedb/lancedb';
|
|
1933
|
+
*
|
|
1934
|
+
* const client = await connect('/path/to/db', {
|
|
1935
|
+
* // Custom connection options
|
|
1936
|
+
* });
|
|
1937
|
+
*
|
|
1938
|
+
* const store = LanceStorage.fromClient('my-id', 'MyStorage', client);
|
|
1939
|
+
* ```
|
|
1940
|
+
*/
|
|
1941
|
+
static fromClient(id, name, client, options) {
|
|
1942
|
+
const instance = new _LanceStorage(id, name, options?.disableInit);
|
|
1943
|
+
instance.lanceClient = client;
|
|
1944
|
+
instance.stores = {
|
|
1945
|
+
workflows: new StoreWorkflowsLance({ client }),
|
|
1946
|
+
scores: new StoreScoresLance({ client }),
|
|
1947
|
+
memory: new StoreMemoryLance({ client })
|
|
1948
|
+
};
|
|
1949
|
+
return instance;
|
|
2298
1950
|
}
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
1951
|
+
/**
|
|
1952
|
+
* @internal
|
|
1953
|
+
* Private constructor to enforce using the create factory method.
|
|
1954
|
+
* Note: stores is initialized in create() after the lanceClient is connected.
|
|
1955
|
+
*/
|
|
1956
|
+
constructor(id, name, disableInit) {
|
|
1957
|
+
super({ id, name, disableInit });
|
|
1958
|
+
this.stores = {};
|
|
2305
1959
|
}
|
|
2306
1960
|
};
|
|
2307
1961
|
var LanceFilterTranslator = class extends filter.BaseFilterTranslator {
|
|
@@ -2650,14 +2304,14 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2650
2304
|
* ```
|
|
2651
2305
|
*/
|
|
2652
2306
|
static async create(uri, options) {
|
|
2653
|
-
const instance = new _LanceVectorStore();
|
|
2307
|
+
const instance = new _LanceVectorStore(options?.id || crypto.randomUUID());
|
|
2654
2308
|
try {
|
|
2655
2309
|
instance.lanceClient = await lancedb.connect(uri, options);
|
|
2656
2310
|
return instance;
|
|
2657
2311
|
} catch (e) {
|
|
2658
2312
|
throw new error.MastraError(
|
|
2659
2313
|
{
|
|
2660
|
-
id: "
|
|
2314
|
+
id: storage.createVectorErrorId("LANCE", "CONNECT", "FAILED"),
|
|
2661
2315
|
domain: error.ErrorDomain.STORAGE,
|
|
2662
2316
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2663
2317
|
details: { uri }
|
|
@@ -2670,8 +2324,8 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2670
2324
|
* @internal
|
|
2671
2325
|
* Private constructor to enforce using the create factory method
|
|
2672
2326
|
*/
|
|
2673
|
-
constructor() {
|
|
2674
|
-
super();
|
|
2327
|
+
constructor(id) {
|
|
2328
|
+
super({ id });
|
|
2675
2329
|
}
|
|
2676
2330
|
close() {
|
|
2677
2331
|
if (this.lanceClient) {
|
|
@@ -2680,6 +2334,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2680
2334
|
}
|
|
2681
2335
|
async query({
|
|
2682
2336
|
tableName,
|
|
2337
|
+
indexName,
|
|
2683
2338
|
queryVector,
|
|
2684
2339
|
filter,
|
|
2685
2340
|
includeVector = false,
|
|
@@ -2687,56 +2342,78 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2687
2342
|
columns = [],
|
|
2688
2343
|
includeAllColumns = false
|
|
2689
2344
|
}) {
|
|
2345
|
+
const resolvedTableName = tableName ?? indexName;
|
|
2346
|
+
if (!queryVector) {
|
|
2347
|
+
throw new error.MastraError({
|
|
2348
|
+
id: storage.createVectorErrorId("LANCE", "QUERY", "MISSING_VECTOR"),
|
|
2349
|
+
text: "queryVector is required for Lance queries. Metadata-only queries are not supported by this vector store.",
|
|
2350
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2351
|
+
category: error.ErrorCategory.USER,
|
|
2352
|
+
details: { indexName: resolvedTableName }
|
|
2353
|
+
});
|
|
2354
|
+
}
|
|
2690
2355
|
try {
|
|
2691
2356
|
if (!this.lanceClient) {
|
|
2692
2357
|
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
2693
2358
|
}
|
|
2694
|
-
if (!
|
|
2695
|
-
throw new Error("tableName is required");
|
|
2696
|
-
}
|
|
2697
|
-
if (!queryVector) {
|
|
2698
|
-
throw new Error("queryVector is required");
|
|
2359
|
+
if (!resolvedTableName) {
|
|
2360
|
+
throw new Error("tableName or indexName is required");
|
|
2699
2361
|
}
|
|
2700
2362
|
} catch (error$1) {
|
|
2701
2363
|
throw new error.MastraError(
|
|
2702
2364
|
{
|
|
2703
|
-
id: "
|
|
2365
|
+
id: storage.createVectorErrorId("LANCE", "QUERY", "INVALID_ARGS"),
|
|
2704
2366
|
domain: error.ErrorDomain.STORAGE,
|
|
2705
2367
|
category: error.ErrorCategory.USER,
|
|
2706
|
-
text:
|
|
2707
|
-
details: { tableName }
|
|
2368
|
+
text: error$1 instanceof Error ? error$1.message : "Invalid query arguments",
|
|
2369
|
+
details: { tableName: resolvedTableName }
|
|
2708
2370
|
},
|
|
2709
2371
|
error$1
|
|
2710
2372
|
);
|
|
2711
2373
|
}
|
|
2712
2374
|
try {
|
|
2713
|
-
const
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2375
|
+
const tables = await this.lanceClient.tableNames();
|
|
2376
|
+
if (!tables.includes(resolvedTableName)) {
|
|
2377
|
+
this.logger.debug(`Table ${resolvedTableName} does not exist. Returning empty results.`);
|
|
2378
|
+
return [];
|
|
2717
2379
|
}
|
|
2380
|
+
const table = await this.lanceClient.openTable(resolvedTableName);
|
|
2718
2381
|
let query = table.search(queryVector);
|
|
2719
2382
|
if (filter && Object.keys(filter).length > 0) {
|
|
2720
2383
|
const whereClause = this.filterTranslator(filter);
|
|
2721
2384
|
this.logger.debug(`Where clause generated: ${whereClause}`);
|
|
2385
|
+
const schema = await table.schema();
|
|
2386
|
+
const schemaColumns = new Set(schema.fields.map((f) => f.name));
|
|
2387
|
+
const filterColumns = this.extractFilterColumns(whereClause);
|
|
2388
|
+
const missingColumns = filterColumns.filter((col) => !schemaColumns.has(col));
|
|
2389
|
+
if (missingColumns.length > 0) {
|
|
2390
|
+
this.logger.debug(
|
|
2391
|
+
`Filter references columns not in schema: ${missingColumns.join(", ")}. Returning empty results.`
|
|
2392
|
+
);
|
|
2393
|
+
return [];
|
|
2394
|
+
}
|
|
2722
2395
|
query = query.where(whereClause);
|
|
2723
2396
|
}
|
|
2724
|
-
if (!includeAllColumns &&
|
|
2397
|
+
if (!includeAllColumns && columns.length > 0) {
|
|
2398
|
+
const selectColumns = [...columns];
|
|
2399
|
+
if (!selectColumns.includes("id")) {
|
|
2400
|
+
selectColumns.push("id");
|
|
2401
|
+
}
|
|
2725
2402
|
query = query.select(selectColumns);
|
|
2726
2403
|
}
|
|
2727
2404
|
query = query.limit(topK);
|
|
2728
2405
|
const results = await query.toArray();
|
|
2729
2406
|
return results.map((result) => {
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
}
|
|
2407
|
+
let metadata = {};
|
|
2408
|
+
if (result._metadata_json) {
|
|
2409
|
+
try {
|
|
2410
|
+
metadata = JSON.parse(result._metadata_json);
|
|
2411
|
+
} catch {
|
|
2412
|
+
metadata = this.extractFlatMetadata(result);
|
|
2737
2413
|
}
|
|
2738
|
-
}
|
|
2739
|
-
|
|
2414
|
+
} else {
|
|
2415
|
+
metadata = this.extractFlatMetadata(result);
|
|
2416
|
+
}
|
|
2740
2417
|
return {
|
|
2741
2418
|
id: String(result.id || ""),
|
|
2742
2419
|
metadata,
|
|
@@ -2748,10 +2425,10 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2748
2425
|
} catch (error$1) {
|
|
2749
2426
|
throw new error.MastraError(
|
|
2750
2427
|
{
|
|
2751
|
-
id: "
|
|
2428
|
+
id: storage.createVectorErrorId("LANCE", "QUERY", "FAILED"),
|
|
2752
2429
|
domain: error.ErrorDomain.STORAGE,
|
|
2753
2430
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2754
|
-
details: { tableName, includeVector, columnsCount: columns?.length, includeAllColumns }
|
|
2431
|
+
details: { tableName: resolvedTableName, includeVector, columnsCount: columns?.length, includeAllColumns }
|
|
2755
2432
|
},
|
|
2756
2433
|
error$1
|
|
2757
2434
|
);
|
|
@@ -2786,13 +2463,14 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2786
2463
|
const translator = new LanceFilterTranslator();
|
|
2787
2464
|
return translator.translate(prefixedFilter);
|
|
2788
2465
|
}
|
|
2789
|
-
async upsert({ tableName, vectors, metadata = [], ids = [] }) {
|
|
2466
|
+
async upsert({ tableName, indexName, vectors, metadata = [], ids = [] }) {
|
|
2467
|
+
const resolvedTableName = tableName ?? indexName;
|
|
2790
2468
|
try {
|
|
2791
2469
|
if (!this.lanceClient) {
|
|
2792
2470
|
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
2793
2471
|
}
|
|
2794
|
-
if (!
|
|
2795
|
-
throw new Error("tableName is required");
|
|
2472
|
+
if (!resolvedTableName) {
|
|
2473
|
+
throw new Error("tableName or indexName is required");
|
|
2796
2474
|
}
|
|
2797
2475
|
if (!vectors || !Array.isArray(vectors) || vectors.length === 0) {
|
|
2798
2476
|
throw new Error("vectors array is required and must not be empty");
|
|
@@ -2800,21 +2478,24 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2800
2478
|
} catch (error$1) {
|
|
2801
2479
|
throw new error.MastraError(
|
|
2802
2480
|
{
|
|
2803
|
-
id: "
|
|
2481
|
+
id: storage.createVectorErrorId("LANCE", "UPSERT", "INVALID_ARGS"),
|
|
2804
2482
|
domain: error.ErrorDomain.STORAGE,
|
|
2805
2483
|
category: error.ErrorCategory.USER,
|
|
2806
|
-
text:
|
|
2807
|
-
details: { tableName }
|
|
2484
|
+
text: error$1 instanceof Error ? error$1.message : "Invalid upsert arguments",
|
|
2485
|
+
details: { tableName: resolvedTableName }
|
|
2808
2486
|
},
|
|
2809
2487
|
error$1
|
|
2810
2488
|
);
|
|
2811
2489
|
}
|
|
2812
2490
|
try {
|
|
2813
2491
|
const tables = await this.lanceClient.tableNames();
|
|
2814
|
-
|
|
2815
|
-
|
|
2492
|
+
const tableExists = tables.includes(resolvedTableName);
|
|
2493
|
+
let table = null;
|
|
2494
|
+
if (!tableExists) {
|
|
2495
|
+
this.logger.debug(`Table ${resolvedTableName} does not exist. Creating it with the first upsert data.`);
|
|
2496
|
+
} else {
|
|
2497
|
+
table = await this.lanceClient.openTable(resolvedTableName);
|
|
2816
2498
|
}
|
|
2817
|
-
const table = await this.lanceClient.openTable(tableName);
|
|
2818
2499
|
const vectorIds = ids.length === vectors.length ? ids : vectors.map((_, i) => ids[i] || crypto.randomUUID());
|
|
2819
2500
|
const data = vectors.map((vector, i) => {
|
|
2820
2501
|
const id = String(vectorIds[i]);
|
|
@@ -2828,18 +2509,61 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2828
2509
|
Object.entries(flattenedMetadata).forEach(([key, value]) => {
|
|
2829
2510
|
rowData[key] = value;
|
|
2830
2511
|
});
|
|
2512
|
+
rowData["_metadata_json"] = JSON.stringify(metadataItem);
|
|
2513
|
+
} else {
|
|
2514
|
+
rowData["_metadata_json"] = "";
|
|
2831
2515
|
}
|
|
2832
2516
|
return rowData;
|
|
2833
2517
|
});
|
|
2834
|
-
|
|
2518
|
+
if (table !== null) {
|
|
2519
|
+
const rowCount = await table.countRows();
|
|
2520
|
+
const schema = await table.schema();
|
|
2521
|
+
const existingColumns = new Set(schema.fields.map((f) => f.name));
|
|
2522
|
+
const dataColumns = new Set(Object.keys(data[0] || {}));
|
|
2523
|
+
const extraColumns = [...dataColumns].filter((col) => !existingColumns.has(col));
|
|
2524
|
+
const missingSchemaColumns = [...existingColumns].filter((col) => !dataColumns.has(col));
|
|
2525
|
+
const hasSchemaMismatch = extraColumns.length > 0 || missingSchemaColumns.length > 0;
|
|
2526
|
+
if (rowCount === 0 && extraColumns.length > 0) {
|
|
2527
|
+
this.logger.warn(
|
|
2528
|
+
`Table ${resolvedTableName} is empty and data has extra columns ${extraColumns.join(", ")}. Recreating with new schema.`
|
|
2529
|
+
);
|
|
2530
|
+
await this.lanceClient.dropTable(resolvedTableName);
|
|
2531
|
+
await this.lanceClient.createTable(resolvedTableName, data);
|
|
2532
|
+
} else if (hasSchemaMismatch) {
|
|
2533
|
+
if (extraColumns.length > 0) {
|
|
2534
|
+
this.logger.warn(
|
|
2535
|
+
`Table ${resolvedTableName} has ${rowCount} rows. Columns ${extraColumns.join(", ")} will be dropped from upsert.`
|
|
2536
|
+
);
|
|
2537
|
+
}
|
|
2538
|
+
const schemaFieldNames = schema.fields.map((f) => f.name);
|
|
2539
|
+
const normalizedData = data.map((row) => {
|
|
2540
|
+
const normalized = {};
|
|
2541
|
+
for (const col of schemaFieldNames) {
|
|
2542
|
+
normalized[col] = col in row ? row[col] : null;
|
|
2543
|
+
}
|
|
2544
|
+
return normalized;
|
|
2545
|
+
});
|
|
2546
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(normalizedData);
|
|
2547
|
+
} else {
|
|
2548
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(data);
|
|
2549
|
+
}
|
|
2550
|
+
} else {
|
|
2551
|
+
this.logger.debug(`Creating table ${resolvedTableName} with initial data`);
|
|
2552
|
+
await this.lanceClient.createTable(resolvedTableName, data);
|
|
2553
|
+
}
|
|
2835
2554
|
return vectorIds;
|
|
2836
2555
|
} catch (error$1) {
|
|
2837
2556
|
throw new error.MastraError(
|
|
2838
2557
|
{
|
|
2839
|
-
id: "
|
|
2558
|
+
id: storage.createVectorErrorId("LANCE", "UPSERT", "FAILED"),
|
|
2840
2559
|
domain: error.ErrorDomain.STORAGE,
|
|
2841
2560
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2842
|
-
details: {
|
|
2561
|
+
details: {
|
|
2562
|
+
tableName: resolvedTableName,
|
|
2563
|
+
vectorCount: vectors.length,
|
|
2564
|
+
metadataCount: metadata.length,
|
|
2565
|
+
idsCount: ids.length
|
|
2566
|
+
}
|
|
2843
2567
|
},
|
|
2844
2568
|
error$1
|
|
2845
2569
|
);
|
|
@@ -2863,7 +2587,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2863
2587
|
async createTable(tableName, data, options) {
|
|
2864
2588
|
if (!this.lanceClient) {
|
|
2865
2589
|
throw new error.MastraError({
|
|
2866
|
-
id: "
|
|
2590
|
+
id: storage.createVectorErrorId("LANCE", "CREATE_TABLE", "INVALID_ARGS"),
|
|
2867
2591
|
domain: error.ErrorDomain.STORAGE,
|
|
2868
2592
|
category: error.ErrorCategory.USER,
|
|
2869
2593
|
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
@@ -2878,7 +2602,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2878
2602
|
} catch (error$1) {
|
|
2879
2603
|
throw new error.MastraError(
|
|
2880
2604
|
{
|
|
2881
|
-
id: "
|
|
2605
|
+
id: storage.createVectorErrorId("LANCE", "CREATE_TABLE", "FAILED"),
|
|
2882
2606
|
domain: error.ErrorDomain.STORAGE,
|
|
2883
2607
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2884
2608
|
details: { tableName }
|
|
@@ -2890,7 +2614,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2890
2614
|
async listTables() {
|
|
2891
2615
|
if (!this.lanceClient) {
|
|
2892
2616
|
throw new error.MastraError({
|
|
2893
|
-
id: "
|
|
2617
|
+
id: storage.createVectorErrorId("LANCE", "LIST_TABLES", "INVALID_ARGS"),
|
|
2894
2618
|
domain: error.ErrorDomain.STORAGE,
|
|
2895
2619
|
category: error.ErrorCategory.USER,
|
|
2896
2620
|
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
@@ -2902,7 +2626,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2902
2626
|
} catch (error$1) {
|
|
2903
2627
|
throw new error.MastraError(
|
|
2904
2628
|
{
|
|
2905
|
-
id: "
|
|
2629
|
+
id: storage.createVectorErrorId("LANCE", "LIST_TABLES", "FAILED"),
|
|
2906
2630
|
domain: error.ErrorDomain.STORAGE,
|
|
2907
2631
|
category: error.ErrorCategory.THIRD_PARTY
|
|
2908
2632
|
},
|
|
@@ -2913,7 +2637,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2913
2637
|
async getTableSchema(tableName) {
|
|
2914
2638
|
if (!this.lanceClient) {
|
|
2915
2639
|
throw new error.MastraError({
|
|
2916
|
-
id: "
|
|
2640
|
+
id: storage.createVectorErrorId("LANCE", "GET_TABLE_SCHEMA", "INVALID_ARGS"),
|
|
2917
2641
|
domain: error.ErrorDomain.STORAGE,
|
|
2918
2642
|
category: error.ErrorCategory.USER,
|
|
2919
2643
|
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
@@ -2926,7 +2650,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2926
2650
|
} catch (error$1) {
|
|
2927
2651
|
throw new error.MastraError(
|
|
2928
2652
|
{
|
|
2929
|
-
id: "
|
|
2653
|
+
id: storage.createVectorErrorId("LANCE", "GET_TABLE_SCHEMA", "FAILED"),
|
|
2930
2654
|
domain: error.ErrorDomain.STORAGE,
|
|
2931
2655
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
2932
2656
|
details: { tableName }
|
|
@@ -2936,7 +2660,17 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2936
2660
|
}
|
|
2937
2661
|
}
|
|
2938
2662
|
/**
|
|
2939
|
-
*
|
|
2663
|
+
* Creates a vector index on a table.
|
|
2664
|
+
*
|
|
2665
|
+
* The behavior of `indexName` depends on whether `tableName` is provided:
|
|
2666
|
+
* - With `tableName`: `indexName` is the column to index (advanced use case)
|
|
2667
|
+
* - Without `tableName`: `indexName` becomes the table name, and 'vector' is used as the column (Memory compatibility)
|
|
2668
|
+
*
|
|
2669
|
+
* @param tableName - Optional table name. If not provided, defaults to indexName.
|
|
2670
|
+
* @param indexName - The index/column name, or table name if tableName is not provided.
|
|
2671
|
+
* @param dimension - Vector dimension size.
|
|
2672
|
+
* @param metric - Distance metric: 'cosine', 'euclidean', or 'dotproduct'.
|
|
2673
|
+
* @param indexConfig - Optional index configuration.
|
|
2940
2674
|
*/
|
|
2941
2675
|
async createIndex({
|
|
2942
2676
|
tableName,
|
|
@@ -2945,13 +2679,12 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2945
2679
|
metric = "cosine",
|
|
2946
2680
|
indexConfig = {}
|
|
2947
2681
|
}) {
|
|
2682
|
+
const resolvedTableName = tableName ?? indexName;
|
|
2683
|
+
const columnToIndex = tableName ? indexName : "vector";
|
|
2948
2684
|
try {
|
|
2949
2685
|
if (!this.lanceClient) {
|
|
2950
2686
|
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
2951
2687
|
}
|
|
2952
|
-
if (!tableName) {
|
|
2953
|
-
throw new Error("tableName is required");
|
|
2954
|
-
}
|
|
2955
2688
|
if (!indexName) {
|
|
2956
2689
|
throw new Error("indexName is required");
|
|
2957
2690
|
}
|
|
@@ -2961,22 +2694,38 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2961
2694
|
} catch (err) {
|
|
2962
2695
|
throw new error.MastraError(
|
|
2963
2696
|
{
|
|
2964
|
-
id: "
|
|
2697
|
+
id: storage.createVectorErrorId("LANCE", "CREATE_INDEX", "INVALID_ARGS"),
|
|
2965
2698
|
domain: error.ErrorDomain.STORAGE,
|
|
2966
2699
|
category: error.ErrorCategory.USER,
|
|
2967
|
-
details: { tableName:
|
|
2700
|
+
details: { tableName: resolvedTableName, indexName, dimension, metric }
|
|
2968
2701
|
},
|
|
2969
2702
|
err
|
|
2970
2703
|
);
|
|
2971
2704
|
}
|
|
2972
2705
|
try {
|
|
2973
2706
|
const tables = await this.lanceClient.tableNames();
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2707
|
+
let table;
|
|
2708
|
+
if (!tables.includes(resolvedTableName)) {
|
|
2709
|
+
this.logger.debug(
|
|
2710
|
+
`Table ${resolvedTableName} does not exist. Creating empty table with dimension ${dimension}.`
|
|
2977
2711
|
);
|
|
2712
|
+
const initVector = new Array(dimension).fill(0);
|
|
2713
|
+
table = await this.lanceClient.createTable(resolvedTableName, [
|
|
2714
|
+
{ id: "__init__", vector: initVector, _metadata_json: "" }
|
|
2715
|
+
]);
|
|
2716
|
+
try {
|
|
2717
|
+
await table.delete("id = '__init__'");
|
|
2718
|
+
} catch (deleteError) {
|
|
2719
|
+
this.logger.warn(
|
|
2720
|
+
`Failed to delete initialization row from ${resolvedTableName}. Subsequent queries may include '__init__' row.`,
|
|
2721
|
+
deleteError
|
|
2722
|
+
);
|
|
2723
|
+
}
|
|
2724
|
+
this.logger.debug(`Table ${resolvedTableName} created. Index creation deferred until data is available.`);
|
|
2725
|
+
return;
|
|
2726
|
+
} else {
|
|
2727
|
+
table = await this.lanceClient.openTable(resolvedTableName);
|
|
2978
2728
|
}
|
|
2979
|
-
const table = await this.lanceClient.openTable(tableName);
|
|
2980
2729
|
let metricType;
|
|
2981
2730
|
if (metric === "euclidean") {
|
|
2982
2731
|
metricType = "l2";
|
|
@@ -2985,8 +2734,15 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2985
2734
|
} else if (metric === "cosine") {
|
|
2986
2735
|
metricType = "cosine";
|
|
2987
2736
|
}
|
|
2737
|
+
const rowCount = await table.countRows();
|
|
2738
|
+
if (rowCount < 256) {
|
|
2739
|
+
this.logger.warn(
|
|
2740
|
+
`Table ${resolvedTableName} has ${rowCount} rows, which is below the 256 row minimum for index creation. Skipping index creation.`
|
|
2741
|
+
);
|
|
2742
|
+
return;
|
|
2743
|
+
}
|
|
2988
2744
|
if (indexConfig.type === "ivfflat") {
|
|
2989
|
-
await table.createIndex(
|
|
2745
|
+
await table.createIndex(columnToIndex, {
|
|
2990
2746
|
config: lancedb.Index.ivfPq({
|
|
2991
2747
|
numPartitions: indexConfig.numPartitions || 128,
|
|
2992
2748
|
numSubVectors: indexConfig.numSubVectors || 16,
|
|
@@ -2995,7 +2751,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
2995
2751
|
});
|
|
2996
2752
|
} else {
|
|
2997
2753
|
this.logger.debug("Creating HNSW PQ index with config:", indexConfig);
|
|
2998
|
-
await table.createIndex(
|
|
2754
|
+
await table.createIndex(columnToIndex, {
|
|
2999
2755
|
config: lancedb.Index.hnswPq({
|
|
3000
2756
|
m: indexConfig?.hnsw?.m || 16,
|
|
3001
2757
|
efConstruction: indexConfig?.hnsw?.efConstruction || 100,
|
|
@@ -3006,10 +2762,10 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3006
2762
|
} catch (error$1) {
|
|
3007
2763
|
throw new error.MastraError(
|
|
3008
2764
|
{
|
|
3009
|
-
id: "
|
|
2765
|
+
id: storage.createVectorErrorId("LANCE", "CREATE_INDEX", "FAILED"),
|
|
3010
2766
|
domain: error.ErrorDomain.STORAGE,
|
|
3011
2767
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
3012
|
-
details: { tableName:
|
|
2768
|
+
details: { tableName: resolvedTableName, indexName, dimension }
|
|
3013
2769
|
},
|
|
3014
2770
|
error$1
|
|
3015
2771
|
);
|
|
@@ -3018,7 +2774,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3018
2774
|
async listIndexes() {
|
|
3019
2775
|
if (!this.lanceClient) {
|
|
3020
2776
|
throw new error.MastraError({
|
|
3021
|
-
id: "
|
|
2777
|
+
id: storage.createVectorErrorId("LANCE", "LIST_INDEXES", "INVALID_ARGS"),
|
|
3022
2778
|
domain: error.ErrorDomain.STORAGE,
|
|
3023
2779
|
category: error.ErrorCategory.USER,
|
|
3024
2780
|
text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
|
|
@@ -3037,7 +2793,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3037
2793
|
} catch (error$1) {
|
|
3038
2794
|
throw new error.MastraError(
|
|
3039
2795
|
{
|
|
3040
|
-
id: "
|
|
2796
|
+
id: storage.createVectorErrorId("LANCE", "LIST_INDEXES", "FAILED"),
|
|
3041
2797
|
domain: error.ErrorDomain.STORAGE,
|
|
3042
2798
|
category: error.ErrorCategory.THIRD_PARTY
|
|
3043
2799
|
},
|
|
@@ -3056,7 +2812,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3056
2812
|
} catch (err) {
|
|
3057
2813
|
throw new error.MastraError(
|
|
3058
2814
|
{
|
|
3059
|
-
id: "
|
|
2815
|
+
id: storage.createVectorErrorId("LANCE", "DESCRIBE_INDEX", "INVALID_ARGS"),
|
|
3060
2816
|
domain: error.ErrorDomain.STORAGE,
|
|
3061
2817
|
category: error.ErrorCategory.USER,
|
|
3062
2818
|
details: { indexName }
|
|
@@ -3091,7 +2847,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3091
2847
|
} catch (error$1) {
|
|
3092
2848
|
throw new error.MastraError(
|
|
3093
2849
|
{
|
|
3094
|
-
id: "
|
|
2850
|
+
id: storage.createVectorErrorId("LANCE", "DESCRIBE_INDEX", "FAILED"),
|
|
3095
2851
|
domain: error.ErrorDomain.STORAGE,
|
|
3096
2852
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
3097
2853
|
details: { indexName }
|
|
@@ -3111,7 +2867,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3111
2867
|
} catch (err) {
|
|
3112
2868
|
throw new error.MastraError(
|
|
3113
2869
|
{
|
|
3114
|
-
id: "
|
|
2870
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_INDEX", "INVALID_ARGS"),
|
|
3115
2871
|
domain: error.ErrorDomain.STORAGE,
|
|
3116
2872
|
category: error.ErrorCategory.USER,
|
|
3117
2873
|
details: { indexName }
|
|
@@ -3134,7 +2890,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3134
2890
|
} catch (error$1) {
|
|
3135
2891
|
throw new error.MastraError(
|
|
3136
2892
|
{
|
|
3137
|
-
id: "
|
|
2893
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_INDEX", "FAILED"),
|
|
3138
2894
|
domain: error.ErrorDomain.STORAGE,
|
|
3139
2895
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
3140
2896
|
details: { indexName }
|
|
@@ -3149,7 +2905,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3149
2905
|
async deleteAllTables() {
|
|
3150
2906
|
if (!this.lanceClient) {
|
|
3151
2907
|
throw new error.MastraError({
|
|
3152
|
-
id: "
|
|
2908
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_ALL_TABLES", "INVALID_ARGS"),
|
|
3153
2909
|
domain: error.ErrorDomain.STORAGE,
|
|
3154
2910
|
category: error.ErrorCategory.USER,
|
|
3155
2911
|
details: { methodName: "deleteAllTables" },
|
|
@@ -3161,7 +2917,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3161
2917
|
} catch (error$1) {
|
|
3162
2918
|
throw new error.MastraError(
|
|
3163
2919
|
{
|
|
3164
|
-
id: "
|
|
2920
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_ALL_TABLES", "FAILED"),
|
|
3165
2921
|
domain: error.ErrorDomain.STORAGE,
|
|
3166
2922
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
3167
2923
|
details: { methodName: "deleteAllTables" }
|
|
@@ -3173,7 +2929,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3173
2929
|
async deleteTable(tableName) {
|
|
3174
2930
|
if (!this.lanceClient) {
|
|
3175
2931
|
throw new error.MastraError({
|
|
3176
|
-
id: "
|
|
2932
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_TABLE", "INVALID_ARGS"),
|
|
3177
2933
|
domain: error.ErrorDomain.STORAGE,
|
|
3178
2934
|
category: error.ErrorCategory.USER,
|
|
3179
2935
|
details: { tableName },
|
|
@@ -3185,7 +2941,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3185
2941
|
} catch (error$1) {
|
|
3186
2942
|
throw new error.MastraError(
|
|
3187
2943
|
{
|
|
3188
|
-
id: "
|
|
2944
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_TABLE", "FAILED"),
|
|
3189
2945
|
domain: error.ErrorDomain.STORAGE,
|
|
3190
2946
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
3191
2947
|
details: { tableName }
|
|
@@ -3194,7 +2950,44 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3194
2950
|
);
|
|
3195
2951
|
}
|
|
3196
2952
|
}
|
|
3197
|
-
async updateVector(
|
|
2953
|
+
async updateVector(params) {
|
|
2954
|
+
const { indexName, update } = params;
|
|
2955
|
+
if ("id" in params && "filter" in params && params.id && params.filter) {
|
|
2956
|
+
throw new error.MastraError({
|
|
2957
|
+
id: storage.createVectorErrorId("LANCE", "UPDATE_VECTOR", "MUTUALLY_EXCLUSIVE"),
|
|
2958
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2959
|
+
category: error.ErrorCategory.USER,
|
|
2960
|
+
text: "id and filter are mutually exclusive",
|
|
2961
|
+
details: { indexName }
|
|
2962
|
+
});
|
|
2963
|
+
}
|
|
2964
|
+
if (!("id" in params || "filter" in params) || !params.id && !params.filter) {
|
|
2965
|
+
throw new error.MastraError({
|
|
2966
|
+
id: storage.createVectorErrorId("LANCE", "UPDATE_VECTOR", "NO_TARGET"),
|
|
2967
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2968
|
+
category: error.ErrorCategory.USER,
|
|
2969
|
+
text: "Either id or filter must be provided",
|
|
2970
|
+
details: { indexName }
|
|
2971
|
+
});
|
|
2972
|
+
}
|
|
2973
|
+
if ("filter" in params && params.filter && Object.keys(params.filter).length === 0) {
|
|
2974
|
+
throw new error.MastraError({
|
|
2975
|
+
id: storage.createVectorErrorId("LANCE", "UPDATE_VECTOR", "EMPTY_FILTER"),
|
|
2976
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2977
|
+
category: error.ErrorCategory.USER,
|
|
2978
|
+
text: "Cannot update with empty filter",
|
|
2979
|
+
details: { indexName }
|
|
2980
|
+
});
|
|
2981
|
+
}
|
|
2982
|
+
if (!update.vector && !update.metadata) {
|
|
2983
|
+
throw new error.MastraError({
|
|
2984
|
+
id: storage.createVectorErrorId("LANCE", "UPDATE_VECTOR", "NO_PAYLOAD"),
|
|
2985
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2986
|
+
category: error.ErrorCategory.USER,
|
|
2987
|
+
text: "No updates provided",
|
|
2988
|
+
details: { indexName }
|
|
2989
|
+
});
|
|
2990
|
+
}
|
|
3198
2991
|
try {
|
|
3199
2992
|
if (!this.lanceClient) {
|
|
3200
2993
|
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
@@ -3202,21 +2995,6 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3202
2995
|
if (!indexName) {
|
|
3203
2996
|
throw new Error("indexName is required");
|
|
3204
2997
|
}
|
|
3205
|
-
if (!id) {
|
|
3206
|
-
throw new Error("id is required");
|
|
3207
|
-
}
|
|
3208
|
-
} catch (err) {
|
|
3209
|
-
throw new error.MastraError(
|
|
3210
|
-
{
|
|
3211
|
-
id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED_INVALID_ARGS",
|
|
3212
|
-
domain: error.ErrorDomain.STORAGE,
|
|
3213
|
-
category: error.ErrorCategory.USER,
|
|
3214
|
-
details: { indexName, id }
|
|
3215
|
-
},
|
|
3216
|
-
err
|
|
3217
|
-
);
|
|
3218
|
-
}
|
|
3219
|
-
try {
|
|
3220
2998
|
const tables = await this.lanceClient.tableNames();
|
|
3221
2999
|
for (const tableName of tables) {
|
|
3222
3000
|
this.logger.debug("Checking table:" + tableName);
|
|
@@ -3226,39 +3004,77 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3226
3004
|
const hasColumn = schema.fields.some((field) => field.name === indexName);
|
|
3227
3005
|
if (hasColumn) {
|
|
3228
3006
|
this.logger.debug(`Found column ${indexName} in table ${tableName}`);
|
|
3229
|
-
|
|
3230
|
-
if (
|
|
3231
|
-
|
|
3007
|
+
let whereClause;
|
|
3008
|
+
if ("id" in params && params.id) {
|
|
3009
|
+
whereClause = `id = '${params.id}'`;
|
|
3010
|
+
} else if ("filter" in params && params.filter) {
|
|
3011
|
+
const translator = new LanceFilterTranslator();
|
|
3012
|
+
const processFilterKeys = (filter) => {
|
|
3013
|
+
const processedFilter = {};
|
|
3014
|
+
Object.entries(filter).forEach(([key, value]) => {
|
|
3015
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
3016
|
+
Object.entries(value).forEach(([nestedKey, nestedValue]) => {
|
|
3017
|
+
processedFilter[`metadata_${key}_${nestedKey}`] = nestedValue;
|
|
3018
|
+
});
|
|
3019
|
+
} else {
|
|
3020
|
+
processedFilter[`metadata_${key}`] = value;
|
|
3021
|
+
}
|
|
3022
|
+
});
|
|
3023
|
+
return processedFilter;
|
|
3024
|
+
};
|
|
3025
|
+
const prefixedFilter = processFilterKeys(params.filter);
|
|
3026
|
+
whereClause = translator.translate(prefixedFilter) || "";
|
|
3027
|
+
if (!whereClause) {
|
|
3028
|
+
throw new Error("Failed to translate filter to SQL");
|
|
3029
|
+
}
|
|
3030
|
+
} else {
|
|
3031
|
+
throw new Error("Either id or filter must be provided");
|
|
3232
3032
|
}
|
|
3233
|
-
const
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3033
|
+
const existingRecords = await table.query().where(whereClause).select(schema.fields.map((field) => field.name)).toArray();
|
|
3034
|
+
if (existingRecords.length === 0) {
|
|
3035
|
+
this.logger.info(`No records found matching criteria in table ${tableName}`);
|
|
3036
|
+
return;
|
|
3037
|
+
}
|
|
3038
|
+
const updatedRecords = existingRecords.map((record) => {
|
|
3039
|
+
const rowData = {};
|
|
3040
|
+
Object.entries(record).forEach(([key, value]) => {
|
|
3041
|
+
if (key !== "_distance") {
|
|
3042
|
+
if (key === indexName) {
|
|
3043
|
+
if (update.vector) {
|
|
3044
|
+
rowData[key] = update.vector;
|
|
3244
3045
|
} else {
|
|
3245
|
-
|
|
3046
|
+
if (Array.isArray(value)) {
|
|
3047
|
+
rowData[key] = [...value];
|
|
3048
|
+
} else if (typeof value === "object" && value !== null) {
|
|
3049
|
+
rowData[key] = Array.from(value);
|
|
3050
|
+
} else {
|
|
3051
|
+
rowData[key] = value;
|
|
3052
|
+
}
|
|
3053
|
+
}
|
|
3054
|
+
} else {
|
|
3055
|
+
rowData[key] = value;
|
|
3056
|
+
}
|
|
3057
|
+
}
|
|
3058
|
+
});
|
|
3059
|
+
if (update.metadata) {
|
|
3060
|
+
Object.entries(update.metadata).forEach(([key, value]) => {
|
|
3061
|
+
rowData[`metadata_${key}`] = value;
|
|
3062
|
+
});
|
|
3063
|
+
const hasMetadataJson = schema.fields.some((f) => f.name === "_metadata_json");
|
|
3064
|
+
if (hasMetadataJson) {
|
|
3065
|
+
let existingMetadata = {};
|
|
3066
|
+
if (record._metadata_json) {
|
|
3067
|
+
try {
|
|
3068
|
+
existingMetadata = JSON.parse(record._metadata_json);
|
|
3069
|
+
} catch {
|
|
3246
3070
|
}
|
|
3247
3071
|
}
|
|
3248
|
-
|
|
3249
|
-
rowData[key] = value;
|
|
3072
|
+
rowData["_metadata_json"] = JSON.stringify({ ...existingMetadata, ...update.metadata });
|
|
3250
3073
|
}
|
|
3251
3074
|
}
|
|
3075
|
+
return rowData;
|
|
3252
3076
|
});
|
|
3253
|
-
|
|
3254
|
-
rowData[indexName] = update.vector;
|
|
3255
|
-
}
|
|
3256
|
-
if (update.metadata) {
|
|
3257
|
-
Object.entries(update.metadata).forEach(([key, value]) => {
|
|
3258
|
-
rowData[`metadata_${key}`] = value;
|
|
3259
|
-
});
|
|
3260
|
-
}
|
|
3261
|
-
await table.add([rowData], { mode: "overwrite" });
|
|
3077
|
+
await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(updatedRecords);
|
|
3262
3078
|
return;
|
|
3263
3079
|
}
|
|
3264
3080
|
} catch (err) {
|
|
@@ -3268,12 +3084,19 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3268
3084
|
}
|
|
3269
3085
|
throw new Error(`No table found with column/index '${indexName}'`);
|
|
3270
3086
|
} catch (error$1) {
|
|
3087
|
+
if (error$1 instanceof error.MastraError) throw error$1;
|
|
3271
3088
|
throw new error.MastraError(
|
|
3272
3089
|
{
|
|
3273
|
-
id: "
|
|
3090
|
+
id: storage.createVectorErrorId("LANCE", "UPDATE_VECTOR", "FAILED"),
|
|
3274
3091
|
domain: error.ErrorDomain.STORAGE,
|
|
3275
3092
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
3276
|
-
details: {
|
|
3093
|
+
details: {
|
|
3094
|
+
indexName,
|
|
3095
|
+
..."id" in params && params.id && { id: params.id },
|
|
3096
|
+
..."filter" in params && params.filter && { filter: JSON.stringify(params.filter) },
|
|
3097
|
+
hasVector: !!update.vector,
|
|
3098
|
+
hasMetadata: !!update.metadata
|
|
3099
|
+
}
|
|
3277
3100
|
},
|
|
3278
3101
|
error$1
|
|
3279
3102
|
);
|
|
@@ -3293,10 +3116,13 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3293
3116
|
} catch (err) {
|
|
3294
3117
|
throw new error.MastraError(
|
|
3295
3118
|
{
|
|
3296
|
-
id: "
|
|
3119
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_VECTOR", "INVALID_ARGS"),
|
|
3297
3120
|
domain: error.ErrorDomain.STORAGE,
|
|
3298
3121
|
category: error.ErrorCategory.USER,
|
|
3299
|
-
details: {
|
|
3122
|
+
details: {
|
|
3123
|
+
indexName,
|
|
3124
|
+
...id && { id }
|
|
3125
|
+
}
|
|
3300
3126
|
},
|
|
3301
3127
|
err
|
|
3302
3128
|
);
|
|
@@ -3323,43 +3149,150 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
|
|
|
3323
3149
|
} catch (error$1) {
|
|
3324
3150
|
throw new error.MastraError(
|
|
3325
3151
|
{
|
|
3326
|
-
id: "
|
|
3152
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_VECTOR", "FAILED"),
|
|
3327
3153
|
domain: error.ErrorDomain.STORAGE,
|
|
3328
3154
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
3329
|
-
details: {
|
|
3155
|
+
details: {
|
|
3156
|
+
indexName,
|
|
3157
|
+
...id && { id }
|
|
3158
|
+
}
|
|
3330
3159
|
},
|
|
3331
3160
|
error$1
|
|
3332
3161
|
);
|
|
3333
3162
|
}
|
|
3334
3163
|
}
|
|
3335
3164
|
/**
|
|
3336
|
-
*
|
|
3337
|
-
*
|
|
3165
|
+
* Extracts column names referenced in a SQL WHERE clause.
|
|
3166
|
+
* Identifies metadata_* prefixed identifiers used in filter conditions.
|
|
3338
3167
|
*/
|
|
3339
|
-
|
|
3340
|
-
const
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3168
|
+
extractFilterColumns(whereClause) {
|
|
3169
|
+
const matches = whereClause.match(/metadata_\w+/g);
|
|
3170
|
+
return matches ? [...new Set(matches)] : [];
|
|
3171
|
+
}
|
|
3172
|
+
/**
|
|
3173
|
+
* Extracts metadata from flattened column names (legacy data without _metadata_json).
|
|
3174
|
+
* Returns keys as-is after stripping the 'metadata_' prefix, without any unflattening.
|
|
3175
|
+
*/
|
|
3176
|
+
extractFlatMetadata(result) {
|
|
3177
|
+
const metadata = {};
|
|
3178
|
+
Object.keys(result).forEach((key) => {
|
|
3179
|
+
if (key !== "id" && key !== "score" && key !== "vector" && key !== "_distance" && key !== "_metadata_json") {
|
|
3180
|
+
if (key.startsWith("metadata_")) {
|
|
3181
|
+
metadata[key.substring("metadata_".length)] = result[key];
|
|
3350
3182
|
}
|
|
3351
|
-
current = current[part];
|
|
3352
|
-
}
|
|
3353
|
-
const lastPart = parts[parts.length - 1];
|
|
3354
|
-
if (lastPart) {
|
|
3355
|
-
current[lastPart] = value;
|
|
3356
3183
|
}
|
|
3357
3184
|
});
|
|
3358
|
-
return
|
|
3185
|
+
return metadata;
|
|
3186
|
+
}
|
|
3187
|
+
async deleteVectors({ indexName, filter, ids }) {
|
|
3188
|
+
if (ids && filter) {
|
|
3189
|
+
throw new error.MastraError({
|
|
3190
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_VECTORS", "MUTUALLY_EXCLUSIVE"),
|
|
3191
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3192
|
+
category: error.ErrorCategory.USER,
|
|
3193
|
+
text: "ids and filter are mutually exclusive",
|
|
3194
|
+
details: { indexName }
|
|
3195
|
+
});
|
|
3196
|
+
}
|
|
3197
|
+
if (!ids && !filter) {
|
|
3198
|
+
throw new error.MastraError({
|
|
3199
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_VECTORS", "NO_TARGET"),
|
|
3200
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3201
|
+
category: error.ErrorCategory.USER,
|
|
3202
|
+
text: "Either filter or ids must be provided",
|
|
3203
|
+
details: { indexName }
|
|
3204
|
+
});
|
|
3205
|
+
}
|
|
3206
|
+
if (ids && ids.length === 0) {
|
|
3207
|
+
throw new error.MastraError({
|
|
3208
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_VECTORS", "EMPTY_IDS"),
|
|
3209
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3210
|
+
category: error.ErrorCategory.USER,
|
|
3211
|
+
text: "Cannot delete with empty ids array",
|
|
3212
|
+
details: { indexName }
|
|
3213
|
+
});
|
|
3214
|
+
}
|
|
3215
|
+
if (filter && Object.keys(filter).length === 0) {
|
|
3216
|
+
throw new error.MastraError({
|
|
3217
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_VECTORS", "EMPTY_FILTER"),
|
|
3218
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3219
|
+
category: error.ErrorCategory.USER,
|
|
3220
|
+
text: "Cannot delete with empty filter",
|
|
3221
|
+
details: { indexName }
|
|
3222
|
+
});
|
|
3223
|
+
}
|
|
3224
|
+
try {
|
|
3225
|
+
if (!this.lanceClient) {
|
|
3226
|
+
throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
|
|
3227
|
+
}
|
|
3228
|
+
if (!indexName) {
|
|
3229
|
+
throw new Error("indexName is required");
|
|
3230
|
+
}
|
|
3231
|
+
const tables = await this.lanceClient.tableNames();
|
|
3232
|
+
for (const tableName of tables) {
|
|
3233
|
+
this.logger.debug("Checking table:" + tableName);
|
|
3234
|
+
const table = await this.lanceClient.openTable(tableName);
|
|
3235
|
+
try {
|
|
3236
|
+
const schema = await table.schema();
|
|
3237
|
+
const hasColumn = schema.fields.some((field) => field.name === indexName);
|
|
3238
|
+
if (hasColumn) {
|
|
3239
|
+
this.logger.debug(`Found column ${indexName} in table ${tableName}`);
|
|
3240
|
+
if (ids) {
|
|
3241
|
+
const idsConditions = ids.map((id) => `id = '${id}'`).join(" OR ");
|
|
3242
|
+
await table.delete(idsConditions);
|
|
3243
|
+
} else if (filter) {
|
|
3244
|
+
const translator = new LanceFilterTranslator();
|
|
3245
|
+
const processFilterKeys = (filter2) => {
|
|
3246
|
+
const processedFilter = {};
|
|
3247
|
+
Object.entries(filter2).forEach(([key, value]) => {
|
|
3248
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
3249
|
+
Object.entries(value).forEach(([nestedKey, nestedValue]) => {
|
|
3250
|
+
processedFilter[`metadata_${key}_${nestedKey}`] = nestedValue;
|
|
3251
|
+
});
|
|
3252
|
+
} else {
|
|
3253
|
+
processedFilter[`metadata_${key}`] = value;
|
|
3254
|
+
}
|
|
3255
|
+
});
|
|
3256
|
+
return processedFilter;
|
|
3257
|
+
};
|
|
3258
|
+
const prefixedFilter = processFilterKeys(filter);
|
|
3259
|
+
const whereClause = translator.translate(prefixedFilter);
|
|
3260
|
+
if (!whereClause) {
|
|
3261
|
+
throw new Error("Failed to translate filter to SQL");
|
|
3262
|
+
}
|
|
3263
|
+
await table.delete(whereClause);
|
|
3264
|
+
}
|
|
3265
|
+
return;
|
|
3266
|
+
}
|
|
3267
|
+
} catch (err) {
|
|
3268
|
+
this.logger.error(`Error checking schema for table ${tableName}:` + err);
|
|
3269
|
+
continue;
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
throw new Error(`No table found with column/index '${indexName}'`);
|
|
3273
|
+
} catch (error$1) {
|
|
3274
|
+
if (error$1 instanceof error.MastraError) throw error$1;
|
|
3275
|
+
throw new error.MastraError(
|
|
3276
|
+
{
|
|
3277
|
+
id: storage.createVectorErrorId("LANCE", "DELETE_VECTORS", "FAILED"),
|
|
3278
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3279
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
3280
|
+
details: {
|
|
3281
|
+
indexName,
|
|
3282
|
+
...filter && { filter: JSON.stringify(filter) },
|
|
3283
|
+
...ids && { idsCount: ids.length }
|
|
3284
|
+
}
|
|
3285
|
+
},
|
|
3286
|
+
error$1
|
|
3287
|
+
);
|
|
3288
|
+
}
|
|
3359
3289
|
}
|
|
3360
3290
|
};
|
|
3361
3291
|
|
|
3362
3292
|
exports.LanceStorage = LanceStorage;
|
|
3363
3293
|
exports.LanceVectorStore = LanceVectorStore;
|
|
3294
|
+
exports.StoreMemoryLance = StoreMemoryLance;
|
|
3295
|
+
exports.StoreScoresLance = StoreScoresLance;
|
|
3296
|
+
exports.StoreWorkflowsLance = StoreWorkflowsLance;
|
|
3364
3297
|
//# sourceMappingURL=index.cjs.map
|
|
3365
3298
|
//# sourceMappingURL=index.cjs.map
|