@mastra/lance 0.0.0-working-memory-per-user-20250620161509 → 0.0.0-zod-v4-compat-part-2-20250820135355

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 (50) hide show
  1. package/CHANGELOG.md +170 -2
  2. package/LICENSE.md +11 -42
  3. package/dist/index.cjs +2321 -695
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.ts +3 -2
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +2286 -660
  8. package/dist/index.js.map +1 -0
  9. package/dist/storage/domains/legacy-evals/index.d.ts +25 -0
  10. package/dist/storage/domains/legacy-evals/index.d.ts.map +1 -0
  11. package/dist/storage/domains/memory/index.d.ts +94 -0
  12. package/dist/storage/domains/memory/index.d.ts.map +1 -0
  13. package/dist/storage/domains/operations/index.d.ts +40 -0
  14. package/dist/storage/domains/operations/index.d.ts.map +1 -0
  15. package/dist/storage/domains/scores/index.d.ts +39 -0
  16. package/dist/storage/domains/scores/index.d.ts.map +1 -0
  17. package/dist/storage/domains/traces/index.d.ts +34 -0
  18. package/dist/storage/domains/traces/index.d.ts.map +1 -0
  19. package/dist/storage/domains/utils.d.ts +10 -0
  20. package/dist/storage/domains/utils.d.ts.map +1 -0
  21. package/dist/storage/domains/workflows/index.d.ts +38 -0
  22. package/dist/storage/domains/workflows/index.d.ts.map +1 -0
  23. package/dist/storage/index.d.ts +233 -0
  24. package/dist/storage/index.d.ts.map +1 -0
  25. package/dist/vector/filter.d.ts +41 -0
  26. package/dist/vector/filter.d.ts.map +1 -0
  27. package/dist/vector/index.d.ts +85 -0
  28. package/dist/vector/index.d.ts.map +1 -0
  29. package/dist/vector/types.d.ts +15 -0
  30. package/dist/vector/types.d.ts.map +1 -0
  31. package/package.json +9 -9
  32. package/src/storage/domains/legacy-evals/index.ts +156 -0
  33. package/src/storage/domains/memory/index.ts +947 -0
  34. package/src/storage/domains/operations/index.ts +489 -0
  35. package/src/storage/domains/scores/index.ts +221 -0
  36. package/src/storage/domains/traces/index.ts +212 -0
  37. package/src/storage/domains/utils.ts +158 -0
  38. package/src/storage/domains/workflows/index.ts +207 -0
  39. package/src/storage/index.test.ts +6 -1262
  40. package/src/storage/index.ts +168 -755
  41. package/src/vector/filter.test.ts +3 -3
  42. package/src/vector/filter.ts +24 -4
  43. package/src/vector/index.test.ts +3 -3
  44. package/src/vector/index.ts +320 -79
  45. package/tsconfig.build.json +9 -0
  46. package/tsconfig.json +1 -1
  47. package/tsup.config.ts +22 -0
  48. package/dist/_tsup-dts-rollup.d.cts +0 -395
  49. package/dist/_tsup-dts-rollup.d.ts +0 -395
  50. package/dist/index.d.cts +0 -2
package/dist/index.js CHANGED
@@ -1,12 +1,1877 @@
1
1
  import { connect, Index } from '@lancedb/lancedb';
2
+ import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
3
+ import { MastraStorage, StoreOperations, LegacyEvalsStorage, TABLE_EVALS, MemoryStorage, TABLE_THREADS, TABLE_MESSAGES, resolveMessageLimit, TABLE_RESOURCES, ScoresStorage, TABLE_SCORERS, TracesStorage, TABLE_TRACES, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, ensureDate } from '@mastra/core/storage';
2
4
  import { MessageList } from '@mastra/core/agent';
3
- import { MastraStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_TRACES, TABLE_EVALS, TABLE_WORKFLOW_SNAPSHOT } from '@mastra/core/storage';
4
5
  import { Utf8, Float64, Binary, Float32, Int32, Field, Schema } from 'apache-arrow';
5
6
  import { MastraVector } from '@mastra/core/vector';
6
7
  import { BaseFilterTranslator } from '@mastra/core/vector/filter';
7
8
 
