@mastra/lance 0.0.0-fix-generate-title-20250616171351 → 0.0.0-fix-fetch-workflow-runs-20250624231457

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.
@@ -1,6 +1,8 @@
1
1
  import { connect } from '@lancedb/lancedb';
2
2
  import type { Connection, ConnectionOptions, SchemaLike, FieldLike } from '@lancedb/lancedb';
3
+ import type { MastraMessageContentV2 } from '@mastra/core/agent';
3
4
  import { MessageList } from '@mastra/core/agent';
5
+ import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
4
6
  import type { MastraMessageV1, MastraMessageV2, StorageThreadType, TraceType } from '@mastra/core/memory';
5
7
  import {
6
8
  MastraStorage,
@@ -56,10 +58,30 @@ export class LanceStorage extends MastraStorage {
56
58
  instance.lanceClient = await connect(uri, options);
57
59
  return instance;
58
60
  } catch (e: any) {
59
- throw new Error(`Failed to connect to LanceDB: ${e}`);
61
+ throw new MastraError(
62
+ {
63
+ id: 'STORAGE_LANCE_STORAGE_CONNECT_FAILED',
64
+ domain: ErrorDomain.STORAGE,
65
+ category: ErrorCategory.THIRD_PARTY,
66
+ text: `Failed to connect to LanceDB: ${e.message || e}`,
67
+ details: { uri, optionsProvided: !!options },
68
+ },
69
+ e,
70
+ );
60
71
  }
61
72
  }
62
73
 
74
+ private getPrimaryKeys(tableName: TABLE_NAMES): string[] {
75
+ let primaryId: string[] = ['id'];
76
+ if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
77
+ primaryId = ['workflow_name', 'run_id'];
78
+ } else if (tableName === TABLE_EVALS) {
79
+ primaryId = ['agent_name', 'metric_name', 'run_id'];
80
+ }
81
+
82
+ return primaryId;
83
+ }
84
+
63
85
  /**
64
86
  * @internal
65
87
  * Private constructor to enforce using the create factory method
@@ -75,11 +97,41 @@ export class LanceStorage extends MastraStorage {
75
97
  tableName: TABLE_NAMES;
76
98
  schema: Record<string, StorageColumn>;
77
99
  }): Promise<void> {
100
+ try {
101
+ if (!this.lanceClient) {
102
+ throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
103
+ }
104
+ if (!tableName) {
105
+ throw new Error('tableName is required for createTable.');
106
+ }
107
+ if (!schema) {
108
+ throw new Error('schema is required for createTable.');
109
+ }
110
+ } catch (error) {
111
+ throw new MastraError(
112
+ {
113
+ id: 'STORAGE_LANCE_STORAGE_CREATE_TABLE_INVALID_ARGS',
114
+ domain: ErrorDomain.STORAGE,
115
+ category: ErrorCategory.USER,
116
+ details: { tableName },
117
+ },
118
+ error,
119
+ );
120
+ }
121
+
78
122
  try {
79
123
  const arrowSchema = this.translateSchema(schema);
80
124
  await this.lanceClient.createEmptyTable(tableName, arrowSchema);
81
125
  } catch (error: any) {
82
- throw new Error(`Failed to create table: ${error}`);
126
+ throw new MastraError(
127
+ {
128
+ id: 'STORAGE_LANCE_STORAGE_CREATE_TABLE_FAILED',
129
+ domain: ErrorDomain.STORAGE,
130
+ category: ErrorCategory.THIRD_PARTY,
131
+ details: { tableName },
132
+ },
133
+ error,
134
+ );
83
135
  }
84
136
  }
85
137
 
@@ -129,15 +181,42 @@ export class LanceStorage extends MastraStorage {
129
181
  * @param tableName Name of the table to drop
130
182
  */
