@mastra/lance 0.0.0-mcp-changeset-20250707162621 → 0.0.0-memory-system-message-error-20250813233316

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 (46) hide show
  1. package/CHANGELOG.md +177 -9
  2. package/LICENSE.md +11 -42
  3. package/dist/index.cjs +1649 -643
  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 +1584 -578
  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 +42 -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 +236 -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 +11 -10
  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 +243 -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 -1332
  40. package/src/storage/index.ts +163 -1162
  41. package/tsconfig.build.json +9 -0
  42. package/tsconfig.json +1 -1
  43. package/tsup.config.ts +17 -0
  44. package/dist/_tsup-dts-rollup.d.cts +0 -409
  45. package/dist/_tsup-dts-rollup.d.ts +0 -409
  46. package/dist/index.d.cts +0 -2
package/dist/index.js CHANGED
@@ -1,110 +1,978 @@
1
1
  import { connect, Index } from '@lancedb/lancedb';
2
- import { MessageList } from '@mastra/core/agent';
3
2
  import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
4
- import { MastraStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_TRACES, TABLE_EVALS, TABLE_WORKFLOW_SNAPSHOT } from '@mastra/core/storage';
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';
4
+ import { MessageList } from '@mastra/core/agent';
5
5
  import { Utf8, Float64, Binary, Float32, Int32, Field, Schema } from 'apache-arrow';
6
6
  import { MastraVector } from '@mastra/core/vector';
7
7
  import { BaseFilterTranslator } from '@mastra/core/vector/filter';
8
8
 
9
9
  // src/storage/index.ts
10
- var LanceStorage = class _LanceStorage extends MastraStorage {
11
- lanceClient;
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
+ }
12
292
  /**
13
- * Creates a new instance of LanceStorage
14
- * @param uri The URI to connect to LanceDB
15
- * @param options connection options
16
- *
17
- * Usage:
18
- *
19
- * Connect to a local database
20
- * ```ts
21
- * const store = await LanceStorage.create('/path/to/db');
22
- * ```
23
- *
24
- * Connect to a LanceDB cloud database
25
- * ```ts
26
- * const store = await LanceStorage.create('db://host:port');
27
- * ```
28
- *
29
- * Connect to a cloud database
30
- * ```ts
31
- * const store = await LanceStorage.create('s3://bucket/db', { storageOptions: { timeout: '60s' } });
32
- * ```
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
33
296
  */
34
- static async create(name, uri, options) {
35
- const instance = new _LanceStorage(name);
297
+ async saveThread({ thread }) {
36
298
  try {
37
- instance.lanceClient = await connect(uri, options);
38
- return instance;
39
- } catch (e) {
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) {
40
693
  throw new MastraError(
41
694
  {
42
- id: "STORAGE_LANCE_STORAGE_CONNECT_FAILED",
695
+ id: "LANCE_STORE_GET_MESSAGES_PAGINATED_FAILED",
43
696
  domain: ErrorDomain.STORAGE,
44
- category: ErrorCategory.THIRD_PARTY,
45
- text: `Failed to connect to LanceDB: ${e.message || e}`,
46
- details: { uri, optionsProvided: !!options }
697
+ category: ErrorCategory.THIRD_PARTY
47
698
  },
48
- e
699
+ error
49
700
  );
50
701
  }
51
702
  }
52
- getPrimaryKeys(tableName) {
53
- let primaryId = ["id"];
54
- if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
55
- primaryId = ["workflow_name", "run_id"];
56
- } else if (tableName === TABLE_EVALS) {
57
- primaryId = ["agent_name", "metric_name", "run_id"];
58
- }
59
- return primaryId;
60
- }
61
703
  /**
62
- * @internal
63
- * Private constructor to enforce using the create factory method
704
+ * Parse message data from LanceDB record format to MastraMessageV2 format
64
705
  */
65
- constructor(name) {
66
- super({ name });
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
+ };
67
721
  }
68
- async createTable({
69
- tableName,
70
- schema
71
- }) {
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();
72
730
  try {
73
- if (!this.lanceClient) {
74
- throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
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
+ }
75
771
  }
76
- if (!tableName) {
77
- throw new Error("tableName is required for createTable.");
772
+ for (const threadId of affectedThreadIds) {
773
+ await this.operations.insert({
774
+ tableName: TABLE_THREADS,
775
+ record: { id: threadId, updatedAt: Date.now() }
776
+ });
78
777
  }
79
- if (!schema) {
80
- throw new Error("schema is required for createTable.");
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
+ }
81
848
  }
849
+ return {
850
+ ...resource,
851
+ createdAt,
852
+ updatedAt,
853
+ workingMemory,
854
+ metadata
855
+ };
82
856
  } catch (error) {
83
857
  throw new MastraError(
84
858
  {
85
- id: "STORAGE_LANCE_STORAGE_CREATE_TABLE_INVALID_ARGS",
859
+ id: "LANCE_STORE_GET_RESOURCE_BY_ID_FAILED",
86
860
  domain: ErrorDomain.STORAGE,
87
- category: ErrorCategory.USER,
88
- details: { tableName }
861
+ category: ErrorCategory.THIRD_PARTY
89
862
  },
90
863
  error
91
864
  );
92
865
  }
866
+ }
867
+ async saveResource({ resource }) {
93
868
  try {
94
- const arrowSchema = this.translateSchema(schema);
95
- await this.lanceClient.createEmptyTable(tableName, arrowSchema);
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;
96
880
  } catch (error) {
97
881
  throw new MastraError(
98
882
  {
99
- id: "STORAGE_LANCE_STORAGE_CREATE_TABLE_FAILED",
883
+ id: "LANCE_STORE_SAVE_RESOURCE_FAILED",
100
884
  domain: ErrorDomain.STORAGE,
101
- category: ErrorCategory.THIRD_PARTY,
102
- details: { tableName }
885
+ category: ErrorCategory.THIRD_PARTY
103
886
  },
104
887
  error
105
888
  );
106
889
  }
107
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
+ }
108
976
  translateSchema(schema) {
109
977
  const fields = Object.entries(schema).map(([name, column]) => {
110
978
  let arrowType;
@@ -140,40 +1008,42 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
140
1008
  });
141
1009
  return new Schema(fields);
142
1010
  }