9
+ // src/storage/index.ts
10
+ var StoreLegacyEvalsLance = class extends LegacyEvalsStorage {
11
+ client;
12
+ constructor({ client }) {
13
+ super();
14
+ this.client = client;
15
+ }
16
+ async getEvalsByAgentName(agentName, type) {
17
+ try {
18
+ const table = await this.client.openTable(TABLE_EVALS);
19
+ const query = table.query().where(`agent_name = '${agentName}'`);
20
+ const records = await query.toArray();
21
+ let filteredRecords = records;
22
+ if (type === "live") {
23
+ filteredRecords = records.filter((record) => record.test_info === null);
24
+ } else if (type === "test") {
25
+ filteredRecords = records.filter((record) => record.test_info !== null);
26
+ }
27
+ return filteredRecords.map((record) => {
28
+ return {
29
+ id: record.id,
30
+ input: record.input,
31
+ output: record.output,
32
+ agentName: record.agent_name,
33
+ metricName: record.metric_name,
34
+ result: JSON.parse(record.result),
35
+ instructions: record.instructions,
36
+ testInfo: record.test_info ? JSON.parse(record.test_info) : null,
37
+ globalRunId: record.global_run_id,
38
+ runId: record.run_id,
39
+ createdAt: new Date(record.created_at).toString()
40
+ };
41
+ });
42
+ } catch (error) {
43
+ throw new MastraError(
44
+ {
45
+ id: "LANCE_STORE_GET_EVALS_BY_AGENT_NAME_FAILED",
46
+ domain: ErrorDomain.STORAGE,
47
+ category: ErrorCategory.THIRD_PARTY,
48
+ details: { agentName }
49
+ },
50
+ error
51
+ );
52
+ }
53
+ }
54
+ async getEvals(options) {
55
+ try {
56
+ const table = await this.client.openTable(TABLE_EVALS);
57
+ const conditions = [];
58
+ if (options.agentName) {
59
+ conditions.push(`agent_name = '${options.agentName}'`);
60
+ }
61
+ if (options.type === "live") {
62
+ conditions.push("length(test_info) = 0");
63
+ } else if (options.type === "test") {
64
+ conditions.push("length(test_info) > 0");
65
+ }
66
+ const startDate = options.dateRange?.start || options.fromDate;
67
+ const endDate = options.dateRange?.end || options.toDate;
68
+ if (startDate) {
69
+ conditions.push(`\`created_at\` >= ${startDate.getTime()}`);
70
+ }
71
+ if (endDate) {
72
+ conditions.push(`\`created_at\` <= ${endDate.getTime()}`);
73
+ }
74
+ let total = 0;
75
+ if (conditions.length > 0) {
76
+ total = await table.countRows(conditions.join(" AND "));
77
+ } else {
78
+ total = await table.countRows();
79
+ }
80
+ const query = table.query();
81
+ if (conditions.length > 0) {
82
+ const whereClause = conditions.join(" AND ");
83
+ query.where(whereClause);
84
+ }
85
+ const records = await query.toArray();
86
+ const evals = records.sort((a, b) => b.created_at - a.created_at).map((record) => {
87
+ return {
88
+ id: record.id,
89
+ input: record.input,
90
+ output: record.output,
91
+ agentName: record.agent_name,
92
+ metricName: record.metric_name,
93
+ result: JSON.parse(record.result),
94
+ instructions: record.instructions,
95
+ testInfo: record.test_info ? JSON.parse(record.test_info) : null,
96
+ globalRunId: record.global_run_id,
97
+ runId: record.run_id,
98
+ createdAt: new Date(record.created_at).toISOString()
99
+ };
100
+ });
101
+ const page = options.page || 0;
102
+ const perPage = options.perPage || 10;
103
+ const pagedEvals = evals.slice(page * perPage, (page + 1) * perPage);
104
+ return {
105
+ evals: pagedEvals,
106
+ total,
107
+ page,
108
+ perPage,
109
+ hasMore: total > (page + 1) * perPage
110
+ };
111
+ } catch (error) {
112
+ throw new MastraError(
113
+ {
114
+ id: "LANCE_STORE_GET_EVALS_FAILED",
115
+ domain: ErrorDomain.STORAGE,
116
+ category: ErrorCategory.THIRD_PARTY,
117
+ details: { agentName: options.agentName ?? "" }
118
+ },
119
+ error
120
+ );
121
+ }
122
+ }
123
+ };
124
+ function getPrimaryKeys(tableName) {
125
+ let primaryId = ["id"];
126
+ if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
127
+ primaryId = ["workflow_name", "run_id"];
128
+ } else if (tableName === TABLE_EVALS) {
129
+ primaryId = ["agent_name", "metric_name", "run_id"];
130
+ }
131
+ return primaryId;
132
+ }
133
+ function validateKeyTypes(keys, tableSchema) {
134
+ const fieldTypes = new Map(
135
+ tableSchema.fields.map((field) => [field.name, field.type?.toString().toLowerCase()])
136
+ );
137
+ for (const [key, value] of Object.entries(keys)) {
138
+ const fieldType = fieldTypes.get(key);
139
+ if (!fieldType) {
140
+ throw new Error(`Field '${key}' does not exist in table schema`);
141
+ }
142
+ if (value !== null) {
143
+ if ((fieldType.includes("int") || fieldType.includes("bigint")) && typeof value !== "number") {
144
+ throw new Error(`Expected numeric value for field '${key}', got ${typeof value}`);
145
+ }
146
+ if (fieldType.includes("utf8") && typeof value !== "string") {
147
+ throw new Error(`Expected string value for field '${key}', got ${typeof value}`);
148
+ }
149
+ if (fieldType.includes("timestamp") && !(value instanceof Date) && typeof value !== "string") {
150
+ throw new Error(`Expected Date or string value for field '${key}', got ${typeof value}`);
151
+ }
152
+ }
153
+ }
154
+ }
155
+ function processResultWithTypeConversion(rawResult, tableSchema) {
156
+ const fieldTypeMap = /* @__PURE__ */ new Map();
157
+ tableSchema.fields.forEach((field) => {
158
+ const fieldName = field.name;
159
+ const fieldTypeStr = field.type.toString().toLowerCase();
160
+ fieldTypeMap.set(fieldName, fieldTypeStr);
161
+ });
162
+ if (Array.isArray(rawResult)) {
163
+ return rawResult.map((item) => processResultWithTypeConversion(item, tableSchema));
164
+ }
165
+ const processedResult = { ...rawResult };
166
+ for (const key in processedResult) {
167
+ const fieldTypeStr = fieldTypeMap.get(key);
168
+ if (!fieldTypeStr) continue;
169
+ if (typeof processedResult[key] === "string") {
170
+ if (fieldTypeStr.includes("int32") || fieldTypeStr.includes("float32")) {
171
+ if (!isNaN(Number(processedResult[key]))) {
172
+ processedResult[key] = Number(processedResult[key]);
173
+ }
174
+ } else if (fieldTypeStr.includes("int64")) {
175
+ processedResult[key] = Number(processedResult[key]);
176
+ } else if (fieldTypeStr.includes("utf8") && key !== "id") {
177
+ try {
178
+ const parsed = JSON.parse(processedResult[key]);
179
+ if (typeof parsed === "object") {
180
+ processedResult[key] = JSON.parse(processedResult[key]);
181
+ }
182
+ } catch {
183
+ }
184
+ }
185
+ } else if (typeof processedResult[key] === "bigint") {
186
+ processedResult[key] = Number(processedResult[key]);
187
+ } else if (fieldTypeStr.includes("float64") && ["createdAt", "updatedAt"].includes(key)) {
188
+ processedResult[key] = new Date(processedResult[key]);
189
+ }
190
+ console.log(key, "processedResult", processedResult);
191
+ }
192
+ return processedResult;
193
+ }
194
+ async function getTableSchema({
195
+ tableName,
196
+ client
197
+ }) {
198
+ try {
199
+ if (!client) {
200
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
201
+ }
202
+ if (!tableName) {
203
+ throw new Error("tableName is required for getTableSchema.");
204
+ }
205
+ } catch (validationError) {
206
+ throw new MastraError(
207
+ {
208
+ id: "STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_INVALID_ARGS",
209
+ domain: ErrorDomain.STORAGE,
210
+ category: ErrorCategory.USER,
211
+ text: validationError.message,
212
+ details: { tableName }
213
+ },
214
+ validationError
215
+ );
216
+ }
217
+ try {
218
+ const table = await client.openTable(tableName);
219
+ const rawSchema = await table.schema();
220
+ const fields = rawSchema.fields;
221
+ return {
222
+ fields,
223
+ metadata: /* @__PURE__ */ new Map(),
224
+ get names() {
225
+ return fields.map((field) => field.name);
226
+ }
227
+ };
228
+ } catch (error) {
229
+ throw new MastraError(
230
+ {
231
+ id: "STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_FAILED",
232
+ domain: ErrorDomain.STORAGE,
233
+ category: ErrorCategory.THIRD_PARTY,
234
+ details: { tableName }
235
+ },
236
+ error
237
+ );
238
+ }
239
+ }
240
+
241
+ // src/storage/domains/memory/index.ts
242
+ var StoreMemoryLance = class extends MemoryStorage {
243
+ client;
244
+ operations;
245
+ constructor({ client, operations }) {
246
+ super();
247
+ this.client = client;
248
+ this.operations = operations;
249
+ }
250
+ async getThreadById({ threadId }) {
251
+ try {
252
+ const thread = await this.operations.load({ tableName: TABLE_THREADS, keys: { id: threadId } });
253
+ if (!thread) {
254
+ return null;
255
+ }
256
+ return {
257
+ ...thread,
258
+ createdAt: new Date(thread.createdAt),
259
+ updatedAt: new Date(thread.updatedAt)
260
+ };
261
+ } catch (error) {
262
+ throw new MastraError(
263
+ {
264
+ id: "LANCE_STORE_GET_THREAD_BY_ID_FAILED",
265
+ domain: ErrorDomain.STORAGE,
266
+ category: ErrorCategory.THIRD_PARTY
267
+ },
268
+ error
269
+ );
270
+ }
271
+ }
272
+ async getThreadsByResourceId({ resourceId }) {
273
+ try {
274
+ const table = await this.client.openTable(TABLE_THREADS);
275
+ const query = table.query().where(`\`resourceId\` = '${resourceId}'`);
276
+ const records = await query.toArray();
277
+ return processResultWithTypeConversion(
278
+ records,
279
+ await getTableSchema({ tableName: TABLE_THREADS, client: this.client })
280
+ );
281
+ } catch (error) {
282
+ throw new MastraError(
283
+ {
284
+ id: "LANCE_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED",
285
+ domain: ErrorDomain.STORAGE,
286
+ category: ErrorCategory.THIRD_PARTY
287
+ },
288
+ error
289
+ );
290
+ }
291
+ }
292
+ /**
293
+ * Saves a thread to the database. This function doesn't overwrite existing threads.
294
+ * @param thread - The thread to save
295
+ * @returns The saved thread
296
+ */
297
+ async saveThread({ thread }) {
298
+ try {
299
+ const record = { ...thread, metadata: JSON.stringify(thread.metadata) };
300
+ const table = await this.client.openTable(TABLE_THREADS);
301
+ await table.add([record], { mode: "append" });
302
+ return thread;
303
+ } catch (error) {
304
+ throw new MastraError(
305
+ {
306
+ id: "LANCE_STORE_SAVE_THREAD_FAILED",
307
+ domain: ErrorDomain.STORAGE,
308
+ category: ErrorCategory.THIRD_PARTY
309
+ },
310
+ error
311
+ );
312
+ }
313
+ }
314
+ async updateThread({
315
+ id,
316
+ title,
317
+ metadata
318
+ }) {
319
+ const maxRetries = 5;
320
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
321
+ try {
322
+ const current = await this.getThreadById({ threadId: id });
323
+ if (!current) {
324
+ throw new Error(`Thread with id ${id} not found`);
325
+ }
326
+ const mergedMetadata = { ...current.metadata, ...metadata };
327
+ const record = {
328
+ id,
329
+ title,
330
+ metadata: JSON.stringify(mergedMetadata),
331
+ updatedAt: (/* @__PURE__ */ new Date()).getTime()
332
+ };
333
+ const table = await this.client.openTable(TABLE_THREADS);
334
+ await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
335
+ const updatedThread = await this.getThreadById({ threadId: id });
336
+ if (!updatedThread) {
337
+ throw new Error(`Failed to retrieve updated thread ${id}`);
338
+ }
339
+ return updatedThread;
340
+ } catch (error) {
341
+ if (error.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
342
+ const delay = Math.pow(2, attempt) * 10;
343
+ await new Promise((resolve) => setTimeout(resolve, delay));
344
+ continue;
345
+ }
346
+ throw new MastraError(
347
+ {
348
+ id: "LANCE_STORE_UPDATE_THREAD_FAILED",
349
+ domain: ErrorDomain.STORAGE,
350
+ category: ErrorCategory.THIRD_PARTY
351
+ },
352
+ error
353
+ );
354
+ }
355
+ }
356
+ throw new MastraError(
357
+ {
358
+ id: "LANCE_STORE_UPDATE_THREAD_FAILED",
359
+ domain: ErrorDomain.STORAGE,
360
+ category: ErrorCategory.THIRD_PARTY
361
+ },
362
+ new Error("All retries exhausted")
363
+ );
364
+ }
365
+ async deleteThread({ threadId }) {
366
+ try {
367
+ const table = await this.client.openTable(TABLE_THREADS);
368
+ await table.delete(`id = '${threadId}'`);
369
+ const messagesTable = await this.client.openTable(TABLE_MESSAGES);
370
+ await messagesTable.delete(`thread_id = '${threadId}'`);
371
+ } catch (error) {
372
+ throw new MastraError(
373
+ {
374
+ id: "LANCE_STORE_DELETE_THREAD_FAILED",
375
+ domain: ErrorDomain.STORAGE,
376
+ category: ErrorCategory.THIRD_PARTY
377
+ },
378
+ error
379
+ );
380
+ }
381
+ }
382
+ async getMessages({
383
+ threadId,
384
+ resourceId,
385
+ selectBy,
386
+ format,
387
+ threadConfig
388
+ }) {
389
+ try {
390
+ if (threadConfig) {
391
+ throw new Error("ThreadConfig is not supported by LanceDB storage");
392
+ }
393
+ const limit = resolveMessageLimit({ last: selectBy?.last, defaultLimit: Number.MAX_SAFE_INTEGER });
394
+ const table = await this.client.openTable(TABLE_MESSAGES);
395
+ let allRecords = [];
396
+ if (selectBy?.include && selectBy.include.length > 0) {
397
+ const threadIds = [...new Set(selectBy.include.map((item) => item.threadId))];
398
+ for (const threadId2 of threadIds) {
399
+ const threadQuery = table.query().where(`thread_id = '${threadId2}'`);
400
+ let threadRecords = await threadQuery.toArray();
401
+ allRecords.push(...threadRecords);
402
+ }
403
+ } else {
404
+ let query = table.query().where(`\`thread_id\` = '${threadId}'`);
405
+ allRecords = await query.toArray();
406
+ }
407
+ allRecords.sort((a, b) => {
408
+ const dateA = new Date(a.createdAt).getTime();
409
+ const dateB = new Date(b.createdAt).getTime();
410
+ return dateA - dateB;
411
+ });
412
+ if (selectBy?.include && selectBy.include.length > 0) {
413
+ allRecords = this.processMessagesWithContext(allRecords, selectBy.include);
414
+ }
415
+ if (limit !== Number.MAX_SAFE_INTEGER) {
416
+ allRecords = allRecords.slice(-limit);
417
+ }
418
+ const messages = processResultWithTypeConversion(
419
+ allRecords,
420
+ await getTableSchema({ tableName: TABLE_MESSAGES, client: this.client })
421
+ );
422
+ const normalized = messages.map((msg) => {
423
+ const { thread_id, ...rest } = msg;
424
+ return {
425
+ ...rest,
426
+ threadId: thread_id,
427
+ content: typeof msg.content === "string" ? (() => {
428
+ try {
429
+ return JSON.parse(msg.content);
430
+ } catch {
431
+ return msg.content;
432
+ }
433
+ })() : msg.content
434
+ };
435
+ });
436
+ const list = new MessageList({ threadId, resourceId }).add(normalized, "memory");
437
+ if (format === "v2") return list.get.all.v2();
438
+ return list.get.all.v1();
439
+ } catch (error) {
440
+ throw new MastraError(
441
+ {
442
+ id: "LANCE_STORE_GET_MESSAGES_FAILED",
443
+ domain: ErrorDomain.STORAGE,
444
+ category: ErrorCategory.THIRD_PARTY
445
+ },
446
+ error
447
+ );
448
+ }
449
+ }
450
+ async saveMessages(args) {
451
+ try {
452
+ const { messages, format = "v1" } = args;
453
+ if (messages.length === 0) {
454
+ return [];
455
+ }
456
+ const threadId = messages[0]?.threadId;
457
+ if (!threadId) {
458
+ throw new Error("Thread ID is required");
459
+ }
460
+ for (const message of messages) {
461
+ if (!message.id) {
462
+ throw new Error("Message ID is required");
463
+ }
464
+ if (!message.threadId) {
465
+ throw new Error("Thread ID is required for all messages");
466
+ }
467
+ if (message.resourceId === null || message.resourceId === void 0) {
468
+ throw new Error("Resource ID cannot be null or undefined");
469
+ }
470
+ if (!message.content) {
471
+ throw new Error("Message content is required");
472
+ }
473
+ }
474
+ const transformedMessages = messages.map((message) => {
475
+ const { threadId: threadId2, type, ...rest } = message;
476
+ return {
477
+ ...rest,
478
+ thread_id: threadId2,
479
+ type: type ?? "v2",
480
+ content: JSON.stringify(message.content)
481
+ };
482
+ });
483
+ const table = await this.client.openTable(TABLE_MESSAGES);
484
+ await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
485
+ const threadsTable = await this.client.openTable(TABLE_THREADS);
486
+ const currentTime = (/* @__PURE__ */ new Date()).getTime();
487
+ const updateRecord = { id: threadId, updatedAt: currentTime };
488
+ await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([updateRecord]);
489
+ const list = new MessageList().add(messages, "memory");
490
+ if (format === `v2`) return list.get.all.v2();
491
+ return list.get.all.v1();
492
+ } catch (error) {
493
+ throw new MastraError(
494
+ {
495
+ id: "LANCE_STORE_SAVE_MESSAGES_FAILED",
496
+ domain: ErrorDomain.STORAGE,
497
+ category: ErrorCategory.THIRD_PARTY
498
+ },
499
+ error
500
+ );
501
+ }
502
+ }
503
+ async getThreadsByResourceIdPaginated(args) {
504
+ try {
505
+ const { resourceId, page = 0, perPage = 10 } = args;
506
+ const table = await this.client.openTable(TABLE_THREADS);
507
+ const total = await table.countRows(`\`resourceId\` = '${resourceId}'`);
508
+ const query = table.query().where(`\`resourceId\` = '${resourceId}'`);
509
+ const offset = page * perPage;
510
+ query.limit(perPage);
511
+ if (offset > 0) {
512
+ query.offset(offset);
513
+ }
514
+ const records = await query.toArray();
515
+ records.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
516
+ const schema = await getTableSchema({ tableName: TABLE_THREADS, client: this.client });
517
+ const threads = records.map((record) => processResultWithTypeConversion(record, schema));
518
+ return {
519
+ threads,
520
+ total,
521
+ page,
522
+ perPage,
523
+ hasMore: total > (page + 1) * perPage
524
+ };
525
+ } catch (error) {
526
+ throw new MastraError(
527
+ {
528
+ id: "LANCE_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
529
+ domain: ErrorDomain.STORAGE,
530
+ category: ErrorCategory.THIRD_PARTY
531
+ },
532
+ error
533
+ );
534
+ }
535
+ }
536
+ /**
537
+ * Processes messages to include context messages based on withPreviousMessages and withNextMessages
538
+ * @param records - The sorted array of records to process
539
+ * @param include - The array of include specifications with context parameters
540
+ * @returns The processed array with context messages included
541
+ */
542
+ processMessagesWithContext(records, include) {
543
+ const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
544
+ if (messagesWithContext.length === 0) {
545
+ return records;
546
+ }
547
+ const messageIndexMap = /* @__PURE__ */ new Map();
548
+ records.forEach((message, index) => {
549
+ messageIndexMap.set(message.id, index);
550
+ });
551
+ const additionalIndices = /* @__PURE__ */ new Set();
552
+ for (const item of messagesWithContext) {
553
+ const messageIndex = messageIndexMap.get(item.id);
554
+ if (messageIndex !== void 0) {
555
+ if (item.withPreviousMessages) {
556
+ const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
557
+ for (let i = startIdx; i < messageIndex; i++) {
558
+ additionalIndices.add(i);
559
+ }
560
+ }
561
+ if (item.withNextMessages) {
562
+ const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
563
+ for (let i = messageIndex + 1; i <= endIdx; i++) {
564
+ additionalIndices.add(i);
565
+ }
566
+ }
567
+ }
568
+ }
569
+ if (additionalIndices.size === 0) {
570
+ return records;
571
+ }
572
+ const originalMatchIds = new Set(include.map((item) => item.id));
573
+ const allIndices = /* @__PURE__ */ new Set();
574
+ records.forEach((record, index) => {
575
+ if (originalMatchIds.has(record.id)) {
576
+ allIndices.add(index);
577
+ }
578
+ });
579
+ additionalIndices.forEach((index) => {
580
+ allIndices.add(index);
581
+ });
582
+ return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
583
+ }
584
+ async getMessagesPaginated(args) {
585
+ try {
586
+ const { threadId, resourceId, selectBy, format = "v1" } = args;
587
+ if (!threadId) {
588
+ throw new Error("Thread ID is required for getMessagesPaginated");
589
+ }
590
+ const page = selectBy?.pagination?.page ?? 0;
591
+ const perPage = selectBy?.pagination?.perPage ?? 10;
592
+ const dateRange = selectBy?.pagination?.dateRange;
593
+ const fromDate = dateRange?.start;
594
+ const toDate = dateRange?.end;
595
+ const table = await this.client.openTable(TABLE_MESSAGES);
596
+ const messages = [];
597
+ if (selectBy?.include && Array.isArray(selectBy.include)) {
598
+ const threadIds = [...new Set(selectBy.include.map((item) => item.threadId))];
599
+ const allThreadMessages = [];
600
+ for (const threadId2 of threadIds) {
601
+ const threadQuery = table.query().where(`thread_id = '${threadId2}'`);
602
+ let threadRecords = await threadQuery.toArray();
603
+ if (fromDate) threadRecords = threadRecords.filter((m) => m.createdAt >= fromDate.getTime());
604
+ if (toDate) threadRecords = threadRecords.filter((m) => m.createdAt <= toDate.getTime());
605
+ allThreadMessages.push(...threadRecords);
606
+ }
607
+ allThreadMessages.sort((a, b) => a.createdAt - b.createdAt);
608
+ const contextMessages = this.processMessagesWithContext(allThreadMessages, selectBy.include);
609
+ messages.push(...contextMessages);
610
+ }
611
+ const conditions = [`thread_id = '${threadId}'`];
612
+ if (resourceId) {
613
+ conditions.push(`\`resourceId\` = '${resourceId}'`);
614
+ }
615
+ if (fromDate) {
616
+ conditions.push(`\`createdAt\` >= ${fromDate.getTime()}`);
617
+ }
618
+ if (toDate) {
619
+ conditions.push(`\`createdAt\` <= ${toDate.getTime()}`);
620
+ }
621
+ let total = 0;
622
+ if (conditions.length > 0) {
623
+ total = await table.countRows(conditions.join(" AND "));
624
+ } else {
625
+ total = await table.countRows();
626
+ }
627
+ if (total === 0 && messages.length === 0) {
628
+ return {
629
+ messages: [],
630
+ total: 0,
631
+ page,
632
+ perPage,
633
+ hasMore: false
634
+ };
635
+ }
636
+ const excludeIds = messages.map((m) => m.id);
637
+ let selectedMessages = [];
638
+ if (selectBy?.last && selectBy.last > 0) {
639
+ const query = table.query();
640
+ if (conditions.length > 0) {
641
+ query.where(conditions.join(" AND "));
642
+ }
643
+ let records = await query.toArray();
644
+ records = records.sort((a, b) => a.createdAt - b.createdAt);
645
+ if (excludeIds.length > 0) {
646
+ records = records.filter((m) => !excludeIds.includes(m.id));
647
+ }
648
+ selectedMessages = records.slice(-selectBy.last);
649
+ } else {
650
+ const query = table.query();
651
+ if (conditions.length > 0) {
652
+ query.where(conditions.join(" AND "));
653
+ }
654
+ let records = await query.toArray();
655
+ records = records.sort((a, b) => a.createdAt - b.createdAt);
656
+ if (excludeIds.length > 0) {
657
+ records = records.filter((m) => !excludeIds.includes(m.id));
658
+ }
659
+ selectedMessages = records.slice(page * perPage, (page + 1) * perPage);
660
+ }
661
+ const allMessages = [...messages, ...selectedMessages];
662
+ const seen = /* @__PURE__ */ new Set();
663
+ const dedupedMessages = allMessages.filter((m) => {
664
+ const key = `${m.id}:${m.thread_id}`;
665
+ if (seen.has(key)) return false;
666
+ seen.add(key);
667
+ return true;
668
+ });
669
+ const formattedMessages = dedupedMessages.map((msg) => {
670
+ const { thread_id, ...rest } = msg;
671
+ return {
672
+ ...rest,
673
+ threadId: thread_id,
674
+ content: typeof msg.content === "string" ? (() => {
675
+ try {
676
+ return JSON.parse(msg.content);
677
+ } catch {
678
+ return msg.content;
679
+ }
680
+ })() : msg.content
681
+ };
682
+ });
683
+ const list = new MessageList().add(formattedMessages, "memory");
684
+ return {
685
+ messages: format === "v2" ? list.get.all.v2() : list.get.all.v1(),
686
+ total,
687
+ // Total should be the count of messages matching the filters
688
+ page,
689
+ perPage,
690
+ hasMore: total > (page + 1) * perPage
691
+ };
692
+ } catch (error) {
693
+ throw new MastraError(
694
+ {
695
+ id: "LANCE_STORE_GET_MESSAGES_PAGINATED_FAILED",
696
+ domain: ErrorDomain.STORAGE,
697
+ category: ErrorCategory.THIRD_PARTY
698
+ },
699
+ error
700
+ );
701
+ }
702
+ }
703
+ /**
704
+ * Parse message data from LanceDB record format to MastraMessageV2 format
705
+ */
706
+ parseMessageData(data) {
707
+ const { thread_id, ...rest } = data;
708
+ return {
709
+ ...rest,
710
+ threadId: thread_id,
711
+ content: typeof data.content === "string" ? (() => {
712
+ try {
713
+ return JSON.parse(data.content);
714
+ } catch {
715
+ return data.content;
716
+ }
717
+ })() : data.content,
718
+ createdAt: new Date(data.createdAt),
719
+ updatedAt: new Date(data.updatedAt)
720
+ };
721
+ }
722
+ async updateMessages(args) {
723
+ const { messages } = args;
724
+ this.logger.debug("Updating messages", { count: messages.length });
725
+ if (!messages.length) {
726
+ return [];
727
+ }
728
+ const updatedMessages = [];
729
+ const affectedThreadIds = /* @__PURE__ */ new Set();
730
+ try {
731
+ for (const updateData of messages) {
732
+ const { id, ...updates } = updateData;
733
+ const existingMessage = await this.operations.load({ tableName: TABLE_MESSAGES, keys: { id } });
734
+ if (!existingMessage) {
735
+ this.logger.warn("Message not found for update", { id });
736
+ continue;
737
+ }
738
+ const existingMsg = this.parseMessageData(existingMessage);
739
+ const originalThreadId = existingMsg.threadId;
740
+ affectedThreadIds.add(originalThreadId);
741
+ const updatePayload = {};
742
+ if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
743
+ if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
744
+ if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
745
+ if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
746
+ updatePayload.thread_id = updates.threadId;
747
+ affectedThreadIds.add(updates.threadId);
748
+ }
749
+ if (updates.content) {
750
+ const existingContent = existingMsg.content;
751
+ let newContent = { ...existingContent };
752
+ if (updates.content.metadata !== void 0) {
753
+ newContent.metadata = {
754
+ ...existingContent.metadata || {},
755
+ ...updates.content.metadata || {}
756
+ };
757
+ }
758
+ if (updates.content.content !== void 0) {
759
+ newContent.content = updates.content.content;
760
+ }
761
+ if ("parts" in updates.content && updates.content.parts !== void 0) {
762
+ newContent.parts = updates.content.parts;
763
+ }
764
+ updatePayload.content = JSON.stringify(newContent);
765
+ }
766
+ await this.operations.insert({ tableName: TABLE_MESSAGES, record: { id, ...updatePayload } });
767
+ const updatedMessage = await this.operations.load({ tableName: TABLE_MESSAGES, keys: { id } });
768
+ if (updatedMessage) {
769
+ updatedMessages.push(this.parseMessageData(updatedMessage));
770
+ }
771
+ }
772
+ for (const threadId of affectedThreadIds) {
773
+ await this.operations.insert({
774
+ tableName: TABLE_THREADS,
775
+ record: { id: threadId, updatedAt: Date.now() }
776
+ });
777
+ }
778
+ return updatedMessages;
779
+ } catch (error) {
780
+ throw new MastraError(
781
+ {
782
+ id: "LANCE_STORE_UPDATE_MESSAGES_FAILED",
783
+ domain: ErrorDomain.STORAGE,
784
+ category: ErrorCategory.THIRD_PARTY,
785
+ details: { count: messages.length }
786
+ },
787
+ error
788
+ );
789
+ }
790
+ }
791
+ async getResourceById({ resourceId }) {
792
+ try {
793
+ const resource = await this.operations.load({ tableName: TABLE_RESOURCES, keys: { id: resourceId } });
794
+ if (!resource) {
795
+ return null;
796
+ }
797
+ let createdAt;
798
+ let updatedAt;
799
+ try {
800
+ if (resource.createdAt instanceof Date) {
801
+ createdAt = resource.createdAt;
802
+ } else if (typeof resource.createdAt === "string") {
803
+ createdAt = new Date(resource.createdAt);
804
+ } else if (typeof resource.createdAt === "number") {
805
+ createdAt = new Date(resource.createdAt);
806
+ } else {
807
+ createdAt = /* @__PURE__ */ new Date();
808
+ }
809
+ if (isNaN(createdAt.getTime())) {
810
+ createdAt = /* @__PURE__ */ new Date();
811
+ }
812
+ } catch {
813
+ createdAt = /* @__PURE__ */ new Date();
814
+ }
815
+ try {
816
+ if (resource.updatedAt instanceof Date) {
817
+ updatedAt = resource.updatedAt;
818
+ } else if (typeof resource.updatedAt === "string") {
819
+ updatedAt = new Date(resource.updatedAt);
820
+ } else if (typeof resource.updatedAt === "number") {
821
+ updatedAt = new Date(resource.updatedAt);
822
+ } else {
823
+ updatedAt = /* @__PURE__ */ new Date();
824
+ }
825
+ if (isNaN(updatedAt.getTime())) {
826
+ updatedAt = /* @__PURE__ */ new Date();
827
+ }
828
+ } catch {
829
+ updatedAt = /* @__PURE__ */ new Date();
830
+ }
831
+ let workingMemory = resource.workingMemory;
832
+ if (workingMemory === null || workingMemory === void 0) {
833
+ workingMemory = void 0;
834
+ } else if (workingMemory === "") {
835
+ workingMemory = "";
836
+ } else if (typeof workingMemory === "object") {
837
+ workingMemory = JSON.stringify(workingMemory);
838
+ }
839
+ let metadata = resource.metadata;
840
+ if (metadata === "" || metadata === null || metadata === void 0) {
841
+ metadata = void 0;
842
+ } else if (typeof metadata === "string") {
843
+ try {
844
+ metadata = JSON.parse(metadata);
845
+ } catch {
846
+ metadata = metadata;
847
+ }
848
+ }
849
+ return {
850
+ ...resource,
851
+ createdAt,
852
+ updatedAt,
853
+ workingMemory,
854
+ metadata
855
+ };
856
+ } catch (error) {
857
+ throw new MastraError(
858
+ {
859
+ id: "LANCE_STORE_GET_RESOURCE_BY_ID_FAILED",
860
+ domain: ErrorDomain.STORAGE,
861
+ category: ErrorCategory.THIRD_PARTY
862
+ },
863
+ error
864
+ );
865
+ }
866
+ }
867
+ async saveResource({ resource }) {
868
+ try {
869
+ const record = {
870
+ ...resource,
871
+ metadata: resource.metadata ? JSON.stringify(resource.metadata) : "",
872
+ createdAt: resource.createdAt.getTime(),
873
+ // Store as timestamp (milliseconds)
874
+ updatedAt: resource.updatedAt.getTime()
875
+ // Store as timestamp (milliseconds)
876
+ };
877
+ const table = await this.client.openTable(TABLE_RESOURCES);
878
+ await table.add([record], { mode: "append" });
879
+ return resource;
880
+ } catch (error) {
881
+ throw new MastraError(
882
+ {
883
+ id: "LANCE_STORE_SAVE_RESOURCE_FAILED",
884
+ domain: ErrorDomain.STORAGE,
885
+ category: ErrorCategory.THIRD_PARTY
886
+ },
887
+ error
888
+ );
889
+ }
890
+ }
891
+ async updateResource({
892
+ resourceId,
893
+ workingMemory,
894
+ metadata
895
+ }) {
896
+ const maxRetries = 3;
897
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
898
+ try {
899
+ const existingResource = await this.getResourceById({ resourceId });
900
+ if (!existingResource) {
901
+ const newResource = {
902
+ id: resourceId,
903
+ workingMemory,
904
+ metadata: metadata || {},
905
+ createdAt: /* @__PURE__ */ new Date(),
906
+ updatedAt: /* @__PURE__ */ new Date()
907
+ };
908
+ return this.saveResource({ resource: newResource });
909
+ }
910
+ const updatedResource = {
911
+ ...existingResource,
912
+ workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
913
+ metadata: {
914
+ ...existingResource.metadata,
915
+ ...metadata
916
+ },
917
+ updatedAt: /* @__PURE__ */ new Date()
918
+ };
919
+ const record = {
920
+ id: resourceId,
921
+ workingMemory: updatedResource.workingMemory || "",
922
+ metadata: updatedResource.metadata ? JSON.stringify(updatedResource.metadata) : "",
923
+ updatedAt: updatedResource.updatedAt.getTime()
924
+ // Store as timestamp (milliseconds)
925
+ };
926
+ const table = await this.client.openTable(TABLE_RESOURCES);
927
+ await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
928
+ return updatedResource;
929
+ } catch (error) {
930
+ if (error.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
931
+ const delay = Math.pow(2, attempt) * 10;
932
+ await new Promise((resolve) => setTimeout(resolve, delay));
933
+ continue;
934
+ }
935
+ throw new MastraError(
936
+ {
937
+ id: "LANCE_STORE_UPDATE_RESOURCE_FAILED",
938
+ domain: ErrorDomain.STORAGE,
939
+ category: ErrorCategory.THIRD_PARTY
940
+ },
941
+ error
942
+ );
943
+ }
944
+ }
945
+ throw new Error("Unexpected end of retry loop");
946
+ }
947
+ };
948
+ var StoreOperationsLance = class extends StoreOperations {
949
+ client;
950
+ constructor({ client }) {
951
+ super();
952
+ this.client = client;
953
+ }
954
+ getDefaultValue(type) {
955
+ switch (type) {
956
+ case "text":
957
+ return "''";
958
+ case "timestamp":
959
+ return "CURRENT_TIMESTAMP";
960
+ case "integer":
961
+ case "bigint":
962
+ return "0";
963
+ case "jsonb":
964
+ return "'{}'";
965
+ case "uuid":
966
+ return "''";
967
+ default:
968
+ return super.getDefaultValue(type);
969
+ }
970
+ }
971
+ async hasColumn(tableName, columnName) {
972
+ const table = await this.client.openTable(tableName);
973
+ const schema = await table.schema();
974
+ return schema.fields.some((field) => field.name === columnName);
975
+ }
976
+ translateSchema(schema) {
977
+ const fields = Object.entries(schema).map(([name, column]) => {
978
+ let arrowType;
979
+ switch (column.type.toLowerCase()) {
980
+ case "text":
981
+ case "uuid":
982
+ arrowType = new Utf8();
983
+ break;
984
+ case "int":
985
+ case "integer":
986
+ arrowType = new Int32();
987
+ break;
988
+ case "bigint":
989
+ arrowType = new Float64();
990
+ break;
991
+ case "float":
992
+ arrowType = new Float32();
993
+ break;
994
+ case "jsonb":
995
+ case "json":
996
+ arrowType = new Utf8();
997
+ break;
998
+ case "binary":
999
+ arrowType = new Binary();
1000
+ break;
1001
+ case "timestamp":
1002
+ arrowType = new Float64();
1003
+ break;
1004
+ default:
1005
+ arrowType = new Utf8();
1006
+ }
1007
+ return new Field(name, arrowType, column.nullable ?? true);
1008
+ });
1009
+ return new Schema(fields);
1010
+ }
1011
+ async createTable({
1012
+ tableName,
1013
+ schema
1014
+ }) {
1015
+ try {
1016
+ if (!this.client) {
1017
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1018
+ }
1019
+ if (!tableName) {
1020
+ throw new Error("tableName is required for createTable.");
1021
+ }
1022
+ if (!schema) {
1023
+ throw new Error("schema is required for createTable.");
1024
+ }
1025
+ } catch (error) {
1026
+ throw new MastraError(
1027
+ {
1028
+ id: "STORAGE_LANCE_STORAGE_CREATE_TABLE_INVALID_ARGS",
1029
+ domain: ErrorDomain.STORAGE,
1030
+ category: ErrorCategory.USER,
1031
+ details: { tableName }
1032
+ },
1033
+ error
1034
+ );
1035
+ }
1036
+ try {
1037
+ const arrowSchema = this.translateSchema(schema);
1038
+ await this.client.createEmptyTable(tableName, arrowSchema);
1039
+ } catch (error) {
1040
+ if (error.message?.includes("already exists")) {
1041
+ this.logger.debug(`Table '${tableName}' already exists, skipping create`);
1042
+ return;
1043
+ }
1044
+ throw new MastraError(
1045
+ {
1046
+ id: "STORAGE_LANCE_STORAGE_CREATE_TABLE_FAILED",
1047
+ domain: ErrorDomain.STORAGE,
1048
+ category: ErrorCategory.THIRD_PARTY,
1049
+ details: { tableName }
1050
+ },
1051
+ error
1052
+ );
1053
+ }
1054
+ }
1055
+ async dropTable({ tableName }) {
1056
+ try {
1057
+ if (!this.client) {
1058
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1059
+ }
1060
+ if (!tableName) {
1061
+ throw new Error("tableName is required for dropTable.");
1062
+ }
1063
+ } catch (validationError) {
1064
+ throw new MastraError(
1065
+ {
1066
+ id: "STORAGE_LANCE_STORAGE_DROP_TABLE_INVALID_ARGS",
1067
+ domain: ErrorDomain.STORAGE,
1068
+ category: ErrorCategory.USER,
1069
+ text: validationError.message,
1070
+ details: { tableName }
1071
+ },
1072
+ validationError
1073
+ );
1074
+ }
1075
+ try {
1076
+ await this.client.dropTable(tableName);
1077
+ } catch (error) {
1078
+ if (error.toString().includes("was not found") || error.message?.includes("Table not found")) {
1079
+ this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
1080
+ return;
1081
+ }
1082
+ throw new MastraError(
1083
+ {
1084
+ id: "STORAGE_LANCE_STORAGE_DROP_TABLE_FAILED",
1085
+ domain: ErrorDomain.STORAGE,
1086
+ category: ErrorCategory.THIRD_PARTY,
1087
+ details: { tableName }
1088
+ },
1089
+ error
1090
+ );
1091
+ }
1092
+ }
1093
+ async alterTable({
1094
+ tableName,
1095
+ schema,
1096
+ ifNotExists
1097
+ }) {
1098
+ try {
1099
+ if (!this.client) {
1100
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1101
+ }
1102
+ if (!tableName) {
1103
+ throw new Error("tableName is required for alterTable.");
1104
+ }
1105
+ if (!schema) {
1106
+ throw new Error("schema is required for alterTable.");
1107
+ }
1108
+ if (!ifNotExists || ifNotExists.length === 0) {
1109
+ this.logger.debug("No columns specified to add in alterTable, skipping.");
1110
+ return;
1111
+ }
1112
+ } catch (validationError) {
1113
+ throw new MastraError(
1114
+ {
1115
+ id: "STORAGE_LANCE_STORAGE_ALTER_TABLE_INVALID_ARGS",
1116
+ domain: ErrorDomain.STORAGE,
1117
+ category: ErrorCategory.USER,
1118
+ text: validationError.message,
1119
+ details: { tableName }
1120
+ },
1121
+ validationError
1122
+ );
1123
+ }
1124
+ try {
1125
+ const table = await this.client.openTable(tableName);
1126
+ const currentSchema = await table.schema();
1127
+ const existingFields = new Set(currentSchema.fields.map((f) => f.name));
1128
+ const typeMap = {
1129
+ text: "string",
1130
+ integer: "int",
1131
+ bigint: "bigint",
1132
+ timestamp: "timestamp",
1133
+ jsonb: "string",
1134
+ uuid: "string"
1135
+ };
1136
+ const columnsToAdd = ifNotExists.filter((col) => schema[col] && !existingFields.has(col)).map((col) => {
1137
+ const colDef = schema[col];
1138
+ return {
1139
+ name: col,
1140
+ valueSql: colDef?.nullable ? `cast(NULL as ${typeMap[colDef.type ?? "text"]})` : `cast(${this.getDefaultValue(colDef?.type ?? "text")} as ${typeMap[colDef?.type ?? "text"]})`
1141
+ };
1142
+ });
1143
+ if (columnsToAdd.length > 0) {
1144
+ await table.addColumns(columnsToAdd);
1145
+ this.logger?.info?.(`Added columns [${columnsToAdd.map((c) => c.name).join(", ")}] to table ${tableName}`);
1146
+ }
1147
+ } catch (error) {
1148
+ throw new MastraError(
1149
+ {
1150
+ id: "STORAGE_LANCE_STORAGE_ALTER_TABLE_FAILED",
1151
+ domain: ErrorDomain.STORAGE,
1152
+ category: ErrorCategory.THIRD_PARTY,
1153
+ details: { tableName }
1154
+ },
1155
+ error
1156
+ );
1157
+ }
1158
+ }
1159
+ async clearTable({ tableName }) {
1160
+ try {
1161
+ if (!this.client) {
1162
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1163
+ }
1164
+ if (!tableName) {
1165
+ throw new Error("tableName is required for clearTable.");
1166
+ }
1167
+ } catch (validationError) {
1168
+ throw new MastraError(
1169
+ {
1170
+ id: "STORAGE_LANCE_STORAGE_CLEAR_TABLE_INVALID_ARGS",
1171
+ domain: ErrorDomain.STORAGE,
1172
+ category: ErrorCategory.USER,
1173
+ text: validationError.message,
1174
+ details: { tableName }
1175
+ },
1176
+ validationError
1177
+ );
1178
+ }
1179
+ try {
1180
+ const table = await this.client.openTable(tableName);
1181
+ await table.delete("1=1");
1182
+ } catch (error) {
1183
+ throw new MastraError(
1184
+ {
1185
+ id: "STORAGE_LANCE_STORAGE_CLEAR_TABLE_FAILED",
1186
+ domain: ErrorDomain.STORAGE,
1187
+ category: ErrorCategory.THIRD_PARTY,
1188
+ details: { tableName }
1189
+ },
1190
+ error
1191
+ );
1192
+ }
1193
+ }
1194
+ async insert({ tableName, record }) {
1195
+ try {
1196
+ if (!this.client) {
1197
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1198
+ }
1199
+ if (!tableName) {
1200
+ throw new Error("tableName is required for insert.");
1201
+ }
1202
+ if (!record || Object.keys(record).length === 0) {
1203
+ throw new Error("record is required and cannot be empty for insert.");
1204
+ }
1205
+ } catch (validationError) {
1206
+ throw new MastraError(
1207
+ {
1208
+ id: "STORAGE_LANCE_STORAGE_INSERT_INVALID_ARGS",
1209
+ domain: ErrorDomain.STORAGE,
1210
+ category: ErrorCategory.USER,
1211
+ text: validationError.message,
1212
+ details: { tableName }
1213
+ },
1214
+ validationError
1215
+ );
1216
+ }
1217
+ try {
1218
+ const table = await this.client.openTable(tableName);
1219
+ const primaryId = getPrimaryKeys(tableName);
1220
+ const processedRecord = { ...record };
1221
+ for (const key in processedRecord) {
1222
+ if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
1223
+ this.logger.debug("Converting object to JSON string: ", processedRecord[key]);
1224
+ processedRecord[key] = JSON.stringify(processedRecord[key]);
1225
+ }
1226
+ }
1227
+ console.log(await table.schema());
1228
+ await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([processedRecord]);
1229
+ } catch (error) {
1230
+ throw new MastraError(
1231
+ {
1232
+ id: "STORAGE_LANCE_STORAGE_INSERT_FAILED",
1233
+ domain: ErrorDomain.STORAGE,
1234
+ category: ErrorCategory.THIRD_PARTY,
1235
+ details: { tableName }
1236
+ },
1237
+ error
1238
+ );
1239
+ }
1240
+ }
1241
+ async batchInsert({ tableName, records }) {
1242
+ try {
1243
+ if (!this.client) {
1244
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1245
+ }
1246
+ if (!tableName) {
1247
+ throw new Error("tableName is required for batchInsert.");
1248
+ }
1249
+ if (!records || records.length === 0) {
1250
+ throw new Error("records array is required and cannot be empty for batchInsert.");
1251
+ }
1252
+ } catch (validationError) {
1253
+ throw new MastraError(
1254
+ {
1255
+ id: "STORAGE_LANCE_STORAGE_BATCH_INSERT_INVALID_ARGS",
1256
+ domain: ErrorDomain.STORAGE,
1257
+ category: ErrorCategory.USER,
1258
+ text: validationError.message,
1259
+ details: { tableName }
1260
+ },
1261
+ validationError
1262
+ );
1263
+ }
1264
+ try {
1265
+ const table = await this.client.openTable(tableName);
1266
+ const primaryId = getPrimaryKeys(tableName);
1267
+ const processedRecords = records.map((record) => {
1268
+ const processedRecord = { ...record };
1269
+ for (const key in processedRecord) {
1270
+ if (processedRecord[key] == null) continue;
1271
+ if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
1272
+ processedRecord[key] = JSON.stringify(processedRecord[key]);
1273
+ }
1274
+ }
1275
+ return processedRecord;
1276
+ });
1277
+ console.log(processedRecords);
1278
+ await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(processedRecords);
1279
+ } catch (error) {
1280
+ throw new MastraError(
1281
+ {
1282
+ id: "STORAGE_LANCE_STORAGE_BATCH_INSERT_FAILED",
1283
+ domain: ErrorDomain.STORAGE,
1284
+ category: ErrorCategory.THIRD_PARTY,
1285
+ details: { tableName }
1286
+ },
1287
+ error
1288
+ );
1289
+ }
1290
+ }
1291
+ async load({ tableName, keys }) {
1292
+ try {
1293
+ if (!this.client) {
1294
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1295
+ }
1296
+ if (!tableName) {
1297
+ throw new Error("tableName is required for load.");
1298
+ }
1299
+ if (!keys || Object.keys(keys).length === 0) {
1300
+ throw new Error("keys are required and cannot be empty for load.");
1301
+ }
1302
+ } catch (validationError) {
1303
+ throw new MastraError(
1304
+ {
1305
+ id: "STORAGE_LANCE_STORAGE_LOAD_INVALID_ARGS",
1306
+ domain: ErrorDomain.STORAGE,
1307
+ category: ErrorCategory.USER,
1308
+ text: validationError.message,
1309
+ details: { tableName }
1310
+ },
1311
+ validationError
1312
+ );
1313
+ }
1314
+ try {
1315
+ const table = await this.client.openTable(tableName);
1316
+ const tableSchema = await getTableSchema({ tableName, client: this.client });
1317
+ const query = table.query();
1318
+ if (Object.keys(keys).length > 0) {
1319
+ validateKeyTypes(keys, tableSchema);
1320
+ const filterConditions = Object.entries(keys).map(([key, value]) => {
1321
+ const isCamelCase = /^[a-z][a-zA-Z]*$/.test(key) && /[A-Z]/.test(key);
1322
+ const quotedKey = isCamelCase ? `\`${key}\`` : key;
1323
+ if (typeof value === "string") {
1324
+ return `${quotedKey} = '${value}'`;
1325
+ } else if (value === null) {
1326
+ return `${quotedKey} IS NULL`;
1327
+ } else {
1328
+ return `${quotedKey} = ${value}`;
1329
+ }
1330
+ }).join(" AND ");
1331
+ this.logger.debug("where clause generated: " + filterConditions);
1332
+ query.where(filterConditions);
1333
+ }
1334
+ const result = await query.limit(1).toArray();
1335
+ if (result.length === 0) {
1336
+ this.logger.debug("No record found");
1337
+ return null;
1338
+ }
1339
+ return processResultWithTypeConversion(result[0], tableSchema);
1340
+ } catch (error) {
1341
+ if (error instanceof MastraError) throw error;
1342
+ throw new MastraError(
1343
+ {
1344
+ id: "STORAGE_LANCE_STORAGE_LOAD_FAILED",
1345
+ domain: ErrorDomain.STORAGE,
1346
+ category: ErrorCategory.THIRD_PARTY,
1347
+ details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
1348
+ },
1349
+ error
1350
+ );
1351
+ }
1352
+ }
1353
+ };
1354
+ var StoreScoresLance = class extends ScoresStorage {
1355
+ client;
1356
+ constructor({ client }) {
1357
+ super();
1358
+ this.client = client;
1359
+ }
1360
+ async saveScore(score) {
1361
+ try {
1362
+ const table = await this.client.openTable(TABLE_SCORERS);
1363
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1364
+ const allowedFields = new Set(schema.fields.map((f) => f.name));
1365
+ const filteredScore = {};
1366
+ Object.keys(score).forEach((key) => {
1367
+ if (allowedFields.has(key)) {
1368
+ filteredScore[key] = score[key];
1369
+ }
1370
+ });
1371
+ for (const key in filteredScore) {
1372
+ if (filteredScore[key] !== null && typeof filteredScore[key] === "object" && !(filteredScore[key] instanceof Date)) {
1373
+ filteredScore[key] = JSON.stringify(filteredScore[key]);
1374
+ }
1375
+ }
1376
+ console.log("Saving score to LanceStorage:", filteredScore);
1377
+ await table.add([filteredScore], { mode: "append" });
1378
+ return { score };
1379
+ } catch (error) {
1380
+ throw new MastraError(
1381
+ {
1382
+ id: "LANCE_STORAGE_SAVE_SCORE_FAILED",
1383
+ text: "Failed to save score in LanceStorage",
1384
+ domain: ErrorDomain.STORAGE,
1385
+ category: ErrorCategory.THIRD_PARTY,
1386
+ details: { error: error?.message }
1387
+ },
1388
+ error
1389
+ );
1390
+ }
1391
+ }
1392
+ async getScoreById({ id }) {
1393
+ try {
1394
+ const table = await this.client.openTable(TABLE_SCORERS);
1395
+ const query = table.query().where(`id = '${id}'`).limit(1);
1396
+ const records = await query.toArray();
1397
+ if (records.length === 0) return null;
1398
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1399
+ return processResultWithTypeConversion(records[0], schema);
1400
+ } catch (error) {
1401
+ throw new MastraError(
1402
+ {
1403
+ id: "LANCE_STORAGE_GET_SCORE_BY_ID_FAILED",
1404
+ text: "Failed to get score by id in LanceStorage",
1405
+ domain: ErrorDomain.STORAGE,
1406
+ category: ErrorCategory.THIRD_PARTY,
1407
+ details: { error: error?.message }
1408
+ },
1409
+ error
1410
+ );
1411
+ }
1412
+ }
1413
+ async getScoresByScorerId({
1414
+ scorerId,
1415
+ pagination
1416
+ }) {
1417
+ try {
1418
+ const table = await this.client.openTable(TABLE_SCORERS);
1419
+ const { page = 0, perPage = 10 } = pagination || {};
1420
+ const offset = page * perPage;
1421
+ const query = table.query().where(`\`scorerId\` = '${scorerId}'`).limit(perPage);
1422
+ if (offset > 0) query.offset(offset);
1423
+ const records = await query.toArray();
1424
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1425
+ const scores = processResultWithTypeConversion(records, schema);
1426
+ const allRecords = await table.query().where(`\`scorerId\` = '${scorerId}'`).toArray();
1427
+ const total = allRecords.length;
1428
+ return {
1429
+ pagination: {
1430
+ page,
1431
+ perPage,
1432
+ total,
1433
+ hasMore: offset + scores.length < total
1434
+ },
1435
+ scores
1436
+ };
1437
+ } catch (error) {
1438
+ throw new MastraError(
1439
+ {
1440
+ id: "LANCE_STORAGE_GET_SCORES_BY_SCORER_ID_FAILED",
1441
+ text: "Failed to get scores by scorerId in LanceStorage",
1442
+ domain: ErrorDomain.STORAGE,
1443
+ category: ErrorCategory.THIRD_PARTY,
1444
+ details: { error: error?.message }
1445
+ },
1446
+ error
1447
+ );
1448
+ }
1449
+ }
1450
+ async getScoresByRunId({
1451
+ runId,
1452
+ pagination
1453
+ }) {
1454
+ try {
1455
+ const table = await this.client.openTable(TABLE_SCORERS);
1456
+ const { page = 0, perPage = 10 } = pagination || {};
1457
+ const offset = page * perPage;
1458
+ const query = table.query().where(`\`runId\` = '${runId}'`).limit(perPage);
1459
+ if (offset > 0) query.offset(offset);
1460
+ const records = await query.toArray();
1461
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1462
+ const scores = processResultWithTypeConversion(records, schema);
1463
+ const allRecords = await table.query().where(`\`runId\` = '${runId}'`).toArray();
1464
+ const total = allRecords.length;
1465
+ return {
1466
+ pagination: {
1467
+ page,
1468
+ perPage,
1469
+ total,
1470
+ hasMore: offset + scores.length < total
1471
+ },
1472
+ scores
1473
+ };
1474
+ } catch (error) {
1475
+ throw new MastraError(
1476
+ {
1477
+ id: "LANCE_STORAGE_GET_SCORES_BY_RUN_ID_FAILED",
1478
+ text: "Failed to get scores by runId in LanceStorage",
1479
+ domain: ErrorDomain.STORAGE,
1480
+ category: ErrorCategory.THIRD_PARTY,
1481
+ details: { error: error?.message }
1482
+ },
1483
+ error
1484
+ );
1485
+ }
1486
+ }
1487
+ async getScoresByEntityId({
1488
+ entityId,
1489
+ entityType,
1490
+ pagination
1491
+ }) {
1492
+ try {
1493
+ const table = await this.client.openTable(TABLE_SCORERS);
1494
+ const { page = 0, perPage = 10 } = pagination || {};
1495
+ const offset = page * perPage;
1496
+ const query = table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).limit(perPage);
1497
+ if (offset > 0) query.offset(offset);
1498
+ const records = await query.toArray();
1499
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1500
+ const scores = processResultWithTypeConversion(records, schema);
1501
+ const allRecords = await table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).toArray();
1502
+ const total = allRecords.length;
1503
+ return {
1504
+ pagination: {
1505
+ page,
1506
+ perPage,
1507
+ total,
1508
+ hasMore: offset + scores.length < total
1509
+ },
1510
+ scores
1511
+ };
1512
+ } catch (error) {
1513
+ throw new MastraError(
1514
+ {
1515
+ id: "LANCE_STORAGE_GET_SCORES_BY_ENTITY_ID_FAILED",
1516
+ text: "Failed to get scores by entityId and entityType in LanceStorage",
1517
+ domain: ErrorDomain.STORAGE,
1518
+ category: ErrorCategory.THIRD_PARTY,
1519
+ details: { error: error?.message }
1520
+ },
1521
+ error
1522
+ );
1523
+ }
1524
+ }
1525
+ };
1526
+ var StoreTracesLance = class extends TracesStorage {
1527
+ client;
1528
+ operations;
1529
+ constructor({ client, operations }) {
1530
+ super();
1531
+ this.client = client;
1532
+ this.operations = operations;
1533
+ }
1534
+ async saveTrace({ trace }) {
1535
+ try {
1536
+ const table = await this.client.openTable(TABLE_TRACES);
1537
+ const record = {
1538
+ ...trace,
1539
+ attributes: JSON.stringify(trace.attributes),
1540
+ status: JSON.stringify(trace.status),
1541
+ events: JSON.stringify(trace.events),
1542
+ links: JSON.stringify(trace.links),
1543
+ other: JSON.stringify(trace.other)
1544
+ };
1545
+ await table.add([record], { mode: "append" });
1546
+ return trace;
1547
+ } catch (error) {
1548
+ throw new MastraError(
1549
+ {
1550
+ id: "LANCE_STORE_SAVE_TRACE_FAILED",
1551
+ domain: ErrorDomain.STORAGE,
1552
+ category: ErrorCategory.THIRD_PARTY
1553
+ },
1554
+ error
1555
+ );
1556
+ }
1557
+ }
1558
+ async getTraceById({ traceId }) {
1559
+ try {
1560
+ const table = await this.client.openTable(TABLE_TRACES);
1561
+ const query = table.query().where(`id = '${traceId}'`);
1562
+ const records = await query.toArray();
1563
+ return records[0];
1564
+ } catch (error) {
1565
+ throw new MastraError(
1566
+ {
1567
+ id: "LANCE_STORE_GET_TRACE_BY_ID_FAILED",
1568
+ domain: ErrorDomain.STORAGE,
1569
+ category: ErrorCategory.THIRD_PARTY
1570
+ },
1571
+ error
1572
+ );
1573
+ }
1574
+ }
1575
+ async getTraces({
1576
+ name,
1577
+ scope,
1578
+ page = 1,
1579
+ perPage = 10,
1580
+ attributes
1581
+ }) {
1582
+ try {
1583
+ const table = await this.client.openTable(TABLE_TRACES);
1584
+ const query = table.query();
1585
+ if (name) {
1586
+ query.where(`name = '${name}'`);
1587
+ }
1588
+ if (scope) {
1589
+ query.where(`scope = '${scope}'`);
1590
+ }
1591
+ if (attributes) {
1592
+ query.where(`attributes = '${JSON.stringify(attributes)}'`);
1593
+ }
1594
+ const offset = (page - 1) * perPage;
1595
+ query.limit(perPage);
1596
+ if (offset > 0) {
1597
+ query.offset(offset);
1598
+ }
1599
+ const records = await query.toArray();
1600
+ return records.map((record) => {
1601
+ const processed = {
1602
+ ...record,
1603
+ attributes: record.attributes ? JSON.parse(record.attributes) : {},
1604
+ status: record.status ? JSON.parse(record.status) : {},
1605
+ events: record.events ? JSON.parse(record.events) : [],
1606
+ links: record.links ? JSON.parse(record.links) : [],
1607
+ other: record.other ? JSON.parse(record.other) : {},
1608
+ startTime: new Date(record.startTime),
1609
+ endTime: new Date(record.endTime),
1610
+ createdAt: new Date(record.createdAt)
1611
+ };
1612
+ if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
1613
+ processed.parentSpanId = "";
1614
+ } else {
1615
+ processed.parentSpanId = String(processed.parentSpanId);
1616
+ }
1617
+ return processed;
1618
+ });
1619
+ } catch (error) {
1620
+ throw new MastraError(
1621
+ {
1622
+ id: "LANCE_STORE_GET_TRACES_FAILED",
1623
+ domain: ErrorDomain.STORAGE,
1624
+ category: ErrorCategory.THIRD_PARTY,
1625
+ details: { name: name ?? "", scope: scope ?? "" }
1626
+ },
1627
+ error
1628
+ );
1629
+ }
1630
+ }
1631
+ async getTracesPaginated(args) {
1632
+ try {
1633
+ const table = await this.client.openTable(TABLE_TRACES);
1634
+ const query = table.query();
1635
+ const conditions = [];
1636
+ if (args.name) {
1637
+ conditions.push(`name = '${args.name}'`);
1638
+ }
1639
+ if (args.scope) {
1640
+ conditions.push(`scope = '${args.scope}'`);
1641
+ }
1642
+ if (args.attributes) {
1643
+ const attributesStr = JSON.stringify(args.attributes);
1644
+ conditions.push(`attributes LIKE '%${attributesStr.replace(/"/g, '\\"')}%'`);
1645
+ }
1646
+ if (args.dateRange?.start) {
1647
+ conditions.push(`\`createdAt\` >= ${args.dateRange.start.getTime()}`);
1648
+ }
1649
+ if (args.dateRange?.end) {
1650
+ conditions.push(`\`createdAt\` <= ${args.dateRange.end.getTime()}`);
1651
+ }
1652
+ if (conditions.length > 0) {
1653
+ const whereClause = conditions.join(" AND ");
1654
+ query.where(whereClause);
1655
+ }
1656
+ let total = 0;
1657
+ if (conditions.length > 0) {
1658
+ const countQuery = table.query().where(conditions.join(" AND "));
1659
+ const allRecords = await countQuery.toArray();
1660
+ total = allRecords.length;
1661
+ } else {
1662
+ total = await table.countRows();
1663
+ }
1664
+ const page = args.page || 0;
1665
+ const perPage = args.perPage || 10;
1666
+ const offset = page * perPage;
1667
+ query.limit(perPage);
1668
+ if (offset > 0) {
1669
+ query.offset(offset);
1670
+ }
1671
+ const records = await query.toArray();
1672
+ const traces = records.map((record) => {
1673
+ const processed = {
1674
+ ...record,
1675
+ attributes: record.attributes ? JSON.parse(record.attributes) : {},
1676
+ status: record.status ? JSON.parse(record.status) : {},
1677
+ events: record.events ? JSON.parse(record.events) : [],
1678
+ links: record.links ? JSON.parse(record.links) : [],
1679
+ other: record.other ? JSON.parse(record.other) : {},
1680
+ startTime: new Date(record.startTime),
1681
+ endTime: new Date(record.endTime),
1682
+ createdAt: new Date(record.createdAt)
1683
+ };
1684
+ if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
1685
+ processed.parentSpanId = "";
1686
+ } else {
1687
+ processed.parentSpanId = String(processed.parentSpanId);
1688
+ }
1689
+ return processed;
1690
+ });
1691
+ return {
1692
+ traces,
1693
+ total,
1694
+ page,
1695
+ perPage,
1696
+ hasMore: total > (page + 1) * perPage
1697
+ };
1698
+ } catch (error) {
1699
+ throw new MastraError(
1700
+ {
1701
+ id: "LANCE_STORE_GET_TRACES_PAGINATED_FAILED",
1702
+ domain: ErrorDomain.STORAGE,
1703
+ category: ErrorCategory.THIRD_PARTY,
1704
+ details: { name: args.name ?? "", scope: args.scope ?? "" }
1705
+ },
1706
+ error
1707
+ );
1708
+ }
1709
+ }
1710
+ async batchTraceInsert({ records }) {
1711
+ this.logger.debug("Batch inserting traces", { count: records.length });
1712
+ await this.operations.batchInsert({
1713
+ tableName: TABLE_TRACES,
1714
+ records
1715
+ });
1716
+ }
1717
+ };
1718
+ function parseWorkflowRun(row) {
1719
+ let parsedSnapshot = row.snapshot;
1720
+ if (typeof parsedSnapshot === "string") {
1721
+ try {
1722
+ parsedSnapshot = JSON.parse(row.snapshot);
1723
+ } catch (e) {
1724
+ console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
1725
+ }
1726
+ }
1727
+ return {
1728
+ workflowName: row.workflow_name,
1729
+ runId: row.run_id,
1730
+ snapshot: parsedSnapshot,
1731
+ createdAt: ensureDate(row.createdAt),
1732
+ updatedAt: ensureDate(row.updatedAt),
1733
+ resourceId: row.resourceId
1734
+ };
1735
+ }
1736
+ var StoreWorkflowsLance = class extends WorkflowsStorage {
1737
+ client;
1738
+ constructor({ client }) {
1739
+ super();
1740
+ this.client = client;
1741
+ }
1742
+ async persistWorkflowSnapshot({
1743
+ workflowName,
1744
+ runId,
1745
+ snapshot
1746
+ }) {
1747
+ try {
1748
+ const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1749
+ const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
1750
+ const records = await query.toArray();
1751
+ let createdAt;
1752
+ const now = Date.now();
1753
+ if (records.length > 0) {
1754
+ createdAt = records[0].createdAt ?? now;
1755
+ } else {
1756
+ createdAt = now;
1757
+ }
1758
+ const record = {
1759
+ workflow_name: workflowName,
1760
+ run_id: runId,
1761
+ snapshot: JSON.stringify(snapshot),
1762
+ createdAt,
1763
+ updatedAt: now
1764
+ };
1765
+ await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
1766
+ } catch (error) {
1767
+ throw new MastraError(
1768
+ {
1769
+ id: "LANCE_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
1770
+ domain: ErrorDomain.STORAGE,
1771
+ category: ErrorCategory.THIRD_PARTY,
1772
+ details: { workflowName, runId }
1773
+ },
1774
+ error
1775
+ );
1776
+ }
1777
+ }
1778
+ async loadWorkflowSnapshot({
1779
+ workflowName,
1780
+ runId
1781
+ }) {
1782
+ try {
1783
+ const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1784
+ const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
1785
+ const records = await query.toArray();
1786
+ return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
1787
+ } catch (error) {
1788
+ throw new MastraError(
1789
+ {
1790
+ id: "LANCE_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
1791
+ domain: ErrorDomain.STORAGE,
1792
+ category: ErrorCategory.THIRD_PARTY,
1793
+ details: { workflowName, runId }
1794
+ },
1795
+ error
1796
+ );
1797
+ }
1798
+ }
1799
+ async getWorkflowRunById(args) {
1800
+ try {
1801
+ const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1802
+ let whereClause = `run_id = '${args.runId}'`;
1803
+ if (args.workflowName) {
1804
+ whereClause += ` AND workflow_name = '${args.workflowName}'`;
1805
+ }
1806
+ const query = table.query().where(whereClause);
1807
+ const records = await query.toArray();
1808
+ if (records.length === 0) return null;
1809
+ const record = records[0];
1810
+ return parseWorkflowRun(record);
1811
+ } catch (error) {
1812
+ throw new MastraError(
1813
+ {
1814
+ id: "LANCE_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
1815
+ domain: ErrorDomain.STORAGE,
1816
+ category: ErrorCategory.THIRD_PARTY,
1817
+ details: { runId: args.runId, workflowName: args.workflowName ?? "" }
1818
+ },
1819
+ error
1820
+ );
1821
+ }
1822
+ }
1823
+ async getWorkflowRuns(args) {
1824
+ try {
1825
+ const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1826
+ let query = table.query();
1827
+ const conditions = [];
1828
+ if (args?.workflowName) {
1829
+ conditions.push(`workflow_name = '${args.workflowName.replace(/'/g, "''")}'`);
1830
+ }
1831
+ if (args?.resourceId) {
1832
+ conditions.push(`\`resourceId\` = '${args.resourceId}'`);
1833
+ }
1834
+ if (args?.fromDate instanceof Date) {
1835
+ conditions.push(`\`createdAt\` >= ${args.fromDate.getTime()}`);
1836
+ }
1837
+ if (args?.toDate instanceof Date) {
1838
+ conditions.push(`\`createdAt\` <= ${args.toDate.getTime()}`);
1839
+ }
1840
+ let total = 0;
1841
+ if (conditions.length > 0) {
1842
+ query = query.where(conditions.join(" AND "));
1843
+ total = await table.countRows(conditions.join(" AND "));
1844
+ } else {
1845
+ total = await table.countRows();
1846
+ }
1847
+ if (args?.limit) {
1848
+ query.limit(args.limit);
1849
+ }
1850
+ if (args?.offset) {
1851
+ query.offset(args.offset);
1852
+ }
1853
+ const records = await query.toArray();
1854
+ return {
1855
+ runs: records.map((record) => parseWorkflowRun(record)),
1856
+ total: total || records.length
1857
+ };
1858
+ } catch (error) {
1859
+ throw new MastraError(
1860
+ {
1861
+ id: "LANCE_STORE_GET_WORKFLOW_RUNS_FAILED",
1862
+ domain: ErrorDomain.STORAGE,
1863
+ category: ErrorCategory.THIRD_PARTY,
1864
+ details: { namespace: args?.namespace ?? "", workflowName: args?.workflowName ?? "" }
1865
+ },
1866
+ error
1867
+ );
1868
+ }
1869
+ }
1870
+ };
1871
+
8
1872
  // src/storage/index.ts
