@mastra/lance 0.0.0-new-scorer-api-20250801075530 → 0.0.0-new-button-export-20251219130424

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +1111 -3
  2. package/README.md +64 -7
  3. package/dist/index.cjs +1525 -1403
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.js +1526 -1404
  7. package/dist/index.js.map +1 -1
  8. package/dist/storage/{domains/operations → db}/index.d.ts +21 -2
  9. package/dist/storage/db/index.d.ts.map +1 -0
  10. package/dist/storage/db/utils.d.ts.map +1 -0
  11. package/dist/storage/domains/memory/index.d.ts +23 -39
  12. package/dist/storage/domains/memory/index.d.ts.map +1 -1
  13. package/dist/storage/domains/scores/index.d.ts +29 -9
  14. package/dist/storage/domains/scores/index.d.ts.map +1 -1
  15. package/dist/storage/domains/workflows/index.d.ts +28 -14
  16. package/dist/storage/domains/workflows/index.d.ts.map +1 -1
  17. package/dist/storage/index.d.ts +88 -109
  18. package/dist/storage/index.d.ts.map +1 -1
  19. package/dist/vector/filter.d.ts +5 -5
  20. package/dist/vector/index.d.ts +8 -5
  21. package/dist/vector/index.d.ts.map +1 -1
  22. package/package.json +29 -11
  23. package/dist/storage/domains/legacy-evals/index.d.ts +0 -25
  24. package/dist/storage/domains/legacy-evals/index.d.ts.map +0 -1
  25. package/dist/storage/domains/operations/index.d.ts.map +0 -1
  26. package/dist/storage/domains/traces/index.d.ts +0 -34
  27. package/dist/storage/domains/traces/index.d.ts.map +0 -1
  28. package/dist/storage/domains/utils.d.ts.map +0 -1
  29. package/eslint.config.js +0 -6
  30. package/src/index.ts +0 -2
  31. package/src/storage/domains/legacy-evals/index.ts +0 -156
  32. package/src/storage/domains/memory/index.ts +0 -947
  33. package/src/storage/domains/operations/index.ts +0 -489
  34. package/src/storage/domains/scores/index.ts +0 -221
  35. package/src/storage/domains/traces/index.ts +0 -212
  36. package/src/storage/domains/utils.ts +0 -158
  37. package/src/storage/domains/workflows/index.ts +0 -207
  38. package/src/storage/index.test.ts +0 -10
  39. package/src/storage/index.ts +0 -442
  40. package/src/vector/filter.test.ts +0 -295
  41. package/src/vector/filter.ts +0 -443
  42. package/src/vector/index.test.ts +0 -1493
  43. package/src/vector/index.ts +0 -941
  44. package/src/vector/types.ts +0 -16
  45. package/tsconfig.build.json +0 -9
  46. package/tsconfig.json +0 -5
  47. package/tsup.config.ts +0 -22
  48. package/vitest.config.ts +0 -11
  49. /package/dist/storage/{domains → db}/utils.d.ts +0 -0
package/dist/index.cjs CHANGED
@@ -4,131 +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');
9
+ var evals = require('@mastra/core/evals');
8
10
  var vector = require('@mastra/core/vector');
9
11
  var filter = require('@mastra/core/vector/filter');
10
12
 
11
13
  // src/storage/index.ts
12
- var StoreLegacyEvalsLance = class extends storage.LegacyEvalsStorage {
13
- client;
14
- constructor({ client }) {
15
- super();
16
- this.client = client;
17
- }
18
- async getEvalsByAgentName(agentName, type) {
19
- try {
20
- const table = await this.client.openTable(storage.TABLE_EVALS);
21
- const query = table.query().where(`agent_name = '${agentName}'`);
22
- const records = await query.toArray();
23
- let filteredRecords = records;
24
- if (type === "live") {
25
- filteredRecords = records.filter((record) => record.test_info === null);
26
- } else if (type === "test") {
27
- filteredRecords = records.filter((record) => record.test_info !== null);
28
- }
29
- return filteredRecords.map((record) => {
30
- return {
31
- id: record.id,
32
- input: record.input,
33
- output: record.output,
34
- agentName: record.agent_name,
35
- metricName: record.metric_name,
36
- result: JSON.parse(record.result),
37
- instructions: record.instructions,
38
- testInfo: record.test_info ? JSON.parse(record.test_info) : null,
39
- globalRunId: record.global_run_id,
40
- runId: record.run_id,
41
- createdAt: new Date(record.created_at).toString()
42
- };
43
- });
44
- } catch (error$1) {
45
- throw new error.MastraError(
46
- {
47
- id: "LANCE_STORE_GET_EVALS_BY_AGENT_NAME_FAILED",
48
- domain: error.ErrorDomain.STORAGE,
49
- category: error.ErrorCategory.THIRD_PARTY,
50
- details: { agentName }
51
- },
52
- error$1
53
- );
54
- }
55
- }
56
- async getEvals(options) {
57
- try {
58
- const table = await this.client.openTable(storage.TABLE_EVALS);
59
- const conditions = [];
60
- if (options.agentName) {
61
- conditions.push(`agent_name = '${options.agentName}'`);
62
- }
63
- if (options.type === "live") {
64
- conditions.push("length(test_info) = 0");
65
- } else if (options.type === "test") {
66
- conditions.push("length(test_info) > 0");
67
- }
68
- const startDate = options.dateRange?.start || options.fromDate;
69
- const endDate = options.dateRange?.end || options.toDate;
70
- if (startDate) {
71
- conditions.push(`\`created_at\` >= ${startDate.getTime()}`);
72
- }
73
- if (endDate) {
74
- conditions.push(`\`created_at\` <= ${endDate.getTime()}`);
75
- }
76
- let total = 0;
77
- if (conditions.length > 0) {
78
- total = await table.countRows(conditions.join(" AND "));
79
- } else {
80
- total = await table.countRows();
81
- }
82
- const query = table.query();
83
- if (conditions.length > 0) {
84
- const whereClause = conditions.join(" AND ");
85
- query.where(whereClause);
86
- }
87
- const records = await query.toArray();
88
- const evals = records.sort((a, b) => b.created_at - a.created_at).map((record) => {
89
- return {
90
- id: record.id,
91
- input: record.input,
92
- output: record.output,
93
- agentName: record.agent_name,
94
- metricName: record.metric_name,
95
- result: JSON.parse(record.result),
96
- instructions: record.instructions,
97
- testInfo: record.test_info ? JSON.parse(record.test_info) : null,
98
- globalRunId: record.global_run_id,
99
- runId: record.run_id,
100
- createdAt: new Date(record.created_at).toISOString()
101
- };
102
- });
103
- const page = options.page || 0;
104
- const perPage = options.perPage || 10;
105
- const pagedEvals = evals.slice(page * perPage, (page + 1) * perPage);
106
- return {
107
- evals: pagedEvals,
108
- total,
109
- page,
110
- perPage,
111
- hasMore: total > (page + 1) * perPage
112
- };
113
- } catch (error$1) {
114
- throw new error.MastraError(
115
- {
116
- id: "LANCE_STORE_GET_EVALS_FAILED",
117
- domain: error.ErrorDomain.STORAGE,
118
- category: error.ErrorCategory.THIRD_PARTY,
119
- details: { agentName: options.agentName ?? "" }
120
- },
121
- error$1
122
- );
123
- }
124
- }
125
- };
126
14
  function getPrimaryKeys(tableName) {
127
15
  let primaryId = ["id"];
128
16
  if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
129
17
  primaryId = ["workflow_name", "run_id"];
130
- } else if (tableName === storage.TABLE_EVALS) {
131
- primaryId = ["agent_name", "metric_name", "run_id"];
132
18
  }
133
19
  return primaryId;
134
20
  }
@@ -189,7 +75,6 @@ function processResultWithTypeConversion(rawResult, tableSchema) {
189
75
  } else if (fieldTypeStr.includes("float64") && ["createdAt", "updatedAt"].includes(key)) {
190
76
  processedResult[key] = new Date(processedResult[key]);
191
77
  }
192
- console.log(key, "processedResult", processedResult);
193
78
  }
194
79
  return processedResult;
195
80
  }
