@mastra/lance 0.2.0 → 0.2.1-alpha.0

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