9
1873
  var LanceStorage = class _LanceStorage extends MastraStorage {
1874
+ stores;
10
1875
  lanceClient;
11
1876
  /**
12
1877
  * Creates a new instance of LanceStorage
@@ -34,9 +1899,27 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
34
1899
  const instance = new _LanceStorage(name);
35
1900
  try {
36
1901
  instance.lanceClient = await connect(uri, options);
1902
+ const operations = new StoreOperationsLance({ client: instance.lanceClient });
1903
+ instance.stores = {
1904
+ operations: new StoreOperationsLance({ client: instance.lanceClient }),
1905
+ workflows: new StoreWorkflowsLance({ client: instance.lanceClient }),
1906
+ traces: new StoreTracesLance({ client: instance.lanceClient, operations }),
1907
+ scores: new StoreScoresLance({ client: instance.lanceClient }),
1908
+ memory: new StoreMemoryLance({ client: instance.lanceClient, operations }),
1909
+ legacyEvals: new StoreLegacyEvalsLance({ client: instance.lanceClient })
1910
+ };
37
1911
  return instance;
38
1912
  } catch (e) {
39
- throw new Error(`Failed to connect to LanceDB: ${e}`);
1913
+ throw new MastraError(
1914
+ {
1915
+ id: "STORAGE_LANCE_STORAGE_CONNECT_FAILED",
1916
+ domain: ErrorDomain.STORAGE,
1917
+ category: ErrorCategory.THIRD_PARTY,
1918
+ text: `Failed to connect to LanceDB: ${e.message || e}`,
1919
+ details: { uri, optionsProvided: !!options }
1920
+ },
1921
+ e
1922
+ );
40
1923
  }
41
1924
  }
42
1925
  /**
@@ -45,312 +1928,49 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
45
1928
  */
46
1929
  constructor(name) {
47
1930
  super({ name });
1931
+ const operations = new StoreOperationsLance({ client: this.lanceClient });
1932
+ this.stores = {
1933
+ operations: new StoreOperationsLance({ client: this.lanceClient }),
1934
+ workflows: new StoreWorkflowsLance({ client: this.lanceClient }),
1935
+ traces: new StoreTracesLance({ client: this.lanceClient, operations }),
1936
+ scores: new StoreScoresLance({ client: this.lanceClient }),
1937
+ legacyEvals: new StoreLegacyEvalsLance({ client: this.lanceClient }),
1938
+ memory: new StoreMemoryLance({ client: this.lanceClient, operations })
1939
+ };
48
1940
  }
49
1941
  async createTable({
50
1942
  tableName,
51
1943
  schema
52
1944
  }) {
53
- try {
54
- const arrowSchema = this.translateSchema(schema);
55
- await this.lanceClient.createEmptyTable(tableName, arrowSchema);
56
- } catch (error) {
57
- throw new Error(`Failed to create table: ${error}`);
58
- }
59
- }
60
- translateSchema(schema) {
61
- const fields = Object.entries(schema).map(([name, column]) => {
62
- let arrowType;
63
- switch (column.type.toLowerCase()) {
64
- case "text":
65
- case "uuid":
66
- arrowType = new Utf8();
67
- break;
68
- case "int":
69
- case "integer":
70
- arrowType = new Int32();
71
- break;
72
- case "bigint":
73
- arrowType = new Float64();
74
- break;
75
- case "float":
76
- arrowType = new Float32();
77
- break;
78
- case "jsonb":
79
- case "json":
80
- arrowType = new Utf8();
81
- break;
82
- case "binary":
83
- arrowType = new Binary();
84
- break;
85
- case "timestamp":
86
- arrowType = new Float64();
87
- break;
88
- default:
89
- arrowType = new Utf8();
90
- }
91
- return new Field(name, arrowType, column.nullable ?? true);
92
- });
93
- return new Schema(fields);
94
- }
95
- /**
96
- * Drop a table if it exists
97
- * @param tableName Name of the table to drop
98
- */
99
- async dropTable(tableName) {
100
- try {
101
- await this.lanceClient.dropTable(tableName);
102
- } catch (error) {
103
- if (error.toString().includes("was not found")) {
104
- this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
105
- return;
106
- }
107
- throw new Error(`Failed to drop table: ${error}`);
108
- }
109
- }
110
- /**
111
- * Get table schema
112
- * @param tableName Name of the table
113
- * @returns Table schema
114
- */
115
- async getTableSchema(tableName) {
116
- try {
117
- const table = await this.lanceClient.openTable(tableName);
118
- const rawSchema = await table.schema();
119
- const fields = rawSchema.fields;
120
- return {
121
- fields,
122
- metadata: /* @__PURE__ */ new Map(),
123
- get names() {
124
- return fields.map((field) => field.name);
125
- }
126
- };
127
- } catch (error) {
128
- throw new Error(`Failed to get table schema: ${error}`);
129
- }
1945
+ return this.stores.operations.createTable({ tableName, schema });
130
1946
  }
131
- getDefaultValue(type) {
132
- switch (type) {
133
- case "text":
134
- return "''";
135
- case "timestamp":
136
- return "CURRENT_TIMESTAMP";
137
- case "integer":
138
- case "bigint":
139
- return "0";
140
- case "jsonb":
141
- return "'{}'";
142
- case "uuid":
143
- return "''";
144
- default:
145
- return super.getDefaultValue(type);
146
- }
1947
+ async dropTable({ tableName }) {
1948
+ return this.stores.operations.dropTable({ tableName });
147
1949
  }
148
- /**
149
- * Alters table schema to add columns if they don't exist
150
- * @param tableName Name of the table
151
- * @param schema Schema of the table
152
- * @param ifNotExists Array of column names to add if they don't exist
153
- */
154
1950
  async alterTable({
155
1951
  tableName,
156
1952
  schema,
157
1953
  ifNotExists
158
1954
  }) {
159
- const table = await this.lanceClient.openTable(tableName);
160
- const currentSchema = await table.schema();
161
- const existingFields = new Set(currentSchema.fields.map((f) => f.name));
162
- const typeMap = {
163
- text: "string",
164
- integer: "int",
165
- bigint: "bigint",
166
- timestamp: "timestamp",
167
- jsonb: "string",
168
- uuid: "string"
169
- };
170
- const columnsToAdd = ifNotExists.filter((col) => schema[col] && !existingFields.has(col)).map((col) => {
171
- const colDef = schema[col];
172
- return {
173
- name: col,
174
- valueSql: colDef?.nullable ? `cast(NULL as ${typeMap[colDef.type ?? "text"]})` : `cast(${this.getDefaultValue(colDef?.type ?? "text")} as ${typeMap[colDef?.type ?? "text"]})`
175
- };
176
- });
177
- if (columnsToAdd.length > 0) {
178
- await table.addColumns(columnsToAdd);
179
- this.logger?.info?.(`Added columns [${columnsToAdd.map((c) => c.name).join(", ")}] to table ${tableName}`);
180
- }
1955
+ return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
181
1956
  }
182
1957
  async clearTable({ tableName }) {
183
- const table = await this.lanceClient.openTable(tableName);
184
- await table.delete("1=1");
1958
+ return this.stores.operations.clearTable({ tableName });
185
1959
  }
186
- /**
187
- * Insert a single record into a table. This function overwrites the existing record if it exists. Use this function for inserting records into tables with custom schemas.
188
- * @param tableName The name of the table to insert into.
189
- * @param record The record to insert.
190
- */
191
1960
  async insert({ tableName, record }) {
192
- try {
193
- const table = await this.lanceClient.openTable(tableName);
194
- const processedRecord = { ...record };
195
- for (const key in processedRecord) {
196
- if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
197
- this.logger.debug("Converting object to JSON string: ", processedRecord[key]);
198
- processedRecord[key] = JSON.stringify(processedRecord[key]);
199
- }
200
- }
201
- await table.add([processedRecord], { mode: "overwrite" });
202
- } catch (error) {
203
- throw new Error(`Failed to insert record: ${error}`);
204
- }
1961
+ return this.stores.operations.insert({ tableName, record });
205
1962
  }
206
- /**
207
- * Insert multiple records into a table. This function overwrites the existing records if they exist. Use this function for inserting records into tables with custom schemas.
208
- * @param tableName The name of the table to insert into.
209
- * @param records The records to insert.
210
- */
211
1963
  async batchInsert({ tableName, records }) {
212
- try {
213
- const table = await this.lanceClient.openTable(tableName);
214
- const processedRecords = records.map((record) => {
215
- const processedRecord = { ...record };
216
- for (const key in processedRecord) {
217
- if (processedRecord[key] == null) continue;
218
- if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
219
- processedRecord[key] = JSON.stringify(processedRecord[key]);
220
- }
221
- }
222
- return processedRecord;
223
- });
224
- await table.add(processedRecords, { mode: "overwrite" });
225
- } catch (error) {
226
- throw new Error(`Failed to batch insert records: ${error}`);
227
- }
1964
+ return this.stores.operations.batchInsert({ tableName, records });
228
1965
  }