131
183
  async dropTable(tableName: TABLE_NAMES): Promise<void> {
184
+ try {
185
+ if (!this.lanceClient) {
186
+ throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
187
+ }
188
+ if (!tableName) {
189
+ throw new Error('tableName is required for dropTable.');
190
+ }
191
+ } catch (validationError: any) {
192
+ throw new MastraError(
193
+ {
194
+ id: 'STORAGE_LANCE_STORAGE_DROP_TABLE_INVALID_ARGS',
195
+ domain: ErrorDomain.STORAGE,
196
+ category: ErrorCategory.USER,
197
+ text: validationError.message,
198
+ details: { tableName },
199
+ },
200
+ validationError,
201
+ );
202
+ }
203
+
132
204
  try {
133
205
  await this.lanceClient.dropTable(tableName);
134
206
  } catch (error: any) {
135
- // Don't throw if the table doesn't exist
136
- if (error.toString().includes('was not found')) {
207
+ if (error.toString().includes('was not found') || error.message?.includes('Table not found')) {
137
208
  this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
138
209
  return;
139
210
  }
140
- throw new Error(`Failed to drop table: ${error}`);
211
+ throw new MastraError(
212
+ {
213
+ id: 'STORAGE_LANCE_STORAGE_DROP_TABLE_FAILED',
214
+ domain: ErrorDomain.STORAGE,
215
+ category: ErrorCategory.THIRD_PARTY,
216
+ details: { tableName },
217
+ },
218
+ error,
219
+ );
141
220
  }
142
221
  }
143
222
 
@@ -147,6 +226,26 @@ export class LanceStorage extends MastraStorage {
147
226
  * @returns Table schema
148
227
  */
149
228
  async getTableSchema(tableName: TABLE_NAMES): Promise<SchemaLike> {
229
+ try {
230
+ if (!this.lanceClient) {
231
+ throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
232
+ }
233
+ if (!tableName) {
234
+ throw new Error('tableName is required for getTableSchema.');
235
+ }
236
+ } catch (validationError: any) {
237
+ throw new MastraError(
238
+ {
239
+ id: 'STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_INVALID_ARGS',
240
+ domain: ErrorDomain.STORAGE,
241
+ category: ErrorCategory.USER,
242
+ text: validationError.message,
243
+ details: { tableName },
244
+ },
245
+ validationError,
246
+ );
247
+ }
248
+
150
249
  try {
151
250
  const table = await this.lanceClient.openTable(tableName);
152
251
  const rawSchema = await table.schema();
@@ -161,7 +260,15 @@ export class LanceStorage extends MastraStorage {
161
260
  },
162
261
  };
163
262
  } catch (error: any) {
164
- throw new Error(`Failed to get table schema: ${error}`);
263
+ throw new MastraError(
264
+ {
265
+ id: 'STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_FAILED',
266
+ domain: ErrorDomain.STORAGE,
267
+ category: ErrorCategory.THIRD_PARTY,
268
+ details: { tableName },
269
+ },
270
+ error,
271
+ );
165
272
  }
166
273
  }
167
274
 
@@ -198,43 +305,114 @@ export class LanceStorage extends MastraStorage {
198
305
  schema: Record<string, StorageColumn>;
199
306
  ifNotExists: string[];
200
307
  }): Promise<void> {
201
- const table = await this.lanceClient.openTable(tableName);
202
- const currentSchema = await table.schema();
203
- const existingFields = new Set(currentSchema.fields.map((f: any) => f.name));
204
-
205
- const typeMap: Record<string, string> = {
206
- text: 'string',
207
- integer: 'int',
208
- bigint: 'bigint',
209
- timestamp: 'timestamp',
210
- jsonb: 'string',
211
- uuid: 'string',
212
- };
308
+ try {
309
+ if (!this.lanceClient) {
310
+ throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
311
+ }
312
+ if (!tableName) {
313
+ throw new Error('tableName is required for alterTable.');
314
+ }
315
+ if (!schema) {
316
+ throw new Error('schema is required for alterTable.');
317
+ }
318
+ if (!ifNotExists || ifNotExists.length === 0) {
319
+ this.logger.debug('No columns specified to add in alterTable, skipping.');
320
+ return;
321
+ }
322
+ } catch (validationError: any) {
323
+ throw new MastraError(
324
+ {
325
+ id: 'STORAGE_LANCE_STORAGE_ALTER_TABLE_INVALID_ARGS',
326
+ domain: ErrorDomain.STORAGE,
327
+ category: ErrorCategory.USER,
328
+ text: validationError.message,
329
+ details: { tableName },
330
+ },
331
+ validationError,
332
+ );
333
+ }
213
334
 
214
- // Find columns to add
215
- const columnsToAdd = ifNotExists
216
- .filter(col => schema[col] && !existingFields.has(col))
217
- .map(col => {
218
- const colDef = schema[col];
219
- return {
220
- name: col,
221
- valueSql: colDef?.nullable
222
- ? `cast(NULL as ${typeMap[colDef.type ?? 'text']})`
223
- : `cast(${this.getDefaultValue(colDef?.type ?? 'text')} as ${typeMap[colDef?.type ?? 'text']})`,
224
- };
225
- });
335
+ try {
336
+ const table = await this.lanceClient.openTable(tableName);
337
+ const currentSchema = await table.schema();
338
+ const existingFields = new Set(currentSchema.fields.map((f: any) => f.name));
339
+
340
+ const typeMap: Record<string, string> = {
341
+ text: 'string',
342
+ integer: 'int',
343
+ bigint: 'bigint',
344
+ timestamp: 'timestamp',
345
+ jsonb: 'string',
346
+ uuid: 'string',
347
+ };
226
348
 
227
- if (columnsToAdd.length > 0) {
228
- await table.addColumns(columnsToAdd);
229
- this.logger?.info?.(`Added columns [${columnsToAdd.map(c => c.name).join(', ')}] to table ${tableName}`);
349
+ // Find columns to add
350
+ const columnsToAdd = ifNotExists
351
+ .filter(col => schema[col] && !existingFields.has(col))
352
+ .map(col => {
353
+ const colDef = schema[col];
354
+ return {
355
+ name: col,
356
+ valueSql: colDef?.nullable
357
+ ? `cast(NULL as ${typeMap[colDef.type ?? 'text']})`
358
+ : `cast(${this.getDefaultValue(colDef?.type ?? 'text')} as ${typeMap[colDef?.type ?? 'text']})`,
359
+ };
360
+ });
361
+
362
+ if (columnsToAdd.length > 0) {
363
+ await table.addColumns(columnsToAdd);
364
+ this.logger?.info?.(`Added columns [${columnsToAdd.map(c => c.name).join(', ')}] to table ${tableName}`);
365
+ }
366
+ } catch (error: any) {
367
+ throw new MastraError(
368
+ {
369
+ id: 'STORAGE_LANCE_STORAGE_ALTER_TABLE_FAILED',
370
+ domain: ErrorDomain.STORAGE,
371
+ category: ErrorCategory.THIRD_PARTY,
372
+ details: { tableName },
373
+ },
374
+ error,
375
+ );
230
376
  }
231
377
  }
232
378
 
233
379
  async clearTable({ tableName }: { tableName: TABLE_NAMES }): Promise<void> {
234
- const table = await this.lanceClient.openTable(tableName);
380
+ try {
381
+ if (!this.lanceClient) {
382
+ throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
383
+ }
384
+ if (!tableName) {
385
+ throw new Error('tableName is required for clearTable.');
386
+ }
387
+ } catch (validationError: any) {
388
+ throw new MastraError(
389
+ {
390
+ id: 'STORAGE_LANCE_STORAGE_CLEAR_TABLE_INVALID_ARGS',
391
+ domain: ErrorDomain.STORAGE,
392
+ category: ErrorCategory.USER,
393
+ text: validationError.message,
394
+ details: { tableName },
395
+ },
396
+ validationError,
397
+ );
398
+ }
399
+
400
+ try {
401
+ const table = await this.lanceClient.openTable(tableName);
235
402
 
236
- // delete function always takes a predicate as an argument, so we use '1=1' to delete all records because it is always true.
237
- await table.delete('1=1');
403
+ // delete function always takes a predicate as an argument, so we use '1=1' to delete all records because it is always true.
404
+ await table.delete('1=1');
405
+ } catch (error: any) {
406
+ throw new MastraError(
407
+ {
408
+ id: 'STORAGE_LANCE_STORAGE_CLEAR_TABLE_FAILED',
409
+ domain: ErrorDomain.STORAGE,
410
+ category: ErrorCategory.THIRD_PARTY,
411
+ details: { tableName },
412
+ },
413
+ error,
414
+ );
415
+ }
238
416
  }
239
417
 
240
418
  /**
@@ -243,9 +421,34 @@ export class LanceStorage extends MastraStorage {
243
421
  * @param record The record to insert.
244
422
  */
245
423
  async insert({ tableName, record }: { tableName: string; record: Record<string, any> }): Promise<void> {
424
+ try {
425
+ if (!this.lanceClient) {
426
+ throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
427
+ }
428
+ if (!tableName) {
429
+ throw new Error('tableName is required for insert.');
430
+ }
431
+ if (!record || Object.keys(record).length === 0) {
432
+ throw new Error('record is required and cannot be empty for insert.');
433
+ }
434
+ } catch (validationError: any) {
435
+ throw new MastraError(
436
+ {
437
+ id: 'STORAGE_LANCE_STORAGE_INSERT_INVALID_ARGS',
438
+ domain: ErrorDomain.STORAGE,
439
+ category: ErrorCategory.USER,
440
+ text: validationError.message,
441
+ details: { tableName },
442
+ },
443
+ validationError,
444
+ );
445
+ }
446
+
246
447
  try {
247
448
  const table = await this.lanceClient.openTable(tableName);
248
449
 
450
+ const primaryId = this.getPrimaryKeys(tableName as TABLE_NAMES);
451
+
249
452
  const processedRecord = { ...record };
250
453
 
251
454
  for (const key in processedRecord) {
@@ -259,9 +462,17 @@ export class LanceStorage extends MastraStorage {
259
462
  }
260
463
  }
261
464
 
262
- await table.add([processedRecord], { mode: 'overwrite' });
465
+ await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([processedRecord]);
263
466
  } catch (error: any) {
264
- throw new Error(`Failed to insert record: ${error}`);
467
+ throw new MastraError(
468
+ {
469
+ id: 'STORAGE_LANCE_STORAGE_INSERT_FAILED',
470
+ domain: ErrorDomain.STORAGE,
471
+ category: ErrorCategory.THIRD_PARTY,
472
+ details: { tableName },
473
+ },
474
+ error,
475
+ );
265
476
  }
266
477
  }
267
478
 
@@ -271,9 +482,34 @@ export class LanceStorage extends MastraStorage {
271
482
  * @param records The records to insert.
272
483
  */
273
484
  async batchInsert({ tableName, records }: { tableName: string; records: Record<string, any>[] }): Promise<void> {
485
+ try {
486
+ if (!this.lanceClient) {
487
+ throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
488
+ }
489
+ if (!tableName) {
490
+ throw new Error('tableName is required for batchInsert.');
491
+ }
492
+ if (!records || records.length === 0) {
493
+ throw new Error('records array is required and cannot be empty for batchInsert.');
494
+ }
495
+ } catch (validationError: any) {
496
+ throw new MastraError(
497
+ {
498
+ id: 'STORAGE_LANCE_STORAGE_BATCH_INSERT_INVALID_ARGS',
499
+ domain: ErrorDomain.STORAGE,
500
+ category: ErrorCategory.USER,
501
+ text: validationError.message,
502
+ details: { tableName },
503
+ },
504
+ validationError,
505
+ );
506
+ }
507
+
274
508
  try {
275
509
  const table = await this.lanceClient.openTable(tableName);
276
510
 
511
+ const primaryId = this.getPrimaryKeys(tableName as TABLE_NAMES);
512
+
277
513
  const processedRecords = records.map(record => {
278
514
  const processedRecord = { ...record };
279
515
 
@@ -294,9 +530,17 @@ export class LanceStorage extends MastraStorage {
294
530
  return processedRecord;
295
531
  });
296
532
 
297
- await table.add(processedRecords, { mode: 'overwrite' });
533
+ await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(processedRecords);
298
534
  } catch (error: any) {
299
- throw new Error(`Failed to batch insert records: ${error}`);
535
+ throw new MastraError(
536
+ {
537
+ id: 'STORAGE_LANCE_STORAGE_BATCH_INSERT_FAILED',
538
+ domain: ErrorDomain.STORAGE,
539
+ category: ErrorCategory.THIRD_PARTY,
540
+ details: { tableName },
541
+ },
542
+ error,
543
+ );
300
544
  }
301
545
  }
302
546
 
@@ -308,6 +552,29 @@ export class LanceStorage extends MastraStorage {
308
552
  * @returns The loaded record with proper type conversions, or null if not found
309
553
  */
310
554
  async load({ tableName, keys }: { tableName: TABLE_NAMES; keys: Record<string, any> }): Promise<any> {
555
+ try {
556
+ if (!this.lanceClient) {
557
+ throw new Error('LanceDB client not initialized. Call LanceStorage.create() first.');
558
+ }
559
+ if (!tableName) {
560
+ throw new Error('tableName is required for load.');
561
+ }
562
+ if (!keys || Object.keys(keys).length === 0) {
563
+ throw new Error('keys are required and cannot be empty for load.');
564
+ }
565
+ } catch (validationError: any) {
566
+ throw new MastraError(
567
+ {
568
+ id: 'STORAGE_LANCE_STORAGE_LOAD_INVALID_ARGS',
569
+ domain: ErrorDomain.STORAGE,
570
+ category: ErrorCategory.USER,
571
+ text: validationError.message,
572
+ details: { tableName },
573
+ },
574
+ validationError,
575
+ );
576
+ }
577
+
311
578
  try {
312
579
  const table = await this.lanceClient.openTable(tableName);
313
580
  const tableSchema = await this.getTableSchema(tableName);
@@ -350,7 +617,17 @@ export class LanceStorage extends MastraStorage {
350
617
  // Process the result with type conversions
351
618
  return this.processResultWithTypeConversion(result[0], tableSchema);
352
619
  } catch (error: any) {
353
- throw new Error(`Failed to load record: ${error}`);
620
+ // If it's already a MastraError (e.g. from validateKeyTypes if we change it later), rethrow
621
+ if (error instanceof MastraError) throw error;
622
+ throw new MastraError(
623
+ {
624
+ id: 'STORAGE_LANCE_STORAGE_LOAD_FAILED',
625
+ domain: ErrorDomain.STORAGE,
626
+ category: ErrorCategory.THIRD_PARTY,
627
+ details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? '' },
628
+ },
629
+ error,
630
+ );
354
631
  }
355
632
  }
356
633
 
@@ -456,7 +733,14 @@ export class LanceStorage extends MastraStorage {
456
733
  try {
457
734
  return this.load({ tableName: TABLE_THREADS, keys: { id: threadId } });
458
735
  } catch (error: any) {
459
- throw new Error(`Failed to get thread by ID: ${error}`);
736
+ throw new MastraError(
737
+ {
738
+ id: 'LANCE_STORE_GET_THREAD_BY_ID_FAILED',
739
+ domain: ErrorDomain.STORAGE,
740
+ category: ErrorCategory.THIRD_PARTY,
741
+ },
742
+ error,
743
+ );
460
744
  }
461
745
  }
462
746
 
@@ -472,7 +756,14 @@ export class LanceStorage extends MastraStorage {
472
756
  await this.getTableSchema(TABLE_THREADS),
473
757
  ) as StorageThreadType[];
474
758
  } catch (error: any) {
475
- throw new Error(`Failed to get threads by resource ID: ${error}`);
759
+ throw new MastraError(
760
+ {
761
+ id: 'LANCE_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED',
762
+ domain: ErrorDomain.STORAGE,
763
+ category: ErrorCategory.THIRD_PARTY,
764
+ },
765
+ error,
766
+ );
476
767
  }
477
768
  }
478
769
 
@@ -489,7 +780,14 @@ export class LanceStorage extends MastraStorage {
489
780
 
490
781
  return thread;
491
782
  } catch (error: any) {
492
- throw new Error(`Failed to save thread: ${error}`);
783
+ throw new MastraError(
784
+ {
785
+ id: 'LANCE_STORE_SAVE_THREAD_FAILED',
786
+ domain: ErrorDomain.STORAGE,
787
+ category: ErrorCategory.THIRD_PARTY,
788
+ },
789
+ error,
790
+ );
493
791
  }
494
792
  }
495
793
 
@@ -505,7 +803,7 @@ export class LanceStorage extends MastraStorage {
505
803
  try {
506
804
  const record = { id, title, metadata: JSON.stringify(metadata) };
507
805
  const table = await this.lanceClient.openTable(TABLE_THREADS);
508
- await table.add([record], { mode: 'overwrite' });
806
+ await table.mergeInsert('id').whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
509
807
 
510
808
  const query = table.query().where(`id = '${id}'`);
511
809
 
@@ -515,7 +813,14 @@ export class LanceStorage extends MastraStorage {
515
813
  await this.getTableSchema(TABLE_THREADS),
516
814
  ) as StorageThreadType;
517
815
  } catch (error: any) {
518
- throw new Error(`Failed to update thread: ${error}`);
816
+ throw new MastraError(
817
+ {
818
+ id: 'LANCE_STORE_UPDATE_THREAD_FAILED',
819
+ domain: ErrorDomain.STORAGE,
820
+ category: ErrorCategory.THIRD_PARTY,
821
+ },
822
+ error,
823
+ );
519
824
  }
520
825
  }
521
826
 
@@ -524,7 +829,14 @@ export class LanceStorage extends MastraStorage {
524
829
  const table = await this.lanceClient.openTable(TABLE_THREADS);
525
830
  await table.delete(`id = '${threadId}'`);
526
831
  } catch (error: any) {
527
- throw new Error(`Failed to delete thread: ${error}`);
832
+ throw new MastraError(
833
+ {
834
+ id: 'LANCE_STORE_DELETE_THREAD_FAILED',
835
+ domain: ErrorDomain.STORAGE,
836
+ category: ErrorCategory.THIRD_PARTY,
837
+ },
838
+ error,
839
+ );
528
840
  }
529
841
  }
