@mastra/lance 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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;
@@ -505,333 +1327,213 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
505
1327
  } else {
506
1328
  return `${quotedKey} = ${value}`;
507
1329
  }
508
- }).join(" AND ");
509
- this.logger.debug("where clause generated: " + filterConditions);
510
- 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
- );
1330
+ }).join(" AND ");
1331
+ this.logger.debug("where clause generated: " + filterConditions);
1332
+ query.where(filterConditions);
1333
+ }
1334
+ const result = await query.limit(1).toArray();
1335
+ if (result.length === 0) {
1336
+ this.logger.debug("No record found");
1337
+ return null;
1338
+ }
1339
+ return processResultWithTypeConversion(result[0], tableSchema);
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 table = await this.client.openTable(TABLE_SCORERS);
1363
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1364
+ const allowedFields = new Set(schema.fields.map((f) => f.name));
1365
+ const filteredScore = {};
1366
+ Object.keys(score).forEach((key) => {
1367
+ if (allowedFields.has(key)) {
1368
+ filteredScore[key] = score[key];
1369
+ }
1370
+ });
1371
+ for (const key in filteredScore) {
1372
+ if (filteredScore[key] !== null && typeof filteredScore[key] === "object" && !(filteredScore[key] instanceof Date)) {
1373
+ filteredScore[key] = JSON.stringify(filteredScore[key]);
1374
+ }
1375
+ }
1376
+ console.log("Saving score to LanceStorage:", filteredScore);
1377
+ await table.add([filteredScore], { mode: "append" });
1378
+ return { score };
644
1379
  } catch (error) {
645
1380
  throw new MastraError(
646
1381
  {
647
- id: "LANCE_STORE_SAVE_THREAD_FAILED",
1382
+ id: "LANCE_STORAGE_SAVE_SCORE_FAILED",
1383
+ text: "Failed to save score in LanceStorage",
648
1384
  domain: ErrorDomain.STORAGE,
649
- category: ErrorCategory.THIRD_PARTY
1385
+ category: ErrorCategory.THIRD_PARTY,
1386
+ details: { error: error?.message }
650
1387
  },
651
1388
  error
652
1389
  );
653
1390
  }
654
1391
  }
655
- async updateThread({
656
- id,
657
- title,
658
- metadata
659
- }) {
1392
+ async getScoreById({ id }) {
660
1393
  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}'`);
1394
+ const table = await this.client.openTable(TABLE_SCORERS);
1395
+ const query = table.query().where(`id = '${id}'`).limit(1);
665
1396
  const records = await query.toArray();
666
- return this.processResultWithTypeConversion(
667
- records[0],
668
- await this.getTableSchema(TABLE_THREADS)
669
- );
1397
+ if (records.length === 0) return null;
1398
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1399
+ return processResultWithTypeConversion(records[0], schema);
670
1400
  } catch (error) {
671
1401
  throw new MastraError(
672
1402
  {
673
- id: "LANCE_STORE_UPDATE_THREAD_FAILED",
1403
+ id: "LANCE_STORAGE_GET_SCORE_BY_ID_FAILED",
1404
+ text: "Failed to get score by id in LanceStorage",
674
1405
  domain: ErrorDomain.STORAGE,
675
- category: ErrorCategory.THIRD_PARTY
1406
+ category: ErrorCategory.THIRD_PARTY,
1407
+ details: { error: error?.message }
676
1408
  },
677
1409
  error
678
1410
  );
679
1411
  }
680
1412
  }