229
- /**
230
- * Load a record from the database by its key(s)
231
- * @param tableName The name of the table to query
232
- * @param keys Record of key-value pairs to use for lookup
233
- * @throws Error if invalid types are provided for keys
234
- * @returns The loaded record with proper type conversions, or null if not found
235
- */
236
1966
  async load({ tableName, keys }) {
237
- try {
238
- const table = await this.lanceClient.openTable(tableName);
239
- const tableSchema = await this.getTableSchema(tableName);
240
- const query = table.query();
241
- if (Object.keys(keys).length > 0) {
242
- this.validateKeyTypes(keys, tableSchema);
243
- const filterConditions = Object.entries(keys).map(([key, value]) => {
244
- const isCamelCase = /^[a-z][a-zA-Z]*$/.test(key) && /[A-Z]/.test(key);
245
- const quotedKey = isCamelCase ? `\`${key}\`` : key;
246
- if (typeof value === "string") {
247
- return `${quotedKey} = '${value}'`;
248
- } else if (value === null) {
249
- return `${quotedKey} IS NULL`;
250
- } else {
251
- return `${quotedKey} = ${value}`;
252
- }
253
- }).join(" AND ");
254
- this.logger.debug("where clause generated: " + filterConditions);
255
- query.where(filterConditions);
256
- }
257
- const result = await query.limit(1).toArray();
258
- if (result.length === 0) {
259
- this.logger.debug("No record found");
260
- return null;
261
- }
262
- return this.processResultWithTypeConversion(result[0], tableSchema);
263
- } catch (error) {
264
- throw new Error(`Failed to load record: ${error}`);
265
- }
266
- }
267
- /**
268
- * Validates that key types match the schema definition
269
- * @param keys The keys to validate
270
- * @param tableSchema The table schema to validate against
271
- * @throws Error if a key has an incompatible type
272
- */
273
- validateKeyTypes(keys, tableSchema) {
274
- const fieldTypes = new Map(
275
- tableSchema.fields.map((field) => [field.name, field.type?.toString().toLowerCase()])
276
- );
277
- for (const [key, value] of Object.entries(keys)) {
278
- const fieldType = fieldTypes.get(key);
279
- if (!fieldType) {
280
- throw new Error(`Field '${key}' does not exist in table schema`);
281
- }
282
- if (value !== null) {
283
- if ((fieldType.includes("int") || fieldType.includes("bigint")) && typeof value !== "number") {
284
- throw new Error(`Expected numeric value for field '${key}', got ${typeof value}`);
285
- }
286
- if (fieldType.includes("utf8") && typeof value !== "string") {
287
- throw new Error(`Expected string value for field '${key}', got ${typeof value}`);
288
- }
289
- if (fieldType.includes("timestamp") && !(value instanceof Date) && typeof value !== "string") {
290
- throw new Error(`Expected Date or string value for field '${key}', got ${typeof value}`);
291
- }
292
- }
293
- }
294
- }
295
- /**
296
- * Process a database result with appropriate type conversions based on the table schema
297
- * @param rawResult The raw result object from the database
298
- * @param tableSchema The schema of the table containing type information
299
- * @returns Processed result with correct data types
300
- */
301
- processResultWithTypeConversion(rawResult, tableSchema) {
302
- const fieldTypeMap = /* @__PURE__ */ new Map();
303
- tableSchema.fields.forEach((field) => {
304
- const fieldName = field.name;
305
- const fieldTypeStr = field.type.toString().toLowerCase();
306
- fieldTypeMap.set(fieldName, fieldTypeStr);
307
- });
308
- if (Array.isArray(rawResult)) {
309
- return rawResult.map((item) => this.processResultWithTypeConversion(item, tableSchema));
310
- }
311
- const processedResult = { ...rawResult };
312
- for (const key in processedResult) {
313
- const fieldTypeStr = fieldTypeMap.get(key);
314
- if (!fieldTypeStr) continue;
315
- if (typeof processedResult[key] === "string") {
316
- if (fieldTypeStr.includes("int32") || fieldTypeStr.includes("float32")) {
317
- if (!isNaN(Number(processedResult[key]))) {
318
- processedResult[key] = Number(processedResult[key]);
319
- }
320
- } else if (fieldTypeStr.includes("int64")) {
321
- processedResult[key] = Number(processedResult[key]);
322
- } else if (fieldTypeStr.includes("utf8")) {
323
- try {
324
- processedResult[key] = JSON.parse(processedResult[key]);
325
- } catch (e) {
326
- this.logger.debug(`Failed to parse JSON for key ${key}: ${e}`);
327
- }
328
- }
329
- } else if (typeof processedResult[key] === "bigint") {
330
- processedResult[key] = Number(processedResult[key]);
331
- }
332
- }
333
- return processedResult;
1967
+ return this.stores.operations.load({ tableName, keys });
334
1968
  }