530
842
 
@@ -617,7 +929,7 @@ export class LanceStorage extends MastraStorage {
617
929
  if (threadConfig) {
618
930
  throw new Error('ThreadConfig is not supported by LanceDB storage');
619
931
  }
620
-
932
+ const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: Number.MAX_SAFE_INTEGER });
621
933
  const table = await this.lanceClient.openTable(TABLE_MESSAGES);
622
934
  let query = table.query().where(`\`threadId\` = '${threadId}'`);
623
935
 
@@ -652,8 +964,8 @@ export class LanceStorage extends MastraStorage {
652
964
  }
653
965
 
654
966
  // If we're fetching the last N messages, take only the last N after sorting
655
- if (selectBy?.last !== undefined && selectBy.last !== false) {
656
- records = records.slice(-selectBy.last);
967
+ if (limit !== Number.MAX_SAFE_INTEGER) {
968
+ records = records.slice(-limit);
657
969
  }
658
970
 
659
971
  const messages = this.processResultWithTypeConversion(records, await this.getTableSchema(TABLE_MESSAGES));
@@ -674,7 +986,14 @@ export class LanceStorage extends MastraStorage {
674
986
  if (format === 'v2') return list.get.all.v2();
675
987
  return list.get.all.v1();
676
988
  } catch (error: any) {
677
- throw new Error(`Failed to get messages: ${error}`);
989
+ throw new MastraError(
990
+ {
991
+ id: 'LANCE_STORE_GET_MESSAGES_FAILED',
992
+ domain: ErrorDomain.STORAGE,
993
+ category: ErrorCategory.THIRD_PARTY,
994
+ },
995
+ error,
996
+ );
678
997
  }
679
998
  }