681
- async deleteThread({ threadId }) {
1413
+ async getScoresByScorerId({
1414
+ scorerId,
1415
+ pagination
1416
+ }) {
682
1417
  try {
683
- const table = await this.lanceClient.openTable(TABLE_THREADS);
684
- await table.delete(`id = '${threadId}'`);
1418
+ const table = await this.client.openTable(TABLE_SCORERS);
1419
+ const { page = 0, perPage = 10 } = pagination || {};
1420
+ const offset = page * perPage;
1421
+ const query = table.query().where(`\`scorerId\` = '${scorerId}'`).limit(perPage);
1422
+ if (offset > 0) query.offset(offset);
1423
+ const records = await query.toArray();
1424
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1425
+ const scores = processResultWithTypeConversion(records, schema);
1426
+ const allRecords = await table.query().where(`\`scorerId\` = '${scorerId}'`).toArray();
1427
+ const total = allRecords.length;
1428
+ return {
1429
+ pagination: {
1430
+ page,
1431
+ perPage,
1432
+ total,
1433
+ hasMore: offset + scores.length < total
1434
+ },
1435
+ scores
1436
+ };
685
1437
  } catch (error) {
686
1438
  throw new MastraError(
687
1439
  {
688
- id: "LANCE_STORE_DELETE_THREAD_FAILED",
1440
+ id: "LANCE_STORAGE_GET_SCORES_BY_SCORER_ID_FAILED",
1441
+ text: "Failed to get scores by scorerId in LanceStorage",
689
1442
  domain: ErrorDomain.STORAGE,
690
- category: ErrorCategory.THIRD_PARTY
1443
+ category: ErrorCategory.THIRD_PARTY,
1444
+ details: { error: error?.message }
691
1445
  },
692
1446
  error
693
1447
  );
694
1448
  }
695
1449
  }
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
1450
+ async getScoresByRunId({
1451
+ runId,
1452
+ pagination
750
1453
  }) {
751
1454
  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();
1455
+ const table = await this.client.openTable(TABLE_SCORERS);
1456
+ const { page = 0, perPage = 10 } = pagination || {};
1457
+ const offset = page * perPage;
1458
+ const query = table.query().where(`\`runId\` = '${runId}'`).limit(perPage);
1459
+ if (offset > 0) query.offset(offset);
1460
+ const records = await query.toArray();
1461
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1462
+ const scores = processResultWithTypeConversion(records, schema);
1463
+ const allRecords = await table.query().where(`\`runId\` = '${runId}'`).toArray();
1464
+ const total = allRecords.length;
1465
+ return {
1466
+ pagination: {
1467
+ page,
1468
+ perPage,
1469
+ total,
1470
+ hasMore: offset + scores.length < total
1471
+ },
1472
+ scores
1473
+ };
791
1474
  } catch (error) {
792
1475
  throw new MastraError(
793
1476
  {
794
- id: "LANCE_STORE_GET_MESSAGES_FAILED",
1477
+ id: "LANCE_STORAGE_GET_SCORES_BY_RUN_ID_FAILED",
1478
+ text: "Failed to get scores by runId in LanceStorage",
795
1479
  domain: ErrorDomain.STORAGE,
796
- category: ErrorCategory.THIRD_PARTY
1480
+ category: ErrorCategory.THIRD_PARTY,
1481
+ details: { error: error?.message }
797
1482
  },
798
1483
  error
799
1484
  );
800
1485
  }
801
1486
  }
802
- async saveMessages(args) {
1487
+ async getScoresByEntityId({
1488
+ entityId,
1489
+ entityType,
1490
+ pagination
1491
+ }) {
803
1492
  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();
1493
+ const table = await this.client.openTable(TABLE_SCORERS);
1494
+ const { page = 0, perPage = 10 } = pagination || {};
1495
+ const offset = page * perPage;
1496
+ const query = table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).limit(perPage);
1497
+ if (offset > 0) query.offset(offset);
1498
+ const records = await query.toArray();
1499
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1500
+ const scores = processResultWithTypeConversion(records, schema);
1501
+ const allRecords = await table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).toArray();
1502
+ const total = allRecords.length;
1503
+ return {
1504
+ pagination: {
1505
+ page,
1506
+ perPage,
1507
+ total,
1508
+ hasMore: offset + scores.length < total
1509
+ },
1510
+ scores
1511
+ };
821
1512
  } catch (error) {
822
1513
  throw new MastraError(
823
1514
  {
824
- id: "LANCE_STORE_SAVE_MESSAGES_FAILED",
1515
+ id: "LANCE_STORAGE_GET_SCORES_BY_ENTITY_ID_FAILED",
1516
+ text: "Failed to get scores by entityId and entityType in LanceStorage",
825
1517
  domain: ErrorDomain.STORAGE,
826
- category: ErrorCategory.THIRD_PARTY
1518
+ category: ErrorCategory.THIRD_PARTY,
1519
+ details: { error: error?.message }
827
1520
  },
828
1521
  error
829
1522
  );
830
1523
  }