335
- getThreadById({ threadId }) {
336
- try {
337
- return this.load({ tableName: TABLE_THREADS, keys: { id: threadId } });
338
- } catch (error) {
339
- throw new Error(`Failed to get thread by ID: ${error}`);
340
- }
1969
+ async getThreadById({ threadId }) {
1970
+ return this.stores.memory.getThreadById({ threadId });
341
1971
  }
342
1972
  async getThreadsByResourceId({ resourceId }) {
343
- try {
344
- const table = await this.lanceClient.openTable(TABLE_THREADS);
345
- const query = table.query().where(`\`resourceId\` = '${resourceId}'`);
346
- const records = await query.toArray();
347
- return this.processResultWithTypeConversion(
348
- records,
349
- await this.getTableSchema(TABLE_THREADS)
350
- );
351
- } catch (error) {
352
- throw new Error(`Failed to get threads by resource ID: ${error}`);
353
- }
1973
+ return this.stores.memory.getThreadsByResourceId({ resourceId });
354
1974
  }
355
1975
  /**
356
1976
  * Saves a thread to the database. This function doesn't overwrite existing threads.
@@ -358,41 +1978,39 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
358
1978
  * @returns The saved thread
359
1979
  */
360
1980
  async saveThread({ thread }) {
361
- try {
362
- const record = { ...thread, metadata: JSON.stringify(thread.metadata) };
363
- const table = await this.lanceClient.openTable(TABLE_THREADS);
364
- await table.add([record], { mode: "append" });
365
- return thread;
366
- } catch (error) {
367
- throw new Error(`Failed to save thread: ${error}`);
368
- }
1981
+ return this.stores.memory.saveThread({ thread });
369
1982
  }
370
1983
  async updateThread({
371
1984
  id,
372
1985
  title,
373
1986
  metadata
374
1987
  }) {
375
- try {
376
- const record = { id, title, metadata: JSON.stringify(metadata) };
377
- const table = await this.lanceClient.openTable(TABLE_THREADS);
378
- await table.add([record], { mode: "overwrite" });
379
- const query = table.query().where(`id = '${id}'`);
380
- const records = await query.toArray();
381
- return this.processResultWithTypeConversion(
382
- records[0],
383
- await this.getTableSchema(TABLE_THREADS)
384
- );
385
- } catch (error) {
386
- throw new Error(`Failed to update thread: ${error}`);
387
- }
1988
+ return this.stores.memory.updateThread({ id, title, metadata });
388
1989
  }
389
1990
  async deleteThread({ threadId }) {
390
- try {
391
- const table = await this.lanceClient.openTable(TABLE_THREADS);
392
- await table.delete(`id = '${threadId}'`);
393
- } catch (error) {
394
- throw new Error(`Failed to delete thread: ${error}`);
395
- }
1991
+ return this.stores.memory.deleteThread({ threadId });
1992
+ }
1993
+ get supports() {
1994
+ return {
1995
+ selectByIncludeResourceScope: true,
1996
+ resourceWorkingMemory: true,
1997
+ hasColumn: true,
1998
+ createTable: true,
1999
+ deleteMessages: false
2000
+ };
2001
+ }
2002
+ async getResourceById({ resourceId }) {
2003
+ return this.stores.memory.getResourceById({ resourceId });
2004
+ }
2005
+ async saveResource({ resource }) {
2006
+ return this.stores.memory.saveResource({ resource });
2007
+ }
2008
+ async updateResource({
2009
+ resourceId,
2010
+ workingMemory,
2011
+ metadata
2012
+ }) {
2013
+ return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
396
2014
  }
397
2015
  /**
398
2016
  * Processes messages to include context messages based on withPreviousMessages and withNextMessages
@@ -448,313 +2066,79 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
448
2066
  selectBy,
449
2067
  format,
450
2068
  threadConfig
451
- }) {
452
- try {
453
- if (threadConfig) {
454
- throw new Error("ThreadConfig is not supported by LanceDB storage");
455
- }
456
- const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: Number.MAX_SAFE_INTEGER });
457
- const table = await this.lanceClient.openTable(TABLE_MESSAGES);
458
- let query = table.query().where(`\`threadId\` = '${threadId}'`);
459
- if (selectBy) {
460
- if (selectBy.include && selectBy.include.length > 0) {
461
- const includeIds = selectBy.include.map((item) => item.id);
462
- const includeClause = includeIds.map((id) => `\`id\` = '${id}'`).join(" OR ");
463
- query = query.where(`(\`threadId\` = '${threadId}' OR (${includeClause}))`);
464
- }
465
- }
466
- let records = await query.toArray();
467
- records.sort((a, b) => {
468
- const dateA = new Date(a.createdAt).getTime();
469
- const dateB = new Date(b.createdAt).getTime();
470
- return dateA - dateB;
471
- });
472
- if (selectBy?.include && selectBy.include.length > 0) {
473
- records = this.processMessagesWithContext(records, selectBy.include);
474
- }
475
- if (limit !== Number.MAX_SAFE_INTEGER) {
476
- records = records.slice(-limit);
477
- }
478
- const messages = this.processResultWithTypeConversion(records, await this.getTableSchema(TABLE_MESSAGES));
479
- const normalized = messages.map((msg) => ({
480
- ...msg,
481
- content: typeof msg.content === "string" ? (() => {
482
- try {
483
- return JSON.parse(msg.content);
484
- } catch {
485
- return msg.content;
486
- }
487
- })() : msg.content
488
- }));
489
- const list = new MessageList({ threadId, resourceId }).add(normalized, "memory");
490
- if (format === "v2") return list.get.all.v2();
491
- return list.get.all.v1();
492
- } catch (error) {
493
- throw new Error(`Failed to get messages: ${error}`);
494
- }
2069
+ }) {
2070
+ return this.stores.memory.getMessages({ threadId, resourceId, selectBy, format, threadConfig });
495
2071
  }
496
2072
  async saveMessages(args) {
497
- try {
498
- const { messages, format = "v1" } = args;
499
- if (messages.length === 0) {
500
- return [];
501
- }
502
- const threadId = messages[0]?.threadId;
503
- if (!threadId) {
504
- throw new Error("Thread ID is required");
505
- }
506
- const transformedMessages = messages.map((message) => ({
507
- ...message,
508
- content: JSON.stringify(message.content)
509
- }));
510
- const table = await this.lanceClient.openTable(TABLE_MESSAGES);
511
- await table.add(transformedMessages, { mode: "overwrite" });
512
- const list = new MessageList().add(messages, "memory");
513
- if (format === `v2`) return list.get.all.v2();
514
- return list.get.all.v1();
515
- } catch (error) {
516
- throw new Error(`Failed to save messages: ${error}`);
517
- }
2073
+ return this.stores.memory.saveMessages(args);
518
2074
  }
519
- async saveTrace({ trace }) {
520
- try {
521
- const table = await this.lanceClient.openTable(TABLE_TRACES);
522
- const record = {
523
- ...trace,
524
- attributes: JSON.stringify(trace.attributes),
525
- status: JSON.stringify(trace.status),
526
- events: JSON.stringify(trace.events),
527
- links: JSON.stringify(trace.links),
528
- other: JSON.stringify(trace.other)
529
- };
530
- await table.add([record], { mode: "append" });
531
- return trace;
532
- } catch (error) {
533
- throw new Error(`Failed to save trace: ${error}`);
534
- }
2075
+ async getThreadsByResourceIdPaginated(args) {
2076
+ return this.stores.memory.getThreadsByResourceIdPaginated(args);
535
2077
  }
536
- async getTraceById({ traceId }) {
537
- try {
538
- const table = await this.lanceClient.openTable(TABLE_TRACES);
539
- const query = table.query().where(`id = '${traceId}'`);
540
- const records = await query.toArray();
541
- return this.processResultWithTypeConversion(records[0], await this.getTableSchema(TABLE_TRACES));
542
- } catch (error) {
543
- throw new Error(`Failed to get trace by ID: ${error}`);
544
- }
2078
+ async getMessagesPaginated(args) {
2079
+ return this.stores.memory.getMessagesPaginated(args);
545
2080
  }
546
- async getTraces({
547
- name,
548
- scope,
549
- page = 1,
550
- perPage = 10,
551
- attributes
552
- }) {
553
- try {
554
- const table = await this.lanceClient.openTable(TABLE_TRACES);
555
- const query = table.query();
556
- if (name) {
557
- query.where(`name = '${name}'`);
558
- }
559
- if (scope) {
560
- query.where(`scope = '${scope}'`);
561
- }
562
- if (attributes) {
563
- query.where(`attributes = '${JSON.stringify(attributes)}'`);
564
- }
565
- const offset = (page - 1) * perPage;
566
- query.limit(perPage);
567
- if (offset > 0) {
568
- query.offset(offset);
569
- }
570
- const records = await query.toArray();
571
- return records.map((record) => {
572
- return {
573
- ...record,
574
- attributes: JSON.parse(record.attributes),
575
- status: JSON.parse(record.status),
576
- events: JSON.parse(record.events),
577
- links: JSON.parse(record.links),
578
- other: JSON.parse(record.other),
579
- startTime: new Date(record.startTime),
580
- endTime: new Date(record.endTime),
581
- createdAt: new Date(record.createdAt)
582
- };
583
- });
584
- } catch (error) {
585
- throw new Error(`Failed to get traces: ${error}`);
586
- }
2081
+ async updateMessages(_args) {
2082
+ return this.stores.memory.updateMessages(_args);
587
2083
  }
588
- async saveEvals({ evals }) {
589
- try {
590
- const table = await this.lanceClient.openTable(TABLE_EVALS);
591
- const transformedEvals = evals.map((evalRecord) => ({
592
- input: evalRecord.input,
593
- output: evalRecord.output,
594
- agent_name: evalRecord.agentName,
595
- metric_name: evalRecord.metricName,
596
- result: JSON.stringify(evalRecord.result),
597
- instructions: evalRecord.instructions,
598
- test_info: JSON.stringify(evalRecord.testInfo),
599
- global_run_id: evalRecord.globalRunId,
600
- run_id: evalRecord.runId,
601
- created_at: new Date(evalRecord.createdAt).getTime()
602
- }));
603
- await table.add(transformedEvals, { mode: "append" });
604
- return evals;
605
- } catch (error) {
606
- throw new Error(`Failed to save evals: ${error}`);
607
- }
2084
+ async getTraceById(args) {
2085
+ return this.stores.traces.getTraceById(args);
2086
+ }
2087
+ async getTraces(args) {
2088
+ return this.stores.traces.getTraces(args);
2089
+ }
2090
+ async getTracesPaginated(args) {
2091
+ return this.stores.traces.getTracesPaginated(args);
608
2092
  }
609
2093
  async getEvalsByAgentName(agentName, type) {
610
- try {
611
- if (type) {
612
- this.logger.warn("Type is not implemented yet in LanceDB storage");
613
- }
614
- const table = await this.lanceClient.openTable(TABLE_EVALS);
615
- const query = table.query().where(`agent_name = '${agentName}'`);
616
- const records = await query.toArray();
617
- return records.map((record) => {
618
- return {
619
- id: record.id,
620
- input: record.input,
621
- output: record.output,
622
- agentName: record.agent_name,
623
- metricName: record.metric_name,
624
- result: JSON.parse(record.result),
625
- instructions: record.instructions,
626
- testInfo: JSON.parse(record.test_info),
627
- globalRunId: record.global_run_id,
628
- runId: record.run_id,
629
- createdAt: new Date(record.created_at).toString()
630
- };
631
- });
632
- } catch (error) {
633
- throw new Error(`Failed to get evals by agent name: ${error}`);
634
- }
2094
+ return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
635
2095
  }
636
- parseWorkflowRun(row) {
637
- let parsedSnapshot = row.snapshot;
638
- if (typeof parsedSnapshot === "string") {
639
- try {
640
- parsedSnapshot = JSON.parse(row.snapshot);
641
- } catch (e) {
642
- console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
643
- }
644
- }
645
- return {
646
- workflowName: row.workflow_name,
647
- runId: row.run_id,
648
- snapshot: parsedSnapshot,
649
- createdAt: this.ensureDate(row.createdAt),
650
- updatedAt: this.ensureDate(row.updatedAt),
651
- resourceId: row.resourceId
652
- };
2096
+ async getEvals(options) {
2097
+ return this.stores.legacyEvals.getEvals(options);
653
2098
  }
654
2099
  async getWorkflowRuns(args) {
655
- try {
656
- const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
657
- const query = table.query();
658
- if (args?.workflowName) {
659
- query.where(`workflow_name = '${args.workflowName}'`);
660
- }
661
- if (args?.fromDate) {
662
- query.where(`\`createdAt\` >= ${args.fromDate.getTime()}`);
663
- }
664
- if (args?.toDate) {
665
- query.where(`\`createdAt\` <= ${args.toDate.getTime()}`);
666
- }
667
- if (args?.limit) {
668
- query.limit(args.limit);
669
- }
670
- if (args?.offset) {
671
- query.offset(args.offset);
672
- }
673
- const records = await query.toArray();
674
- return {
675
- runs: records.map((record) => this.parseWorkflowRun(record)),
676
- total: records.length
677
- };
678
- } catch (error) {
679
- throw new Error(`Failed to get workflow runs: ${error}`);
680
- }
2100
+ return this.stores.workflows.getWorkflowRuns(args);
681
2101
  }
682
- /**
683
- * Retrieve a single workflow run by its runId.
684
- * @param args The ID of the workflow run to retrieve
685
- * @returns The workflow run object or null if not found
686
- */
687
2102
  async getWorkflowRunById(args) {
688
- try {
689
- const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
690
- let whereClause = `run_id = '${args.runId}'`;
691
- if (args.workflowName) {
692
- whereClause += ` AND workflow_name = '${args.workflowName}'`;
693
- }
694
- const query = table.query().where(whereClause);
695
- const records = await query.toArray();
696
- if (records.length === 0) return null;
697
- const record = records[0];
698
- return this.parseWorkflowRun(record);
699
- } catch (error) {
700
- throw new Error(`Failed to get workflow run by id: ${error}`);
701
- }
2103
+ return this.stores.workflows.getWorkflowRunById(args);
702
2104
  }
703
2105
  async persistWorkflowSnapshot({
704
2106
  workflowName,
705
2107
  runId,
706
2108
  snapshot
707
2109
  }) {
708
- try {
709
- const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
710
- const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
711
- const records = await query.toArray();
712
- let createdAt;
713
- const now = Date.now();
714
- let mode = "append";
715
- if (records.length > 0) {
716
- createdAt = records[0].createdAt ?? now;
717
- mode = "overwrite";
718
- } else {
719
- createdAt = now;
720
- }
721
- const record = {
722
- workflow_name: workflowName,
723
- run_id: runId,
724
- snapshot: JSON.stringify(snapshot),
725
- createdAt,
726
- updatedAt: now
727
- };
728
- await table.add([record], { mode });
729
- } catch (error) {
730
- throw new Error(`Failed to persist workflow snapshot: ${error}`);
731
- }
2110
+ return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
732
2111
  }
733
2112
  async loadWorkflowSnapshot({
734
2113
  workflowName,
735
2114
  runId
736
2115
  }) {
737
- try {
738
- const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
739
- const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
740
- const records = await query.toArray();
741
- return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
742
- } catch (error) {
743
- throw new Error(`Failed to load workflow snapshot: ${error}`);
744
- }
2116
+ return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
2117
+ }
2118
+ async getScoreById({ id: _id }) {
2119
+ return this.stores.scores.getScoreById({ id: _id });
745
2120
  }
746
- async getTracesPaginated(_args) {
747
- throw new Error("Method not implemented.");
2121
+ async getScoresByScorerId({
2122
+ scorerId,
2123
+ pagination
2124
+ }) {
2125
+ return this.stores.scores.getScoresByScorerId({ scorerId, pagination });
748
2126
  }
749
- async getThreadsByResourceIdPaginated(_args) {
750
- throw new Error("Method not implemented.");
2127
+ async saveScore(_score) {
2128
+ return this.stores.scores.saveScore(_score);
751
2129
  }
752
- async getMessagesPaginated(_args) {
753
- throw new Error("Method not implemented.");
2130
+ async getScoresByRunId({
2131
+ runId,
2132
+ pagination
2133
+ }) {
2134
+ return this.stores.scores.getScoresByRunId({ runId, pagination });
754
2135
  }
755
- async updateMessages(_args) {
756
- this.logger.error("updateMessages is not yet implemented in LanceStore");
757
- throw new Error("Method not implemented");
2136
+ async getScoresByEntityId({
2137
+ entityId,
2138
+ entityType,
2139
+ pagination
2140
+ }) {
2141
+ return this.stores.scores.getScoresByEntityId({ entityId, entityType, pagination });
758
2142
  }
759
2143
  };
760
2144
  var LanceFilterTranslator = class extends BaseFilterTranslator {
@@ -1108,7 +2492,15 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
1108
2492
  instance.lanceClient = await connect(uri, options);
1109
2493
  return instance;
1110
2494
  } catch (e) {
1111
- throw new Error(`Failed to connect to LanceDB: ${e}`);
2495
+ throw new MastraError(
2496
+ {
2497
+ id: "STORAGE_LANCE_VECTOR_CONNECT_FAILED",
2498
+ domain: ErrorDomain.STORAGE,
2499
+ category: ErrorCategory.THIRD_PARTY,
2500
+ details: { uri }
2501
+ },
2502
+ e
2503
+ );
1112
2504
  }
1113
2505
  }
1114
2506
  /**
@@ -1132,14 +2524,27 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
1132
2524
  columns = [],
1133
2525
  includeAllColumns = false
1134
2526
  }) {
1135
- if (!this.lanceClient) {
1136
- throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
1137
- }
1138
- if (!tableName) {
1139
- throw new Error("tableName is required");
1140
- }
1141
- if (!queryVector) {
1142
- throw new Error("queryVector is required");
2527
+ try {
2528
+ if (!this.lanceClient) {
2529
+ throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
2530
+ }
2531
+ if (!tableName) {
2532
+ throw new Error("tableName is required");
2533
+ }
2534
+ if (!queryVector) {
2535
+ throw new Error("queryVector is required");
2536
+ }
2537
+ } catch (error) {
2538
+ throw new MastraError(
2539
+ {
2540
+ id: "STORAGE_LANCE_VECTOR_QUERY_FAILED_INVALID_ARGS",
2541
+ domain: ErrorDomain.STORAGE,
2542
+ category: ErrorCategory.USER,
2543
+ text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
2544
+ details: { tableName }
2545
+ },
2546
+ error
2547
+ );
1143
2548
  }
1144
2549
  try {
1145
2550
  const table = await this.lanceClient.openTable(tableName);
@@ -1178,7 +2583,15 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
1178
2583
  };
1179
2584
  });
1180
2585
  } catch (error) {
1181
- throw new Error(`Failed to query vectors: ${error.message}`);
2586
+ throw new MastraError(
2587
+ {
2588
+ id: "STORAGE_LANCE_VECTOR_QUERY_FAILED",
2589
+ domain: ErrorDomain.STORAGE,
2590
+ category: ErrorCategory.THIRD_PARTY,
2591
+ details: { tableName, includeVector, columnsCount: columns?.length, includeAllColumns }
2592
+ },
2593
+ error
2594
+ );
1182
2595
  }
1183
2596
  }
1184
2597
  filterTranslator(filter) {
@@ -1211,14 +2624,27 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
1211
2624
  return translator.translate(prefixedFilter);
1212
2625
  }
1213
2626
  async upsert({ tableName, vectors, metadata = [], ids = [] }) {
1214
- if (!this.lanceClient) {
1215
- throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
1216
- }
1217
- if (!tableName) {
1218
- throw new Error("tableName is required");
1219
- }
1220
- if (!vectors || !Array.isArray(vectors) || vectors.length === 0) {
1221
- throw new Error("vectors array is required and must not be empty");
2627
+ try {
2628
+ if (!this.lanceClient) {
2629
+ throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
2630
+ }
2631
+ if (!tableName) {
2632
+ throw new Error("tableName is required");
2633
+ }
2634
+ if (!vectors || !Array.isArray(vectors) || vectors.length === 0) {
2635
+ throw new Error("vectors array is required and must not be empty");
2636
+ }
2637
+ } catch (error) {
2638
+ throw new MastraError(
2639
+ {
2640
+ id: "STORAGE_LANCE_VECTOR_UPSERT_FAILED_INVALID_ARGS",
2641
+ domain: ErrorDomain.STORAGE,
2642
+ category: ErrorCategory.USER,
2643
+ text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
2644
+ details: { tableName }
2645
+ },
2646
+ error
2647
+ );
1222
2648
  }
1223
2649
  try {
1224
2650
  const tables = await this.lanceClient.tableNames();
@@ -1245,7 +2671,15 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
1245
2671
  await table.add(data, { mode: "overwrite" });
1246
2672
  return vectorIds;
1247
2673
  } catch (error) {
1248
- throw new Error(`Failed to upsert vectors: ${error.message}`);
2674
+ throw new MastraError(
2675
+ {
2676
+ id: "STORAGE_LANCE_VECTOR_UPSERT_FAILED",
2677
+ domain: ErrorDomain.STORAGE,
2678
+ category: ErrorCategory.THIRD_PARTY,
2679
+ details: { tableName, vectorCount: vectors.length, metadataCount: metadata.length, idsCount: ids.length }
2680
+ },
2681
+ error
2682
+ );
1249
2683
  }
1250
2684
  }
1251
2685
  /**
@@ -1265,29 +2699,78 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
1265
2699
  }
1266
2700
  async createTable(tableName, data, options) {
1267
2701
  if (!this.lanceClient) {
1268
- throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
2702
+ throw new MastraError({
2703
+ id: "STORAGE_LANCE_VECTOR_CREATE_TABLE_FAILED_INVALID_ARGS",
2704
+ domain: ErrorDomain.STORAGE,
2705
+ category: ErrorCategory.USER,
2706
+ text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
2707
+ details: { tableName }
2708
+ });
2709
+ }
2710
+ if (Array.isArray(data)) {
2711
+ data = data.map((record) => this.flattenObject(record));
1269
2712
  }
1270
2713
  try {
1271
- if (Array.isArray(data)) {
1272
- data = data.map((record) => this.flattenObject(record));
1273
- }
1274
2714
  return await this.lanceClient.createTable(tableName, data, options);
1275
2715
  } catch (error) {
1276
- throw new Error(`Failed to create table: ${error.message}`);
2716
+ throw new MastraError(
2717
+ {
2718
+ id: "STORAGE_LANCE_VECTOR_CREATE_TABLE_FAILED",
2719
+ domain: ErrorDomain.STORAGE,
2720
+ category: ErrorCategory.THIRD_PARTY,
2721
+ details: { tableName }
2722
+ },
2723
+ error
2724
+ );
1277
2725
  }
1278
2726
  }
1279
2727
  async listTables() {
1280
2728
  if (!this.lanceClient) {
1281
- throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
2729
+ throw new MastraError({
2730
+ id: "STORAGE_LANCE_VECTOR_LIST_TABLES_FAILED_INVALID_ARGS",
2731
+ domain: ErrorDomain.STORAGE,
2732
+ category: ErrorCategory.USER,
2733
+ text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
2734
+ details: { methodName: "listTables" }
2735
+ });
2736
+ }
2737
+ try {
2738
+ return await this.lanceClient.tableNames();
2739
+ } catch (error) {
2740
+ throw new MastraError(
2741
+ {
2742
+ id: "STORAGE_LANCE_VECTOR_LIST_TABLES_FAILED",
2743
+ domain: ErrorDomain.STORAGE,
2744
+ category: ErrorCategory.THIRD_PARTY
2745
+ },
2746
+ error
2747
+ );
1282
2748
  }
1283
- return await this.lanceClient.tableNames();
1284
2749
  }
1285
2750
  async getTableSchema(tableName) {
1286
2751
  if (!this.lanceClient) {
1287
- throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
2752
+ throw new MastraError({
2753
+ id: "STORAGE_LANCE_VECTOR_GET_TABLE_SCHEMA_FAILED_INVALID_ARGS",
2754
+ domain: ErrorDomain.STORAGE,
2755
+ category: ErrorCategory.USER,
2756
+ text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
2757
+ details: { tableName }
2758
+ });
2759
+ }
2760
+ try {
2761
+ const table = await this.lanceClient.openTable(tableName);
2762
+ return await table.schema();
2763
+ } catch (error) {
2764
+ throw new MastraError(
2765
+ {
2766
+ id: "STORAGE_LANCE_VECTOR_GET_TABLE_SCHEMA_FAILED",
2767
+ domain: ErrorDomain.STORAGE,
2768
+ category: ErrorCategory.THIRD_PARTY,
2769
+ details: { tableName }
2770
+ },
2771
+ error
2772
+ );
1288
2773
  }
1289
- const table = await this.lanceClient.openTable(tableName);
1290
- return await table.schema();
1291
2774
  }
1292
2775
  /**
1293
2776
  * indexName is actually a column name in a table in lanceDB
@@ -1299,10 +2782,10 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
1299
2782
  metric = "cosine",
1300
2783
  indexConfig = {}
1301
2784
  }) {
1302
- if (!this.lanceClient) {
1303
- throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
1304
- }
1305
2785
  try {
2786
+ if (!this.lanceClient) {
2787
+ throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
2788
+ }
1306
2789
  if (!tableName) {
1307
2790
  throw new Error("tableName is required");
1308
2791
  }
@@ -1312,6 +2795,18 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
1312
2795
  if (typeof dimension !== "number" || dimension <= 0) {
1313
2796
  throw new Error("dimension must be a positive number");
1314
2797
  }
2798
+ } catch (err) {
2799
+ throw new MastraError(
2800
+ {
2801
+ id: "STORAGE_LANCE_VECTOR_CREATE_INDEX_FAILED_INVALID_ARGS",
2802
+ domain: ErrorDomain.STORAGE,
2803
+ category: ErrorCategory.USER,
2804
+ details: { tableName: tableName || "", indexName, dimension, metric }
2805
+ },
2806
+ err
2807
+ );
2808
+ }
2809
+ try {
1315
2810
  const tables = await this.lanceClient.tableNames();
1316
2811
  if (!tables.includes(tableName)) {
1317
2812
  throw new Error(
@@ -1346,12 +2841,26 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
1346
2841
  });
1347
2842
  }
1348
2843
  } catch (error) {
1349
- throw new Error(`Failed to create index: ${error.message}`);
2844
+ throw new MastraError(
2845
+ {
2846
+ id: "STORAGE_LANCE_VECTOR_CREATE_INDEX_FAILED",
2847
+ domain: ErrorDomain.STORAGE,
2848
+ category: ErrorCategory.THIRD_PARTY,
2849
+ details: { tableName: tableName || "", indexName, dimension }
2850
+ },
2851
+ error
2852
+ );
1350
2853
  }
1351
2854
  }
1352
2855
  async listIndexes() {
1353
2856
  if (!this.lanceClient) {
1354
- throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
2857
+ throw new MastraError({
2858
+ id: "STORAGE_LANCE_VECTOR_LIST_INDEXES_FAILED_INVALID_ARGS",
2859
+ domain: ErrorDomain.STORAGE,
2860
+ category: ErrorCategory.USER,
2861
+ text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
2862
+ details: { methodName: "listIndexes" }
2863
+ });
1355
2864
  }
1356
2865
  try {
1357
2866
  const tables = await this.lanceClient.tableNames();
@@ -1363,15 +2872,34 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
1363
2872
  }
1364
2873
  return allIndices;
1365
2874
  } catch (error) {
1366
- throw new Error(`Failed to list indexes: ${error.message}`);
2875
+ throw new MastraError(
2876
+ {
2877
+ id: "STORAGE_LANCE_VECTOR_LIST_INDEXES_FAILED",
2878
+ domain: ErrorDomain.STORAGE,
2879
+ category: ErrorCategory.THIRD_PARTY
2880
+ },
2881
+ error
2882
+ );
1367
2883
  }
1368
2884
  }
1369
2885
  async describeIndex({ indexName }) {
1370
- if (!this.lanceClient) {
1371
- throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
1372
- }
1373
- if (!indexName) {
1374
- throw new Error("indexName is required");
2886
+ try {
2887
+ if (!this.lanceClient) {
2888
+ throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
2889
+ }
2890
+ if (!indexName) {
2891
+ throw new Error("indexName is required");
2892
+ }
2893
+ } catch (err) {
2894
+ throw new MastraError(
2895
+ {
2896
+ id: "STORAGE_LANCE_VECTOR_DESCRIBE_INDEX_FAILED_INVALID_ARGS",
2897
+ domain: ErrorDomain.STORAGE,
2898
+ category: ErrorCategory.USER,
2899
+ details: { indexName }
2900
+ },
2901
+ err
2902
+ );
1375
2903
  }
1376
2904
  try {
1377
2905
  const tables = await this.lanceClient.tableNames();
@@ -1398,15 +2926,35 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
1398
2926
  }
1399
2927
  throw new Error(`IndexName: ${indexName} not found`);
1400
2928
  } catch (error) {
1401
- throw new Error(`Failed to describe index: ${error.message}`);
2929
+ throw new MastraError(
2930
+ {
2931
+ id: "STORAGE_LANCE_VECTOR_DESCRIBE_INDEX_FAILED",
2932
+ domain: ErrorDomain.STORAGE,
2933
+ category: ErrorCategory.THIRD_PARTY,
2934
+ details: { indexName }
2935
+ },
2936
+ error
2937
+ );
1402
2938
  }
1403
2939
  }
1404
2940
  async deleteIndex({ indexName }) {
1405
- if (!this.lanceClient) {
1406
- throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
1407
- }
1408
- if (!indexName) {
1409
- throw new Error("indexName is required");
2941
+ try {
2942
+ if (!this.lanceClient) {
2943
+ throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
2944
+ }
2945
+ if (!indexName) {
2946
+ throw new Error("indexName is required");
2947
+ }
2948
+ } catch (err) {
2949
+ throw new MastraError(
2950
+ {
2951
+ id: "STORAGE_LANCE_VECTOR_DELETE_INDEX_FAILED_INVALID_ARGS",
2952
+ domain: ErrorDomain.STORAGE,
2953
+ category: ErrorCategory.USER,
2954
+ details: { indexName }
2955
+ },
2956
+ err
2957
+ );
1410
2958
  }
1411
2959
  try {
1412
2960
  const tables = await this.lanceClient.tableNames();
@@ -1421,7 +2969,15 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
1421
2969
  }
1422
2970
  throw new Error(`Index ${indexName} not found`);
1423
2971
  } catch (error) {
1424
- throw new Error(`Failed to delete index: ${error.message}`);
2972
+ throw new MastraError(
2973
+ {
2974
+ id: "STORAGE_LANCE_VECTOR_DELETE_INDEX_FAILED",
2975
+ domain: ErrorDomain.STORAGE,
2976
+ category: ErrorCategory.THIRD_PARTY,
2977
+ details: { indexName }
2978
+ },
2979
+ error
2980
+ );
1425
2981
  }
1426
2982
  }
1427
2983
  /**
@@ -1429,33 +2985,73 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
1429
2985
  */
1430
2986
  async deleteAllTables() {
1431
2987
  if (!this.lanceClient) {
1432
- throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
2988
+ throw new MastraError({
2989
+ id: "STORAGE_LANCE_VECTOR_DELETE_ALL_TABLES_FAILED_INVALID_ARGS",
2990
+ domain: ErrorDomain.STORAGE,
2991
+ category: ErrorCategory.USER,
2992
+ details: { methodName: "deleteAllTables" },
2993
+ text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance"
2994
+ });
1433
2995
  }
1434
2996
  try {
1435
2997
  await this.lanceClient.dropAllTables();
1436
2998
  } catch (error) {
1437
- throw new Error(`Failed to delete tables: ${error.message}`);
2999
+ throw new MastraError(
3000
+ {
3001
+ id: "STORAGE_LANCE_VECTOR_DELETE_ALL_TABLES_FAILED",
3002
+ domain: ErrorDomain.STORAGE,
3003
+ category: ErrorCategory.THIRD_PARTY,
3004
+ details: { methodName: "deleteAllTables" }
3005
+ },
3006
+ error
3007
+ );
1438
3008
  }
1439
3009
  }
1440
3010
  async deleteTable(tableName) {
1441
3011
  if (!this.lanceClient) {
1442
- throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
3012
+ throw new MastraError({
3013
+ id: "STORAGE_LANCE_VECTOR_DELETE_TABLE_FAILED_INVALID_ARGS",
3014
+ domain: ErrorDomain.STORAGE,
3015
+ category: ErrorCategory.USER,
3016
+ details: { tableName },
3017
+ text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance"
3018
+ });
1443
3019
  }
1444
3020
  try {
1445
3021
  await this.lanceClient.dropTable(tableName);
1446
3022
  } catch (error) {
1447
- throw new Error(`Failed to delete tables: ${error.message}`);
3023
+ throw new MastraError(
3024
+ {
3025
+ id: "STORAGE_LANCE_VECTOR_DELETE_TABLE_FAILED",
3026
+ domain: ErrorDomain.STORAGE,
3027
+ category: ErrorCategory.THIRD_PARTY,
3028
+ details: { tableName }
3029
+ },
3030
+ error
3031
+ );
1448
3032
  }
1449
3033
  }
1450
3034
  async updateVector({ indexName, id, update }) {
1451
- if (!this.lanceClient) {
1452
- throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
1453
- }
1454
- if (!indexName) {
1455
- throw new Error("indexName is required");
1456
- }
1457
- if (!id) {
1458
- throw new Error("id is required");
3035
+ try {
3036
+ if (!this.lanceClient) {
3037
+ throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
3038
+ }
3039
+ if (!indexName) {
3040
+ throw new Error("indexName is required");
3041
+ }
3042
+ if (!id) {
3043
+ throw new Error("id is required");
3044
+ }
3045
+ } catch (err) {
3046
+ throw new MastraError(
3047
+ {
3048
+ id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED_INVALID_ARGS",
3049
+ domain: ErrorDomain.STORAGE,
3050
+ category: ErrorCategory.USER,
3051
+ details: { indexName, id }
3052
+ },
3053
+ err
3054
+ );
1459
3055
  }
1460
3056
  try {
1461
3057
  const tables = await this.lanceClient.tableNames();
@@ -1509,18 +3105,38 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
1509
3105
  }
1510
3106
  throw new Error(`No table found with column/index '${indexName}'`);
1511
3107
  } catch (error) {
1512
- throw new Error(`Failed to update index: ${error.message}`);
3108
+ throw new MastraError(
3109
+ {
3110
+ id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED",
3111
+ domain: ErrorDomain.STORAGE,
3112
+ category: ErrorCategory.THIRD_PARTY,
3113
+ details: { indexName, id, hasVector: !!update.vector, hasMetadata: !!update.metadata }
3114
+ },
3115
+ error
3116
+ );
1513
3117
  }
1514
3118
  }
1515
3119
  async deleteVector({ indexName, id }) {
1516
- if (!this.lanceClient) {
1517
- throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
1518
- }
1519
- if (!indexName) {
1520
- throw new Error("indexName is required");
1521
- }
1522
- if (!id) {
1523
- throw new Error("id is required");
3120
+ try {
3121
+ if (!this.lanceClient) {
3122
+ throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
3123
+ }
3124
+ if (!indexName) {
3125
+ throw new Error("indexName is required");
3126
+ }
3127
+ if (!id) {
3128
+ throw new Error("id is required");
3129
+ }
3130
+ } catch (err) {
3131
+ throw new MastraError(
3132
+ {
3133
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTOR_FAILED_INVALID_ARGS",
3134
+ domain: ErrorDomain.STORAGE,
3135
+ category: ErrorCategory.USER,
3136
+ details: { indexName, id }
3137
+ },
3138
+ err
3139
+ );
1524
3140
  }
1525
3141
  try {
1526
3142
  const tables = await this.lanceClient.tableNames();
@@ -1542,7 +3158,15 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
1542
3158
  }
1543
3159
  throw new Error(`No table found with column/index '${indexName}'`);
1544
3160
  } catch (error) {
1545
- throw new Error(`Failed to delete index: ${error.message}`);
3161
+ throw new MastraError(
3162
+ {
3163
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTOR_FAILED",
3164
+ domain: ErrorDomain.STORAGE,
3165
+ category: ErrorCategory.THIRD_PARTY,
3166
+ details: { indexName, id }
3167
+ },
3168
+ error
3169
+ );
1546
3170
  }
1547
3171
  }
1548
3172
  /**
@@ -1573,3 +3197,5 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
1573
3197
  };
1574
3198
 
1575
3199
  export { LanceStorage, LanceVectorStore };
3200
+ //# sourceMappingURL=index.js.map
3201
+ //# sourceMappingURL=index.js.map