680
999
 
@@ -701,12 +1020,20 @@ export class LanceStorage extends MastraStorage {
701
1020
  }));
702
1021
 
703
1022
  const table = await this.lanceClient.openTable(TABLE_MESSAGES);
704
- await table.add(transformedMessages, { mode: 'overwrite' });
1023
+ await table.mergeInsert('id').whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
1024
+
705
1025
  const list = new MessageList().add(messages, 'memory');
706
1026
  if (format === `v2`) return list.get.all.v2();
707
1027
  return list.get.all.v1();
708
1028
  } catch (error: any) {
709
- throw new Error(`Failed to save messages: ${error}`);
1029
+ throw new MastraError(
1030
+ {
1031
+ id: 'LANCE_STORE_SAVE_MESSAGES_FAILED',
1032
+ domain: ErrorDomain.STORAGE,
1033
+ category: ErrorCategory.THIRD_PARTY,
1034
+ },
1035
+ error,
1036
+ );
710
1037
  }
711
1038
  }
712
1039
 
@@ -725,7 +1052,14 @@ export class LanceStorage extends MastraStorage {
725
1052
 
726
1053
  return trace;
727
1054
  } catch (error: any) {
728
- throw new Error(`Failed to save trace: ${error}`);
1055
+ throw new MastraError(
1056
+ {
1057
+ id: 'LANCE_STORE_SAVE_TRACE_FAILED',
1058
+ domain: ErrorDomain.STORAGE,
1059
+ category: ErrorCategory.THIRD_PARTY,
1060
+ },
1061
+ error,
1062
+ );
729
1063
  }