143
- /**
144
- * Drop a table if it exists
145
- * @param tableName Name of the table to drop
146
- */
147
- async dropTable(tableName) {
1011
+ async createTable({
1012
+ tableName,
1013
+ schema
1014
+ }) {
148
1015
  try {
149
- if (!this.lanceClient) {
1016
+ if (!this.client) {
150
1017
  throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
151
1018
  }
152
1019
  if (!tableName) {
153
- throw new Error("tableName is required for dropTable.");
1020
+ throw new Error("tableName is required for createTable.");
154
1021
  }
155
- } catch (validationError) {
1022
+ if (!schema) {
1023
+ throw new Error("schema is required for createTable.");
1024
+ }
1025
+ } catch (error) {
156
1026
  throw new MastraError(
157
1027
  {
158
- id: "STORAGE_LANCE_STORAGE_DROP_TABLE_INVALID_ARGS",
1028
+ id: "STORAGE_LANCE_STORAGE_CREATE_TABLE_INVALID_ARGS",
159
1029
  domain: ErrorDomain.STORAGE,
160
1030
  category: ErrorCategory.USER,
161
- text: validationError.message,
162
1031
  details: { tableName }
163
1032
  },
164
- validationError
1033
+ error
165
1034
  );
166
1035
  }
167
1036
  try {
168
- await this.lanceClient.dropTable(tableName);
1037
+ const arrowSchema = this.translateSchema(schema);
1038
+ await this.client.createEmptyTable(tableName, arrowSchema);
169
1039
  } catch (error) {
170
- if (error.toString().includes("was not found") || error.message?.includes("Table not found")) {
171
- this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
1040
+ if (error.message?.includes("already exists")) {
1041
+ this.logger.debug(`Table '${tableName}' already exists, skipping create`);
172
1042
  return;
173
1043
  }
174
1044
  throw new MastraError(
175
1045
  {
176
- id: "STORAGE_LANCE_STORAGE_DROP_TABLE_FAILED",
1046
+ id: "STORAGE_LANCE_STORAGE_CREATE_TABLE_FAILED",
177
1047
  domain: ErrorDomain.STORAGE,
178
1048
  category: ErrorCategory.THIRD_PARTY,
179
1049
  details: { tableName }
@@ -182,23 +1052,18 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
182
1052
  );
183
1053
  }
184
1054
  }
185
- /**
186
- * Get table schema
187
- * @param tableName Name of the table
188
- * @returns Table schema
189
- */
190
- async getTableSchema(tableName) {
1055
+ async dropTable({ tableName }) {
191
1056
  try {
192
- if (!this.lanceClient) {
1057
+ if (!this.client) {
193
1058
  throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
194
1059
  }
195
1060
  if (!tableName) {
196
- throw new Error("tableName is required for getTableSchema.");
1061
+ throw new Error("tableName is required for dropTable.");
197
1062
  }
198
1063
  } catch (validationError) {
199
1064
  throw new MastraError(
200
1065
  {
201
- id: "STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_INVALID_ARGS",
1066
+ id: "STORAGE_LANCE_STORAGE_DROP_TABLE_INVALID_ARGS",
202
1067
  domain: ErrorDomain.STORAGE,
203
1068
  category: ErrorCategory.USER,
204
1069
  text: validationError.message,
@@ -208,20 +1073,15 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
208
1073
  );
209
1074
  }
210
1075
  try {
211
- const table = await this.lanceClient.openTable(tableName);
212
- const rawSchema = await table.schema();
213
- const fields = rawSchema.fields;
214
- return {
215
- fields,
216
- metadata: /* @__PURE__ */ new Map(),
217
- get names() {
218
- return fields.map((field) => field.name);
219
- }
220
- };
1076
+ await this.client.dropTable(tableName);
221
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
+ }
222
1082
  throw new MastraError(
223
1083
  {
224
- id: "STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_FAILED",
1084
+ id: "STORAGE_LANCE_STORAGE_DROP_TABLE_FAILED",
225
1085
  domain: ErrorDomain.STORAGE,
226
1086
  category: ErrorCategory.THIRD_PARTY,
227
1087
  details: { tableName }
@@ -230,36 +1090,13 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
230
1090
  );
231
1091
  }
232
1092
  }
233
- getDefaultValue(type) {
234
- switch (type) {
235
- case "text":
236
- return "''";
237
- case "timestamp":
238
- return "CURRENT_TIMESTAMP";
239
- case "integer":
240
- case "bigint":
241
- return "0";
242
- case "jsonb":
243
- return "'{}'";
244
- case "uuid":
245
- return "''";
246
- default:
247
- return super.getDefaultValue(type);
248
- }
249
- }
250
- /**
251
- * Alters table schema to add columns if they don't exist
252
- * @param tableName Name of the table
253
- * @param schema Schema of the table
254
- * @param ifNotExists Array of column names to add if they don't exist
255
- */
256
1093
  async alterTable({
257
1094
  tableName,
258
1095
  schema,
259
1096
  ifNotExists
260
1097
  }) {
261
1098
  try {
262
- if (!this.lanceClient) {
1099
+ if (!this.client) {
263
1100
  throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
264
1101
  }
265
1102
  if (!tableName) {
@@ -285,7 +1122,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
285
1122
  );
286
1123
  }
287
1124
  try {
288
- const table = await this.lanceClient.openTable(tableName);
1125
+ const table = await this.client.openTable(tableName);
289
1126
  const currentSchema = await table.schema();
290
1127
  const existingFields = new Set(currentSchema.fields.map((f) => f.name));
291
1128
  const typeMap = {
@@ -321,7 +1158,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
321
1158
  }
322
1159
  async clearTable({ tableName }) {
323
1160
  try {
324
- if (!this.lanceClient) {
1161
+ if (!this.client) {
325
1162
  throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
326
1163
  }
327
1164
  if (!tableName) {
@@ -340,7 +1177,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
340
1177
  );
341
1178
  }
342
1179
  try {
343
- const table = await this.lanceClient.openTable(tableName);
1180
+ const table = await this.client.openTable(tableName);
344
1181
  await table.delete("1=1");
345
1182
  } catch (error) {
346
1183
  throw new MastraError(
@@ -354,14 +1191,9 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
354
1191
  );
355
1192
  }
356
1193
  }
357
- /**
358
- * 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.
359
- * @param tableName The name of the table to insert into.
360
- * @param record The record to insert.
361
- */
362
1194
  async insert({ tableName, record }) {
363
1195
  try {
364
- if (!this.lanceClient) {
1196
+ if (!this.client) {
365
1197
  throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
366
1198
  }
367
1199
  if (!tableName) {
@@ -383,8 +1215,8 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
383
1215
  );
384
1216
  }
385
1217
  try {
386
- const table = await this.lanceClient.openTable(tableName);
387
- const primaryId = this.getPrimaryKeys(tableName);
1218
+ const table = await this.client.openTable(tableName);
1219
+ const primaryId = getPrimaryKeys(tableName);
388
1220
  const processedRecord = { ...record };
389
1221
  for (const key in processedRecord) {
390
1222
  if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
@@ -392,6 +1224,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
392
1224
  processedRecord[key] = JSON.stringify(processedRecord[key]);
393
1225
  }
394
1226
  }
1227
+ console.log(await table.schema());
395
1228
  await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([processedRecord]);
396
1229
  } catch (error) {
397
1230
  throw new MastraError(
@@ -405,14 +1238,9 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
405
1238
  );
406
1239
  }
407
1240
  }
408
- /**
409
- * 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.
410
- * @param tableName The name of the table to insert into.
411
- * @param records The records to insert.
412
- */
413
1241
  async batchInsert({ tableName, records }) {
414
1242
  try {
415
- if (!this.lanceClient) {
1243
+ if (!this.client) {
416
1244
  throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
417
1245
  }
418
1246
  if (!tableName) {
@@ -434,8 +1262,8 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
434
1262
  );
435
1263
  }
436
1264
  try {
437
- const table = await this.lanceClient.openTable(tableName);
438
- const primaryId = this.getPrimaryKeys(tableName);
1265
+ const table = await this.client.openTable(tableName);
1266
+ const primaryId = getPrimaryKeys(tableName);
439
1267
  const processedRecords = records.map((record) => {
440
1268
  const processedRecord = { ...record };
441
1269
  for (const key in processedRecord) {
@@ -446,6 +1274,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
446
1274
  }
447
1275
  return processedRecord;
448
1276
  });
1277
+ console.log(processedRecords);
449
1278
  await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(processedRecords);
450
1279
  } catch (error) {
451
1280
  throw new MastraError(
@@ -459,16 +1288,9 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
459
1288
  );
460
1289
  }
461
1290
  }
462
- /**
463
- * Load a record from the database by its key(s)
464
- * @param tableName The name of the table to query
465
- * @param keys Record of key-value pairs to use for lookup
466
- * @throws Error if invalid types are provided for keys
467
- * @returns The loaded record with proper type conversions, or null if not found
468
- */
469
1291
  async load({ tableName, keys }) {
470
1292
  try {
471
- if (!this.lanceClient) {
1293
+ if (!this.client) {
472
1294
  throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
473
1295
  }
474
1296
  if (!tableName) {
@@ -490,11 +1312,11 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
490
1312
  );
491
1313
  }
492
1314
  try {
493
- const table = await this.lanceClient.openTable(tableName);
494
- const tableSchema = await this.getTableSchema(tableName);
1315
+ const table = await this.client.openTable(tableName);
1316
+ const tableSchema = await getTableSchema({ tableName, client: this.client });
495
1317
  const query = table.query();
496
1318
  if (Object.keys(keys).length > 0) {
497
- this.validateKeyTypes(keys, tableSchema);
1319
+ validateKeyTypes(keys, tableSchema);
498
1320
  const filterConditions = Object.entries(keys).map(([key, value]) => {
499
1321
  const isCamelCase = /^[a-z][a-zA-Z]*$/.test(key) && /[A-Z]/.test(key);
500
1322
  const quotedKey = isCamelCase ? `\`${key}\`` : key;
@@ -508,330 +1330,228 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
508
1330
  }).join(" AND ");
509
1331
  this.logger.debug("where clause generated: " + filterConditions);
510
1332
  query.where(filterConditions);
511
- }
512
- const result = await query.limit(1).toArray();
513
- if (result.length === 0) {
514
- this.logger.debug("No record found");
515
- return null;
516
- }
517
- return this.processResultWithTypeConversion(result[0], tableSchema);
518
- } catch (error) {
519
- if (error instanceof MastraError) throw error;
520
- throw new MastraError(
521
- {
522
- id: "STORAGE_LANCE_STORAGE_LOAD_FAILED",
523
- domain: ErrorDomain.STORAGE,
524
- category: ErrorCategory.THIRD_PARTY,
525
- details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
526
- },
527
- error
528
- );
529
- }
530
- }
531
- /**
532
- * Validates that key types match the schema definition
533
- * @param keys The keys to validate
534
- * @param tableSchema The table schema to validate against
535
- * @throws Error if a key has an incompatible type
536
- */
537
- validateKeyTypes(keys, tableSchema) {
538
- const fieldTypes = new Map(
539
- tableSchema.fields.map((field) => [field.name, field.type?.toString().toLowerCase()])
540
- );
541
- for (const [key, value] of Object.entries(keys)) {
542
- const fieldType = fieldTypes.get(key);
543
- if (!fieldType) {
544
- throw new Error(`Field '${key}' does not exist in table schema`);
545
- }
546
- if (value !== null) {
547
- if ((fieldType.includes("int") || fieldType.includes("bigint")) && typeof value !== "number") {
548
- throw new Error(`Expected numeric value for field '${key}', got ${typeof value}`);
549
- }
550
- if (fieldType.includes("utf8") && typeof value !== "string") {
551
- throw new Error(`Expected string value for field '${key}', got ${typeof value}`);
552
- }
553
- if (fieldType.includes("timestamp") && !(value instanceof Date) && typeof value !== "string") {
554
- throw new Error(`Expected Date or string value for field '${key}', got ${typeof value}`);
555
- }
556
- }
557
- }
558
- }
559
- /**
560
- * Process a database result with appropriate type conversions based on the table schema
561
- * @param rawResult The raw result object from the database
562
- * @param tableSchema The schema of the table containing type information
563
- * @returns Processed result with correct data types
564
- */
565
- processResultWithTypeConversion(rawResult, tableSchema) {
566
- const fieldTypeMap = /* @__PURE__ */ new Map();
567
- tableSchema.fields.forEach((field) => {
568
- const fieldName = field.name;
569
- const fieldTypeStr = field.type.toString().toLowerCase();
570
- fieldTypeMap.set(fieldName, fieldTypeStr);
571
- });
572
- if (Array.isArray(rawResult)) {
573
- return rawResult.map((item) => this.processResultWithTypeConversion(item, tableSchema));
574
- }
575
- const processedResult = { ...rawResult };
576
- for (const key in processedResult) {
577
- const fieldTypeStr = fieldTypeMap.get(key);
578
- if (!fieldTypeStr) continue;
579
- if (typeof processedResult[key] === "string") {
580
- if (fieldTypeStr.includes("int32") || fieldTypeStr.includes("float32")) {
581
- if (!isNaN(Number(processedResult[key]))) {
582
- processedResult[key] = Number(processedResult[key]);
583
- }
584
- } else if (fieldTypeStr.includes("int64")) {
585
- processedResult[key] = Number(processedResult[key]);
586
- } else if (fieldTypeStr.includes("utf8")) {
587
- try {
588
- processedResult[key] = JSON.parse(processedResult[key]);
589
- } catch (e) {
590
- this.logger.debug(`Failed to parse JSON for key ${key}: ${e}`);
591
- }
592
- }
593
- } else if (typeof processedResult[key] === "bigint") {
594
- processedResult[key] = Number(processedResult[key]);
595
- }
596
- }
597
- return processedResult;
598
- }
599
- getThreadById({ threadId }) {
600
- try {
601
- return this.load({ tableName: TABLE_THREADS, keys: { id: threadId } });
602
- } catch (error) {
603
- throw new MastraError(
604
- {
605
- id: "LANCE_STORE_GET_THREAD_BY_ID_FAILED",
606
- domain: ErrorDomain.STORAGE,
607
- category: ErrorCategory.THIRD_PARTY
608
- },
609
- error
610
- );
611
- }
612
- }
613
- async getThreadsByResourceId({ resourceId }) {
614
- try {
615
- const table = await this.lanceClient.openTable(TABLE_THREADS);
616
- const query = table.query().where(`\`resourceId\` = '${resourceId}'`);
617
- const records = await query.toArray();
618
- return this.processResultWithTypeConversion(
619
- records,
620
- await this.getTableSchema(TABLE_THREADS)
621
- );
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);
622
1340
  } catch (error) {
1341
+ if (error instanceof MastraError) throw error;
623
1342
  throw new MastraError(
624
1343
  {
625
- id: "LANCE_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED",
1344
+ id: "STORAGE_LANCE_STORAGE_LOAD_FAILED",
626
1345
  domain: ErrorDomain.STORAGE,
627
- category: ErrorCategory.THIRD_PARTY
1346
+ category: ErrorCategory.THIRD_PARTY,
1347
+ details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
628
1348
  },
629
1349
  error
630
1350
  );
631
1351
  }
632
1352
  }
633
- /**
634
- * Saves a thread to the database. This function doesn't overwrite existing threads.
635
- * @param thread - The thread to save
636
- * @returns The saved thread
637
- */
638
- async saveThread({ thread }) {
1353
+ };
1354
+ var StoreScoresLance = class extends ScoresStorage {
1355
+ client;
1356
+ constructor({ client }) {
1357
+ super();
1358
+ this.client = client;
1359
+ }
1360
+ async saveScore(score) {
639
1361
  try {
640
- const record = { ...thread, metadata: JSON.stringify(thread.metadata) };
641
- const table = await this.lanceClient.openTable(TABLE_THREADS);
642
- await table.add([record], { mode: "append" });
643
- return thread;
1362
+ const id = crypto.randomUUID();
1363
+ const table = await this.client.openTable(TABLE_SCORERS);
1364
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1365
+ const allowedFields = new Set(schema.fields.map((f) => f.name));
1366
+ const filteredScore = {};
1367
+ Object.keys(score).forEach((key) => {
1368
+ if (allowedFields.has(key)) {
1369
+ filteredScore[key] = score[key];
1370
+ }
1371
+ });
1372
+ for (const key in filteredScore) {
1373
+ if (filteredScore[key] !== null && typeof filteredScore[key] === "object" && !(filteredScore[key] instanceof Date)) {
1374
+ filteredScore[key] = JSON.stringify(filteredScore[key]);
1375
+ }
1376
+ }
1377
+ filteredScore.id = id;
1378
+ await table.add([filteredScore], { mode: "append" });
1379
+ return { score };
644
1380
  } catch (error) {
645
1381
  throw new MastraError(
646
1382
  {
647
- id: "LANCE_STORE_SAVE_THREAD_FAILED",
1383
+ id: "LANCE_STORAGE_SAVE_SCORE_FAILED",
1384
+ text: "Failed to save score in LanceStorage",
648
1385
  domain: ErrorDomain.STORAGE,
649
- category: ErrorCategory.THIRD_PARTY
1386
+ category: ErrorCategory.THIRD_PARTY,
1387
+ details: { error: error?.message }
650
1388
  },
651
1389
  error
652
1390
  );
653
1391
  }
654
1392
  }
655
- async updateThread({
656
- id,
657
- title,
658
- metadata
659
- }) {
1393
+ async getScoreById({ id }) {
660
1394
  try {
661
- const record = { id, title, metadata: JSON.stringify(metadata) };
662
- const table = await this.lanceClient.openTable(TABLE_THREADS);
663
- await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
664
- const query = table.query().where(`id = '${id}'`);
1395
+ const table = await this.client.openTable(TABLE_SCORERS);
1396
+ const query = table.query().where(`id = '${id}'`).limit(1);
665
1397
  const records = await query.toArray();
666
- return this.processResultWithTypeConversion(
667
- records[0],
668
- await this.getTableSchema(TABLE_THREADS)
669
- );
1398
+ if (records.length === 0) return null;
1399
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1400
+ return processResultWithTypeConversion(records[0], schema);
670
1401
  } catch (error) {
671
1402
  throw new MastraError(
672
1403
  {
673
- id: "LANCE_STORE_UPDATE_THREAD_FAILED",
1404
+ id: "LANCE_STORAGE_GET_SCORE_BY_ID_FAILED",
1405
+ text: "Failed to get score by id in LanceStorage",
674
1406
  domain: ErrorDomain.STORAGE,
675
- category: ErrorCategory.THIRD_PARTY
1407
+ category: ErrorCategory.THIRD_PARTY,
1408
+ details: { error: error?.message }
676
1409
  },
677
1410
  error
678
1411
  );
679
1412
  }
680
1413
  }
681
- async deleteThread({ threadId }) {
1414
+ async getScoresByScorerId({
1415
+ scorerId,
1416
+ pagination,
1417
+ entityId,
1418
+ entityType,
1419
+ source
1420
+ }) {
682
1421
  try {
683
- const table = await this.lanceClient.openTable(TABLE_THREADS);
684
- await table.delete(`id = '${threadId}'`);
1422
+ const table = await this.client.openTable(TABLE_SCORERS);
1423
+ const { page = 0, perPage = 10 } = pagination || {};
1424
+ const offset = page * perPage;
1425
+ let query = table.query().where(`\`scorerId\` = '${scorerId}'`);
1426
+ if (source) {
1427
+ query = query.where(`\`source\` = '${source}'`);
1428
+ }
1429
+ if (entityId) {
1430
+ query = query.where(`\`entityId\` = '${entityId}'`);
1431
+ }
1432
+ if (entityType) {
1433
+ query = query.where(`\`entityType\` = '${entityType}'`);
1434
+ }
1435
+ query = query.limit(perPage);
1436
+ if (offset > 0) query.offset(offset);
1437
+ const records = await query.toArray();
1438
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1439
+ const scores = processResultWithTypeConversion(records, schema);
1440
+ let totalQuery = table.query().where(`\`scorerId\` = '${scorerId}'`);
1441
+ if (source) {
1442
+ totalQuery = totalQuery.where(`\`source\` = '${source}'`);
1443
+ }
1444
+ const allRecords = await totalQuery.toArray();
1445
+ const total = allRecords.length;
1446
+ return {
1447
+ pagination: {
1448
+ page,
1449
+ perPage,
1450
+ total,
1451
+ hasMore: offset + scores.length < total
1452
+ },
1453
+ scores
1454
+ };
685
1455
  } catch (error) {
686
1456
  throw new MastraError(
687
1457
  {
688
- id: "LANCE_STORE_DELETE_THREAD_FAILED",
1458
+ id: "LANCE_STORAGE_GET_SCORES_BY_SCORER_ID_FAILED",
1459
+ text: "Failed to get scores by scorerId in LanceStorage",
689
1460
  domain: ErrorDomain.STORAGE,
690
- category: ErrorCategory.THIRD_PARTY
1461
+ category: ErrorCategory.THIRD_PARTY,
1462
+ details: { error: error?.message }
691
1463
  },
692
1464
  error
693
1465
  );
694
1466
  }
695
1467
  }
696
- /**
697
- * Processes messages to include context messages based on withPreviousMessages and withNextMessages
698
- * @param records - The sorted array of records to process
699
- * @param include - The array of include specifications with context parameters
700
- * @returns The processed array with context messages included
701
- */
702
- processMessagesWithContext(records, include) {
703
- const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
704
- if (messagesWithContext.length === 0) {
705
- return records;
706
- }
707
- const messageIndexMap = /* @__PURE__ */ new Map();
708
- records.forEach((message, index) => {
709
- messageIndexMap.set(message.id, index);
710
- });
711
- const additionalIndices = /* @__PURE__ */ new Set();
712
- for (const item of messagesWithContext) {
713
- const messageIndex = messageIndexMap.get(item.id);
714
- if (messageIndex !== void 0) {
715
- if (item.withPreviousMessages) {
716
- const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
717
- for (let i = startIdx; i < messageIndex; i++) {
718
- additionalIndices.add(i);
719
- }
720
- }
721
- if (item.withNextMessages) {
722
- const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
723
- for (let i = messageIndex + 1; i <= endIdx; i++) {
724
- additionalIndices.add(i);
725
- }
726
- }
727
- }
728
- }
729
- if (additionalIndices.size === 0) {
730
- return records;
731
- }
732
- const originalMatchIds = new Set(include.map((item) => item.id));
733
- const allIndices = /* @__PURE__ */ new Set();
734
- records.forEach((record, index) => {
735
- if (originalMatchIds.has(record.id)) {
736
- allIndices.add(index);
737
- }
738
- });
739
- additionalIndices.forEach((index) => {
740
- allIndices.add(index);
741
- });
742
- return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
743
- }
744
- async getMessages({
745
- threadId,
746
- resourceId,
747
- selectBy,
748
- format,
749
- threadConfig
1468
+ async getScoresByRunId({
1469
+ runId,
1470
+ pagination
750
1471
  }) {
751
1472
  try {
752
- if (threadConfig) {
753
- throw new Error("ThreadConfig is not supported by LanceDB storage");
754
- }
755
- const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: Number.MAX_SAFE_INTEGER });
756
- const table = await this.lanceClient.openTable(TABLE_MESSAGES);
757
- let query = table.query().where(`\`threadId\` = '${threadId}'`);
758
- if (selectBy) {
759
- if (selectBy.include && selectBy.include.length > 0) {
760
- const includeIds = selectBy.include.map((item) => item.id);
761
- const includeClause = includeIds.map((id) => `\`id\` = '${id}'`).join(" OR ");
762
- query = query.where(`(\`threadId\` = '${threadId}' OR (${includeClause}))`);
763
- }
764
- }
765
- let records = await query.toArray();
766
- records.sort((a, b) => {
767
- const dateA = new Date(a.createdAt).getTime();
768
- const dateB = new Date(b.createdAt).getTime();
769
- return dateA - dateB;
770
- });
771
- if (selectBy?.include && selectBy.include.length > 0) {
772
- records = this.processMessagesWithContext(records, selectBy.include);
773
- }
774
- if (limit !== Number.MAX_SAFE_INTEGER) {
775
- records = records.slice(-limit);
776
- }
777
- const messages = this.processResultWithTypeConversion(records, await this.getTableSchema(TABLE_MESSAGES));
778
- const normalized = messages.map((msg) => ({
779
- ...msg,
780
- content: typeof msg.content === "string" ? (() => {
781
- try {
782
- return JSON.parse(msg.content);
783
- } catch {
784
- return msg.content;
785
- }
786
- })() : msg.content
787
- }));
788
- const list = new MessageList({ threadId, resourceId }).add(normalized, "memory");
789
- if (format === "v2") return list.get.all.v2();
790
- return list.get.all.v1();
1473
+ const table = await this.client.openTable(TABLE_SCORERS);
1474
+ const { page = 0, perPage = 10 } = pagination || {};
1475
+ const offset = page * perPage;
1476
+ const query = table.query().where(`\`runId\` = '${runId}'`).limit(perPage);
1477
+ if (offset > 0) query.offset(offset);
1478
+ const records = await query.toArray();
1479
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1480
+ const scores = processResultWithTypeConversion(records, schema);
1481
+ const allRecords = await table.query().where(`\`runId\` = '${runId}'`).toArray();
1482
+ const total = allRecords.length;
1483
+ return {
1484
+ pagination: {
1485
+ page,
1486
+ perPage,
1487
+ total,
1488
+ hasMore: offset + scores.length < total
1489
+ },
1490
+ scores
1491
+ };
791
1492
  } catch (error) {
792
1493
  throw new MastraError(
793
1494
  {
794
- id: "LANCE_STORE_GET_MESSAGES_FAILED",
1495
+ id: "LANCE_STORAGE_GET_SCORES_BY_RUN_ID_FAILED",
1496
+ text: "Failed to get scores by runId in LanceStorage",
795
1497
  domain: ErrorDomain.STORAGE,
796
- category: ErrorCategory.THIRD_PARTY
1498
+ category: ErrorCategory.THIRD_PARTY,
1499
+ details: { error: error?.message }
797
1500
  },
798
1501
  error
799
1502
  );
800
1503
  }
801
1504
  }
802
- async saveMessages(args) {
1505
+ async getScoresByEntityId({
1506
+ entityId,
1507
+ entityType,
1508
+ pagination
1509
+ }) {
803
1510
  try {
804
- const { messages, format = "v1" } = args;
805
- if (messages.length === 0) {
806
- return [];
807
- }
808
- const threadId = messages[0]?.threadId;
809
- if (!threadId) {
810
- throw new Error("Thread ID is required");
811
- }
812
- const transformedMessages = messages.map((message) => ({
813
- ...message,
814
- content: JSON.stringify(message.content)
815
- }));
816
- const table = await this.lanceClient.openTable(TABLE_MESSAGES);
817
- await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
818
- const list = new MessageList().add(messages, "memory");
819
- if (format === `v2`) return list.get.all.v2();
820
- return list.get.all.v1();
1511
+ const table = await this.client.openTable(TABLE_SCORERS);
1512
+ const { page = 0, perPage = 10 } = pagination || {};
1513
+ const offset = page * perPage;
1514
+ const query = table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).limit(perPage);
1515
+ if (offset > 0) query.offset(offset);
1516
+ const records = await query.toArray();
1517
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1518
+ const scores = processResultWithTypeConversion(records, schema);
1519
+ const allRecords = await table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).toArray();
1520
+ const total = allRecords.length;
1521
+ return {
1522
+ pagination: {
1523
+ page,
1524
+ perPage,
1525
+ total,
1526
+ hasMore: offset + scores.length < total
1527
+ },
1528
+ scores
1529
+ };
821
1530
  } catch (error) {
822
1531
  throw new MastraError(
823
1532
  {
824
- id: "LANCE_STORE_SAVE_MESSAGES_FAILED",
1533
+ id: "LANCE_STORAGE_GET_SCORES_BY_ENTITY_ID_FAILED",
1534
+ text: "Failed to get scores by entityId and entityType in LanceStorage",
825
1535
  domain: ErrorDomain.STORAGE,
826
- category: ErrorCategory.THIRD_PARTY
1536
+ category: ErrorCategory.THIRD_PARTY,
1537
+ details: { error: error?.message }
827
1538
  },
828
1539
  error
829
1540
  );
830
1541
  }
831
1542
  }
1543
+ };
1544
+ var StoreTracesLance = class extends TracesStorage {
1545
+ client;
1546
+ operations;
1547
+ constructor({ client, operations }) {
1548
+ super();
1549
+ this.client = client;
1550
+ this.operations = operations;
1551
+ }
832
1552
  async saveTrace({ trace }) {
833
1553
  try {
834
- const table = await this.lanceClient.openTable(TABLE_TRACES);
1554
+ const table = await this.client.openTable(TABLE_TRACES);
835
1555
  const record = {
836
1556
  ...trace,
837
1557
  attributes: JSON.stringify(trace.attributes),
@@ -855,10 +1575,10 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
855
1575
  }
856
1576
  async getTraceById({ traceId }) {
857
1577
  try {
858
- const table = await this.lanceClient.openTable(TABLE_TRACES);
1578
+ const table = await this.client.openTable(TABLE_TRACES);
859
1579
  const query = table.query().where(`id = '${traceId}'`);
860
1580
  const records = await query.toArray();
861
- return this.processResultWithTypeConversion(records[0], await this.getTableSchema(TABLE_TRACES));
1581
+ return records[0];
862
1582
  } catch (error) {
863
1583
  throw new MastraError(
864
1584
  {
@@ -878,7 +1598,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
878
1598
  attributes
879
1599
  }) {
880
1600
  try {
881
- const table = await this.lanceClient.openTable(TABLE_TRACES);
1601
+ const table = await this.client.openTable(TABLE_TRACES);
882
1602
  const query = table.query();
883
1603
  if (name) {
884
1604
  query.where(`name = '${name}'`);
@@ -896,17 +1616,23 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
896
1616
  }
897
1617
  const records = await query.toArray();
898
1618
  return records.map((record) => {
899
- return {
1619
+ const processed = {
900
1620
  ...record,
901
- attributes: JSON.parse(record.attributes),
902
- status: JSON.parse(record.status),
903
- events: JSON.parse(record.events),
904
- links: JSON.parse(record.links),
905
- other: JSON.parse(record.other),
1621
+ attributes: record.attributes ? JSON.parse(record.attributes) : {},
1622
+ status: record.status ? JSON.parse(record.status) : {},
1623
+ events: record.events ? JSON.parse(record.events) : [],
1624
+ links: record.links ? JSON.parse(record.links) : [],
1625
+ other: record.other ? JSON.parse(record.other) : {},
906
1626
  startTime: new Date(record.startTime),
907
1627
  endTime: new Date(record.endTime),
908
1628
  createdAt: new Date(record.createdAt)
909
1629
  };
1630
+ if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
1631
+ processed.parentSpanId = "";
1632
+ } else {
1633
+ processed.parentSpanId = String(processed.parentSpanId);
1634
+ }
1635
+ return processed;
910
1636
  });
911
1637
  } catch (error) {
912
1638
  throw new MastraError(
@@ -920,131 +1646,177 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
920
1646
  );
921
1647
  }
922
1648
  }
923
- async saveEvals({ evals }) {
1649
+ async getTracesPaginated(args) {
924
1650
  try {
925
- const table = await this.lanceClient.openTable(TABLE_EVALS);
926
- const transformedEvals = evals.map((evalRecord) => ({
927
- input: evalRecord.input,
928
- output: evalRecord.output,
929
- agent_name: evalRecord.agentName,
930
- metric_name: evalRecord.metricName,
931
- result: JSON.stringify(evalRecord.result),
932
- instructions: evalRecord.instructions,
933
- test_info: JSON.stringify(evalRecord.testInfo),
934
- global_run_id: evalRecord.globalRunId,
935
- run_id: evalRecord.runId,
936
- created_at: new Date(evalRecord.createdAt).getTime()
937
- }));
938
- await table.add(transformedEvals, { mode: "append" });
939
- return evals;
1651
+ const table = await this.client.openTable(TABLE_TRACES);
1652
+ const query = table.query();
1653
+ const conditions = [];
1654
+ if (args.name) {
1655
+ conditions.push(`name = '${args.name}'`);
1656
+ }
1657
+ if (args.scope) {
1658
+ conditions.push(`scope = '${args.scope}'`);
1659
+ }
1660
+ if (args.attributes) {
1661
+ const attributesStr = JSON.stringify(args.attributes);
1662
+ conditions.push(`attributes LIKE '%${attributesStr.replace(/"/g, '\\"')}%'`);
1663
+ }
1664
+ if (args.dateRange?.start) {
1665
+ conditions.push(`\`createdAt\` >= ${args.dateRange.start.getTime()}`);
1666
+ }
1667
+ if (args.dateRange?.end) {
1668
+ conditions.push(`\`createdAt\` <= ${args.dateRange.end.getTime()}`);
1669
+ }
1670
+ if (conditions.length > 0) {
1671
+ const whereClause = conditions.join(" AND ");
1672
+ query.where(whereClause);
1673
+ }
1674
+ let total = 0;
1675
+ if (conditions.length > 0) {
1676
+ const countQuery = table.query().where(conditions.join(" AND "));
1677
+ const allRecords = await countQuery.toArray();
1678
+ total = allRecords.length;
1679
+ } else {
1680
+ total = await table.countRows();
1681
+ }
1682
+ const page = args.page || 0;
1683
+ const perPage = args.perPage || 10;
1684
+ const offset = page * perPage;
1685
+ query.limit(perPage);
1686
+ if (offset > 0) {
1687
+ query.offset(offset);
1688
+ }
1689
+ const records = await query.toArray();
1690
+ const traces = records.map((record) => {
1691
+ const processed = {
1692
+ ...record,
1693
+ attributes: record.attributes ? JSON.parse(record.attributes) : {},
1694
+ status: record.status ? JSON.parse(record.status) : {},
1695
+ events: record.events ? JSON.parse(record.events) : [],
1696
+ links: record.links ? JSON.parse(record.links) : [],
1697
+ other: record.other ? JSON.parse(record.other) : {},
1698
+ startTime: new Date(record.startTime),
1699
+ endTime: new Date(record.endTime),
1700
+ createdAt: new Date(record.createdAt)
1701
+ };
1702
+ if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
1703
+ processed.parentSpanId = "";
1704
+ } else {
1705
+ processed.parentSpanId = String(processed.parentSpanId);
1706
+ }
1707
+ return processed;
1708
+ });
1709
+ return {
1710
+ traces,
1711
+ total,
1712
+ page,
1713
+ perPage,
1714
+ hasMore: total > (page + 1) * perPage
1715
+ };
940
1716
  } catch (error) {
941
1717
  throw new MastraError(
942
1718
  {
943
- id: "LANCE_STORE_SAVE_EVALS_FAILED",
1719
+ id: "LANCE_STORE_GET_TRACES_PAGINATED_FAILED",
944
1720
  domain: ErrorDomain.STORAGE,
945
- category: ErrorCategory.THIRD_PARTY
1721
+ category: ErrorCategory.THIRD_PARTY,
1722
+ details: { name: args.name ?? "", scope: args.scope ?? "" }
946
1723
  },
947
1724
  error
948
1725
  );
949
1726
  }
950
1727
  }
951
- async getEvalsByAgentName(agentName, type) {
1728
+ async batchTraceInsert({ records }) {
1729
+ this.logger.debug("Batch inserting traces", { count: records.length });
1730
+ await this.operations.batchInsert({
1731
+ tableName: TABLE_TRACES,
1732
+ records
1733
+ });
1734
+ }
1735
+ };
1736
+ function parseWorkflowRun(row) {
1737
+ let parsedSnapshot = row.snapshot;
1738
+ if (typeof parsedSnapshot === "string") {
952
1739
  try {
953
- if (type) {
954
- this.logger.warn("Type is not implemented yet in LanceDB storage");
955
- }
956
- const table = await this.lanceClient.openTable(TABLE_EVALS);
957
- const query = table.query().where(`agent_name = '${agentName}'`);
1740
+ parsedSnapshot = JSON.parse(row.snapshot);
1741
+ } catch (e) {
1742
+ console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
1743
+ }
1744
+ }
1745
+ return {
1746
+ workflowName: row.workflow_name,
1747
+ runId: row.run_id,
1748
+ snapshot: parsedSnapshot,
1749
+ createdAt: ensureDate(row.createdAt),
1750
+ updatedAt: ensureDate(row.updatedAt),
1751
+ resourceId: row.resourceId
1752
+ };
1753
+ }
1754
+ var StoreWorkflowsLance = class extends WorkflowsStorage {
1755
+ client;
1756
+ constructor({ client }) {
1757
+ super();
1758
+ this.client = client;
1759
+ }
1760
+ async persistWorkflowSnapshot({
1761
+ workflowName,
1762
+ runId,
1763
+ snapshot
1764
+ }) {
1765
+ try {
1766
+ const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1767
+ const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
958
1768
  const records = await query.toArray();
959
- return records.map((record) => {
960
- return {
961
- id: record.id,
962
- input: record.input,
963
- output: record.output,
964
- agentName: record.agent_name,
965
- metricName: record.metric_name,
966
- result: JSON.parse(record.result),
967
- instructions: record.instructions,
968
- testInfo: JSON.parse(record.test_info),
969
- globalRunId: record.global_run_id,
970
- runId: record.run_id,
971
- createdAt: new Date(record.created_at).toString()
972
- };
973
- });
1769
+ let createdAt;
1770
+ const now = Date.now();
1771
+ if (records.length > 0) {
1772
+ createdAt = records[0].createdAt ?? now;
1773
+ } else {
1774
+ createdAt = now;
1775
+ }
1776
+ const record = {
1777
+ workflow_name: workflowName,
1778
+ run_id: runId,
1779
+ snapshot: JSON.stringify(snapshot),
1780
+ createdAt,
1781
+ updatedAt: now
1782
+ };
1783
+ await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
974
1784
  } catch (error) {
975
1785
  throw new MastraError(
976
1786
  {
977
- id: "LANCE_STORE_GET_EVALS_BY_AGENT_NAME_FAILED",
1787
+ id: "LANCE_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
978
1788
  domain: ErrorDomain.STORAGE,
979
1789
  category: ErrorCategory.THIRD_PARTY,
980
- details: { agentName }
1790
+ details: { workflowName, runId }
981
1791
  },
982
1792
  error
983
1793
  );
984
1794
  }
985
1795
  }
986
- parseWorkflowRun(row) {
987
- let parsedSnapshot = row.snapshot;
988
- if (typeof parsedSnapshot === "string") {
989
- try {
990
- parsedSnapshot = JSON.parse(row.snapshot);
991
- } catch (e) {
992
- console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
993
- }
994
- }
995
- return {
996
- workflowName: row.workflow_name,
997
- runId: row.run_id,
998
- snapshot: parsedSnapshot,
999
- createdAt: this.ensureDate(row.createdAt),
1000
- updatedAt: this.ensureDate(row.updatedAt),
1001
- resourceId: row.resourceId
1002
- };
1003
- }
1004
- async getWorkflowRuns(args) {
1005
- try {
1006
- const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
1007
- const query = table.query();
1008
- if (args?.workflowName) {
1009
- query.where(`workflow_name = '${args.workflowName}'`);
1010
- }
1011
- if (args?.fromDate) {
1012
- query.where(`\`createdAt\` >= ${args.fromDate.getTime()}`);
1013
- }
1014
- if (args?.toDate) {
1015
- query.where(`\`createdAt\` <= ${args.toDate.getTime()}`);
1016
- }
1017
- if (args?.limit) {
1018
- query.limit(args.limit);
1019
- }
1020
- if (args?.offset) {
1021
- query.offset(args.offset);
1022
- }
1796
+ async loadWorkflowSnapshot({
1797
+ workflowName,
1798
+ runId
1799
+ }) {
1800
+ try {
1801
+ const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1802
+ const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
1023
1803
  const records = await query.toArray();
1024
- return {
1025
- runs: records.map((record) => this.parseWorkflowRun(record)),
1026
- total: records.length
1027
- };
1804
+ return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
1028
1805
  } catch (error) {
1029
1806
  throw new MastraError(
1030
1807
  {
1031
- id: "LANCE_STORE_GET_WORKFLOW_RUNS_FAILED",
1808
+ id: "LANCE_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
1032
1809
  domain: ErrorDomain.STORAGE,
1033
1810
  category: ErrorCategory.THIRD_PARTY,
1034
- details: { namespace: args?.namespace ?? "", workflowName: args?.workflowName ?? "" }
1811
+ details: { workflowName, runId }
1035
1812
  },
1036
1813
  error
1037
1814
  );
1038
1815
  }
1039
1816
  }
1040
- /**
1041
- * Retrieve a single workflow run by its runId.
1042
- * @param args The ID of the workflow run to retrieve
1043
- * @returns The workflow run object or null if not found
1044
- */
1045
1817
  async getWorkflowRunById(args) {
1046
1818
  try {
1047
- const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
1819
+ const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1048
1820
  let whereClause = `run_id = '${args.runId}'`;
1049
1821
  if (args.workflowName) {
1050
1822
  whereClause += ` AND workflow_name = '${args.workflowName}'`;
@@ -1053,7 +1825,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
1053
1825
  const records = await query.toArray();
1054
1826
  if (records.length === 0) return null;
1055
1827
  const record = records[0];
1056
- return this.parseWorkflowRun(record);
1828
+ return parseWorkflowRun(record);
1057
1829
  } catch (error) {
1058
1830
  throw new MastraError(
1059
1831
  {
@@ -1066,96 +1838,328 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
1066
1838
  );
1067
1839
  }
1068
1840
  }
1069
- async persistWorkflowSnapshot({
1070
- workflowName,
1071
- runId,
1072
- snapshot
1073
- }) {
1841
+ async getWorkflowRuns(args) {
1074
1842
  try {
1075
- const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
1076
- const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
1077
- const records = await query.toArray();
1078
- let createdAt;
1079
- const now = Date.now();
1080
- if (records.length > 0) {
1081
- createdAt = records[0].createdAt ?? now;
1843
+ const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1844
+ let query = table.query();
1845
+ const conditions = [];
1846
+ if (args?.workflowName) {
1847
+ conditions.push(`workflow_name = '${args.workflowName.replace(/'/g, "''")}'`);
1848
+ }
1849
+ if (args?.resourceId) {
1850
+ conditions.push(`\`resourceId\` = '${args.resourceId}'`);
1851
+ }
1852
+ if (args?.fromDate instanceof Date) {
1853
+ conditions.push(`\`createdAt\` >= ${args.fromDate.getTime()}`);
1854
+ }
1855
+ if (args?.toDate instanceof Date) {
1856
+ conditions.push(`\`createdAt\` <= ${args.toDate.getTime()}`);
1857
+ }
1858
+ let total = 0;
1859
+ if (conditions.length > 0) {
1860
+ query = query.where(conditions.join(" AND "));
1861
+ total = await table.countRows(conditions.join(" AND "));
1082
1862
  } else {
1083
- createdAt = now;
1863
+ total = await table.countRows();
1084
1864
  }
1085
- const record = {
1086
- workflow_name: workflowName,
1087
- run_id: runId,
1088
- snapshot: JSON.stringify(snapshot),
1089
- createdAt,
1090
- updatedAt: now
1865
+ if (args?.limit) {
1866
+ query.limit(args.limit);
1867
+ }
1868
+ if (args?.offset) {
1869
+ query.offset(args.offset);
1870
+ }
1871
+ const records = await query.toArray();
1872
+ return {
1873
+ runs: records.map((record) => parseWorkflowRun(record)),
1874
+ total: total || records.length
1091
1875
  };
1092
- await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
1093
1876
  } catch (error) {
1094
1877
  throw new MastraError(
1095
1878
  {
1096
- id: "LANCE_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
1879
+ id: "LANCE_STORE_GET_WORKFLOW_RUNS_FAILED",
1097
1880
  domain: ErrorDomain.STORAGE,
1098
1881
  category: ErrorCategory.THIRD_PARTY,
1099
- details: { workflowName, runId }
1882
+ details: { namespace: args?.namespace ?? "", workflowName: args?.workflowName ?? "" }
1100
1883
  },
1101
1884
  error
1102
1885
  );
1103
1886
  }
1104
1887
  }
1105
- async loadWorkflowSnapshot({
1106
- workflowName,
1107
- runId
1108
- }) {
1888
+ };
1889
+
1890
+ // src/storage/index.ts
1891
+ var LanceStorage = class _LanceStorage extends MastraStorage {
1892
+ stores;
1893
+ lanceClient;
1894
+ /**
1895
+ * Creates a new instance of LanceStorage
1896
+ * @param uri The URI to connect to LanceDB
1897
+ * @param options connection options
1898
+ *
1899
+ * Usage:
1900
+ *
1901
+ * Connect to a local database
1902
+ * ```ts
1903
+ * const store = await LanceStorage.create('/path/to/db');
1904
+ * ```
1905
+ *
1906
+ * Connect to a LanceDB cloud database
1907
+ * ```ts
1908
+ * const store = await LanceStorage.create('db://host:port');
1909
+ * ```
1910
+ *
1911
+ * Connect to a cloud database
1912
+ * ```ts
1913
+ * const store = await LanceStorage.create('s3://bucket/db', { storageOptions: { timeout: '60s' } });
1914
+ * ```
1915
+ */
1916
+ static async create(name, uri, options) {
1917
+ const instance = new _LanceStorage(name);
1109
1918
  try {
1110
- const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
1111
- const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
1112
- const records = await query.toArray();
1113
- return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
1114
- } catch (error) {
1919
+ instance.lanceClient = await connect(uri, options);
1920
+ const operations = new StoreOperationsLance({ client: instance.lanceClient });
1921
+ instance.stores = {
1922
+ operations: new StoreOperationsLance({ client: instance.lanceClient }),
1923
+ workflows: new StoreWorkflowsLance({ client: instance.lanceClient }),
1924
+ traces: new StoreTracesLance({ client: instance.lanceClient, operations }),
1925
+ scores: new StoreScoresLance({ client: instance.lanceClient }),
1926
+ memory: new StoreMemoryLance({ client: instance.lanceClient, operations }),
1927
+ legacyEvals: new StoreLegacyEvalsLance({ client: instance.lanceClient })
1928
+ };
1929
+ return instance;
1930
+ } catch (e) {
1115
1931
  throw new MastraError(
1116
1932
  {
1117
- id: "LANCE_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
1933
+ id: "STORAGE_LANCE_STORAGE_CONNECT_FAILED",
1118
1934
  domain: ErrorDomain.STORAGE,
1119
1935
  category: ErrorCategory.THIRD_PARTY,
1120
- details: { workflowName, runId }
1936
+ text: `Failed to connect to LanceDB: ${e.message || e}`,
1937
+ details: { uri, optionsProvided: !!options }
1121
1938
  },
1122
- error
1939
+ e
1123
1940
  );
1124
1941
  }
1125
1942
  }
1126
- async getTracesPaginated(_args) {
1127
- throw new MastraError(
1128
- {
1129
- id: "LANCE_STORE_GET_TRACES_PAGINATED_FAILED",
1130
- domain: ErrorDomain.STORAGE,
1131
- category: ErrorCategory.THIRD_PARTY
1132
- },
1133
- "Method not implemented."
1134
- );
1943
+ /**
1944
+ * @internal
1945
+ * Private constructor to enforce using the create factory method
1946
+ */
1947
+ constructor(name) {
1948
+ super({ name });
1949
+ const operations = new StoreOperationsLance({ client: this.lanceClient });
1950
+ this.stores = {
1951
+ operations: new StoreOperationsLance({ client: this.lanceClient }),
1952
+ workflows: new StoreWorkflowsLance({ client: this.lanceClient }),
1953
+ traces: new StoreTracesLance({ client: this.lanceClient, operations }),
1954
+ scores: new StoreScoresLance({ client: this.lanceClient }),
1955
+ legacyEvals: new StoreLegacyEvalsLance({ client: this.lanceClient }),
1956
+ memory: new StoreMemoryLance({ client: this.lanceClient, operations })
1957
+ };
1135
1958
  }
1136
- async getThreadsByResourceIdPaginated(_args) {
1137
- throw new MastraError(
1138
- {
1139
- id: "LANCE_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
1140
- domain: ErrorDomain.STORAGE,
1141
- category: ErrorCategory.THIRD_PARTY
1142
- },
1143
- "Method not implemented."
1144
- );
1959
+ async createTable({
1960
+ tableName,
1961
+ schema
1962
+ }) {
1963
+ return this.stores.operations.createTable({ tableName, schema });
1145
1964
  }
1146
- async getMessagesPaginated(_args) {
1147
- throw new MastraError(
1148
- {
1149
- id: "LANCE_STORE_GET_MESSAGES_PAGINATED_FAILED",
1150
- domain: ErrorDomain.STORAGE,
1151
- category: ErrorCategory.THIRD_PARTY
1152
- },
1153
- "Method not implemented."
1154
- );
1965
+ async dropTable({ tableName }) {
1966
+ return this.stores.operations.dropTable({ tableName });
1967
+ }
1968
+ async alterTable({
1969
+ tableName,
1970
+ schema,
1971
+ ifNotExists
1972
+ }) {
1973
+ return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
1974
+ }
1975
+ async clearTable({ tableName }) {
1976
+ return this.stores.operations.clearTable({ tableName });
1977
+ }
1978
+ async insert({ tableName, record }) {
1979
+ return this.stores.operations.insert({ tableName, record });
1980
+ }
1981
+ async batchInsert({ tableName, records }) {
1982
+ return this.stores.operations.batchInsert({ tableName, records });
1983
+ }
1984
+ async load({ tableName, keys }) {
1985
+ return this.stores.operations.load({ tableName, keys });
1986
+ }
1987
+ async getThreadById({ threadId }) {
1988
+ return this.stores.memory.getThreadById({ threadId });
1989
+ }
1990
+ async getThreadsByResourceId({ resourceId }) {
1991
+ return this.stores.memory.getThreadsByResourceId({ resourceId });
1992
+ }
1993
+ /**
1994
+ * Saves a thread to the database. This function doesn't overwrite existing threads.
1995
+ * @param thread - The thread to save
1996
+ * @returns The saved thread
1997
+ */
1998
+ async saveThread({ thread }) {
1999
+ return this.stores.memory.saveThread({ thread });
2000
+ }
2001
+ async updateThread({
2002
+ id,
2003
+ title,
2004
+ metadata
2005
+ }) {
2006
+ return this.stores.memory.updateThread({ id, title, metadata });
2007
+ }
2008
+ async deleteThread({ threadId }) {
2009
+ return this.stores.memory.deleteThread({ threadId });
2010
+ }
2011
+ get supports() {
2012
+ return {
2013
+ selectByIncludeResourceScope: true,
2014
+ resourceWorkingMemory: true,
2015
+ hasColumn: true,
2016
+ createTable: true,
2017
+ deleteMessages: false
2018
+ };
2019
+ }
2020
+ async getResourceById({ resourceId }) {
2021
+ return this.stores.memory.getResourceById({ resourceId });
2022
+ }
2023
+ async saveResource({ resource }) {
2024
+ return this.stores.memory.saveResource({ resource });
2025
+ }
2026
+ async updateResource({
2027
+ resourceId,
2028
+ workingMemory,
2029
+ metadata
2030
+ }) {
2031
+ return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
2032
+ }
2033
+ /**
2034
+ * Processes messages to include context messages based on withPreviousMessages and withNextMessages
2035
+ * @param records - The sorted array of records to process
2036
+ * @param include - The array of include specifications with context parameters
2037
+ * @returns The processed array with context messages included
2038
+ */
2039
+ processMessagesWithContext(records, include) {
2040
+ const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
2041
+ if (messagesWithContext.length === 0) {
2042
+ return records;
2043
+ }
2044
+ const messageIndexMap = /* @__PURE__ */ new Map();
2045
+ records.forEach((message, index) => {
2046
+ messageIndexMap.set(message.id, index);
2047
+ });
2048
+ const additionalIndices = /* @__PURE__ */ new Set();
2049
+ for (const item of messagesWithContext) {
2050
+ const messageIndex = messageIndexMap.get(item.id);
2051
+ if (messageIndex !== void 0) {
2052
+ if (item.withPreviousMessages) {
2053
+ const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
2054
+ for (let i = startIdx; i < messageIndex; i++) {
2055
+ additionalIndices.add(i);
2056
+ }
2057
+ }
2058
+ if (item.withNextMessages) {
2059
+ const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
2060
+ for (let i = messageIndex + 1; i <= endIdx; i++) {
2061
+ additionalIndices.add(i);
2062
+ }
2063
+ }
2064
+ }
2065
+ }
2066
+ if (additionalIndices.size === 0) {
2067
+ return records;
2068
+ }
2069
+ const originalMatchIds = new Set(include.map((item) => item.id));
2070
+ const allIndices = /* @__PURE__ */ new Set();
2071
+ records.forEach((record, index) => {
2072
+ if (originalMatchIds.has(record.id)) {
2073
+ allIndices.add(index);
2074
+ }
2075
+ });
2076
+ additionalIndices.forEach((index) => {
2077
+ allIndices.add(index);
2078
+ });
2079
+ return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
2080
+ }
2081
+ async getMessages({
2082
+ threadId,
2083
+ resourceId,
2084
+ selectBy,
2085
+ format,
2086
+ threadConfig
2087
+ }) {
2088
+ return this.stores.memory.getMessages({ threadId, resourceId, selectBy, format, threadConfig });
2089
+ }
2090
+ async saveMessages(args) {
2091
+ return this.stores.memory.saveMessages(args);
2092
+ }
2093
+ async getThreadsByResourceIdPaginated(args) {
2094
+ return this.stores.memory.getThreadsByResourceIdPaginated(args);
2095
+ }
2096
+ async getMessagesPaginated(args) {
2097
+ return this.stores.memory.getMessagesPaginated(args);
1155
2098
  }
1156
2099
  async updateMessages(_args) {
1157
- this.logger.error("updateMessages is not yet implemented in LanceStore");
1158
- throw new Error("Method not implemented");
2100
+ return this.stores.memory.updateMessages(_args);
2101
+ }
2102
+ async getTraceById(args) {
2103
+ return this.stores.traces.getTraceById(args);
2104
+ }
2105
+ async getTraces(args) {
2106
+ return this.stores.traces.getTraces(args);
2107
+ }
2108
+ async getTracesPaginated(args) {
2109
+ return this.stores.traces.getTracesPaginated(args);
2110
+ }
2111
+ async getEvalsByAgentName(agentName, type) {
2112
+ return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
2113
+ }
2114
+ async getEvals(options) {
2115
+ return this.stores.legacyEvals.getEvals(options);
2116
+ }
2117
+ async getWorkflowRuns(args) {
2118
+ return this.stores.workflows.getWorkflowRuns(args);
2119
+ }
2120
+ async getWorkflowRunById(args) {
2121
+ return this.stores.workflows.getWorkflowRunById(args);
2122
+ }
2123
+ async persistWorkflowSnapshot({
2124
+ workflowName,
2125
+ runId,
2126
+ snapshot
2127
+ }) {
2128
+ return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
2129
+ }
2130
+ async loadWorkflowSnapshot({
2131
+ workflowName,
2132
+ runId
2133
+ }) {
2134
+ return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
2135
+ }
2136
+ async getScoreById({ id: _id }) {
2137
+ return this.stores.scores.getScoreById({ id: _id });
2138
+ }
2139
+ async getScoresByScorerId({
2140
+ scorerId,
2141
+ source,
2142
+ entityId,
2143
+ entityType,
2144
+ pagination
2145
+ }) {
2146
+ return this.stores.scores.getScoresByScorerId({ scorerId, source, pagination, entityId, entityType });
2147
+ }
2148
+ async saveScore(_score) {
2149
+ return this.stores.scores.saveScore(_score);
2150
+ }
2151
+ async getScoresByRunId({
2152
+ runId,
2153
+ pagination
2154
+ }) {
2155
+ return this.stores.scores.getScoresByRunId({ runId, pagination });
2156
+ }
2157
+ async getScoresByEntityId({
2158
+ entityId,
2159
+ entityType,
2160
+ pagination
2161
+ }) {
2162
+ return this.stores.scores.getScoresByEntityId({ entityId, entityType, pagination });
1159
2163
  }
1160
2164
  };
1161
2165
  var LanceFilterTranslator = class extends BaseFilterTranslator {
@@ -2214,3 +3218,5 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2214
3218
  };
2215
3219
 
2216
3220
  export { LanceStorage, LanceVectorStore };
3221
+ //# sourceMappingURL=index.js.map
3222
+ //# sourceMappingURL=index.js.map