831
1524
  }
1525
+ };
1526
+ var StoreTracesLance = class extends TracesStorage {
1527
+ client;
1528
+ operations;
1529
+ constructor({ client, operations }) {
1530
+ super();
1531
+ this.client = client;
1532
+ this.operations = operations;
1533
+ }
832
1534
  async saveTrace({ trace }) {
833
1535
  try {
834
- const table = await this.lanceClient.openTable(TABLE_TRACES);
1536
+ const table = await this.client.openTable(TABLE_TRACES);
835
1537
  const record = {
836
1538
  ...trace,
837
1539
  attributes: JSON.stringify(trace.attributes),
@@ -855,10 +1557,10 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
855
1557
  }
856
1558
  async getTraceById({ traceId }) {
857
1559
  try {
858
- const table = await this.lanceClient.openTable(TABLE_TRACES);
1560
+ const table = await this.client.openTable(TABLE_TRACES);
859
1561
  const query = table.query().where(`id = '${traceId}'`);
860
1562
  const records = await query.toArray();
861
- return this.processResultWithTypeConversion(records[0], await this.getTableSchema(TABLE_TRACES));
1563
+ return records[0];
862
1564
  } catch (error) {
863
1565
  throw new MastraError(
864
1566
  {
@@ -878,7 +1580,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
878
1580
  attributes
879
1581
  }) {
880
1582
  try {
881
- const table = await this.lanceClient.openTable(TABLE_TRACES);
1583
+ const table = await this.client.openTable(TABLE_TRACES);
882
1584
  const query = table.query();
883
1585
  if (name) {
884
1586
  query.where(`name = '${name}'`);
@@ -896,17 +1598,23 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
896
1598
  }
897
1599
  const records = await query.toArray();
898
1600
  return records.map((record) => {
899
- return {
1601
+ const processed = {
900
1602
  ...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),
1603
+ attributes: record.attributes ? JSON.parse(record.attributes) : {},
1604
+ status: record.status ? JSON.parse(record.status) : {},
1605
+ events: record.events ? JSON.parse(record.events) : [],
1606
+ links: record.links ? JSON.parse(record.links) : [],
1607
+ other: record.other ? JSON.parse(record.other) : {},
906
1608
  startTime: new Date(record.startTime),
907
1609
  endTime: new Date(record.endTime),
908
1610
  createdAt: new Date(record.createdAt)
909
1611
  };
1612
+ if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
1613
+ processed.parentSpanId = "";
1614
+ } else {
1615
+ processed.parentSpanId = String(processed.parentSpanId);
1616
+ }
1617
+ return processed;
910
1618
  });
911
1619
  } catch (error) {
912
1620
  throw new MastraError(
@@ -920,131 +1628,177 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
920
1628
  );
921
1629
  }
922
1630
  }
923
- async saveEvals({ evals }) {
1631
+ async getTracesPaginated(args) {
924
1632
  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;
1633
+ const table = await this.client.openTable(TABLE_TRACES);
1634
+ const query = table.query();
1635
+ const conditions = [];
1636
+ if (args.name) {
1637
+ conditions.push(`name = '${args.name}'`);
1638
+ }
1639
+ if (args.scope) {
1640
+ conditions.push(`scope = '${args.scope}'`);
1641
+ }
1642
+ if (args.attributes) {
1643
+ const attributesStr = JSON.stringify(args.attributes);
1644
+ conditions.push(`attributes LIKE '%${attributesStr.replace(/"/g, '\\"')}%'`);
1645
+ }
1646
+ if (args.dateRange?.start) {
1647
+ conditions.push(`\`createdAt\` >= ${args.dateRange.start.getTime()}`);
1648
+ }
1649
+ if (args.dateRange?.end) {
1650
+ conditions.push(`\`createdAt\` <= ${args.dateRange.end.getTime()}`);
1651
+ }
1652
+ if (conditions.length > 0) {
1653
+ const whereClause = conditions.join(" AND ");
1654
+ query.where(whereClause);
1655
+ }
1656
+ let total = 0;
1657
+ if (conditions.length > 0) {
1658
+ const countQuery = table.query().where(conditions.join(" AND "));
1659
+ const allRecords = await countQuery.toArray();
1660
+ total = allRecords.length;
1661
+ } else {
1662
+ total = await table.countRows();
1663
+ }
1664
+ const page = args.page || 0;
1665
+ const perPage = args.perPage || 10;
1666
+ const offset = page * perPage;
1667
+ query.limit(perPage);
1668
+ if (offset > 0) {
1669
+ query.offset(offset);
1670
+ }
1671
+ const records = await query.toArray();
1672
+ const traces = records.map((record) => {
1673
+ const processed = {
1674
+ ...record,
1675
+ attributes: record.attributes ? JSON.parse(record.attributes) : {},
1676
+ status: record.status ? JSON.parse(record.status) : {},
1677
+ events: record.events ? JSON.parse(record.events) : [],
1678
+ links: record.links ? JSON.parse(record.links) : [],
1679
+ other: record.other ? JSON.parse(record.other) : {},
1680
+ startTime: new Date(record.startTime),
1681
+ endTime: new Date(record.endTime),
1682
+ createdAt: new Date(record.createdAt)
1683
+ };
1684
+ if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
1685
+ processed.parentSpanId = "";
1686
+ } else {
1687
+ processed.parentSpanId = String(processed.parentSpanId);
1688
+ }
1689
+ return processed;
1690
+ });
1691
+ return {
1692
+ traces,
1693
+ total,
1694
+ page,
1695
+ perPage,
1696
+ hasMore: total > (page + 1) * perPage
1697
+ };
940
1698
  } catch (error) {
941
1699
  throw new MastraError(
942
1700
  {
943
- id: "LANCE_STORE_SAVE_EVALS_FAILED",
1701
+ id: "LANCE_STORE_GET_TRACES_PAGINATED_FAILED",
944
1702
  domain: ErrorDomain.STORAGE,
945
- category: ErrorCategory.THIRD_PARTY
1703
+ category: ErrorCategory.THIRD_PARTY,
1704
+ details: { name: args.name ?? "", scope: args.scope ?? "" }
946
1705
  },
947
1706
  error
948
1707
  );
949
1708
  }
950
1709
  }
951
- async getEvalsByAgentName(agentName, type) {
1710
+ async batchTraceInsert({ records }) {
1711
+ this.logger.debug("Batch inserting traces", { count: records.length });
1712
+ await this.operations.batchInsert({
1713
+ tableName: TABLE_TRACES,
1714
+ records
1715
+ });
1716
+ }
1717
+ };
1718
+ function parseWorkflowRun(row) {
1719
+ let parsedSnapshot = row.snapshot;
1720
+ if (typeof parsedSnapshot === "string") {
952
1721
  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}'`);
1722
+ parsedSnapshot = JSON.parse(row.snapshot);
1723
+ } catch (e) {
1724
+ console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
1725
+ }
1726
+ }
1727
+ return {
1728
+ workflowName: row.workflow_name,
1729
+ runId: row.run_id,
1730
+ snapshot: parsedSnapshot,
1731
+ createdAt: ensureDate(row.createdAt),
1732
+ updatedAt: ensureDate(row.updatedAt),
1733
+ resourceId: row.resourceId
1734
+ };
1735
+ }
1736
+ var StoreWorkflowsLance = class extends WorkflowsStorage {
1737
+ client;
1738
+ constructor({ client }) {
1739
+ super();
1740
+ this.client = client;
1741
+ }
1742
+ async persistWorkflowSnapshot({
1743
+ workflowName,
1744
+ runId,
1745
+ snapshot
1746
+ }) {
1747
+ try {
1748
+ const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1749
+ const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
958
1750
  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
- });
1751
+ let createdAt;
1752
+ const now = Date.now();
1753
+ if (records.length > 0) {
1754
+ createdAt = records[0].createdAt ?? now;
1755
+ } else {
1756
+ createdAt = now;
1757
+ }
1758
+ const record = {
1759
+ workflow_name: workflowName,
1760
+ run_id: runId,
1761
+ snapshot: JSON.stringify(snapshot),
1762
+ createdAt,
1763
+ updatedAt: now
1764
+ };
1765
+ await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
974
1766
  } catch (error) {
975
1767
  throw new MastraError(
976
1768
  {
977
- id: "LANCE_STORE_GET_EVALS_BY_AGENT_NAME_FAILED",
1769
+ id: "LANCE_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
978
1770
  domain: ErrorDomain.STORAGE,
979
1771
  category: ErrorCategory.THIRD_PARTY,
980
- details: { agentName }
1772
+ details: { workflowName, runId }
981
1773
  },
982
1774
  error
983
1775
  );
984
1776
  }
985
1777
  }
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
- }
1778
+ async loadWorkflowSnapshot({
1779
+ workflowName,
1780
+ runId
1781
+ }) {
1782
+ try {
1783
+ const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1784
+ const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
1023
1785
  const records = await query.toArray();
1024
- return {
1025
- runs: records.map((record) => this.parseWorkflowRun(record)),
1026
- total: records.length
1027
- };
1786
+ return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
1028
1787
  } catch (error) {
1029
1788
  throw new MastraError(
1030
1789
  {
1031
- id: "LANCE_STORE_GET_WORKFLOW_RUNS_FAILED",
1790
+ id: "LANCE_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
1032
1791
  domain: ErrorDomain.STORAGE,
1033
1792
  category: ErrorCategory.THIRD_PARTY,
1034
- details: { namespace: args?.namespace ?? "", workflowName: args?.workflowName ?? "" }
1793
+ details: { workflowName, runId }
1035
1794
  },
1036
1795
  error
1037
1796
  );
1038
1797
  }
1039
1798
  }
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
1799
  async getWorkflowRunById(args) {
1046
1800
  try {
1047
- const table = await this.lanceClient.openTable(TABLE_WORKFLOW_SNAPSHOT);
1801
+ const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1048
1802
  let whereClause = `run_id = '${args.runId}'`;
1049
1803
  if (args.workflowName) {
1050
1804
  whereClause += ` AND workflow_name = '${args.workflowName}'`;
@@ -1053,7 +1807,7 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
1053
1807
  const records = await query.toArray();
1054
1808
  if (records.length === 0) return null;
1055
1809
  const record = records[0];
1056
- return this.parseWorkflowRun(record);
1810
+ return parseWorkflowRun(record);
1057
1811
  } catch (error) {
1058
1812
  throw new MastraError(
1059
1813
  {
@@ -1066,96 +1820,324 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
1066
1820
  );
1067
1821
  }
1068
1822
  }
1069
- async persistWorkflowSnapshot({
1070
- workflowName,
1071
- runId,
1072
- snapshot
1073
- }) {
1823
+ async getWorkflowRuns(args) {
1074
1824
  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;
1825
+ const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1826
+ let query = table.query();
1827
+ const conditions = [];
1828
+ if (args?.workflowName) {
1829
+ conditions.push(`workflow_name = '${args.workflowName.replace(/'/g, "''")}'`);
1830
+ }
1831
+ if (args?.resourceId) {
1832
+ conditions.push(`\`resourceId\` = '${args.resourceId}'`);
1833
+ }
1834
+ if (args?.fromDate instanceof Date) {
1835
+ conditions.push(`\`createdAt\` >= ${args.fromDate.getTime()}`);
1836
+ }
1837
+ if (args?.toDate instanceof Date) {
1838
+ conditions.push(`\`createdAt\` <= ${args.toDate.getTime()}`);
1839
+ }
1840
+ let total = 0;
1841
+ if (conditions.length > 0) {
1842
+ query = query.where(conditions.join(" AND "));
1843
+ total = await table.countRows(conditions.join(" AND "));
1082
1844
  } else {
1083
- createdAt = now;
1845
+ total = await table.countRows();
1084
1846
  }
1085
- const record = {
1086
- workflow_name: workflowName,
1087
- run_id: runId,
1088
- snapshot: JSON.stringify(snapshot),
1089
- createdAt,
1090
- updatedAt: now
1847
+ if (args?.limit) {
1848
+ query.limit(args.limit);
1849
+ }
1850
+ if (args?.offset) {
1851
+ query.offset(args.offset);
1852
+ }
1853
+ const records = await query.toArray();
1854
+ return {
1855
+ runs: records.map((record) => parseWorkflowRun(record)),
1856
+ total: total || records.length
1091
1857
  };
1092
- await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
1093
1858
  } catch (error) {
1094
1859
  throw new MastraError(
1095
1860
  {
1096
- id: "LANCE_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
1861
+ id: "LANCE_STORE_GET_WORKFLOW_RUNS_FAILED",
1097
1862
  domain: ErrorDomain.STORAGE,
1098
1863
  category: ErrorCategory.THIRD_PARTY,
1099
- details: { workflowName, runId }
1864
+ details: { namespace: args?.namespace ?? "", workflowName: args?.workflowName ?? "" }
1100
1865
  },
1101
1866
  error
1102
1867
  );
1103
1868
  }
1104
1869
  }
1105
- async loadWorkflowSnapshot({
1106
- workflowName,
1107
- runId
1108
- }) {
1870
+ };
1871
+
1872
+ // src/storage/index.ts
1873
+ var LanceStorage = class _LanceStorage extends MastraStorage {
1874
+ stores;
1875
+ lanceClient;
1876
+ /**
1877
+ * Creates a new instance of LanceStorage
1878
+ * @param uri The URI to connect to LanceDB
1879
+ * @param options connection options
1880
+ *
1881
+ * Usage:
1882
+ *
1883
+ * Connect to a local database
1884
+ * ```ts
1885
+ * const store = await LanceStorage.create('/path/to/db');
1886
+ * ```
1887
+ *
1888
+ * Connect to a LanceDB cloud database
1889
+ * ```ts
1890
+ * const store = await LanceStorage.create('db://host:port');
1891
+ * ```
1892
+ *
1893
+ * Connect to a cloud database
1894
+ * ```ts
1895
+ * const store = await LanceStorage.create('s3://bucket/db', { storageOptions: { timeout: '60s' } });
1896
+ * ```
1897
+ */
1898
+ static async create(name, uri, options) {
1899
+ const instance = new _LanceStorage(name);
1109
1900
  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) {
1901
+ instance.lanceClient = await connect(uri, options);
1902
+ const operations = new StoreOperationsLance({ client: instance.lanceClient });
1903
+ instance.stores = {
1904
+ operations: new StoreOperationsLance({ client: instance.lanceClient }),
1905
+ workflows: new StoreWorkflowsLance({ client: instance.lanceClient }),
1906
+ traces: new StoreTracesLance({ client: instance.lanceClient, operations }),
1907
+ scores: new StoreScoresLance({ client: instance.lanceClient }),
1908
+ memory: new StoreMemoryLance({ client: instance.lanceClient, operations }),
1909
+ legacyEvals: new StoreLegacyEvalsLance({ client: instance.lanceClient })
1910
+ };
1911
+ return instance;
1912
+ } catch (e) {
1115
1913
  throw new MastraError(
1116
1914
  {
1117
- id: "LANCE_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
1915
+ id: "STORAGE_LANCE_STORAGE_CONNECT_FAILED",
1118
1916
  domain: ErrorDomain.STORAGE,
1119
1917
  category: ErrorCategory.THIRD_PARTY,
1120
- details: { workflowName, runId }
1918
+ text: `Failed to connect to LanceDB: ${e.message || e}`,
1919
+ details: { uri, optionsProvided: !!options }
1121
1920
  },
1122
- error
1921
+ e
1123
1922
  );
1124
1923
  }
1125
1924
  }
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
- );
1925
+ /**
1926
+ * @internal
1927
+ * Private constructor to enforce using the create factory method
1928
+ */
1929
+ constructor(name) {
1930
+ super({ name });
1931
+ const operations = new StoreOperationsLance({ client: this.lanceClient });
1932
+ this.stores = {
1933
+ operations: new StoreOperationsLance({ client: this.lanceClient }),
1934
+ workflows: new StoreWorkflowsLance({ client: this.lanceClient }),
1935
+ traces: new StoreTracesLance({ client: this.lanceClient, operations }),
1936
+ scores: new StoreScoresLance({ client: this.lanceClient }),
1937
+ legacyEvals: new StoreLegacyEvalsLance({ client: this.lanceClient }),
1938
+ memory: new StoreMemoryLance({ client: this.lanceClient, operations })
1939
+ };
1135
1940
  }
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
- );
1941
+ async createTable({
1942
+ tableName,
1943
+ schema
1944
+ }) {
1945
+ return this.stores.operations.createTable({ tableName, schema });
1145
1946
  }
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
- );
1947
+ async dropTable({ tableName }) {
1948
+ return this.stores.operations.dropTable({ tableName });
1949
+ }
1950
+ async alterTable({
1951
+ tableName,
1952
+ schema,
1953
+ ifNotExists
1954
+ }) {
1955
+ return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
1956
+ }
1957
+ async clearTable({ tableName }) {
1958
+ return this.stores.operations.clearTable({ tableName });
1959
+ }
1960
+ async insert({ tableName, record }) {
1961
+ return this.stores.operations.insert({ tableName, record });
1962
+ }
1963
+ async batchInsert({ tableName, records }) {
1964
+ return this.stores.operations.batchInsert({ tableName, records });
1965
+ }
1966
+ async load({ tableName, keys }) {
1967
+ return this.stores.operations.load({ tableName, keys });
1968
+ }
1969
+ async getThreadById({ threadId }) {
1970
+ return this.stores.memory.getThreadById({ threadId });
1971
+ }
1972
+ async getThreadsByResourceId({ resourceId }) {
1973
+ return this.stores.memory.getThreadsByResourceId({ resourceId });
1974
+ }
1975
+ /**
1976
+ * Saves a thread to the database. This function doesn't overwrite existing threads.
1977
+ * @param thread - The thread to save
1978
+ * @returns The saved thread
1979
+ */
1980
+ async saveThread({ thread }) {
1981
+ return this.stores.memory.saveThread({ thread });
1982
+ }
1983
+ async updateThread({
1984
+ id,
1985
+ title,
1986
+ metadata
1987
+ }) {
1988
+ return this.stores.memory.updateThread({ id, title, metadata });
1989
+ }
1990
+ async deleteThread({ threadId }) {
1991
+ return this.stores.memory.deleteThread({ threadId });
1992
+ }
1993
+ get supports() {
1994
+ return {
1995
+ selectByIncludeResourceScope: true,
1996
+ resourceWorkingMemory: true,
1997
+ hasColumn: true,
1998
+ createTable: true
1999
+ };
2000
+ }
2001
+ async getResourceById({ resourceId }) {
2002
+ return this.stores.memory.getResourceById({ resourceId });
2003
+ }
2004
+ async saveResource({ resource }) {
2005
+ return this.stores.memory.saveResource({ resource });
2006
+ }
2007
+ async updateResource({
2008
+ resourceId,
2009
+ workingMemory,
2010
+ metadata
2011
+ }) {
2012
+ return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
2013
+ }
2014
+ /**
2015
+ * Processes messages to include context messages based on withPreviousMessages and withNextMessages
2016
+ * @param records - The sorted array of records to process
2017
+ * @param include - The array of include specifications with context parameters
2018
+ * @returns The processed array with context messages included
2019
+ */
2020
+ processMessagesWithContext(records, include) {
2021
+ const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
2022
+ if (messagesWithContext.length === 0) {
2023
+ return records;
2024
+ }
2025
+ const messageIndexMap = /* @__PURE__ */ new Map();
2026
+ records.forEach((message, index) => {
2027
+ messageIndexMap.set(message.id, index);
2028
+ });
2029
+ const additionalIndices = /* @__PURE__ */ new Set();
2030
+ for (const item of messagesWithContext) {
2031
+ const messageIndex = messageIndexMap.get(item.id);
2032
+ if (messageIndex !== void 0) {
2033
+ if (item.withPreviousMessages) {
2034
+ const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
2035
+ for (let i = startIdx; i < messageIndex; i++) {
2036
+ additionalIndices.add(i);
2037
+ }
2038
+ }
2039
+ if (item.withNextMessages) {
2040
+ const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
2041
+ for (let i = messageIndex + 1; i <= endIdx; i++) {
2042
+ additionalIndices.add(i);
2043
+ }
2044
+ }
2045
+ }
2046
+ }
2047
+ if (additionalIndices.size === 0) {
2048
+ return records;
2049
+ }
2050
+ const originalMatchIds = new Set(include.map((item) => item.id));
2051
+ const allIndices = /* @__PURE__ */ new Set();
2052
+ records.forEach((record, index) => {
2053
+ if (originalMatchIds.has(record.id)) {
2054
+ allIndices.add(index);
2055
+ }
2056
+ });
2057
+ additionalIndices.forEach((index) => {
2058
+ allIndices.add(index);
2059
+ });
2060
+ return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
2061
+ }
2062
+ async getMessages({
2063
+ threadId,
2064
+ resourceId,
2065
+ selectBy,
2066
+ format,
2067
+ threadConfig
2068
+ }) {
2069
+ return this.stores.memory.getMessages({ threadId, resourceId, selectBy, format, threadConfig });
2070
+ }
2071
+ async saveMessages(args) {
2072
+ return this.stores.memory.saveMessages(args);
2073
+ }
2074
+ async getThreadsByResourceIdPaginated(args) {
2075
+ return this.stores.memory.getThreadsByResourceIdPaginated(args);
2076
+ }
2077
+ async getMessagesPaginated(args) {
2078
+ return this.stores.memory.getMessagesPaginated(args);
1155
2079
  }