730
1064
  }
731
1065
 
@@ -736,7 +1070,14 @@ export class LanceStorage extends MastraStorage {
736
1070
  const records = await query.toArray();
737
1071
  return this.processResultWithTypeConversion(records[0], await this.getTableSchema(TABLE_TRACES)) as TraceType;
738
1072
  } catch (error: any) {
739
- throw new Error(`Failed to get trace by ID: ${error}`);
1073
+ throw new MastraError(
1074
+ {
1075
+ id: 'LANCE_STORE_GET_TRACE_BY_ID_FAILED',
1076
+ domain: ErrorDomain.STORAGE,
1077
+ category: ErrorCategory.THIRD_PARTY,
1078
+ },
1079
+ error,
1080
+ );
740
1081
  }
741
1082
  }
742
1083
 
@@ -795,7 +1136,15 @@ export class LanceStorage extends MastraStorage {
795
1136
  };
796
1137
  }) as TraceType[];
797
1138
  } catch (error: any) {
798
- throw new Error(`Failed to get traces: ${error}`);
1139
+ throw new MastraError(
1140
+ {
1141
+ id: 'LANCE_STORE_GET_TRACES_FAILED',
1142
+ domain: ErrorDomain.STORAGE,
1143
+ category: ErrorCategory.THIRD_PARTY,
1144
+ details: { name: name ?? '', scope: scope ?? '' },
1145
+ },
1146
+ error,
1147
+ );
799
1148
  }