@@ -207,7 +92,7 @@ async function getTableSchema({
207
92
  } catch (validationError) {
208
93
  throw new error.MastraError(
209
94
  {
210
- id: "STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_INVALID_ARGS",
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: "STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_FAILED",
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,625 +125,503 @@ async function getTableSchema({
240
125
  }
241
126
  }
242
127
 
243
- // src/storage/domains/memory/index.ts
244
- var StoreMemoryLance = class extends storage.MemoryStorage {
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
- operations;
247
- constructor({ client, operations }) {
248
- super();
134
+ constructor({ client }) {
135
+ super({ name: "lance-db" });
249
136
  this.client = client;
250
- this.operations = operations;
251
137
  }
252
- async getThreadById({ threadId }) {
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
- const thread = await this.operations.load({ tableName: storage.TABLE_THREADS, keys: { id: threadId } });
255
- if (!thread) {
256
- return null;
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: "LANCE_STORE_GET_THREAD_BY_ID_FAILED",
212
+ id: storage.createStorageErrorId("LANCE", "CREATE_TABLE", "INVALID_ARGS"),
267
213
  domain: error.ErrorDomain.STORAGE,
268
- category: error.ErrorCategory.THIRD_PARTY
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 table = await this.client.openTable(storage.TABLE_THREADS);
277
- const query = table.query().where(`\`resourceId\` = '${resourceId}'`);
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: "LANCE_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED",
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
- const record = { ...thread, metadata: JSON.stringify(thread.metadata) };
302
- const table = await this.client.openTable(storage.TABLE_THREADS);
303
- await table.add([record], { mode: "append" });
304
- return thread;
305
- } catch (error$1) {
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: "LANCE_STORE_SAVE_THREAD_FAILED",
250
+ id: storage.createStorageErrorId("LANCE", "DROP_TABLE", "INVALID_ARGS"),
309
251
  domain: error.ErrorDomain.STORAGE,
310
- category: error.ErrorCategory.THIRD_PARTY
252
+ category: error.ErrorCategory.USER,
253
+ text: validationError.message,
254
+ details: { tableName }
311
255
  },
312
- error$1
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
- const table = await this.client.openTable(storage.TABLE_THREADS);
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: "LANCE_STORE_DELETE_THREAD_FAILED",
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
- async getMessages({
385
- threadId,
386
- resourceId,
387
- selectBy,
388
- format,
389
- threadConfig
277
+ async alterTable({
278
+ tableName,
279
+ schema,
280
+ ifNotExists
390
281
  }) {
391
282
  try {
392
- if (threadConfig) {
393
- throw new Error("ThreadConfig is not supported by LanceDB storage");
394
- }
395
- const limit = storage.resolveMessageLimit({ last: selectBy?.last, defaultLimit: Number.MAX_SAFE_INTEGER });
396
- const table = await this.client.openTable(storage.TABLE_MESSAGES);
397
- let allRecords = [];
398
- if (selectBy?.include && selectBy.include.length > 0) {
399
- const threadIds = [...new Set(selectBy.include.map((item) => item.threadId))];
400
- for (const threadId2 of threadIds) {
401
- const threadQuery = table.query().where(`thread_id = '${threadId2}'`);
402
- let threadRecords = await threadQuery.toArray();
403
- allRecords.push(...threadRecords);
404
- }
405
- } else {
406
- let query = table.query().where(`\`thread_id\` = '${threadId}'`);
407
- allRecords = await query.toArray();
283
+ if (!this.client) {
284
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
408
285
  }
409
- allRecords.sort((a, b) => {
410
- const dateA = new Date(a.createdAt).getTime();
411
- const dateB = new Date(b.createdAt).getTime();
412
- return dateA - dateB;
413
- });
414
- if (selectBy?.include && selectBy.include.length > 0) {
415
- allRecords = this.processMessagesWithContext(allRecords, selectBy.include);
286
+ if (!tableName) {
287
+ throw new Error("tableName is required for alterTable.");
416
288
  }
417
- if (limit !== Number.MAX_SAFE_INTEGER) {
418
- allRecords = allRecords.slice(-limit);
289
+ if (!schema) {
290
+ throw new Error("schema is required for alterTable.");
419
291
  }
420
- const messages = processResultWithTypeConversion(
421
- allRecords,
422
- await getTableSchema({ tableName: storage.TABLE_MESSAGES, client: this.client })
292
+ if (!ifNotExists || ifNotExists.length === 0) {
293
+ this.logger.debug("No columns specified to add in alterTable, skipping.");
294
+ return;
295
+ }
296
+ } catch (validationError) {
297
+ throw new error.MastraError(
298
+ {
299
+ id: storage.createStorageErrorId("LANCE", "ALTER_TABLE", "INVALID_ARGS"),
300
+ domain: error.ErrorDomain.STORAGE,
301
+ category: error.ErrorCategory.USER,
302
+ text: validationError.message,
303
+ details: { tableName }
304
+ },
305
+ validationError
423
306
  );
424
- const normalized = messages.map((msg) => {
425
- const { thread_id, ...rest } = msg;
307
+ }
308
+ try {
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];
426
322
  return {
427
- ...rest,
428
- threadId: thread_id,
429
- content: typeof msg.content === "string" ? (() => {
430
- try {
431
- return JSON.parse(msg.content);
432
- } catch {
433
- return msg.content;
434
- }
435
- })() : msg.content
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"]})`
436
325
  };
437
326
  });
438
- const list = new agent.MessageList({ threadId, resourceId }).add(normalized, "memory");
439
- if (format === "v2") return list.get.all.v2();
440
- return list.get.all.v1();
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
+ }
441
331
  } catch (error$1) {
442
332
  throw new error.MastraError(
443
333
  {
444
- id: "LANCE_STORE_GET_MESSAGES_FAILED",
334
+ id: storage.createStorageErrorId("LANCE", "ALTER_TABLE", "FAILED"),
445
335
  domain: error.ErrorDomain.STORAGE,
446
- category: error.ErrorCategory.THIRD_PARTY
336
+ category: error.ErrorCategory.THIRD_PARTY,
337
+ details: { tableName }
447
338
  },
448
339
  error$1
449
340
  );
450
341
  }
451
342
  }
452
- async saveMessages(args) {
343
+ async clearTable({ tableName }) {
453
344
  try {
454
- const { messages, format = "v1" } = args;
455
- if (messages.length === 0) {
456
- return [];
457
- }
458
- const threadId = messages[0]?.threadId;
459
- if (!threadId) {
460
- throw new Error("Thread ID is required");
345
+ if (!this.client) {
346
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
461
347
  }
462
- for (const message of messages) {
463
- if (!message.id) {
464
- throw new Error("Message ID is required");
465
- }
466
- if (!message.threadId) {
467
- throw new Error("Thread ID is required for all messages");
468
- }
469
- if (message.resourceId === null || message.resourceId === void 0) {
470
- throw new Error("Resource ID cannot be null or undefined");
471
- }
472
- if (!message.content) {
473
- throw new Error("Message content is required");
474
- }
348
+ if (!tableName) {
349
+ throw new Error("tableName is required for clearTable.");
475
350
  }
476
- const transformedMessages = messages.map((message) => {
477
- const { threadId: threadId2, type, ...rest } = message;
478
- return {
479
- ...rest,
480
- thread_id: threadId2,
481
- type: type ?? "v2",
482
- content: JSON.stringify(message.content)
483
- };
484
- });
485
- const table = await this.client.openTable(storage.TABLE_MESSAGES);
486
- await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
487
- const threadsTable = await this.client.openTable(storage.TABLE_THREADS);
488
- const currentTime = (/* @__PURE__ */ new Date()).getTime();
489
- const updateRecord = { id: threadId, updatedAt: currentTime };
490
- await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([updateRecord]);
491
- const list = new agent.MessageList().add(messages, "memory");
492
- if (format === `v2`) return list.get.all.v2();
493
- return list.get.all.v1();
494
- } catch (error$1) {
351
+ } catch (validationError) {
495
352
  throw new error.MastraError(
496
353
  {
497
- id: "LANCE_STORE_SAVE_MESSAGES_FAILED",
354
+ id: storage.createStorageErrorId("LANCE", "CLEAR_TABLE", "INVALID_ARGS"),
498
355
  domain: error.ErrorDomain.STORAGE,
499
- category: error.ErrorCategory.THIRD_PARTY
356
+ category: error.ErrorCategory.USER,
357
+ text: validationError.message,
358
+ details: { tableName }
500
359
  },
501
- error$1
360
+ validationError
502
361
  );
503
362
  }
504
- }
505
- async getThreadsByResourceIdPaginated(args) {
506
363
  try {
507
- const { resourceId, page = 0, perPage = 10 } = args;
508
- const table = await this.client.openTable(storage.TABLE_THREADS);
509
- const total = await table.countRows(`\`resourceId\` = '${resourceId}'`);
510
- const query = table.query().where(`\`resourceId\` = '${resourceId}'`);
511
- const offset = page * perPage;
512
- query.limit(perPage);
513
- if (offset > 0) {
514
- query.offset(offset);
515
- }
516
- const records = await query.toArray();
517
- records.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
518
- const schema = await getTableSchema({ tableName: storage.TABLE_THREADS, client: this.client });
519
- const threads = records.map((record) => processResultWithTypeConversion(record, schema));
520
- return {
521
- threads,
522
- total,
523
- page,
524
- perPage,
525
- hasMore: total > (page + 1) * perPage
526
- };
364
+ const table = await this.client.openTable(tableName);
365
+ await table.delete("1=1");
527
366
  } catch (error$1) {
528
367
  throw new error.MastraError(
529
368
  {
530
- id: "LANCE_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
369
+ id: storage.createStorageErrorId("LANCE", "CLEAR_TABLE", "FAILED"),
531
370
  domain: error.ErrorDomain.STORAGE,
532
- category: error.ErrorCategory.THIRD_PARTY
371
+ category: error.ErrorCategory.THIRD_PARTY,
372
+ details: { tableName }
533
373
  },
534
374
  error$1
535
375
  );
536
376
  }
537
377
  }
538
- /**
539
- * Processes messages to include context messages based on withPreviousMessages and withNextMessages
540
- * @param records - The sorted array of records to process
541
- * @param include - The array of include specifications with context parameters
542
- * @returns The processed array with context messages included
543
- */
544
- processMessagesWithContext(records, include) {
545
- const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
546
- if (messagesWithContext.length === 0) {
547
- return records;
548
- }
549
- const messageIndexMap = /* @__PURE__ */ new Map();
550
- records.forEach((message, index) => {
551
- messageIndexMap.set(message.id, index);
552
- });
553
- const additionalIndices = /* @__PURE__ */ new Set();
554
- for (const item of messagesWithContext) {
555
- const messageIndex = messageIndexMap.get(item.id);
556
- if (messageIndex !== void 0) {
557
- if (item.withPreviousMessages) {
558
- const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
559
- for (let i = startIdx; i < messageIndex; i++) {
560
- additionalIndices.add(i);
561
- }
562
- }
563
- if (item.withNextMessages) {
564
- const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
565
- for (let i = messageIndex + 1; i <= endIdx; i++) {
566
- additionalIndices.add(i);
567
- }
568
- }
569
- }
570
- }
571
- if (additionalIndices.size === 0) {
572
- return records;
573
- }
574
- const originalMatchIds = new Set(include.map((item) => item.id));
575
- const allIndices = /* @__PURE__ */ new Set();
576
- records.forEach((record, index) => {
577
- if (originalMatchIds.has(record.id)) {
578
- allIndices.add(index);
579
- }
580
- });
581
- additionalIndices.forEach((index) => {
582
- allIndices.add(index);
583
- });
584
- return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
585
- }
586
- async getMessagesPaginated(args) {
378
+ async insert({ tableName, record }) {
587
379
  try {
588
- const { threadId, resourceId, selectBy, format = "v1" } = args;
589
- if (!threadId) {
590
- throw new Error("Thread ID is required for getMessagesPaginated");
591
- }
592
- const page = selectBy?.pagination?.page ?? 0;
593
- const perPage = selectBy?.pagination?.perPage ?? 10;
594
- const dateRange = selectBy?.pagination?.dateRange;
595
- const fromDate = dateRange?.start;
596
- const toDate = dateRange?.end;
597
- const table = await this.client.openTable(storage.TABLE_MESSAGES);
598
- const messages = [];
599
- if (selectBy?.include && Array.isArray(selectBy.include)) {
600
- const threadIds = [...new Set(selectBy.include.map((item) => item.threadId))];
601
- const allThreadMessages = [];
602
- for (const threadId2 of threadIds) {
603
- const threadQuery = table.query().where(`thread_id = '${threadId2}'`);
604
- let threadRecords = await threadQuery.toArray();
605
- if (fromDate) threadRecords = threadRecords.filter((m) => m.createdAt >= fromDate.getTime());
606
- if (toDate) threadRecords = threadRecords.filter((m) => m.createdAt <= toDate.getTime());
607
- allThreadMessages.push(...threadRecords);
608
- }
609
- allThreadMessages.sort((a, b) => a.createdAt - b.createdAt);
610
- const contextMessages = this.processMessagesWithContext(allThreadMessages, selectBy.include);
611
- messages.push(...contextMessages);
612
- }
613
- const conditions = [`thread_id = '${threadId}'`];
614
- if (resourceId) {
615
- conditions.push(`\`resourceId\` = '${resourceId}'`);
616
- }
617
- if (fromDate) {
618
- conditions.push(`\`createdAt\` >= ${fromDate.getTime()}`);
619
- }
620
- if (toDate) {
621
- conditions.push(`\`createdAt\` <= ${toDate.getTime()}`);
380
+ if (!this.client) {
381
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
622
382
  }
623
- let total = 0;
624
- if (conditions.length > 0) {
625
- total = await table.countRows(conditions.join(" AND "));
626
- } else {
627
- total = await table.countRows();
383
+ if (!tableName) {
384
+ throw new Error("tableName is required for insert.");
628
385
  }
629
- if (total === 0 && messages.length === 0) {
630
- return {
631
- messages: [],
632
- total: 0,
633
- page,
634
- perPage,
635
- hasMore: false
636
- };
386
+ if (!record || Object.keys(record).length === 0) {
387
+ throw new Error("record is required and cannot be empty for insert.");
637
388
  }
638
- const excludeIds = messages.map((m) => m.id);
639
- let selectedMessages = [];
640
- if (selectBy?.last && selectBy.last > 0) {
641
- const query = table.query();
642
- if (conditions.length > 0) {
643
- query.where(conditions.join(" AND "));
644
- }
645
- let records = await query.toArray();
646
- records = records.sort((a, b) => a.createdAt - b.createdAt);
647
- if (excludeIds.length > 0) {
648
- records = records.filter((m) => !excludeIds.includes(m.id));
649
- }
650
- selectedMessages = records.slice(-selectBy.last);
651
- } else {
652
- const query = table.query();
653
- if (conditions.length > 0) {
654
- query.where(conditions.join(" AND "));
655
- }
656
- let records = await query.toArray();
657
- records = records.sort((a, b) => a.createdAt - b.createdAt);
658
- if (excludeIds.length > 0) {
659
- 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]);
660
409
  }
661
- selectedMessages = records.slice(page * perPage, (page + 1) * perPage);
662
- }
663
- const allMessages = [...messages, ...selectedMessages];
664
- const seen = /* @__PURE__ */ new Set();
665
- const dedupedMessages = allMessages.filter((m) => {
666
- const key = `${m.id}:${m.thread_id}`;
667
- if (seen.has(key)) return false;
668
- seen.add(key);
669
- return true;
670
- });
671
- const formattedMessages = dedupedMessages.map((msg) => {
672
- const { thread_id, ...rest } = msg;
673
- return {
674
- ...rest,
675
- threadId: thread_id,
676
- content: typeof msg.content === "string" ? (() => {
677
- try {
678
- return JSON.parse(msg.content);
679
- } catch {
680
- return msg.content;
681
- }
682
- })() : msg.content
683
- };
684
- });
685
- const list = new agent.MessageList().add(formattedMessages, "memory");
686
- return {
687
- messages: format === "v2" ? list.get.all.v2() : list.get.all.v1(),
688
- total,
689
- // Total should be the count of messages matching the filters
690
- page,
691
- perPage,
692
- hasMore: total > (page + 1) * perPage
693
- };
410
+ }
411
+ await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([processedRecord]);
694
412
  } catch (error$1) {
695
413
  throw new error.MastraError(
696
414
  {
697
- id: "LANCE_STORE_GET_MESSAGES_PAGINATED_FAILED",
415
+ id: storage.createStorageErrorId("LANCE", "INSERT", "FAILED"),
698
416
  domain: error.ErrorDomain.STORAGE,
699
- category: error.ErrorCategory.THIRD_PARTY
417
+ category: error.ErrorCategory.THIRD_PARTY,
418
+ details: { tableName }
700
419
  },
701
420
  error$1
702
421
  );
703
422
  }
704
423
  }
705
- /**
706
- * Parse message data from LanceDB record format to MastraMessageV2 format
707
- */
708
- parseMessageData(data) {
709
- const { thread_id, ...rest } = data;
710
- return {
711
- ...rest,
712
- threadId: thread_id,
713
- content: typeof data.content === "string" ? (() => {
714
- try {
715
- return JSON.parse(data.content);
716
- } catch {
717
- return data.content;
718
- }
719
- })() : data.content,
720
- createdAt: new Date(data.createdAt),
721
- updatedAt: new Date(data.updatedAt)
722
- };
723
- }
724
- async updateMessages(args) {
725
- const { messages } = args;
726
- this.logger.debug("Updating messages", { count: messages.length });
727
- if (!messages.length) {
728
- return [];
729
- }
730
- const updatedMessages = [];
731
- const affectedThreadIds = /* @__PURE__ */ new Set();
424
+ async batchInsert({ tableName, records }) {
732
425
  try {
733
- for (const updateData of messages) {
734
- const { id, ...updates } = updateData;
735
- const existingMessage = await this.operations.load({ tableName: storage.TABLE_MESSAGES, keys: { id } });
736
- if (!existingMessage) {
737
- this.logger.warn("Message not found for update", { id });
738
- continue;
739
- }
740
- const existingMsg = this.parseMessageData(existingMessage);
741
- const originalThreadId = existingMsg.threadId;
742
- affectedThreadIds.add(originalThreadId);
743
- const updatePayload = {};
744
- if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
745
- if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
746
- if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
747
- if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
748
- updatePayload.thread_id = updates.threadId;
749
- affectedThreadIds.add(updates.threadId);
750
- }
751
- if (updates.content) {
752
- const existingContent = existingMsg.content;
753
- let newContent = { ...existingContent };
754
- if (updates.content.metadata !== void 0) {
755
- newContent.metadata = {
756
- ...existingContent.metadata || {},
757
- ...updates.content.metadata || {}
758
- };
759
- }
760
- if (updates.content.content !== void 0) {
761
- newContent.content = updates.content.content;
762
- }
763
- if ("parts" in updates.content && updates.content.parts !== void 0) {
764
- newContent.parts = updates.content.parts;
765
- }
766
- updatePayload.content = JSON.stringify(newContent);
767
- }
768
- await this.operations.insert({ tableName: storage.TABLE_MESSAGES, record: { id, ...updatePayload } });
769
- const updatedMessage = await this.operations.load({ tableName: storage.TABLE_MESSAGES, keys: { id } });
770
- if (updatedMessage) {
771
- updatedMessages.push(this.parseMessageData(updatedMessage));
772
- }
426
+ if (!this.client) {
427
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
773
428
  }
774
- for (const threadId of affectedThreadIds) {
775
- await this.operations.insert({
776
- tableName: storage.TABLE_THREADS,
777
- record: { id: threadId, updatedAt: Date.now() }
778
- });
429
+ if (!tableName) {
430
+ throw new Error("tableName is required for batchInsert.");
779
431
  }
780
- return updatedMessages;
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
+ );
446
+ }
447
+ try {
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]);
456
+ }
457
+ }
458
+ return processedRecord;
459
+ });
460
+ await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(processedRecords);
781
461
  } catch (error$1) {
782
462
  throw new error.MastraError(
783
463
  {
784
- id: "LANCE_STORE_UPDATE_MESSAGES_FAILED",
464
+ id: storage.createStorageErrorId("LANCE", "BATCH_INSERT", "FAILED"),
785
465
  domain: error.ErrorDomain.STORAGE,
786
466
  category: error.ErrorCategory.THIRD_PARTY,
787
- details: { count: messages.length }
467
+ details: { tableName }
788
468
  },
789
469
  error$1
790
470
  );
791
471
  }
792
472
  }
793
- async getResourceById({ resourceId }) {
473
+ async load({ tableName, keys }) {
794
474
  try {
795
- const resource = await this.operations.load({ tableName: storage.TABLE_RESOURCES, keys: { id: resourceId } });
796
- if (!resource) {
475
+ if (!this.client) {
476
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
477
+ }
478
+ if (!tableName) {
479
+ throw new Error("tableName is required for load.");
480
+ }
481
+ if (!keys || Object.keys(keys).length === 0) {
482
+ throw new Error("keys are required and cannot be empty for load.");
483
+ }
484
+ } catch (validationError) {
485
+ throw new error.MastraError(
486
+ {
487
+ id: storage.createStorageErrorId("LANCE", "LOAD", "INVALID_ARGS"),
488
+ domain: error.ErrorDomain.STORAGE,
489
+ category: error.ErrorCategory.USER,
490
+ text: validationError.message,
491
+ details: { tableName }
492
+ },
493
+ validationError
494
+ );
495
+ }
496
+ try {
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");
797
519
  return null;
798
520
  }
799
- let createdAt;
800
- let updatedAt;
801
- try {
802
- if (resource.createdAt instanceof Date) {
803
- createdAt = resource.createdAt;
804
- } else if (typeof resource.createdAt === "string") {
805
- createdAt = new Date(resource.createdAt);
806
- } else if (typeof resource.createdAt === "number") {
807
- createdAt = new Date(resource.createdAt);
808
- } else {
809
- createdAt = /* @__PURE__ */ new Date();
810
- }
811
- if (isNaN(createdAt.getTime())) {
812
- createdAt = /* @__PURE__ */ new Date();
521
+ return processResultWithTypeConversion(result[0], tableSchema);
522
+ } catch (error$1) {
523
+ if (error$1 instanceof error.MastraError) throw error$1;
524
+ throw new error.MastraError(
525
+ {
526
+ id: storage.createStorageErrorId("LANCE", "LOAD", "FAILED"),
527
+ domain: error.ErrorDomain.STORAGE,
528
+ category: error.ErrorCategory.THIRD_PARTY,
529
+ details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
530
+ },
531
+ error$1
532
+ );
533
+ }
534
+ }
535
+ };
536
+
537
+ // src/storage/domains/memory/index.ts
538
+ var StoreMemoryLance = class extends storage.MemoryStorage {
539
+ client;
540
+ #db;
541
+ constructor(config) {
542
+ super();
543
+ const client = resolveLanceConfig(config);
544
+ this.client = client;
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"]
555
+ });
556
+ }
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 });
567
+ try {
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);
813
573
  }
814
- } catch {
815
- createdAt = /* @__PURE__ */ new Date();
816
574
  }
817
- try {
818
- if (resource.updatedAt instanceof Date) {
819
- updatedAt = resource.updatedAt;
820
- } else if (typeof resource.updatedAt === "string") {
821
- updatedAt = new Date(resource.updatedAt);
822
- } else if (typeof resource.updatedAt === "number") {
823
- updatedAt = new Date(resource.updatedAt);
824
- } else {
825
- updatedAt = /* @__PURE__ */ new Date();
826
- }
827
- if (isNaN(updatedAt.getTime())) {
828
- updatedAt = /* @__PURE__ */ new Date();
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]);
829
592
  }
830
- } catch {
831
- updatedAt = /* @__PURE__ */ new Date();
832
- }
833
- let workingMemory = resource.workingMemory;
834
- if (workingMemory === null || workingMemory === void 0) {
835
- workingMemory = void 0;
836
- } else if (workingMemory === "") {
837
- workingMemory = "";
838
- } else if (typeof workingMemory === "object") {
839
- workingMemory = JSON.stringify(workingMemory);
840
593
  }
841
- let metadata = resource.metadata;
842
- if (metadata === "" || metadata === null || metadata === void 0) {
843
- metadata = void 0;
844
- } else if (typeof metadata === "string") {
845
- try {
846
- metadata = JSON.parse(metadata);
847
- } catch {
848
- metadata = metadata;
849
- }
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;
850
615
  }
851
616
  return {
852
- ...resource,
853
- createdAt,
854
- updatedAt,
855
- workingMemory,
856
- metadata
617
+ ...thread,
618
+ createdAt: new Date(thread.createdAt),
619
+ updatedAt: new Date(thread.updatedAt)
857
620
  };
858
621
  } catch (error$1) {
859
622
  throw new error.MastraError(
860
623
  {
861
- id: "LANCE_STORE_GET_RESOURCE_BY_ID_FAILED",
624
+ id: storage.createStorageErrorId("LANCE", "GET_THREAD_BY_ID", "FAILED"),
862
625
  domain: error.ErrorDomain.STORAGE,
863
626
  category: error.ErrorCategory.THIRD_PARTY
864
627
  },
@@ -866,23 +629,21 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
866
629
  );
867
630
  }
868
631
  }
869
- async saveResource({ resource }) {
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 }) {
870
638
  try {
871
- const record = {
872
- ...resource,
873
- metadata: resource.metadata ? JSON.stringify(resource.metadata) : "",
874
- createdAt: resource.createdAt.getTime(),
875
- // Store as timestamp (milliseconds)
876
- updatedAt: resource.updatedAt.getTime()
877
- // Store as timestamp (milliseconds)
878
- };
879
- const table = await this.client.openTable(storage.TABLE_RESOURCES);
639
+ const record = { ...thread, metadata: JSON.stringify(thread.metadata) };
640
+ const table = await this.client.openTable(storage.TABLE_THREADS);
880
641
  await table.add([record], { mode: "append" });
881
- return resource;
642
+ return thread;
882
643
  } catch (error$1) {
883
644
  throw new error.MastraError(
884
645
  {
885
- id: "LANCE_STORE_SAVE_RESOURCE_FAILED",
646
+ id: storage.createStorageErrorId("LANCE", "SAVE_THREAD", "FAILED"),
886
647
  domain: error.ErrorDomain.STORAGE,
887
648
  category: error.ErrorCategory.THIRD_PARTY
888
649
  },
@@ -890,44 +651,32 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
890
651
  );
891
652
  }
892
653
  }
893
- async updateResource({
894
- resourceId,
895
- workingMemory,
654
+ async updateThread({
655
+ id,
656
+ title,
896
657
  metadata
897
658
  }) {
898
- const maxRetries = 3;
659
+ const maxRetries = 5;
899
660
  for (let attempt = 0; attempt < maxRetries; attempt++) {
900
661
  try {
901
- const existingResource = await this.getResourceById({ resourceId });
902
- if (!existingResource) {
903
- const newResource = {
904
- id: resourceId,
905
- workingMemory,
906
- metadata: metadata || {},
907
- createdAt: /* @__PURE__ */ new Date(),
908
- updatedAt: /* @__PURE__ */ new Date()
909
- };
910
- return this.saveResource({ resource: newResource });
662
+ const current = await this.getThreadById({ threadId: id });
663
+ if (!current) {
664
+ throw new Error(`Thread with id ${id} not found`);
911
665
  }
912
- const updatedResource = {
913
- ...existingResource,
914
- workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
915
- metadata: {
916
- ...existingResource.metadata,
917
- ...metadata
918
- },
919
- updatedAt: /* @__PURE__ */ new Date()
920
- };
666
+ const mergedMetadata = { ...current.metadata, ...metadata };
921
667
  const record = {
922
- id: resourceId,
923
- workingMemory: updatedResource.workingMemory || "",
924
- metadata: updatedResource.metadata ? JSON.stringify(updatedResource.metadata) : "",
925
- updatedAt: updatedResource.updatedAt.getTime()
926
- // Store as timestamp (milliseconds)
668
+ id,
669
+ title,
670
+ metadata: JSON.stringify(mergedMetadata),
671
+ updatedAt: (/* @__PURE__ */ new Date()).getTime()
927
672
  };
928
- const table = await this.client.openTable(storage.TABLE_RESOURCES);
673
+ const table = await this.client.openTable(storage.TABLE_THREADS);
929
674
  await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
930
- return updatedResource;
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;
931
680
  } catch (error$1) {
932
681
  if (error$1.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
933
682
  const delay = Math.pow(2, attempt) * 10;
@@ -936,7 +685,7 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
936
685
  }
937
686
  throw new error.MastraError(
938
687
  {
939
- id: "LANCE_STORE_UPDATE_RESOURCE_FAILED",
688
+ id: storage.createStorageErrorId("LANCE", "UPDATE_THREAD", "FAILED"),
940
689
  domain: error.ErrorDomain.STORAGE,
941
690
  category: error.ErrorCategory.THIRD_PARTY
942
691
  },
@@ -944,444 +693,679 @@ var StoreMemoryLance = class extends storage.MemoryStorage {
944
693
  );
945
694
  }
946
695
  }
947
- throw new Error("Unexpected end of retry loop");
948
- }
949
- };
950
- var StoreOperationsLance = class extends storage.StoreOperations {
951
- client;
952
- constructor({ client }) {
953
- super();
954
- this.client = client;
955
- }
956
- getDefaultValue(type) {
957
- switch (type) {
958
- case "text":
959
- return "''";
960
- case "timestamp":
961
- return "CURRENT_TIMESTAMP";
962
- case "integer":
963
- case "bigint":
964
- return "0";
965
- case "jsonb":
966
- return "'{}'";
967
- case "uuid":
968
- return "''";
969
- default:
970
- return super.getDefaultValue(type);
971
- }
972
- }
973
- async hasColumn(tableName, columnName) {
974
- const table = await this.client.openTable(tableName);
975
- const schema = await table.schema();
976
- return schema.fields.some((field) => field.name === columnName);
977
- }
978
- translateSchema(schema) {
979
- const fields = Object.entries(schema).map(([name, column]) => {
980
- let arrowType;
981
- switch (column.type.toLowerCase()) {
982
- case "text":
983
- case "uuid":
984
- arrowType = new apacheArrow.Utf8();
985
- break;
986
- case "int":
987
- case "integer":
988
- arrowType = new apacheArrow.Int32();
989
- break;
990
- case "bigint":
991
- arrowType = new apacheArrow.Float64();
992
- break;
993
- case "float":
994
- arrowType = new apacheArrow.Float32();
995
- break;
996
- case "jsonb":
997
- case "json":
998
- arrowType = new apacheArrow.Utf8();
999
- break;
1000
- case "binary":
1001
- arrowType = new apacheArrow.Binary();
1002
- break;
1003
- case "timestamp":
1004
- arrowType = new apacheArrow.Float64();
1005
- break;
1006
- default:
1007
- arrowType = new apacheArrow.Utf8();
1008
- }
1009
- return new apacheArrow.Field(name, arrowType, column.nullable ?? true);
1010
- });
1011
- return new apacheArrow.Schema(fields);
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
+ );
1012
704
  }
1013
- async createTable({
1014
- tableName,
1015
- schema
1016
- }) {
705
+ async deleteThread({ threadId }) {
1017
706
  try {
1018
- if (!this.client) {
1019
- throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1020
- }
1021
- if (!tableName) {
1022
- throw new Error("tableName is required for createTable.");
1023
- }
1024
- if (!schema) {
1025
- throw new Error("schema is required for createTable.");
1026
- }
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}'`);
1027
711
  } catch (error$1) {
1028
712
  throw new error.MastraError(
1029
713
  {
1030
- id: "STORAGE_LANCE_STORAGE_CREATE_TABLE_INVALID_ARGS",
714
+ id: storage.createStorageErrorId("LANCE", "DELETE_THREAD", "FAILED"),
1031
715
  domain: error.ErrorDomain.STORAGE,
1032
- category: error.ErrorCategory.USER,
1033
- details: { tableName }
716
+ category: error.ErrorCategory.THIRD_PARTY
1034
717
  },
1035
718
  error$1
1036
719
  );
1037
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: [] };
1038
738
  try {
1039
- const arrowSchema = this.translateSchema(schema);
1040
- await this.client.createEmptyTable(tableName, arrowSchema);
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() };
1041
751
  } catch (error$1) {
1042
- if (error$1.message?.includes("already exists")) {
1043
- this.logger.debug(`Table '${tableName}' already exists, skipping create`);
1044
- return;
1045
- }
1046
752
  throw new error.MastraError(
1047
753
  {
1048
- id: "STORAGE_LANCE_STORAGE_CREATE_TABLE_FAILED",
754
+ id: storage.createStorageErrorId("LANCE", "LIST_MESSAGES_BY_ID", "FAILED"),
1049
755
  domain: error.ErrorDomain.STORAGE,
1050
756
  category: error.ErrorCategory.THIRD_PARTY,
1051
- details: { tableName }
757
+ details: {
758
+ messageIds: JSON.stringify(messageIds)
759
+ }
1052
760
  },
1053
761
  error$1
1054
762
  );
1055
763
  }
1056
764
  }
1057
- async dropTable({ tableName }) {
1058
- try {
1059
- if (!this.client) {
1060
- throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1061
- }
1062
- if (!tableName) {
1063
- throw new Error("tableName is required for dropTable.");
1064
- }
1065
- } catch (validationError) {
1066
- throw new error.MastraError(
1067
- {
1068
- id: "STORAGE_LANCE_STORAGE_DROP_TABLE_INVALID_ARGS",
1069
- domain: error.ErrorDomain.STORAGE,
1070
- category: error.ErrorCategory.USER,
1071
- text: validationError.message,
1072
- details: { tableName }
1073
- },
1074
- validationError
1075
- );
1076
- }
1077
- try {
1078
- await this.client.dropTable(tableName);
1079
- } catch (error$1) {
1080
- if (error$1.toString().includes("was not found") || error$1.message?.includes("Table not found")) {
1081
- this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
1082
- return;
1083
- }
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())) {
1084
769
  throw new error.MastraError(
1085
770
  {
1086
- id: "STORAGE_LANCE_STORAGE_DROP_TABLE_FAILED",
771
+ id: storage.createStorageErrorId("LANCE", "LIST_MESSAGES", "INVALID_THREAD_ID"),
1087
772
  domain: error.ErrorDomain.STORAGE,
1088
773
  category: error.ErrorCategory.THIRD_PARTY,
1089
- details: { tableName }
774
+ details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
1090
775
  },
1091
- error$1
776
+ new Error("threadId must be a non-empty string or array of non-empty strings")
1092
777
  );
1093
778
  }
1094
- }
1095
- async alterTable({
1096
- tableName,
1097
- schema,
1098
- ifNotExists
1099
- }) {
779
+ const perPage = storage.normalizePerPage(perPageInput, 40);
780
+ const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1100
781
  try {
1101
- if (!this.client) {
1102
- throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
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
+ );
1103
792
  }
1104
- if (!tableName) {
1105
- throw new Error("tableName is required for alterTable.");
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)}'`);
1106
799
  }
1107
- if (!schema) {
1108
- throw new Error("schema is required for alterTable.");
800
+ if (filter?.dateRange?.start) {
801
+ const startTime = filter.dateRange.start instanceof Date ? filter.dateRange.start.getTime() : new Date(filter.dateRange.start).getTime();
802
+ conditions.push(`\`createdAt\` >= ${startTime}`);
1109
803
  }
1110
- if (!ifNotExists || ifNotExists.length === 0) {
1111
- this.logger.debug("No columns specified to add in alterTable, skipping.");
1112
- return;
804
+ if (filter?.dateRange?.end) {
805
+ const endTime = filter.dateRange.end instanceof Date ? filter.dateRange.end.getTime() : new Date(filter.dateRange.end).getTime();
806
+ conditions.push(`\`createdAt\` <= ${endTime}`);
1113
807
  }
1114
- } catch (validationError) {
1115
- throw new error.MastraError(
1116
- {
1117
- id: "STORAGE_LANCE_STORAGE_ALTER_TABLE_INVALID_ARGS",
1118
- domain: error.ErrorDomain.STORAGE,
1119
- category: error.ErrorCategory.USER,
1120
- text: validationError.message,
1121
- details: { tableName }
1122
- },
1123
- validationError
1124
- );
1125
- }
1126
- try {
1127
- const table = await this.client.openTable(tableName);
1128
- const currentSchema = await table.schema();
1129
- const existingFields = new Set(currentSchema.fields.map((f) => f.name));
1130
- const typeMap = {
1131
- text: "string",
1132
- integer: "int",
1133
- bigint: "bigint",
1134
- timestamp: "timestamp",
1135
- jsonb: "string",
1136
- uuid: "string"
1137
- };
1138
- const columnsToAdd = ifNotExists.filter((col) => schema[col] && !existingFields.has(col)).map((col) => {
1139
- const colDef = schema[col];
808
+ const whereClause = conditions.join(" AND ");
809
+ const total = await table.countRows(whereClause);
810
+ const query = table.query().where(whereClause);
811
+ let allRecords = await query.toArray();
812
+ allRecords.sort((a, b) => {
813
+ const aValue = field === "createdAt" ? a.createdAt : a[field];
814
+ const bValue = field === "createdAt" ? b.createdAt : b[field];
815
+ if (aValue == null && bValue == null) return 0;
816
+ if (aValue == null) return direction === "ASC" ? -1 : 1;
817
+ if (bValue == null) return direction === "ASC" ? 1 : -1;
818
+ if (typeof aValue === "string" && typeof bValue === "string") {
819
+ return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
820
+ }
821
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
822
+ });
823
+ const paginatedRecords = allRecords.slice(offset, offset + perPage);
824
+ const messages = paginatedRecords.map((row) => this.normalizeMessage(row));
825
+ if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
1140
826
  return {
1141
- name: col,
1142
- valueSql: colDef?.nullable ? `cast(NULL as ${typeMap[colDef.type ?? "text"]})` : `cast(${this.getDefaultValue(colDef?.type ?? "text")} as ${typeMap[colDef?.type ?? "text"]})`
827
+ messages: [],
828
+ total: 0,
829
+ page,
830
+ perPage: perPageForResponse,
831
+ hasMore: false
1143
832
  };
1144
- });
1145
- if (columnsToAdd.length > 0) {
1146
- await table.addColumns(columnsToAdd);
1147
- this.logger?.info?.(`Added columns [${columnsToAdd.map((c) => c.name).join(", ")}] to table ${tableName}`);
1148
833
  }
834
+ const messageIds = new Set(messages.map((m) => m.id));
835
+ if (include && include.length > 0) {
836
+ const threadIds2 = [...new Set(include.map((item) => item.threadId || threadId))];
837
+ const allThreadMessages = [];
838
+ for (const tid of threadIds2) {
839
+ const threadQuery = table.query().where(`thread_id = '${tid}'`);
840
+ let threadRecords = await threadQuery.toArray();
841
+ allThreadMessages.push(...threadRecords);
842
+ }
843
+ allThreadMessages.sort((a, b) => a.createdAt - b.createdAt);
844
+ const contextMessages = this.processMessagesWithContext(allThreadMessages, include);
845
+ const includedMessages = contextMessages.map((row) => this.normalizeMessage(row));
846
+ for (const includeMsg of includedMessages) {
847
+ if (!messageIds.has(includeMsg.id)) {
848
+ messages.push(includeMsg);
849
+ messageIds.add(includeMsg.id);
850
+ }
851
+ }
852
+ }
853
+ const list = new agent.MessageList().add(messages, "memory");
854
+ let finalMessages = list.get.all.db();
855
+ finalMessages = finalMessages.sort((a, b) => {
856
+ const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
857
+ const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
858
+ if (aValue == null && bValue == null) return 0;
859
+ if (aValue == null) return direction === "ASC" ? -1 : 1;
860
+ if (bValue == null) return direction === "ASC" ? 1 : -1;
861
+ if (typeof aValue === "string" && typeof bValue === "string") {
862
+ return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
863
+ }
864
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
865
+ });
866
+ const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
867
+ const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
868
+ const fetchedAll = perPageInput === false || allThreadMessagesReturned;
869
+ const hasMore = !fetchedAll && offset + perPage < total;
870
+ return {
871
+ messages: finalMessages,
872
+ total,
873
+ page,
874
+ perPage: perPageForResponse,
875
+ hasMore
876
+ };
1149
877
  } catch (error$1) {
1150
- throw new error.MastraError(
878
+ const mastraError = new error.MastraError(
1151
879
  {
1152
- id: "STORAGE_LANCE_STORAGE_ALTER_TABLE_FAILED",
880
+ id: storage.createStorageErrorId("LANCE", "LIST_MESSAGES", "FAILED"),
1153
881
  domain: error.ErrorDomain.STORAGE,
1154
882
  category: error.ErrorCategory.THIRD_PARTY,
1155
- details: { tableName }
883
+ details: {
884
+ threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
885
+ resourceId: resourceId ?? ""
886
+ }
1156
887
  },
1157
888
  error$1
1158
889
  );
890
+ this.logger?.error?.(mastraError.toString());
891
+ this.logger?.trackException?.(mastraError);
892
+ return {
893
+ messages: [],
894
+ total: 0,
895
+ page,
896
+ perPage: perPageForResponse,
897
+ hasMore: false
898
+ };
1159
899
  }
1160
900
  }
1161
- async clearTable({ tableName }) {
901
+ async saveMessages(args) {
1162
902
  try {
1163
- if (!this.client) {
1164
- throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
903
+ const { messages } = args;
904
+ if (messages.length === 0) {
905
+ return { messages: [] };
1165
906
  }
1166
- if (!tableName) {
1167
- throw new Error("tableName is required for clearTable.");
907
+ const threadId = messages[0]?.threadId;
908
+ if (!threadId) {
909
+ throw new Error("Thread ID is required");
1168
910
  }
1169
- } catch (validationError) {
911
+ for (const message of messages) {
912
+ if (!message.id) {
913
+ throw new Error("Message ID is required");
914
+ }
915
+ if (!message.threadId) {
916
+ throw new Error("Thread ID is required for all messages");
917
+ }
918
+ if (message.resourceId === null || message.resourceId === void 0) {
919
+ throw new Error("Resource ID cannot be null or undefined");
920
+ }
921
+ if (!message.content) {
922
+ throw new Error("Message content is required");
923
+ }
924
+ }
925
+ const transformedMessages = messages.map((message) => {
926
+ const { threadId: threadId2, type, ...rest } = message;
927
+ return {
928
+ ...rest,
929
+ thread_id: threadId2,
930
+ type: type ?? "v2",
931
+ content: JSON.stringify(message.content)
932
+ };
933
+ });
934
+ const table = await this.client.openTable(storage.TABLE_MESSAGES);
935
+ await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
936
+ const threadsTable = await this.client.openTable(storage.TABLE_THREADS);
937
+ const currentTime = (/* @__PURE__ */ new Date()).getTime();
938
+ const updateRecord = { id: threadId, updatedAt: currentTime };
939
+ await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([updateRecord]);
940
+ const list = new agent.MessageList().add(messages, "memory");
941
+ return { messages: list.get.all.db() };
942
+ } catch (error$1) {
1170
943
  throw new error.MastraError(
1171
944
  {
1172
- id: "STORAGE_LANCE_STORAGE_CLEAR_TABLE_INVALID_ARGS",
945
+ id: storage.createStorageErrorId("LANCE", "SAVE_MESSAGES", "FAILED"),
1173
946
  domain: error.ErrorDomain.STORAGE,
1174
- category: error.ErrorCategory.USER,
1175
- text: validationError.message,
1176
- details: { tableName }
947
+ category: error.ErrorCategory.THIRD_PARTY
1177
948
  },
1178
- validationError
949
+ error$1
1179
950
  );
1180
951
  }
952
+ }
953
+ async listThreadsByResourceId(args) {
1181
954
  try {
1182
- const table = await this.client.openTable(tableName);
1183
- await table.delete("1=1");
955
+ const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
956
+ const perPage = storage.normalizePerPage(perPageInput, 100);
957
+ if (page < 0) {
958
+ throw new error.MastraError(
959
+ {
960
+ id: storage.createStorageErrorId("LANCE", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
961
+ domain: error.ErrorDomain.STORAGE,
962
+ category: error.ErrorCategory.USER,
963
+ details: { page }
964
+ },
965
+ new Error("page must be >= 0")
966
+ );
967
+ }
968
+ const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
969
+ const { field, direction } = this.parseOrderBy(orderBy);
970
+ const table = await this.client.openTable(storage.TABLE_THREADS);
971
+ const total = await table.countRows(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
972
+ const query = table.query().where(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
973
+ const records = await query.toArray();
974
+ records.sort((a, b) => {
975
+ const aValue = ["createdAt", "updatedAt"].includes(field) ? new Date(a[field]).getTime() : a[field];
976
+ const bValue = ["createdAt", "updatedAt"].includes(field) ? new Date(b[field]).getTime() : b[field];
977
+ if (aValue == null && bValue == null) return 0;
978
+ if (aValue == null) return direction === "ASC" ? -1 : 1;
979
+ if (bValue == null) return direction === "ASC" ? 1 : -1;
980
+ if (typeof aValue === "string" && typeof bValue === "string") {
981
+ return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
982
+ }
983
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
984
+ });
985
+ const paginatedRecords = records.slice(offset, offset + perPage);
986
+ const schema = await getTableSchema({ tableName: storage.TABLE_THREADS, client: this.client });
987
+ const threads = paginatedRecords.map(
988
+ (record) => processResultWithTypeConversion(record, schema)
989
+ );
990
+ return {
991
+ threads,
992
+ total,
993
+ page,
994
+ perPage: perPageForResponse,
995
+ hasMore: offset + perPage < total
996
+ };
1184
997
  } catch (error$1) {
1185
998
  throw new error.MastraError(
1186
999
  {
1187
- id: "STORAGE_LANCE_STORAGE_CLEAR_TABLE_FAILED",
1000
+ id: storage.createStorageErrorId("LANCE", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
1188
1001
  domain: error.ErrorDomain.STORAGE,
1189
- category: error.ErrorCategory.THIRD_PARTY,
1190
- details: { tableName }
1002
+ category: error.ErrorCategory.THIRD_PARTY
1191
1003
  },
1192
1004
  error$1
1193
1005
  );
1194
1006
  }
1195
1007
  }
1196
- async insert({ tableName, record }) {
1197
- try {
1198
- if (!this.client) {
1199
- throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1200
- }
1201
- if (!tableName) {
1202
- throw new Error("tableName is required for insert.");
1008
+ /**
1009
+ * Processes messages to include context messages based on withPreviousMessages and withNextMessages
1010
+ * @param records - The sorted array of records to process
1011
+ * @param include - The array of include specifications with context parameters
1012
+ * @returns The processed array with context messages included
1013
+ */
1014
+ processMessagesWithContext(records, include) {
1015
+ const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
1016
+ if (messagesWithContext.length === 0) {
1017
+ return records;
1018
+ }
1019
+ const messageIndexMap = /* @__PURE__ */ new Map();
1020
+ records.forEach((message, index) => {
1021
+ messageIndexMap.set(message.id, index);
1022
+ });
1023
+ const additionalIndices = /* @__PURE__ */ new Set();
1024
+ for (const item of messagesWithContext) {
1025
+ const messageIndex = messageIndexMap.get(item.id);
1026
+ if (messageIndex !== void 0) {
1027
+ if (item.withPreviousMessages) {
1028
+ const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
1029
+ for (let i = startIdx; i < messageIndex; i++) {
1030
+ additionalIndices.add(i);
1031
+ }
1032
+ }
1033
+ if (item.withNextMessages) {
1034
+ const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
1035
+ for (let i = messageIndex + 1; i <= endIdx; i++) {
1036
+ additionalIndices.add(i);
1037
+ }
1038
+ }
1203
1039
  }
1204
- if (!record || Object.keys(record).length === 0) {
1205
- throw new Error("record is required and cannot be empty for insert.");
1040
+ }
1041
+ if (additionalIndices.size === 0) {
1042
+ return records;
1043
+ }
1044
+ const originalMatchIds = new Set(include.map((item) => item.id));
1045
+ const allIndices = /* @__PURE__ */ new Set();
1046
+ records.forEach((record, index) => {
1047
+ if (originalMatchIds.has(record.id)) {
1048
+ allIndices.add(index);
1206
1049
  }
1207
- } catch (validationError) {
1208
- throw new error.MastraError(
1209
- {
1210
- id: "STORAGE_LANCE_STORAGE_INSERT_INVALID_ARGS",
1211
- domain: error.ErrorDomain.STORAGE,
1212
- category: error.ErrorCategory.USER,
1213
- text: validationError.message,
1214
- details: { tableName }
1215
- },
1216
- validationError
1217
- );
1050
+ });
1051
+ additionalIndices.forEach((index) => {
1052
+ allIndices.add(index);
1053
+ });
1054
+ return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
1055
+ }
1056
+ /**
1057
+ * Parse message data from LanceDB record format to MastraDBMessage format
1058
+ */
1059
+ parseMessageData(data) {
1060
+ const { thread_id, ...rest } = data;
1061
+ return {
1062
+ ...rest,
1063
+ threadId: thread_id,
1064
+ content: typeof data.content === "string" ? (() => {
1065
+ try {
1066
+ return JSON.parse(data.content);
1067
+ } catch {
1068
+ return data.content;
1069
+ }
1070
+ })() : data.content,
1071
+ createdAt: new Date(data.createdAt),
1072
+ updatedAt: new Date(data.updatedAt)
1073
+ };
1074
+ }
1075
+ async updateMessages(args) {
1076
+ const { messages } = args;
1077
+ this.logger.debug("Updating messages", { count: messages.length });
1078
+ if (!messages.length) {
1079
+ return [];
1218
1080
  }
1081
+ const updatedMessages = [];
1082
+ const affectedThreadIds = /* @__PURE__ */ new Set();
1219
1083
  try {
1220
- const table = await this.client.openTable(tableName);
1221
- const primaryId = getPrimaryKeys(tableName);
1222
- const processedRecord = { ...record };
1223
- for (const key in processedRecord) {
1224
- if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
1225
- this.logger.debug("Converting object to JSON string: ", processedRecord[key]);
1226
- processedRecord[key] = JSON.stringify(processedRecord[key]);
1084
+ for (const updateData of messages) {
1085
+ const { id, ...updates } = updateData;
1086
+ const existingMessage = await this.#db.load({ tableName: storage.TABLE_MESSAGES, keys: { id } });
1087
+ if (!existingMessage) {
1088
+ this.logger.warn("Message not found for update", { id });
1089
+ continue;
1090
+ }
1091
+ const existingMsg = this.parseMessageData(existingMessage);
1092
+ const originalThreadId = existingMsg.threadId;
1093
+ affectedThreadIds.add(originalThreadId);
1094
+ const updatePayload = {};
1095
+ if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
1096
+ if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
1097
+ if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
1098
+ if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
1099
+ updatePayload.thread_id = updates.threadId;
1100
+ affectedThreadIds.add(updates.threadId);
1101
+ }
1102
+ if (updates.content) {
1103
+ const existingContent = existingMsg.content;
1104
+ let newContent = { ...existingContent };
1105
+ if (updates.content.metadata !== void 0) {
1106
+ newContent.metadata = {
1107
+ ...existingContent.metadata || {},
1108
+ ...updates.content.metadata || {}
1109
+ };
1110
+ }
1111
+ if (updates.content.content !== void 0) {
1112
+ newContent.content = updates.content.content;
1113
+ }
1114
+ if ("parts" in updates.content && updates.content.parts !== void 0) {
1115
+ newContent.parts = updates.content.parts;
1116
+ }
1117
+ updatePayload.content = JSON.stringify(newContent);
1118
+ }
1119
+ await this.#db.insert({ tableName: storage.TABLE_MESSAGES, record: { id, ...updatePayload } });
1120
+ const updatedMessage = await this.#db.load({ tableName: storage.TABLE_MESSAGES, keys: { id } });
1121
+ if (updatedMessage) {
1122
+ updatedMessages.push(this.parseMessageData(updatedMessage));
1227
1123
  }
1228
1124
  }
1229
- console.log(await table.schema());
1230
- await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([processedRecord]);
1125
+ for (const threadId of affectedThreadIds) {
1126
+ await this.#db.insert({
1127
+ tableName: storage.TABLE_THREADS,
1128
+ record: { id: threadId, updatedAt: Date.now() }
1129
+ });
1130
+ }
1131
+ return updatedMessages;
1231
1132
  } catch (error$1) {
1232
1133
  throw new error.MastraError(
1233
1134
  {
1234
- id: "STORAGE_LANCE_STORAGE_INSERT_FAILED",
1135
+ id: storage.createStorageErrorId("LANCE", "UPDATE_MESSAGES", "FAILED"),
1235
1136
  domain: error.ErrorDomain.STORAGE,
1236
1137
  category: error.ErrorCategory.THIRD_PARTY,
1237
- details: { tableName }
1138
+ details: { count: messages.length }
1238
1139
  },
1239
1140
  error$1
1240
1141
  );
1241
1142
  }
1242
1143
  }
1243
- async batchInsert({ tableName, records }) {
1144
+ async getResourceById({ resourceId }) {
1244
1145
  try {
1245
- if (!this.client) {
1246
- throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1146
+ const resource = await this.#db.load({ tableName: storage.TABLE_RESOURCES, keys: { id: resourceId } });
1147
+ if (!resource) {
1148
+ return null;
1247
1149
  }
1248
- if (!tableName) {
1249
- throw new Error("tableName is required for batchInsert.");
1150
+ let createdAt;
1151
+ let updatedAt;
1152
+ try {
1153
+ if (resource.createdAt instanceof Date) {
1154
+ createdAt = resource.createdAt;
1155
+ } else if (typeof resource.createdAt === "string") {
1156
+ createdAt = new Date(resource.createdAt);
1157
+ } else if (typeof resource.createdAt === "number") {
1158
+ createdAt = new Date(resource.createdAt);
1159
+ } else {
1160
+ createdAt = /* @__PURE__ */ new Date();
1161
+ }
1162
+ if (isNaN(createdAt.getTime())) {
1163
+ createdAt = /* @__PURE__ */ new Date();
1164
+ }
1165
+ } catch {
1166
+ createdAt = /* @__PURE__ */ new Date();
1250
1167
  }
1251
- if (!records || records.length === 0) {
1252
- throw new Error("records array is required and cannot be empty for batchInsert.");
1168
+ try {
1169
+ if (resource.updatedAt instanceof Date) {
1170
+ updatedAt = resource.updatedAt;
1171
+ } else if (typeof resource.updatedAt === "string") {
1172
+ updatedAt = new Date(resource.updatedAt);
1173
+ } else if (typeof resource.updatedAt === "number") {
1174
+ updatedAt = new Date(resource.updatedAt);
1175
+ } else {
1176
+ updatedAt = /* @__PURE__ */ new Date();
1177
+ }
1178
+ if (isNaN(updatedAt.getTime())) {
1179
+ updatedAt = /* @__PURE__ */ new Date();
1180
+ }
1181
+ } catch {
1182
+ updatedAt = /* @__PURE__ */ new Date();
1183
+ }
1184
+ let workingMemory = resource.workingMemory;
1185
+ if (workingMemory === null || workingMemory === void 0) {
1186
+ workingMemory = void 0;
1187
+ } else if (workingMemory === "") {
1188
+ workingMemory = "";
1189
+ } else if (typeof workingMemory === "object") {
1190
+ workingMemory = JSON.stringify(workingMemory);
1191
+ }
1192
+ let metadata = resource.metadata;
1193
+ if (metadata === "" || metadata === null || metadata === void 0) {
1194
+ metadata = void 0;
1195
+ } else if (typeof metadata === "string") {
1196
+ try {
1197
+ metadata = JSON.parse(metadata);
1198
+ } catch {
1199
+ metadata = metadata;
1200
+ }
1253
1201
  }
1254
- } catch (validationError) {
1202
+ return {
1203
+ ...resource,
1204
+ createdAt,
1205
+ updatedAt,
1206
+ workingMemory,
1207
+ metadata
1208
+ };
1209
+ } catch (error$1) {
1255
1210
  throw new error.MastraError(
1256
1211
  {
1257
- id: "STORAGE_LANCE_STORAGE_BATCH_INSERT_INVALID_ARGS",
1212
+ id: storage.createStorageErrorId("LANCE", "GET_RESOURCE_BY_ID", "FAILED"),
1258
1213
  domain: error.ErrorDomain.STORAGE,
1259
- category: error.ErrorCategory.USER,
1260
- text: validationError.message,
1261
- details: { tableName }
1214
+ category: error.ErrorCategory.THIRD_PARTY
1262
1215
  },
1263
- validationError
1216
+ error$1
1264
1217
  );
1265
1218
  }
1219
+ }
1220
+ async saveResource({ resource }) {
1266
1221
  try {
1267
- const table = await this.client.openTable(tableName);
1268
- const primaryId = getPrimaryKeys(tableName);
1269
- const processedRecords = records.map((record) => {
1270
- const processedRecord = { ...record };
1271
- for (const key in processedRecord) {
1272
- if (processedRecord[key] == null) continue;
1273
- if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
1274
- processedRecord[key] = JSON.stringify(processedRecord[key]);
1275
- }
1276
- }
1277
- return processedRecord;
1278
- });
1279
- console.log(processedRecords);
1280
- await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(processedRecords);
1222
+ const record = {
1223
+ ...resource,
1224
+ metadata: resource.metadata ? JSON.stringify(resource.metadata) : "",
1225
+ createdAt: resource.createdAt.getTime(),
1226
+ // Store as timestamp (milliseconds)
1227
+ updatedAt: resource.updatedAt.getTime()
1228
+ // Store as timestamp (milliseconds)
1229
+ };
1230
+ const table = await this.client.openTable(storage.TABLE_RESOURCES);
1231
+ await table.add([record], { mode: "append" });
1232
+ return resource;
1281
1233
  } catch (error$1) {
1282
1234
  throw new error.MastraError(
1283
1235
  {
1284
- id: "STORAGE_LANCE_STORAGE_BATCH_INSERT_FAILED",
1236
+ id: storage.createStorageErrorId("LANCE", "SAVE_RESOURCE", "FAILED"),
1285
1237
  domain: error.ErrorDomain.STORAGE,
1286
- category: error.ErrorCategory.THIRD_PARTY,
1287
- details: { tableName }
1238
+ category: error.ErrorCategory.THIRD_PARTY
1288
1239
  },
1289
1240
  error$1
1290
1241
  );
1291
1242
  }
1292
1243
  }
1293
- async load({ tableName, keys }) {
1294
- try {
1295
- if (!this.client) {
1296
- throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1297
- }
1298
- if (!tableName) {
1299
- throw new Error("tableName is required for load.");
1300
- }
1301
- if (!keys || Object.keys(keys).length === 0) {
1302
- throw new Error("keys are required and cannot be empty for load.");
1244
+ async updateResource({
1245
+ resourceId,
1246
+ workingMemory,
1247
+ metadata
1248
+ }) {
1249
+ const maxRetries = 3;
1250
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
1251
+ try {
1252
+ const existingResource = await this.getResourceById({ resourceId });
1253
+ if (!existingResource) {
1254
+ const newResource = {
1255
+ id: resourceId,
1256
+ workingMemory,
1257
+ metadata: metadata || {},
1258
+ createdAt: /* @__PURE__ */ new Date(),
1259
+ updatedAt: /* @__PURE__ */ new Date()
1260
+ };
1261
+ return this.saveResource({ resource: newResource });
1262
+ }
1263
+ const updatedResource = {
1264
+ ...existingResource,
1265
+ workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
1266
+ metadata: {
1267
+ ...existingResource.metadata,
1268
+ ...metadata
1269
+ },
1270
+ updatedAt: /* @__PURE__ */ new Date()
1271
+ };
1272
+ const record = {
1273
+ id: resourceId,
1274
+ workingMemory: updatedResource.workingMemory || "",
1275
+ metadata: updatedResource.metadata ? JSON.stringify(updatedResource.metadata) : "",
1276
+ updatedAt: updatedResource.updatedAt.getTime()
1277
+ // Store as timestamp (milliseconds)
1278
+ };
1279
+ const table = await this.client.openTable(storage.TABLE_RESOURCES);
1280
+ await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
1281
+ return updatedResource;
1282
+ } catch (error$1) {
1283
+ if (error$1.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
1284
+ const delay = Math.pow(2, attempt) * 10;
1285
+ await new Promise((resolve) => setTimeout(resolve, delay));
1286
+ continue;
1287
+ }
1288
+ throw new error.MastraError(
1289
+ {
1290
+ id: storage.createStorageErrorId("LANCE", "UPDATE_RESOURCE", "FAILED"),
1291
+ domain: error.ErrorDomain.STORAGE,
1292
+ category: error.ErrorCategory.THIRD_PARTY
1293
+ },
1294
+ error$1
1295
+ );
1303
1296
  }
1304
- } catch (validationError) {
1305
- throw new error.MastraError(
1306
- {
1307
- id: "STORAGE_LANCE_STORAGE_LOAD_INVALID_ARGS",
1308
- domain: error.ErrorDomain.STORAGE,
1309
- category: error.ErrorCategory.USER,
1310
- text: validationError.message,
1311
- details: { tableName }
1312
- },
1313
- validationError
1314
- );
1315
1297
  }
1298
+ throw new Error("Unexpected end of retry loop");
1299
+ }
1300
+ };
1301
+ var StoreScoresLance = class extends storage.ScoresStorage {
1302
+ client;
1303
+ #db;
1304
+ constructor(config) {
1305
+ super();
1306
+ const client = resolveLanceConfig(config);
1307
+ this.client = client;
1308
+ this.#db = new LanceDB({ client });
1309
+ }
1310
+ async init() {
1311
+ await this.#db.createTable({ tableName: storage.TABLE_SCORERS, schema: storage.SCORERS_SCHEMA });
1312
+ await this.#db.alterTable({
1313
+ tableName: storage.TABLE_SCORERS,
1314
+ schema: storage.SCORERS_SCHEMA,
1315
+ ifNotExists: ["spanId", "requestContext"]
1316
+ });
1317
+ }
1318
+ async dangerouslyClearAll() {
1319
+ await this.#db.clearTable({ tableName: storage.TABLE_SCORERS });
1320
+ }
1321
+ async saveScore(score) {
1322
+ let validatedScore;
1316
1323
  try {
1317
- const table = await this.client.openTable(tableName);
1318
- const tableSchema = await getTableSchema({ tableName, client: this.client });
1319
- const query = table.query();
1320
- if (Object.keys(keys).length > 0) {
1321
- validateKeyTypes(keys, tableSchema);
1322
- const filterConditions = Object.entries(keys).map(([key, value]) => {
1323
- const isCamelCase = /^[a-z][a-zA-Z]*$/.test(key) && /[A-Z]/.test(key);
1324
- const quotedKey = isCamelCase ? `\`${key}\`` : key;
1325
- if (typeof value === "string") {
1326
- return `${quotedKey} = '${value}'`;
1327
- } else if (value === null) {
1328
- return `${quotedKey} IS NULL`;
1329
- } else {
1330
- return `${quotedKey} = ${value}`;
1331
- }
1332
- }).join(" AND ");
1333
- this.logger.debug("where clause generated: " + filterConditions);
1334
- query.where(filterConditions);
1335
- }
1336
- const result = await query.limit(1).toArray();
1337
- if (result.length === 0) {
1338
- this.logger.debug("No record found");
1339
- return null;
1340
- }
1341
- return processResultWithTypeConversion(result[0], tableSchema);
1324
+ validatedScore = evals.saveScorePayloadSchema.parse(score);
1342
1325
  } catch (error$1) {
1343
- if (error$1 instanceof error.MastraError) throw error$1;
1344
1326
  throw new error.MastraError(
1345
1327
  {
1346
- id: "STORAGE_LANCE_STORAGE_LOAD_FAILED",
1328
+ id: storage.createStorageErrorId("LANCE", "SAVE_SCORE", "VALIDATION_FAILED"),
1329
+ text: "Failed to save score in LanceStorage",
1347
1330
  domain: error.ErrorDomain.STORAGE,
1348
- category: error.ErrorCategory.THIRD_PARTY,
1349
- details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
1331
+ category: error.ErrorCategory.USER,
1332
+ details: {
1333
+ scorer: score.scorer?.id ?? "unknown",
1334
+ entityId: score.entityId ?? "unknown",
1335
+ entityType: score.entityType ?? "unknown",
1336
+ traceId: score.traceId ?? "",
1337
+ spanId: score.spanId ?? ""
1338
+ }
1350
1339
  },
1351
1340
  error$1
1352
1341
  );
1353
1342
  }
1354
- }
1355
- };
1356
- var StoreScoresLance = class extends storage.ScoresStorage {
1357
- client;
1358
- constructor({ client }) {
1359
- super();
1360
- this.client = client;
1361
- }
1362
- async saveScore(score) {
1343
+ const id = crypto.randomUUID();
1344
+ const now = /* @__PURE__ */ new Date();
1363
1345
  try {
1364
1346
  const table = await this.client.openTable(storage.TABLE_SCORERS);
1365
1347
  const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
1366
1348
  const allowedFields = new Set(schema.fields.map((f) => f.name));
1367
1349
  const filteredScore = {};
1368
- Object.keys(score).forEach((key) => {
1350
+ for (const key of Object.keys(validatedScore)) {
1369
1351
  if (allowedFields.has(key)) {
1370
- filteredScore[key] = score[key];
1352
+ filteredScore[key] = validatedScore[key];
1371
1353
  }
1372
- });
1354
+ }
1373
1355
  for (const key in filteredScore) {
1374
1356
  if (filteredScore[key] !== null && typeof filteredScore[key] === "object" && !(filteredScore[key] instanceof Date)) {
1375
1357
  filteredScore[key] = JSON.stringify(filteredScore[key]);
1376
1358
  }
1377
1359
  }
1378
- console.log("Saving score to LanceStorage:", filteredScore);
1360
+ filteredScore.id = id;
1361
+ filteredScore.createdAt = now;
1362
+ filteredScore.updatedAt = now;
1379
1363
  await table.add([filteredScore], { mode: "append" });
1380
- return { score };
1364
+ return { score: { ...validatedScore, id, createdAt: now, updatedAt: now } };
1381
1365
  } catch (error$1) {
1382
1366
  throw new error.MastraError(
1383
1367
  {
1384
- id: "LANCE_STORAGE_SAVE_SCORE_FAILED",
1368
+ id: storage.createStorageErrorId("LANCE", "SAVE_SCORE", "FAILED"),
1385
1369
  text: "Failed to save score in LanceStorage",
1386
1370
  domain: error.ErrorDomain.STORAGE,
1387
1371
  category: error.ErrorCategory.THIRD_PARTY,
@@ -1397,12 +1381,11 @@ var StoreScoresLance = class extends storage.ScoresStorage {
1397
1381
  const query = table.query().where(`id = '${id}'`).limit(1);
1398
1382
  const records = await query.toArray();
1399
1383
  if (records.length === 0) return null;
1400
- const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
1401
- return processResultWithTypeConversion(records[0], schema);
1384
+ return await this.transformScoreRow(records[0]);
1402
1385
  } catch (error$1) {
1403
1386
  throw new error.MastraError(
1404
1387
  {
1405
- id: "LANCE_STORAGE_GET_SCORE_BY_ID_FAILED",
1388
+ id: storage.createStorageErrorId("LANCE", "GET_SCORE_BY_ID", "FAILED"),
1406
1389
  text: "Failed to get score by id in LanceStorage",
1407
1390
  domain: error.ErrorDomain.STORAGE,
1408
1391
  category: error.ErrorCategory.THIRD_PARTY,
@@ -1412,34 +1395,76 @@ var StoreScoresLance = class extends storage.ScoresStorage {
1412
1395
  );
1413
1396
  }
1414
1397
  }
1415
- async getScoresByScorerId({
1398
+ /**
1399
+ * LanceDB-specific score row transformation.
1400
+ *
1401
+ * Note: This implementation does NOT use coreTransformScoreRow because:
1402
+ * 1. LanceDB stores schema information in the table itself (requires async fetch)
1403
+ * 2. Uses processResultWithTypeConversion utility for LanceDB-specific type handling
1404
+ */
1405
+ async transformScoreRow(row) {
1406
+ const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
1407
+ const transformed = processResultWithTypeConversion(row, schema);
1408
+ return {
1409
+ ...transformed,
1410
+ createdAt: row.createdAt,
1411
+ updatedAt: row.updatedAt
1412
+ };
1413
+ }
1414
+ async listScoresByScorerId({
1416
1415
  scorerId,
1417
- pagination
1416
+ pagination,
1417
+ entityId,
1418
+ entityType,
1419
+ source
1418
1420
  }) {
1419
1421
  try {
1422
+ const { page, perPage: perPageInput } = pagination;
1423
+ const perPage = storage.normalizePerPage(perPageInput, 100);
1424
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1420
1425
  const table = await this.client.openTable(storage.TABLE_SCORERS);
1421
- const { page = 0, perPage = 10 } = pagination || {};
1422
- const offset = page * perPage;
1423
- const query = table.query().where(`\`scorerId\` = '${scorerId}'`).limit(perPage);
1424
- if (offset > 0) query.offset(offset);
1425
- const records = await query.toArray();
1426
- const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
1427
- const scores = processResultWithTypeConversion(records, schema);
1428
- const allRecords = await table.query().where(`\`scorerId\` = '${scorerId}'`).toArray();
1426
+ let query = table.query().where(`\`scorerId\` = '${scorerId}'`);
1427
+ if (source) {
1428
+ query = query.where(`\`source\` = '${source}'`);
1429
+ }
1430
+ if (entityId) {
1431
+ query = query.where(`\`entityId\` = '${entityId}'`);
1432
+ }
1433
+ if (entityType) {
1434
+ query = query.where(`\`entityType\` = '${entityType}'`);
1435
+ }
1436
+ let totalQuery = table.query().where(`\`scorerId\` = '${scorerId}'`);
1437
+ if (source) {
1438
+ totalQuery = totalQuery.where(`\`source\` = '${source}'`);
1439
+ }
1440
+ if (entityId) {
1441
+ totalQuery = totalQuery.where(`\`entityId\` = '${entityId}'`);
1442
+ }
1443
+ if (entityType) {
1444
+ totalQuery = totalQuery.where(`\`entityType\` = '${entityType}'`);
1445
+ }
1446
+ const allRecords = await totalQuery.toArray();
1429
1447
  const total = allRecords.length;
1448
+ const end = perPageInput === false ? total : start + perPage;
1449
+ if (perPageInput !== false) {
1450
+ query = query.limit(perPage);
1451
+ if (start > 0) query = query.offset(start);
1452
+ }
1453
+ const records = await query.toArray();
1454
+ const scores = await Promise.all(records.map(async (record) => await this.transformScoreRow(record)));
1430
1455
  return {
1431
1456
  pagination: {
1432
1457
  page,
1433
- perPage,
1458
+ perPage: perPageForResponse,
1434
1459
  total,
1435
- hasMore: offset + scores.length < total
1460
+ hasMore: end < total
1436
1461
  },
1437
1462
  scores
1438
1463
  };
1439
1464
  } catch (error$1) {
1440
1465
  throw new error.MastraError(
1441
1466
  {
1442
- id: "LANCE_STORAGE_GET_SCORES_BY_SCORER_ID_FAILED",
1467
+ id: storage.createStorageErrorId("LANCE", "LIST_SCORES_BY_SCORER_ID", "FAILED"),
1443
1468
  text: "Failed to get scores by scorerId in LanceStorage",
1444
1469
  domain: error.ErrorDomain.STORAGE,
1445
1470
  category: error.ErrorCategory.THIRD_PARTY,
@@ -1449,274 +1474,135 @@ var StoreScoresLance = class extends storage.ScoresStorage {
1449
1474
  );
1450
1475
  }
1451
1476
  }
1452
- async getScoresByRunId({
1477
+ async listScoresByRunId({
1453
1478
  runId,
1454
1479
  pagination
1455
1480
  }) {
1456
1481
  try {
1482
+ const { page, perPage: perPageInput } = pagination;
1483
+ const perPage = storage.normalizePerPage(perPageInput, 100);
1484
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1457
1485
  const table = await this.client.openTable(storage.TABLE_SCORERS);
1458
- const { page = 0, perPage = 10 } = pagination || {};
1459
- const offset = page * perPage;
1460
- const query = table.query().where(`\`runId\` = '${runId}'`).limit(perPage);
1461
- if (offset > 0) query.offset(offset);
1462
- const records = await query.toArray();
1463
- const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
1464
- const scores = processResultWithTypeConversion(records, schema);
1465
1486
  const allRecords = await table.query().where(`\`runId\` = '${runId}'`).toArray();
1466
1487
  const total = allRecords.length;
1467
- return {
1468
- pagination: {
1469
- page,
1470
- perPage,
1471
- total,
1472
- hasMore: offset + scores.length < total
1473
- },
1474
- scores
1475
- };
1476
- } catch (error$1) {
1477
- throw new error.MastraError(
1478
- {
1479
- id: "LANCE_STORAGE_GET_SCORES_BY_RUN_ID_FAILED",
1480
- text: "Failed to get scores by runId in LanceStorage",
1481
- domain: error.ErrorDomain.STORAGE,
1482
- category: error.ErrorCategory.THIRD_PARTY,
1483
- details: { error: error$1?.message }
1484
- },
1485
- error$1
1486
- );
1487
- }
1488
- }
1489
- async getScoresByEntityId({
1490
- entityId,
1491
- entityType,
1492
- pagination
1493
- }) {
1494
- try {
1495
- const table = await this.client.openTable(storage.TABLE_SCORERS);
1496
- const { page = 0, perPage = 10 } = pagination || {};
1497
- const offset = page * perPage;
1498
- const query = table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).limit(perPage);
1499
- if (offset > 0) query.offset(offset);
1488
+ const end = perPageInput === false ? total : start + perPage;
1489
+ let query = table.query().where(`\`runId\` = '${runId}'`);
1490
+ if (perPageInput !== false) {
1491
+ query = query.limit(perPage);
1492
+ if (start > 0) query = query.offset(start);
1493
+ }
1500
1494
  const records = await query.toArray();
1501
- const schema = await getTableSchema({ tableName: storage.TABLE_SCORERS, client: this.client });
1502
- const scores = processResultWithTypeConversion(records, schema);
1503
- const allRecords = await table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).toArray();
1504
- const total = allRecords.length;
1495
+ const scores = await Promise.all(records.map(async (record) => await this.transformScoreRow(record)));
1505
1496
  return {
1506
1497
  pagination: {
1507
1498
  page,
1508
- perPage,
1499
+ perPage: perPageForResponse,
1509
1500
  total,
1510
- hasMore: offset + scores.length < total
1501
+ hasMore: end < total
1511
1502
  },
1512
1503
  scores
1513
- };
1514
- } catch (error$1) {
1515
- throw new error.MastraError(
1516
- {
1517
- id: "LANCE_STORAGE_GET_SCORES_BY_ENTITY_ID_FAILED",
1518
- text: "Failed to get scores by entityId and entityType in LanceStorage",
1519
- domain: error.ErrorDomain.STORAGE,
1520
- category: error.ErrorCategory.THIRD_PARTY,
1521
- details: { error: error$1?.message }
1522
- },
1523
- error$1
1524
- );
1525
- }
1526
- }
1527
- };
1528
- var StoreTracesLance = class extends storage.TracesStorage {
1529
- client;
1530
- operations;
1531
- constructor({ client, operations }) {
1532
- super();
1533
- this.client = client;
1534
- this.operations = operations;
1535
- }
1536
- async saveTrace({ trace }) {
1537
- try {
1538
- const table = await this.client.openTable(storage.TABLE_TRACES);
1539
- const record = {
1540
- ...trace,
1541
- attributes: JSON.stringify(trace.attributes),
1542
- status: JSON.stringify(trace.status),
1543
- events: JSON.stringify(trace.events),
1544
- links: JSON.stringify(trace.links),
1545
- other: JSON.stringify(trace.other)
1546
- };
1547
- await table.add([record], { mode: "append" });
1548
- return trace;
1549
- } catch (error$1) {
1550
- throw new error.MastraError(
1551
- {
1552
- id: "LANCE_STORE_SAVE_TRACE_FAILED",
1553
- domain: error.ErrorDomain.STORAGE,
1554
- category: error.ErrorCategory.THIRD_PARTY
1555
- },
1556
- error$1
1557
- );
1558
- }
1559
- }
1560
- async getTraceById({ traceId }) {
1561
- try {
1562
- const table = await this.client.openTable(storage.TABLE_TRACES);
1563
- const query = table.query().where(`id = '${traceId}'`);
1564
- const records = await query.toArray();
1565
- return records[0];
1504
+ };
1566
1505
  } catch (error$1) {
1567
1506
  throw new error.MastraError(
1568
1507
  {
1569
- id: "LANCE_STORE_GET_TRACE_BY_ID_FAILED",
1508
+ id: storage.createStorageErrorId("LANCE", "LIST_SCORES_BY_RUN_ID", "FAILED"),
1509
+ text: "Failed to get scores by runId in LanceStorage",
1570
1510
  domain: error.ErrorDomain.STORAGE,
1571
- category: error.ErrorCategory.THIRD_PARTY
1511
+ category: error.ErrorCategory.THIRD_PARTY,
1512
+ details: { error: error$1?.message }
1572
1513
  },
1573
1514
  error$1
1574
1515
  );
1575
1516
  }
1576
1517
  }
1577
- async getTraces({
1578
- name,
1579
- scope,
1580
- page = 1,
1581
- perPage = 10,
1582
- attributes
1518
+ async listScoresByEntityId({
1519
+ entityId,
1520
+ entityType,
1521
+ pagination
1583
1522
  }) {
1584
1523
  try {
1585
- const table = await this.client.openTable(storage.TABLE_TRACES);
1586
- const query = table.query();
1587
- if (name) {
1588
- query.where(`name = '${name}'`);
1589
- }
1590
- if (scope) {
1591
- query.where(`scope = '${scope}'`);
1592
- }
1593
- if (attributes) {
1594
- query.where(`attributes = '${JSON.stringify(attributes)}'`);
1595
- }
1596
- const offset = (page - 1) * perPage;
1597
- query.limit(perPage);
1598
- if (offset > 0) {
1599
- query.offset(offset);
1524
+ const { page, perPage: perPageInput } = pagination;
1525
+ const perPage = storage.normalizePerPage(perPageInput, 100);
1526
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1527
+ const table = await this.client.openTable(storage.TABLE_SCORERS);
1528
+ const allRecords = await table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).toArray();
1529
+ const total = allRecords.length;
1530
+ const end = perPageInput === false ? total : start + perPage;
1531
+ let query = table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`);
1532
+ if (perPageInput !== false) {
1533
+ query = query.limit(perPage);
1534
+ if (start > 0) query = query.offset(start);
1600
1535
  }
1601
1536
  const records = await query.toArray();
1602
- return records.map((record) => {
1603
- const processed = {
1604
- ...record,
1605
- attributes: record.attributes ? JSON.parse(record.attributes) : {},
1606
- status: record.status ? JSON.parse(record.status) : {},
1607
- events: record.events ? JSON.parse(record.events) : [],
1608
- links: record.links ? JSON.parse(record.links) : [],
1609
- other: record.other ? JSON.parse(record.other) : {},
1610
- startTime: new Date(record.startTime),
1611
- endTime: new Date(record.endTime),
1612
- createdAt: new Date(record.createdAt)
1613
- };
1614
- if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
1615
- processed.parentSpanId = "";
1616
- } else {
1617
- processed.parentSpanId = String(processed.parentSpanId);
1618
- }
1619
- return processed;
1620
- });
1537
+ const scores = await Promise.all(records.map(async (record) => await this.transformScoreRow(record)));
1538
+ return {
1539
+ pagination: {
1540
+ page,
1541
+ perPage: perPageForResponse,
1542
+ total,
1543
+ hasMore: end < total
1544
+ },
1545
+ scores
1546
+ };
1621
1547
  } catch (error$1) {
1622
1548
  throw new error.MastraError(
1623
1549
  {
1624
- id: "LANCE_STORE_GET_TRACES_FAILED",
1550
+ id: storage.createStorageErrorId("LANCE", "LIST_SCORES_BY_ENTITY_ID", "FAILED"),
1551
+ text: "Failed to get scores by entityId and entityType in LanceStorage",
1625
1552
  domain: error.ErrorDomain.STORAGE,
1626
1553
  category: error.ErrorCategory.THIRD_PARTY,
1627
- details: { name: name ?? "", scope: scope ?? "" }
1554
+ details: { error: error$1?.message }
1628
1555
  },
1629
1556
  error$1
1630
1557
  );
1631
1558
  }
1632
1559
  }
1633
- async getTracesPaginated(args) {
1560
+ async listScoresBySpan({
1561
+ traceId,
1562
+ spanId,
1563
+ pagination
1564
+ }) {
1634
1565
  try {
1635
- const table = await this.client.openTable(storage.TABLE_TRACES);
1636
- const query = table.query();
1637
- const conditions = [];
1638
- if (args.name) {
1639
- conditions.push(`name = '${args.name}'`);
1640
- }
1641
- if (args.scope) {
1642
- conditions.push(`scope = '${args.scope}'`);
1643
- }
1644
- if (args.attributes) {
1645
- const attributesStr = JSON.stringify(args.attributes);
1646
- conditions.push(`attributes LIKE '%${attributesStr.replace(/"/g, '\\"')}%'`);
1647
- }
1648
- if (args.dateRange?.start) {
1649
- conditions.push(`\`createdAt\` >= ${args.dateRange.start.getTime()}`);
1650
- }
1651
- if (args.dateRange?.end) {
1652
- conditions.push(`\`createdAt\` <= ${args.dateRange.end.getTime()}`);
1653
- }
1654
- if (conditions.length > 0) {
1655
- const whereClause = conditions.join(" AND ");
1656
- query.where(whereClause);
1657
- }
1658
- let total = 0;
1659
- if (conditions.length > 0) {
1660
- const countQuery = table.query().where(conditions.join(" AND "));
1661
- const allRecords = await countQuery.toArray();
1662
- total = allRecords.length;
1663
- } else {
1664
- total = await table.countRows();
1665
- }
1666
- const page = args.page || 0;
1667
- const perPage = args.perPage || 10;
1668
- const offset = page * perPage;
1669
- query.limit(perPage);
1670
- if (offset > 0) {
1671
- query.offset(offset);
1566
+ const { page, perPage: perPageInput } = pagination;
1567
+ const perPage = storage.normalizePerPage(perPageInput, 100);
1568
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1569
+ const table = await this.client.openTable(storage.TABLE_SCORERS);
1570
+ const allRecords = await table.query().where(`\`traceId\` = '${traceId}' AND \`spanId\` = '${spanId}'`).toArray();
1571
+ const total = allRecords.length;
1572
+ const end = perPageInput === false ? total : start + perPage;
1573
+ let query = table.query().where(`\`traceId\` = '${traceId}' AND \`spanId\` = '${spanId}'`);
1574
+ if (perPageInput !== false) {
1575
+ query = query.limit(perPage);
1576
+ if (start > 0) query = query.offset(start);
1672
1577
  }
1673
1578
  const records = await query.toArray();
1674
- const traces = records.map((record) => {
1675
- const processed = {
1676
- ...record,
1677
- attributes: record.attributes ? JSON.parse(record.attributes) : {},
1678
- status: record.status ? JSON.parse(record.status) : {},
1679
- events: record.events ? JSON.parse(record.events) : [],
1680
- links: record.links ? JSON.parse(record.links) : [],
1681
- other: record.other ? JSON.parse(record.other) : {},
1682
- startTime: new Date(record.startTime),
1683
- endTime: new Date(record.endTime),
1684
- createdAt: new Date(record.createdAt)
1685
- };
1686
- if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
1687
- processed.parentSpanId = "";
1688
- } else {
1689
- processed.parentSpanId = String(processed.parentSpanId);
1690
- }
1691
- return processed;
1692
- });
1579
+ const scores = await Promise.all(records.map(async (record) => await this.transformScoreRow(record)));
1693
1580
  return {
1694
- traces,
1695
- total,
1696
- page,
1697
- perPage,
1698
- hasMore: total > (page + 1) * perPage
1581
+ pagination: {
1582
+ page,
1583
+ perPage: perPageForResponse,
1584
+ total,
1585
+ hasMore: end < total
1586
+ },
1587
+ scores
1699
1588
  };
1700
1589
  } catch (error$1) {
1701
1590
  throw new error.MastraError(
1702
1591
  {
1703
- id: "LANCE_STORE_GET_TRACES_PAGINATED_FAILED",
1592
+ id: storage.createStorageErrorId("LANCE", "LIST_SCORES_BY_SPAN", "FAILED"),
1593
+ text: "Failed to get scores by traceId and spanId in LanceStorage",
1704
1594
  domain: error.ErrorDomain.STORAGE,
1705
1595
  category: error.ErrorCategory.THIRD_PARTY,
1706
- details: { name: args.name ?? "", scope: args.scope ?? "" }
1596
+ details: { error: error$1?.message }
1707
1597
  },
1708
1598
  error$1
1709
1599
  );
1710
1600
  }
1711
1601
  }
1712
- async batchTraceInsert({ records }) {
1713
- this.logger.debug("Batch inserting traces", { count: records.length });
1714
- await this.operations.batchInsert({
1715
- tableName: storage.TABLE_TRACES,
1716
- records
1717
- });
1718
- }
1719
1602
  };
1603
+ function escapeSql(str) {
1604
+ return str.replace(/'/g, "''");
1605
+ }
1720
1606
  function parseWorkflowRun(row) {
1721
1607
  let parsedSnapshot = row.snapshot;
1722
1608
  if (typeof parsedSnapshot === "string") {
@@ -1737,38 +1623,104 @@ function parseWorkflowRun(row) {
1737
1623
  }
1738
1624
  var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
1739
1625
  client;
1740
- constructor({ client }) {
1626
+ #db;
1627
+ constructor(config) {
1741
1628
  super();
1629
+ const client = resolveLanceConfig(config);
1742
1630
  this.client = client;
1631
+ this.#db = new LanceDB({ client });
1632
+ }
1633
+ async init() {
1634
+ const schema = storage.TABLE_SCHEMAS[storage.TABLE_WORKFLOW_SNAPSHOT];
1635
+ await this.#db.createTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT, schema });
1636
+ await this.#db.alterTable({
1637
+ tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
1638
+ schema,
1639
+ ifNotExists: ["resourceId"]
1640
+ });
1641
+ }
1642
+ async dangerouslyClearAll() {
1643
+ await this.#db.clearTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT });
1644
+ }
1645
+ async updateWorkflowResults({
1646
+ workflowName,
1647
+ runId,
1648
+ stepId,
1649
+ result,
1650
+ requestContext
1651
+ }) {
1652
+ let snapshot = await this.loadWorkflowSnapshot({ workflowName, runId });
1653
+ if (!snapshot) {
1654
+ snapshot = {
1655
+ context: {},
1656
+ activePaths: [],
1657
+ timestamp: Date.now(),
1658
+ suspendedPaths: {},
1659
+ activeStepsPath: {},
1660
+ resumeLabels: {},
1661
+ serializedStepGraph: [],
1662
+ status: "pending",
1663
+ value: {},
1664
+ waitingPaths: {},
1665
+ runId,
1666
+ requestContext: {}
1667
+ };
1668
+ }
1669
+ snapshot.context[stepId] = result;
1670
+ snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
1671
+ await this.persistWorkflowSnapshot({ workflowName, runId, snapshot });
1672
+ return snapshot.context;
1673
+ }
1674
+ async updateWorkflowState({
1675
+ workflowName,
1676
+ runId,
1677
+ opts
1678
+ }) {
1679
+ const snapshot = await this.loadWorkflowSnapshot({ workflowName, runId });
1680
+ if (!snapshot) {
1681
+ return void 0;
1682
+ }
1683
+ if (!snapshot.context) {
1684
+ throw new Error(`Snapshot not found for runId ${runId}`);
1685
+ }
1686
+ const updatedSnapshot = { ...snapshot, ...opts };
1687
+ await this.persistWorkflowSnapshot({ workflowName, runId, snapshot: updatedSnapshot });
1688
+ return updatedSnapshot;
1743
1689
  }
1744
1690
  async persistWorkflowSnapshot({
1745
1691
  workflowName,
1746
1692
  runId,
1747
- snapshot
1693
+ resourceId,
1694
+ snapshot,
1695
+ createdAt,
1696
+ updatedAt
1748
1697
  }) {
1749
1698
  try {
1750
1699
  const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
1751
- const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
1700
+ const query = table.query().where(`workflow_name = '${escapeSql(workflowName)}' AND run_id = '${escapeSql(runId)}'`);
1752
1701
  const records = await query.toArray();
1753
- let createdAt;
1754
- const now = Date.now();
1702
+ let createdAtValue;
1703
+ const now = createdAt?.getTime() ?? Date.now();
1755
1704
  if (records.length > 0) {
1756
- createdAt = records[0].createdAt ?? now;
1705
+ createdAtValue = records[0].createdAt ?? now;
1757
1706
  } else {
1758
- createdAt = now;
1707
+ createdAtValue = now;
1759
1708
  }
1709
+ const { status, value, ...rest } = snapshot;
1760
1710
  const record = {
1761
1711
  workflow_name: workflowName,
1762
1712
  run_id: runId,
1763
- snapshot: JSON.stringify(snapshot),
1764
- createdAt,
1765
- updatedAt: now
1713
+ resourceId,
1714
+ snapshot: JSON.stringify({ status, value, ...rest }),
1715
+ // this is to ensure status is always just before value, for when querying the db by status
1716
+ createdAt: createdAtValue,
1717
+ updatedAt: updatedAt ?? now
1766
1718
  };
1767
1719
  await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
1768
1720
  } catch (error$1) {
1769
1721
  throw new error.MastraError(
1770
1722
  {
1771
- id: "LANCE_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
1723
+ id: storage.createStorageErrorId("LANCE", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
1772
1724
  domain: error.ErrorDomain.STORAGE,
1773
1725
  category: error.ErrorCategory.THIRD_PARTY,
1774
1726
  details: { workflowName, runId }
@@ -1783,13 +1735,13 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
1783
1735
  }) {
1784
1736
  try {
1785
1737
  const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
1786
- const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
1738
+ const query = table.query().where(`workflow_name = '${escapeSql(workflowName)}' AND run_id = '${escapeSql(runId)}'`);
1787
1739
  const records = await query.toArray();
1788
1740
  return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
1789
1741
  } catch (error$1) {
1790
1742
  throw new error.MastraError(
1791
1743
  {
1792
- id: "LANCE_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
1744
+ id: storage.createStorageErrorId("LANCE", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
1793
1745
  domain: error.ErrorDomain.STORAGE,
1794
1746
  category: error.ErrorCategory.THIRD_PARTY,
1795
1747
  details: { workflowName, runId }
@@ -1801,9 +1753,9 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
1801
1753
  async getWorkflowRunById(args) {
1802
1754
  try {
1803
1755
  const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
1804
- let whereClause = `run_id = '${args.runId}'`;
1756
+ let whereClause = `run_id = '${escapeSql(args.runId)}'`;
1805
1757
  if (args.workflowName) {
1806
- whereClause += ` AND workflow_name = '${args.workflowName}'`;
1758
+ whereClause += ` AND workflow_name = '${escapeSql(args.workflowName)}'`;
1807
1759
  }
1808
1760
  const query = table.query().where(whereClause);
1809
1761
  const records = await query.toArray();
@@ -1813,7 +1765,7 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
1813
1765
  } catch (error$1) {
1814
1766
  throw new error.MastraError(
1815
1767
  {
1816
- id: "LANCE_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
1768
+ id: storage.createStorageErrorId("LANCE", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
1817
1769
  domain: error.ErrorDomain.STORAGE,
1818
1770
  category: error.ErrorCategory.THIRD_PARTY,
1819
1771
  details: { runId: args.runId, workflowName: args.workflowName ?? "" }
@@ -1822,16 +1774,37 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
1822
1774
  );
1823
1775
  }
1824
1776
  }
1825
- async getWorkflowRuns(args) {
1777
+ async deleteWorkflowRunById({ runId, workflowName }) {
1778
+ try {
1779
+ const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
1780
+ const whereClause = `run_id = '${escapeSql(runId)}' AND workflow_name = '${escapeSql(workflowName)}'`;
1781
+ await table.delete(whereClause);
1782
+ } catch (error$1) {
1783
+ throw new error.MastraError(
1784
+ {
1785
+ id: storage.createStorageErrorId("LANCE", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
1786
+ domain: error.ErrorDomain.STORAGE,
1787
+ category: error.ErrorCategory.THIRD_PARTY,
1788
+ details: { runId, workflowName }
1789
+ },
1790
+ error$1
1791
+ );
1792
+ }
1793
+ }
1794
+ async listWorkflowRuns(args) {
1826
1795
  try {
1827
1796
  const table = await this.client.openTable(storage.TABLE_WORKFLOW_SNAPSHOT);
1828
1797
  let query = table.query();
1829
1798
  const conditions = [];
1830
1799
  if (args?.workflowName) {
1831
- conditions.push(`workflow_name = '${args.workflowName.replace(/'/g, "''")}'`);
1800
+ conditions.push(`workflow_name = '${escapeSql(args.workflowName)}'`);
1801
+ }
1802
+ if (args?.status) {
1803
+ const escapedStatus = args.status.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/%/g, "\\%").replace(/_/g, "\\_");
1804
+ conditions.push(`\`snapshot\` LIKE '%"status":"${escapedStatus}","value"%'`);
1832
1805
  }
1833
1806
  if (args?.resourceId) {
1834
- conditions.push(`\`resourceId\` = '${args.resourceId}'`);
1807
+ conditions.push(`\`resourceId\` = '${escapeSql(args.resourceId)}'`);
1835
1808
  }
1836
1809
  if (args?.fromDate instanceof Date) {
1837
1810
  conditions.push(`\`createdAt\` >= ${args.fromDate.getTime()}`);
@@ -1846,11 +1819,22 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
1846
1819
  } else {
1847
1820
  total = await table.countRows();
1848
1821
  }
1849
- if (args?.limit) {
1850
- query.limit(args.limit);
1851
- }
1852
- if (args?.offset) {
1853
- query.offset(args.offset);
1822
+ if (args?.perPage !== void 0 && args?.page !== void 0) {
1823
+ const normalizedPerPage = storage.normalizePerPage(args.perPage, Number.MAX_SAFE_INTEGER);
1824
+ if (args.page < 0 || !Number.isInteger(args.page)) {
1825
+ throw new error.MastraError(
1826
+ {
1827
+ id: storage.createStorageErrorId("LANCE", "LIST_WORKFLOW_RUNS", "INVALID_PAGINATION"),
1828
+ domain: error.ErrorDomain.STORAGE,
1829
+ category: error.ErrorCategory.USER,
1830
+ details: { page: args.page, perPage: args.perPage }
1831
+ },
1832
+ new Error(`Invalid pagination parameters: page=${args.page}, perPage=${args.perPage}`)
1833
+ );
1834
+ }
1835
+ const offset = args.page * normalizedPerPage;
1836
+ query.limit(normalizedPerPage);
1837
+ query.offset(offset);
1854
1838
  }
1855
1839
  const records = await query.toArray();
1856
1840
  return {
@@ -1860,10 +1844,10 @@ var StoreWorkflowsLance = class extends storage.WorkflowsStorage {
1860
1844
  } catch (error$1) {
1861
1845
  throw new error.MastraError(
1862
1846
  {
1863
- id: "LANCE_STORE_GET_WORKFLOW_RUNS_FAILED",
1847
+ id: storage.createStorageErrorId("LANCE", "LIST_WORKFLOW_RUNS", "FAILED"),
1864
1848
  domain: error.ErrorDomain.STORAGE,
1865
1849
  category: error.ErrorCategory.THIRD_PARTY,
1866
- details: { namespace: args?.namespace ?? "", workflowName: args?.workflowName ?? "" }
1850
+ details: { resourceId: args?.resourceId ?? "", workflowName: args?.workflowName ?? "" }
1867
1851
  },
1868
1852
  error$1
1869
1853
  );
@@ -1877,48 +1861,52 @@ var LanceStorage = class _LanceStorage extends storage.MastraStorage {
1877
1861
  lanceClient;
1878
1862
  /**
1879
1863
  * Creates a new instance of LanceStorage
1864
+ * @param id The unique identifier for this storage instance
1865
+ * @param name The name for this storage instance
1880
1866
  * @param uri The URI to connect to LanceDB
1881
- * @param options connection options
1867
+ * @param connectionOptions connection options for LanceDB
1868
+ * @param storageOptions storage options including disableInit
1882
1869
  *
1883
1870
  * Usage:
1884
1871
  *
1885
1872
  * Connect to a local database
1886
1873
  * ```ts
1887
- * const store = await LanceStorage.create('/path/to/db');
1874
+ * const store = await LanceStorage.create('my-storage-id', 'MyStorage', '/path/to/db');
1888
1875
  * ```
1889
1876
  *
1890
1877
  * Connect to a LanceDB cloud database
1891
1878
  * ```ts
1892
- * const store = await LanceStorage.create('db://host:port');
1879
+ * const store = await LanceStorage.create('my-storage-id', 'MyStorage', 'db://host:port');
1893
1880
  * ```
1894
1881
  *
1895
1882
  * Connect to a cloud database
1896
1883
  * ```ts
1897
- * const store = await LanceStorage.create('s3://bucket/db', { storageOptions: { timeout: '60s' } });
1884
+ * const store = await LanceStorage.create('my-storage-id', 'MyStorage', 's3://bucket/db', { storageOptions: { timeout: '60s' } });
1885
+ * ```
1886
+ *
1887
+ * Disable auto-init for runtime (after CI/CD has run migrations)
1888
+ * ```ts
1889
+ * const store = await LanceStorage.create('my-storage-id', 'MyStorage', '/path/to/db', undefined, { disableInit: true });
1898
1890
  * ```
1899
1891
  */
1900
- static async create(name, uri, options) {
1901
- const instance = new _LanceStorage(name);
1892
+ static async create(id, name, uri, connectionOptions, storageOptions) {
1893
+ const instance = new _LanceStorage(id, name, storageOptions?.disableInit);
1902
1894
  try {
1903
- instance.lanceClient = await lancedb.connect(uri, options);
1904
- const operations = new StoreOperationsLance({ client: instance.lanceClient });
1895
+ instance.lanceClient = await lancedb.connect(uri, connectionOptions);
1905
1896
  instance.stores = {
1906
- operations: new StoreOperationsLance({ client: instance.lanceClient }),
1907
1897
  workflows: new StoreWorkflowsLance({ client: instance.lanceClient }),
1908
- traces: new StoreTracesLance({ client: instance.lanceClient, operations }),
1909
1898
  scores: new StoreScoresLance({ client: instance.lanceClient }),
1910
- memory: new StoreMemoryLance({ client: instance.lanceClient, operations }),
1911
- legacyEvals: new StoreLegacyEvalsLance({ client: instance.lanceClient })
1899
+ memory: new StoreMemoryLance({ client: instance.lanceClient })
1912
1900
  };
1913
1901
  return instance;
1914
1902
  } catch (e) {
1915
1903
  throw new error.MastraError(
1916
1904
  {
1917
- id: "STORAGE_LANCE_STORAGE_CONNECT_FAILED",
1905
+ id: storage.createStorageErrorId("LANCE", "CONNECT", "FAILED"),
1918
1906
  domain: error.ErrorDomain.STORAGE,
1919
1907
  category: error.ErrorCategory.THIRD_PARTY,
1920
1908
  text: `Failed to connect to LanceDB: ${e.message || e}`,
1921
- details: { uri, optionsProvided: !!options }
1909
+ details: { uri, optionsProvided: !!connectionOptions }
1922
1910
  },
1923
1911
  e
1924
1912
  );
@@ -1926,54 +1914,16 @@ var LanceStorage = class _LanceStorage extends storage.MastraStorage {
1926
1914
  }
1927
1915
  /**
1928
1916
  * @internal
1929
- * Private constructor to enforce using the create factory method
1917
+ * Private constructor to enforce using the create factory method.
1918
+ * Note: stores is initialized in create() after the lanceClient is connected.
1930
1919
  */
1931
- constructor(name) {
1932
- super({ name });
1933
- const operations = new StoreOperationsLance({ client: this.lanceClient });
1934
- this.stores = {
1935
- operations: new StoreOperationsLance({ client: this.lanceClient }),
1936
- workflows: new StoreWorkflowsLance({ client: this.lanceClient }),
1937
- traces: new StoreTracesLance({ client: this.lanceClient, operations }),
1938
- scores: new StoreScoresLance({ client: this.lanceClient }),
1939
- legacyEvals: new StoreLegacyEvalsLance({ client: this.lanceClient }),
1940
- memory: new StoreMemoryLance({ client: this.lanceClient, operations })
1941
- };
1942
- }
1943
- async createTable({
1944
- tableName,
1945
- schema
1946
- }) {
1947
- return this.stores.operations.createTable({ tableName, schema });
1948
- }
1949
- async dropTable({ tableName }) {
1950
- return this.stores.operations.dropTable({ tableName });
1951
- }
1952
- async alterTable({
1953
- tableName,
1954
- schema,
1955
- ifNotExists
1956
- }) {
1957
- return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
1958
- }
1959
- async clearTable({ tableName }) {
1960
- return this.stores.operations.clearTable({ tableName });
1961
- }
1962
- async insert({ tableName, record }) {
1963
- return this.stores.operations.insert({ tableName, record });
1964
- }
1965
- async batchInsert({ tableName, records }) {
1966
- return this.stores.operations.batchInsert({ tableName, records });
1967
- }
1968
- async load({ tableName, keys }) {
1969
- return this.stores.operations.load({ tableName, keys });
1920
+ constructor(id, name, disableInit) {
1921
+ super({ id, name, disableInit });
1922
+ this.stores = {};
1970
1923
  }
1971
1924
  async getThreadById({ threadId }) {
1972
1925
  return this.stores.memory.getThreadById({ threadId });
1973
1926
  }
1974
- async getThreadsByResourceId({ resourceId }) {
1975
- return this.stores.memory.getThreadsByResourceId({ resourceId });
1976
- }
1977
1927
  /**
1978
1928
  * Saves a thread to the database. This function doesn't overwrite existing threads.
1979
1929
  * @param thread - The thread to save
@@ -1992,13 +1942,17 @@ var LanceStorage = class _LanceStorage extends storage.MastraStorage {
1992
1942
  async deleteThread({ threadId }) {
1993
1943
  return this.stores.memory.deleteThread({ threadId });
1994
1944
  }
1945
+ async deleteMessages(messageIds) {
1946
+ return this.stores.memory.deleteMessages(messageIds);
1947
+ }
1995
1948
  get supports() {
1996
1949
  return {
1997
1950
  selectByIncludeResourceScope: true,
1998
1951
  resourceWorkingMemory: true,
1999
1952
  hasColumn: true,
2000
1953
  createTable: true,
2001
- deleteMessages: false
1954
+ deleteMessages: true,
1955
+ listScoresBySpan: true
2002
1956
  };
2003
1957
  }
2004
1958
  async getResourceById({ resourceId }) {
@@ -2062,54 +2016,47 @@ var LanceStorage = class _LanceStorage extends storage.MastraStorage {
2062
2016
  });
2063
2017
  return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
2064
2018
  }
2065
- async getMessages({
2066
- threadId,
2067
- resourceId,
2068
- selectBy,
2069
- format,
2070
- threadConfig
2071
- }) {
2072
- return this.stores.memory.getMessages({ threadId, resourceId, selectBy, format, threadConfig });
2019
+ async listMessagesById({ messageIds }) {
2020
+ return this.stores.memory.listMessagesById({ messageIds });
2073
2021
  }
2074
2022
  async saveMessages(args) {
2075
2023
  return this.stores.memory.saveMessages(args);
2076
2024
  }
2077
- async getThreadsByResourceIdPaginated(args) {
2078
- return this.stores.memory.getThreadsByResourceIdPaginated(args);
2079
- }
2080
- async getMessagesPaginated(args) {
2081
- return this.stores.memory.getMessagesPaginated(args);
2082
- }
2083
2025
  async updateMessages(_args) {
2084
2026
  return this.stores.memory.updateMessages(_args);
2085
2027
  }
2086
- async getTraceById(args) {
2087
- return this.stores.traces.getTraceById(args);
2028
+ async listWorkflowRuns(args) {
2029
+ return this.stores.workflows.listWorkflowRuns(args);
2088
2030
  }
2089
- async getTraces(args) {
2090
- return this.stores.traces.getTraces(args);
2091
- }
2092
- async getTracesPaginated(args) {
2093
- return this.stores.traces.getTracesPaginated(args);
2094
- }
2095
- async getEvalsByAgentName(agentName, type) {
2096
- return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
2031
+ async getWorkflowRunById(args) {
2032
+ return this.stores.workflows.getWorkflowRunById(args);
2097
2033
  }
2098
- async getEvals(options) {
2099
- return this.stores.legacyEvals.getEvals(options);
2034
+ async deleteWorkflowRunById({ runId, workflowName }) {
2035
+ return this.stores.workflows.deleteWorkflowRunById({ runId, workflowName });
2100
2036
  }
2101
- async getWorkflowRuns(args) {
2102
- return this.stores.workflows.getWorkflowRuns(args);
2037
+ async updateWorkflowResults({
2038
+ workflowName,
2039
+ runId,
2040
+ stepId,
2041
+ result,
2042
+ requestContext
2043
+ }) {
2044
+ return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
2103
2045
  }
2104
- async getWorkflowRunById(args) {
2105
- return this.stores.workflows.getWorkflowRunById(args);
2046
+ async updateWorkflowState({
2047
+ workflowName,
2048
+ runId,
2049
+ opts
2050
+ }) {
2051
+ return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
2106
2052
  }
2107
2053
  async persistWorkflowSnapshot({
2108
2054
  workflowName,
2109
2055
  runId,
2056
+ resourceId,
2110
2057
  snapshot
2111
2058
  }) {
2112
- return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
2059
+ return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
2113
2060
  }
2114
2061
  async loadWorkflowSnapshot({
2115
2062
  workflowName,
@@ -2120,27 +2067,37 @@ var LanceStorage = class _LanceStorage extends storage.MastraStorage {
2120
2067
  async getScoreById({ id: _id }) {
2121
2068
  return this.stores.scores.getScoreById({ id: _id });
2122
2069
  }
2123
- async getScoresByScorerId({
2070
+ async listScoresByScorerId({
2124
2071
  scorerId,
2072
+ source,
2073
+ entityId,
2074
+ entityType,
2125
2075
  pagination
2126
2076
  }) {
2127
- return this.stores.scores.getScoresByScorerId({ scorerId, pagination });
2077
+ return this.stores.scores.listScoresByScorerId({ scorerId, source, pagination, entityId, entityType });
2128
2078
  }
2129
- async saveScore(_score) {
2130
- return this.stores.scores.saveScore(_score);
2079
+ async saveScore(score) {
2080
+ return this.stores.scores.saveScore(score);
2131
2081
  }
2132
- async getScoresByRunId({
2082
+ async listScoresByRunId({
2133
2083
  runId,
2134
2084
  pagination
2135
2085
  }) {
2136
- return this.stores.scores.getScoresByRunId({ runId, pagination });
2086
+ return this.stores.scores.listScoresByRunId({ runId, pagination });
2137
2087
  }
2138
- async getScoresByEntityId({
2088
+ async listScoresByEntityId({
2139
2089
  entityId,
2140
2090
  entityType,
2141
2091
  pagination
2142
2092
  }) {
2143
- return this.stores.scores.getScoresByEntityId({ entityId, entityType, pagination });
2093
+ return this.stores.scores.listScoresByEntityId({ entityId, entityType, pagination });
2094
+ }
2095
+ async listScoresBySpan({
2096
+ traceId,
2097
+ spanId,
2098
+ pagination
2099
+ }) {
2100
+ return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
2144
2101
  }
2145
2102
  };
2146
2103
  var LanceFilterTranslator = class extends filter.BaseFilterTranslator {
@@ -2489,14 +2446,14 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2489
2446
  * ```
2490
2447
  */
2491
2448
  static async create(uri, options) {
2492
- const instance = new _LanceVectorStore();
2449
+ const instance = new _LanceVectorStore(options?.id || crypto.randomUUID());
2493
2450
  try {
2494
2451
  instance.lanceClient = await lancedb.connect(uri, options);
2495
2452
  return instance;
2496
2453
  } catch (e) {
2497
2454
  throw new error.MastraError(
2498
2455
  {
2499
- id: "STORAGE_LANCE_VECTOR_CONNECT_FAILED",
2456
+ id: storage.createVectorErrorId("LANCE", "CONNECT", "FAILED"),
2500
2457
  domain: error.ErrorDomain.STORAGE,
2501
2458
  category: error.ErrorCategory.THIRD_PARTY,
2502
2459
  details: { uri }
@@ -2509,8 +2466,8 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2509
2466
  * @internal
2510
2467
  * Private constructor to enforce using the create factory method
2511
2468
  */
2512
- constructor() {
2513
- super();
2469
+ constructor(id) {
2470
+ super({ id });
2514
2471
  }
2515
2472
  close() {
2516
2473
  if (this.lanceClient) {
@@ -2539,7 +2496,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2539
2496
  } catch (error$1) {
2540
2497
  throw new error.MastraError(
2541
2498
  {
2542
- id: "STORAGE_LANCE_VECTOR_QUERY_FAILED_INVALID_ARGS",
2499
+ id: storage.createVectorErrorId("LANCE", "QUERY", "INVALID_ARGS"),
2543
2500
  domain: error.ErrorDomain.STORAGE,
2544
2501
  category: error.ErrorCategory.USER,
2545
2502
  text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
@@ -2587,7 +2544,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2587
2544
  } catch (error$1) {
2588
2545
  throw new error.MastraError(
2589
2546
  {
2590
- id: "STORAGE_LANCE_VECTOR_QUERY_FAILED",
2547
+ id: storage.createVectorErrorId("LANCE", "QUERY", "FAILED"),
2591
2548
  domain: error.ErrorDomain.STORAGE,
2592
2549
  category: error.ErrorCategory.THIRD_PARTY,
2593
2550
  details: { tableName, includeVector, columnsCount: columns?.length, includeAllColumns }
@@ -2639,7 +2596,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2639
2596
  } catch (error$1) {
2640
2597
  throw new error.MastraError(
2641
2598
  {
2642
- id: "STORAGE_LANCE_VECTOR_UPSERT_FAILED_INVALID_ARGS",
2599
+ id: storage.createVectorErrorId("LANCE", "UPSERT", "INVALID_ARGS"),
2643
2600
  domain: error.ErrorDomain.STORAGE,
2644
2601
  category: error.ErrorCategory.USER,
2645
2602
  text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
@@ -2675,7 +2632,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2675
2632
  } catch (error$1) {
2676
2633
  throw new error.MastraError(
2677
2634
  {
2678
- id: "STORAGE_LANCE_VECTOR_UPSERT_FAILED",
2635
+ id: storage.createVectorErrorId("LANCE", "UPSERT", "FAILED"),
2679
2636
  domain: error.ErrorDomain.STORAGE,
2680
2637
  category: error.ErrorCategory.THIRD_PARTY,
2681
2638
  details: { tableName, vectorCount: vectors.length, metadataCount: metadata.length, idsCount: ids.length }
@@ -2702,7 +2659,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2702
2659
  async createTable(tableName, data, options) {
2703
2660
  if (!this.lanceClient) {
2704
2661
  throw new error.MastraError({
2705
- id: "STORAGE_LANCE_VECTOR_CREATE_TABLE_FAILED_INVALID_ARGS",
2662
+ id: storage.createVectorErrorId("LANCE", "CREATE_TABLE", "INVALID_ARGS"),
2706
2663
  domain: error.ErrorDomain.STORAGE,
2707
2664
  category: error.ErrorCategory.USER,
2708
2665
  text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
@@ -2717,7 +2674,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2717
2674
  } catch (error$1) {
2718
2675
  throw new error.MastraError(
2719
2676
  {
2720
- id: "STORAGE_LANCE_VECTOR_CREATE_TABLE_FAILED",
2677
+ id: storage.createVectorErrorId("LANCE", "CREATE_TABLE", "FAILED"),
2721
2678
  domain: error.ErrorDomain.STORAGE,
2722
2679
  category: error.ErrorCategory.THIRD_PARTY,
2723
2680
  details: { tableName }
@@ -2729,7 +2686,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2729
2686
  async listTables() {
2730
2687
  if (!this.lanceClient) {
2731
2688
  throw new error.MastraError({
2732
- id: "STORAGE_LANCE_VECTOR_LIST_TABLES_FAILED_INVALID_ARGS",
2689
+ id: storage.createVectorErrorId("LANCE", "LIST_TABLES", "INVALID_ARGS"),
2733
2690
  domain: error.ErrorDomain.STORAGE,
2734
2691
  category: error.ErrorCategory.USER,
2735
2692
  text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
@@ -2741,7 +2698,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2741
2698
  } catch (error$1) {
2742
2699
  throw new error.MastraError(
2743
2700
  {
2744
- id: "STORAGE_LANCE_VECTOR_LIST_TABLES_FAILED",
2701
+ id: storage.createVectorErrorId("LANCE", "LIST_TABLES", "FAILED"),
2745
2702
  domain: error.ErrorDomain.STORAGE,
2746
2703
  category: error.ErrorCategory.THIRD_PARTY
2747
2704
  },
@@ -2752,7 +2709,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2752
2709
  async getTableSchema(tableName) {
2753
2710
  if (!this.lanceClient) {
2754
2711
  throw new error.MastraError({
2755
- id: "STORAGE_LANCE_VECTOR_GET_TABLE_SCHEMA_FAILED_INVALID_ARGS",
2712
+ id: storage.createVectorErrorId("LANCE", "GET_TABLE_SCHEMA", "INVALID_ARGS"),
2756
2713
  domain: error.ErrorDomain.STORAGE,
2757
2714
  category: error.ErrorCategory.USER,
2758
2715
  text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
@@ -2765,7 +2722,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2765
2722
  } catch (error$1) {
2766
2723
  throw new error.MastraError(
2767
2724
  {
2768
- id: "STORAGE_LANCE_VECTOR_GET_TABLE_SCHEMA_FAILED",
2725
+ id: storage.createVectorErrorId("LANCE", "GET_TABLE_SCHEMA", "FAILED"),
2769
2726
  domain: error.ErrorDomain.STORAGE,
2770
2727
  category: error.ErrorCategory.THIRD_PARTY,
2771
2728
  details: { tableName }
@@ -2800,7 +2757,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2800
2757
  } catch (err) {
2801
2758
  throw new error.MastraError(
2802
2759
  {
2803
- id: "STORAGE_LANCE_VECTOR_CREATE_INDEX_FAILED_INVALID_ARGS",
2760
+ id: storage.createVectorErrorId("LANCE", "CREATE_INDEX", "INVALID_ARGS"),
2804
2761
  domain: error.ErrorDomain.STORAGE,
2805
2762
  category: error.ErrorCategory.USER,
2806
2763
  details: { tableName: tableName || "", indexName, dimension, metric }
@@ -2845,7 +2802,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2845
2802
  } catch (error$1) {
2846
2803
  throw new error.MastraError(
2847
2804
  {
2848
- id: "STORAGE_LANCE_VECTOR_CREATE_INDEX_FAILED",
2805
+ id: storage.createVectorErrorId("LANCE", "CREATE_INDEX", "FAILED"),
2849
2806
  domain: error.ErrorDomain.STORAGE,
2850
2807
  category: error.ErrorCategory.THIRD_PARTY,
2851
2808
  details: { tableName: tableName || "", indexName, dimension }
@@ -2857,7 +2814,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2857
2814
  async listIndexes() {
2858
2815
  if (!this.lanceClient) {
2859
2816
  throw new error.MastraError({
2860
- id: "STORAGE_LANCE_VECTOR_LIST_INDEXES_FAILED_INVALID_ARGS",
2817
+ id: storage.createVectorErrorId("LANCE", "LIST_INDEXES", "INVALID_ARGS"),
2861
2818
  domain: error.ErrorDomain.STORAGE,
2862
2819
  category: error.ErrorCategory.USER,
2863
2820
  text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
@@ -2876,7 +2833,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2876
2833
  } catch (error$1) {
2877
2834
  throw new error.MastraError(
2878
2835
  {
2879
- id: "STORAGE_LANCE_VECTOR_LIST_INDEXES_FAILED",
2836
+ id: storage.createVectorErrorId("LANCE", "LIST_INDEXES", "FAILED"),
2880
2837
  domain: error.ErrorDomain.STORAGE,
2881
2838
  category: error.ErrorCategory.THIRD_PARTY
2882
2839
  },
@@ -2895,7 +2852,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2895
2852
  } catch (err) {
2896
2853
  throw new error.MastraError(
2897
2854
  {
2898
- id: "STORAGE_LANCE_VECTOR_DESCRIBE_INDEX_FAILED_INVALID_ARGS",
2855
+ id: storage.createVectorErrorId("LANCE", "DESCRIBE_INDEX", "INVALID_ARGS"),
2899
2856
  domain: error.ErrorDomain.STORAGE,
2900
2857
  category: error.ErrorCategory.USER,
2901
2858
  details: { indexName }
@@ -2930,7 +2887,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2930
2887
  } catch (error$1) {
2931
2888
  throw new error.MastraError(
2932
2889
  {
2933
- id: "STORAGE_LANCE_VECTOR_DESCRIBE_INDEX_FAILED",
2890
+ id: storage.createVectorErrorId("LANCE", "DESCRIBE_INDEX", "FAILED"),
2934
2891
  domain: error.ErrorDomain.STORAGE,
2935
2892
  category: error.ErrorCategory.THIRD_PARTY,
2936
2893
  details: { indexName }
@@ -2950,7 +2907,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2950
2907
  } catch (err) {
2951
2908
  throw new error.MastraError(
2952
2909
  {
2953
- id: "STORAGE_LANCE_VECTOR_DELETE_INDEX_FAILED_INVALID_ARGS",
2910
+ id: storage.createVectorErrorId("LANCE", "DELETE_INDEX", "INVALID_ARGS"),
2954
2911
  domain: error.ErrorDomain.STORAGE,
2955
2912
  category: error.ErrorCategory.USER,
2956
2913
  details: { indexName }
@@ -2973,7 +2930,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2973
2930
  } catch (error$1) {
2974
2931
  throw new error.MastraError(
2975
2932
  {
2976
- id: "STORAGE_LANCE_VECTOR_DELETE_INDEX_FAILED",
2933
+ id: storage.createVectorErrorId("LANCE", "DELETE_INDEX", "FAILED"),
2977
2934
  domain: error.ErrorDomain.STORAGE,
2978
2935
  category: error.ErrorCategory.THIRD_PARTY,
2979
2936
  details: { indexName }
@@ -2988,7 +2945,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
2988
2945
  async deleteAllTables() {
2989
2946
  if (!this.lanceClient) {
2990
2947
  throw new error.MastraError({
2991
- id: "STORAGE_LANCE_VECTOR_DELETE_ALL_TABLES_FAILED_INVALID_ARGS",
2948
+ id: storage.createVectorErrorId("LANCE", "DELETE_ALL_TABLES", "INVALID_ARGS"),
2992
2949
  domain: error.ErrorDomain.STORAGE,
2993
2950
  category: error.ErrorCategory.USER,
2994
2951
  details: { methodName: "deleteAllTables" },
@@ -3000,7 +2957,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
3000
2957
  } catch (error$1) {
3001
2958
  throw new error.MastraError(
3002
2959
  {
3003
- id: "STORAGE_LANCE_VECTOR_DELETE_ALL_TABLES_FAILED",
2960
+ id: storage.createVectorErrorId("LANCE", "DELETE_ALL_TABLES", "FAILED"),
3004
2961
  domain: error.ErrorDomain.STORAGE,
3005
2962
  category: error.ErrorCategory.THIRD_PARTY,
3006
2963
  details: { methodName: "deleteAllTables" }
@@ -3012,7 +2969,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
3012
2969
  async deleteTable(tableName) {
3013
2970
  if (!this.lanceClient) {
3014
2971
  throw new error.MastraError({
3015
- id: "STORAGE_LANCE_VECTOR_DELETE_TABLE_FAILED_INVALID_ARGS",
2972
+ id: storage.createVectorErrorId("LANCE", "DELETE_TABLE", "INVALID_ARGS"),
3016
2973
  domain: error.ErrorDomain.STORAGE,
3017
2974
  category: error.ErrorCategory.USER,
3018
2975
  details: { tableName },
@@ -3024,7 +2981,7 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
3024
2981
  } catch (error$1) {
3025
2982
  throw new error.MastraError(
3026
2983
  {
3027
- id: "STORAGE_LANCE_VECTOR_DELETE_TABLE_FAILED",
2984
+ id: storage.createVectorErrorId("LANCE", "DELETE_TABLE", "FAILED"),
3028
2985
  domain: error.ErrorDomain.STORAGE,
3029
2986
  category: error.ErrorCategory.THIRD_PARTY,
3030
2987
  details: { tableName }
@@ -3033,7 +2990,44 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
3033
2990
  );
3034
2991
  }
3035
2992
  }
3036
- async updateVector({ indexName, id, update }) {
2993
+ async updateVector(params) {
2994
+ const { indexName, update } = params;
2995
+ if ("id" in params && "filter" in params && params.id && params.filter) {
2996
+ throw new error.MastraError({
2997
+ id: storage.createVectorErrorId("LANCE", "UPDATE_VECTOR", "MUTUALLY_EXCLUSIVE"),
2998
+ domain: error.ErrorDomain.STORAGE,
2999
+ category: error.ErrorCategory.USER,
3000
+ text: "id and filter are mutually exclusive",
3001
+ details: { indexName }
3002
+ });
3003
+ }
3004
+ if (!("id" in params || "filter" in params) || !params.id && !params.filter) {
3005
+ throw new error.MastraError({
3006
+ id: storage.createVectorErrorId("LANCE", "UPDATE_VECTOR", "NO_TARGET"),
3007
+ domain: error.ErrorDomain.STORAGE,
3008
+ category: error.ErrorCategory.USER,
3009
+ text: "Either id or filter must be provided",
3010
+ details: { indexName }
3011
+ });
3012
+ }
3013
+ if ("filter" in params && params.filter && Object.keys(params.filter).length === 0) {
3014
+ throw new error.MastraError({
3015
+ id: storage.createVectorErrorId("LANCE", "UPDATE_VECTOR", "EMPTY_FILTER"),
3016
+ domain: error.ErrorDomain.STORAGE,
3017
+ category: error.ErrorCategory.USER,
3018
+ text: "Cannot update with empty filter",
3019
+ details: { indexName }
3020
+ });
3021
+ }
3022
+ if (!update.vector && !update.metadata) {
3023
+ throw new error.MastraError({
3024
+ id: storage.createVectorErrorId("LANCE", "UPDATE_VECTOR", "NO_PAYLOAD"),
3025
+ domain: error.ErrorDomain.STORAGE,
3026
+ category: error.ErrorCategory.USER,
3027
+ text: "No updates provided",
3028
+ details: { indexName }
3029
+ });
3030
+ }
3037
3031
  try {
3038
3032
  if (!this.lanceClient) {
3039
3033
  throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
@@ -3041,21 +3035,6 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
3041
3035
  if (!indexName) {
3042
3036
  throw new Error("indexName is required");
3043
3037
  }
3044
- if (!id) {
3045
- throw new Error("id is required");
3046
- }
3047
- } catch (err) {
3048
- throw new error.MastraError(
3049
- {
3050
- id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED_INVALID_ARGS",
3051
- domain: error.ErrorDomain.STORAGE,
3052
- category: error.ErrorCategory.USER,
3053
- details: { indexName, id }
3054
- },
3055
- err
3056
- );
3057
- }
3058
- try {
3059
3038
  const tables = await this.lanceClient.tableNames();
3060
3039
  for (const tableName of tables) {
3061
3040
  this.logger.debug("Checking table:" + tableName);
@@ -3065,39 +3044,66 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
3065
3044
  const hasColumn = schema.fields.some((field) => field.name === indexName);
3066
3045
  if (hasColumn) {
3067
3046
  this.logger.debug(`Found column ${indexName} in table ${tableName}`);
3068
- const existingRecord = await table.query().where(`id = '${id}'`).select(schema.fields.map((field) => field.name)).limit(1).toArray();
3069
- if (existingRecord.length === 0) {
3070
- throw new Error(`Record with id '${id}' not found in table ${tableName}`);
3047
+ let whereClause;
3048
+ if ("id" in params && params.id) {
3049
+ whereClause = `id = '${params.id}'`;
3050
+ } else if ("filter" in params && params.filter) {
3051
+ const translator = new LanceFilterTranslator();
3052
+ const processFilterKeys = (filter) => {
3053
+ const processedFilter = {};
3054
+ Object.entries(filter).forEach(([key, value]) => {
3055
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3056
+ Object.entries(value).forEach(([nestedKey, nestedValue]) => {
3057
+ processedFilter[`metadata_${key}_${nestedKey}`] = nestedValue;
3058
+ });
3059
+ } else {
3060
+ processedFilter[`metadata_${key}`] = value;
3061
+ }
3062
+ });
3063
+ return processedFilter;
3064
+ };
3065
+ const prefixedFilter = processFilterKeys(params.filter);
3066
+ whereClause = translator.translate(prefixedFilter) || "";
3067
+ if (!whereClause) {
3068
+ throw new Error("Failed to translate filter to SQL");
3069
+ }
3070
+ } else {
3071
+ throw new Error("Either id or filter must be provided");
3071
3072
  }
3072
- const rowData = {
3073
- id
3074
- };
3075
- Object.entries(existingRecord[0]).forEach(([key, value]) => {
3076
- if (key !== "id" && key !== "_distance") {
3077
- if (key === indexName) {
3078
- if (!update.vector) {
3079
- if (Array.isArray(value)) {
3080
- rowData[key] = [...value];
3081
- } else if (typeof value === "object" && value !== null) {
3082
- rowData[key] = Array.from(value);
3073
+ const existingRecords = await table.query().where(whereClause).select(schema.fields.map((field) => field.name)).toArray();
3074
+ if (existingRecords.length === 0) {
3075
+ this.logger.info(`No records found matching criteria in table ${tableName}`);
3076
+ return;
3077
+ }
3078
+ const updatedRecords = existingRecords.map((record) => {
3079
+ const rowData = {};
3080
+ Object.entries(record).forEach(([key, value]) => {
3081
+ if (key !== "_distance") {
3082
+ if (key === indexName) {
3083
+ if (update.vector) {
3084
+ rowData[key] = update.vector;
3083
3085
  } else {
3084
- rowData[key] = value;
3086
+ if (Array.isArray(value)) {
3087
+ rowData[key] = [...value];
3088
+ } else if (typeof value === "object" && value !== null) {
3089
+ rowData[key] = Array.from(value);
3090
+ } else {
3091
+ rowData[key] = value;
3092
+ }
3085
3093
  }
3094
+ } else {
3095
+ rowData[key] = value;
3086
3096
  }
3087
- } else {
3088
- rowData[key] = value;
3089
3097
  }
3098
+ });
3099
+ if (update.metadata) {
3100
+ Object.entries(update.metadata).forEach(([key, value]) => {
3101
+ rowData[`metadata_${key}`] = value;
3102
+ });
3090
3103
  }
3104
+ return rowData;
3091
3105
  });
3092
- if (update.vector) {
3093
- rowData[indexName] = update.vector;
3094
- }
3095
- if (update.metadata) {
3096
- Object.entries(update.metadata).forEach(([key, value]) => {
3097
- rowData[`metadata_${key}`] = value;
3098
- });
3099
- }
3100
- await table.add([rowData], { mode: "overwrite" });
3106
+ await table.add(updatedRecords, { mode: "overwrite" });
3101
3107
  return;
3102
3108
  }
3103
3109
  } catch (err) {
@@ -3107,12 +3113,19 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
3107
3113
  }
3108
3114
  throw new Error(`No table found with column/index '${indexName}'`);
3109
3115
  } catch (error$1) {
3116
+ if (error$1 instanceof error.MastraError) throw error$1;
3110
3117
  throw new error.MastraError(
3111
3118
  {
3112
- id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED",
3119
+ id: storage.createVectorErrorId("LANCE", "UPDATE_VECTOR", "FAILED"),
3113
3120
  domain: error.ErrorDomain.STORAGE,
3114
3121
  category: error.ErrorCategory.THIRD_PARTY,
3115
- details: { indexName, id, hasVector: !!update.vector, hasMetadata: !!update.metadata }
3122
+ details: {
3123
+ indexName,
3124
+ ..."id" in params && params.id && { id: params.id },
3125
+ ..."filter" in params && params.filter && { filter: JSON.stringify(params.filter) },
3126
+ hasVector: !!update.vector,
3127
+ hasMetadata: !!update.metadata
3128
+ }
3116
3129
  },
3117
3130
  error$1
3118
3131
  );
@@ -3132,10 +3145,13 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
3132
3145
  } catch (err) {
3133
3146
  throw new error.MastraError(
3134
3147
  {
3135
- id: "STORAGE_LANCE_VECTOR_DELETE_VECTOR_FAILED_INVALID_ARGS",
3148
+ id: storage.createVectorErrorId("LANCE", "DELETE_VECTOR", "INVALID_ARGS"),
3136
3149
  domain: error.ErrorDomain.STORAGE,
3137
3150
  category: error.ErrorCategory.USER,
3138
- details: { indexName, id }
3151
+ details: {
3152
+ indexName,
3153
+ ...id && { id }
3154
+ }
3139
3155
  },
3140
3156
  err
3141
3157
  );
@@ -3162,10 +3178,13 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
3162
3178
  } catch (error$1) {
3163
3179
  throw new error.MastraError(
3164
3180
  {
3165
- id: "STORAGE_LANCE_VECTOR_DELETE_VECTOR_FAILED",
3181
+ id: storage.createVectorErrorId("LANCE", "DELETE_VECTOR", "FAILED"),
3166
3182
  domain: error.ErrorDomain.STORAGE,
3167
3183
  category: error.ErrorCategory.THIRD_PARTY,
3168
- details: { indexName, id }
3184
+ details: {
3185
+ indexName,
3186
+ ...id && { id }
3187
+ }
3169
3188
  },
3170
3189
  error$1
3171
3190
  );
@@ -3196,6 +3215,109 @@ var LanceVectorStore = class _LanceVectorStore extends vector.MastraVector {
3196
3215
  });
3197
3216
  return result;
3198
3217
  }
3218
+ async deleteVectors({ indexName, filter, ids }) {
3219
+ if (ids && filter) {
3220
+ throw new error.MastraError({
3221
+ id: storage.createVectorErrorId("LANCE", "DELETE_VECTORS", "MUTUALLY_EXCLUSIVE"),
3222
+ domain: error.ErrorDomain.STORAGE,
3223
+ category: error.ErrorCategory.USER,
3224
+ text: "ids and filter are mutually exclusive",
3225
+ details: { indexName }
3226
+ });
3227
+ }
3228
+ if (!ids && !filter) {
3229
+ throw new error.MastraError({
3230
+ id: storage.createVectorErrorId("LANCE", "DELETE_VECTORS", "NO_TARGET"),
3231
+ domain: error.ErrorDomain.STORAGE,
3232
+ category: error.ErrorCategory.USER,
3233
+ text: "Either filter or ids must be provided",
3234
+ details: { indexName }
3235
+ });
3236
+ }
3237
+ if (ids && ids.length === 0) {
3238
+ throw new error.MastraError({
3239
+ id: storage.createVectorErrorId("LANCE", "DELETE_VECTORS", "EMPTY_IDS"),
3240
+ domain: error.ErrorDomain.STORAGE,
3241
+ category: error.ErrorCategory.USER,
3242
+ text: "Cannot delete with empty ids array",
3243
+ details: { indexName }
3244
+ });
3245
+ }
3246
+ if (filter && Object.keys(filter).length === 0) {
3247
+ throw new error.MastraError({
3248
+ id: storage.createVectorErrorId("LANCE", "DELETE_VECTORS", "EMPTY_FILTER"),
3249
+ domain: error.ErrorDomain.STORAGE,
3250
+ category: error.ErrorCategory.USER,
3251
+ text: "Cannot delete with empty filter",
3252
+ details: { indexName }
3253
+ });
3254
+ }
3255
+ try {
3256
+ if (!this.lanceClient) {
3257
+ throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
3258
+ }
3259
+ if (!indexName) {
3260
+ throw new Error("indexName is required");
3261
+ }
3262
+ const tables = await this.lanceClient.tableNames();
3263
+ for (const tableName of tables) {
3264
+ this.logger.debug("Checking table:" + tableName);
3265
+ const table = await this.lanceClient.openTable(tableName);
3266
+ try {
3267
+ const schema = await table.schema();
3268
+ const hasColumn = schema.fields.some((field) => field.name === indexName);
3269
+ if (hasColumn) {
3270
+ this.logger.debug(`Found column ${indexName} in table ${tableName}`);
3271
+ if (ids) {
3272
+ const idsConditions = ids.map((id) => `id = '${id}'`).join(" OR ");
3273
+ await table.delete(idsConditions);
3274
+ } else if (filter) {
3275
+ const translator = new LanceFilterTranslator();
3276
+ const processFilterKeys = (filter2) => {
3277
+ const processedFilter = {};
3278
+ Object.entries(filter2).forEach(([key, value]) => {
3279
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3280
+ Object.entries(value).forEach(([nestedKey, nestedValue]) => {
3281
+ processedFilter[`metadata_${key}_${nestedKey}`] = nestedValue;
3282
+ });
3283
+ } else {
3284
+ processedFilter[`metadata_${key}`] = value;
3285
+ }
3286
+ });
3287
+ return processedFilter;
3288
+ };
3289
+ const prefixedFilter = processFilterKeys(filter);
3290
+ const whereClause = translator.translate(prefixedFilter);
3291
+ if (!whereClause) {
3292
+ throw new Error("Failed to translate filter to SQL");
3293
+ }
3294
+ await table.delete(whereClause);
3295
+ }
3296
+ return;
3297
+ }
3298
+ } catch (err) {
3299
+ this.logger.error(`Error checking schema for table ${tableName}:` + err);
3300
+ continue;
3301
+ }
3302
+ }
3303
+ throw new Error(`No table found with column/index '${indexName}'`);
3304
+ } catch (error$1) {
3305
+ if (error$1 instanceof error.MastraError) throw error$1;
3306
+ throw new error.MastraError(
3307
+ {
3308
+ id: storage.createVectorErrorId("LANCE", "DELETE_VECTORS", "FAILED"),
3309
+ domain: error.ErrorDomain.STORAGE,
3310
+ category: error.ErrorCategory.THIRD_PARTY,
3311
+ details: {
3312
+ indexName,
3313
+ ...filter && { filter: JSON.stringify(filter) },
3314
+ ...ids && { idsCount: ids.length }
3315
+ }
3316
+ },
3317
+ error$1
3318
+ );
3319
+ }
3320
+ }
3199
3321
  };
3200
3322
 
3201
3323
  exports.LanceStorage = LanceStorage;