1156
2080
  async updateMessages(_args) {
1157
- this.logger.error("updateMessages is not yet implemented in LanceStore");
1158
- throw new Error("Method not implemented");
2081
+ return this.stores.memory.updateMessages(_args);
2082
+ }
2083
+ async getTraceById(args) {
2084
+ return this.stores.traces.getTraceById(args);
2085
+ }
2086
+ async getTraces(args) {
2087
+ return this.stores.traces.getTraces(args);
2088
+ }
2089
+ async getTracesPaginated(args) {
2090
+ return this.stores.traces.getTracesPaginated(args);
2091
+ }
2092
+ async getEvalsByAgentName(agentName, type) {
2093
+ return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
2094
+ }
2095
+ async getEvals(options) {
2096
+ return this.stores.legacyEvals.getEvals(options);
2097
+ }
2098
+ async getWorkflowRuns(args) {
2099
+ return this.stores.workflows.getWorkflowRuns(args);
2100
+ }
2101
+ async getWorkflowRunById(args) {
2102
+ return this.stores.workflows.getWorkflowRunById(args);
2103
+ }
2104
+ async persistWorkflowSnapshot({
2105
+ workflowName,
2106
+ runId,
2107
+ snapshot
2108
+ }) {
2109
+ return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
2110
+ }
2111
+ async loadWorkflowSnapshot({
2112
+ workflowName,
2113
+ runId
2114
+ }) {
2115
+ return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
2116
+ }
2117
+ async getScoreById({ id: _id }) {
2118
+ return this.stores.scores.getScoreById({ id: _id });
2119
+ }
2120
+ async getScoresByScorerId({
2121
+ scorerId,
2122
+ pagination
2123
+ }) {
2124
+ return this.stores.scores.getScoresByScorerId({ scorerId, pagination });
2125
+ }
2126
+ async saveScore(_score) {
2127
+ return this.stores.scores.saveScore(_score);
2128
+ }
2129
+ async getScoresByRunId({
2130
+ runId,
2131
+ pagination
2132
+ }) {
2133
+ return this.stores.scores.getScoresByRunId({ runId, pagination });
2134
+ }
2135
+ async getScoresByEntityId({
2136
+ entityId,
2137
+ entityType,
2138
+ pagination
2139
+ }) {
2140
+ return this.stores.scores.getScoresByEntityId({ entityId, entityType, pagination });
1159
2141
  }
1160
2142
  };
1161
2143
  var LanceFilterTranslator = class extends BaseFilterTranslator {