800
1149
  }
801
1150
 
@@ -818,7 +1167,14 @@ export class LanceStorage extends MastraStorage {
818
1167
  await table.add(transformedEvals, { mode: 'append' });
819
1168
  return evals;
820
1169
  } catch (error: any) {
821
- throw new Error(`Failed to save evals: ${error}`);
1170
+ throw new MastraError(
1171
+ {
1172
+ id: 'LANCE_STORE_SAVE_EVALS_FAILED',
1173
+ domain: ErrorDomain.STORAGE,
1174
+ category: ErrorCategory.THIRD_PARTY,
1175
+ },
1176
+ error,
1177
+ );
822
1178
  }
823
1179
  }
824
1180
 
@@ -846,7 +1202,15 @@ export class LanceStorage extends MastraStorage {
846
1202
  };
847
1203
  }) as EvalRow[];
848
1204
  } catch (error: any) {
849
- throw new Error(`Failed to get evals by agent name: ${error}`);
1205
+ throw new MastraError(
1206
+ {
1207
+ id: 'LANCE_STORE_GET_EVALS_BY_AGENT_NAME_FAILED',
1208
+ domain: ErrorDomain.STORAGE,
1209
+ category: ErrorCategory.THIRD_PARTY,
1210
+ details: { agentName },
1211
+ },
1212
+ error,
1213
+ );
850
1214
  }
