@mastra/lance 0.0.0-share-agent-metadata-with-cloud-20250718110128 → 0.0.0-stream-vnext-usage-20250908171242

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