851
1215
  }
852
1216
 
@@ -909,7 +1273,15 @@ export class LanceStorage extends MastraStorage {
909
1273
  total: records.length,
910
1274
  };
911
1275
  } catch (error: any) {
912
- throw new Error(`Failed to get workflow runs: ${error}`);
1276
+ throw new MastraError(
1277
+ {
1278
+ id: 'LANCE_STORE_GET_WORKFLOW_RUNS_FAILED',
1279
+ domain: ErrorDomain.STORAGE,
1280
+ category: ErrorCategory.THIRD_PARTY,
1281
+ details: { namespace: args?.namespace ?? '', workflowName: args?.workflowName ?? '' },
1282
+ },
1283
+ error,
1284
+ );
913
1285
  }
914
1286
  }
915
1287
 
@@ -937,7 +1309,15 @@ export class LanceStorage extends MastraStorage {
937
1309
  const record = records[0];
938
1310
  return this.parseWorkflowRun(record);
939
1311
  } catch (error: any) {
940
- throw new Error(`Failed to get workflow run by id: ${error}`);
1312
+ throw new MastraError(
1313
+ {
1314
+ id: 'LANCE_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED',
1315
+ domain: ErrorDomain.STORAGE,
1316
+ category: ErrorCategory.THIRD_PARTY,
1317
+ details: { runId: args.runId, workflowName: args.workflowName ?? '' },
1318
+ },
1319
+ error,
1320
+ );
941
1321
  }
942
1322
  }
943
1323
 
@@ -958,11 +1338,9 @@ export class LanceStorage extends MastraStorage {
958
1338
  const records = await query.toArray();
959
1339
  let createdAt: number;
960
1340
  const now = Date.now();
961
- let mode: 'append' | 'overwrite' = 'append';
962
1341
 
963
1342
  if (records.length > 0) {
964
1343
  createdAt = records[0].createdAt ?? now;
965
- mode = 'overwrite';
966
1344
  } else {
967
1345
  createdAt = now;
968
1346
  }
@@ -975,9 +1353,21 @@ export class LanceStorage extends MastraStorage {
975
1353
  updatedAt: now,
976
1354
  };
977
1355
 
978
- await table.add([record], { mode });
1356
+ await table
1357
+ .mergeInsert(['workflow_name', 'run_id'])
1358
+ .whenMatchedUpdateAll()
1359
+ .whenNotMatchedInsertAll()
1360
+ .execute([record]);
979
1361
  } catch (error: any) {
980
- throw new Error(`Failed to persist workflow snapshot: ${error}`);
1362
+ throw new MastraError(
1363
+ {
1364
+ id: 'LANCE_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED',
1365
+ domain: ErrorDomain.STORAGE,
1366
+ category: ErrorCategory.THIRD_PARTY,
1367
+ details: { workflowName, runId },
1368
+ },
1369
+ error,
1370
+ );
981
1371
  }
982
1372
  }
983
1373
  async loadWorkflowSnapshot({
@@ -993,12 +1383,27 @@ export class LanceStorage extends MastraStorage {
993
1383
  const records = await query.toArray();
994
1384
  return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
995
1385
  } catch (error: any) {
996
- throw new Error(`Failed to load workflow snapshot: ${error}`);
1386
+ throw new MastraError(
1387
+ {
1388
+ id: 'LANCE_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED',
1389
+ domain: ErrorDomain.STORAGE,
1390
+ category: ErrorCategory.THIRD_PARTY,
1391
+ details: { workflowName, runId },
1392
+ },
1393
+ error,
1394
+ );
997
1395
  }
998
1396
  }
999
1397
 
1000
1398
  async getTracesPaginated(_args: StorageGetTracesArg): Promise<PaginationInfo & { traces: Trace[] }> {
1001
- throw new Error('Method not implemented.');
1399
+ throw new MastraError(
1400
+ {
1401
+ id: 'LANCE_STORE_GET_TRACES_PAGINATED_FAILED',
1402
+ domain: ErrorDomain.STORAGE,
1403
+ category: ErrorCategory.THIRD_PARTY,
1404
+ },
1405
+ 'Method not implemented.',
1406
+ );
1002
1407
  }
1003
1408
 
1004
1409
  async getThreadsByResourceIdPaginated(_args: {
@@ -1006,12 +1411,37 @@ export class LanceStorage extends MastraStorage {
1006
1411
  page?: number;
1007
1412
  perPage?: number;
1008
1413
  }): Promise<PaginationInfo & { threads: StorageThreadType[] }> {
1009
- throw new Error('Method not implemented.');
1414
+ throw new MastraError(
1415
+ {
1416
+ id: 'LANCE_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED',
1417
+ domain: ErrorDomain.STORAGE,
1418
+ category: ErrorCategory.THIRD_PARTY,
1419
+ },
1420
+ 'Method not implemented.',
1421
+ );
1010
1422
  }
1011
1423
 
1012
1424
  async getMessagesPaginated(
1013
1425
  _args: StorageGetMessagesArg,
1014
1426
  ): Promise<PaginationInfo & { messages: MastraMessageV1[] | MastraMessageV2[] }> {
1015
- throw new Error('Method not implemented.');
1427
+ throw new MastraError(
1428
+ {
1429
+ id: 'LANCE_STORE_GET_MESSAGES_PAGINATED_FAILED',
1430
+ domain: ErrorDomain.STORAGE,
1431
+ category: ErrorCategory.THIRD_PARTY,
1432
+ },
1433
+ 'Method not implemented.',
1434
+ );
1435
+ }
1436
+
1437
+ async updateMessages(_args: {
1438
+ messages: Partial<Omit<MastraMessageV2, 'createdAt'>> &
1439
+ {
1440
+ id: string;
1441
+ content?: { metadata?: MastraMessageContentV2['metadata']; content?: MastraMessageContentV2['content'] };
1442
+ }[];
1443
+ }): Promise<MastraMessageV2[]> {
1444
+ this.logger.error('updateMessages is not yet implemented in LanceStore');
1445
+ throw new Error('Method not implemented');
1016
1446
  }
1017
1447
  }