@mastra/lance 0.0.0-new-scorer-api-20250801075530 → 0.0.0-new-button-export-20251219130424

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 (49) hide show
  1. package/CHANGELOG.md +1111 -3
  2. package/README.md +64 -7
  3. package/dist/index.cjs +1525 -1403
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.js +1526 -1404
  7. package/dist/index.js.map +1 -1
  8. package/dist/storage/{domains/operations → db}/index.d.ts +21 -2
  9. package/dist/storage/db/index.d.ts.map +1 -0
  10. package/dist/storage/db/utils.d.ts.map +1 -0
  11. package/dist/storage/domains/memory/index.d.ts +23 -39
  12. package/dist/storage/domains/memory/index.d.ts.map +1 -1
  13. package/dist/storage/domains/scores/index.d.ts +29 -9
  14. package/dist/storage/domains/scores/index.d.ts.map +1 -1
  15. package/dist/storage/domains/workflows/index.d.ts +28 -14
  16. package/dist/storage/domains/workflows/index.d.ts.map +1 -1
  17. package/dist/storage/index.d.ts +88 -109
  18. package/dist/storage/index.d.ts.map +1 -1
  19. package/dist/vector/filter.d.ts +5 -5
  20. package/dist/vector/index.d.ts +8 -5
  21. package/dist/vector/index.d.ts.map +1 -1
  22. package/package.json +29 -11
  23. package/dist/storage/domains/legacy-evals/index.d.ts +0 -25
  24. package/dist/storage/domains/legacy-evals/index.d.ts.map +0 -1
  25. package/dist/storage/domains/operations/index.d.ts.map +0 -1
  26. package/dist/storage/domains/traces/index.d.ts +0 -34
  27. package/dist/storage/domains/traces/index.d.ts.map +0 -1
  28. package/dist/storage/domains/utils.d.ts.map +0 -1
  29. package/eslint.config.js +0 -6
  30. package/src/index.ts +0 -2
  31. package/src/storage/domains/legacy-evals/index.ts +0 -156
  32. package/src/storage/domains/memory/index.ts +0 -947
  33. package/src/storage/domains/operations/index.ts +0 -489
  34. package/src/storage/domains/scores/index.ts +0 -221
  35. package/src/storage/domains/traces/index.ts +0 -212
  36. package/src/storage/domains/utils.ts +0 -158
  37. package/src/storage/domains/workflows/index.ts +0 -207
  38. package/src/storage/index.test.ts +0 -10
  39. package/src/storage/index.ts +0 -442
  40. package/src/vector/filter.test.ts +0 -295
  41. package/src/vector/filter.ts +0 -443
  42. package/src/vector/index.test.ts +0 -1493
  43. package/src/vector/index.ts +0 -941
  44. package/src/vector/types.ts +0 -16
  45. package/tsconfig.build.json +0 -9
  46. package/tsconfig.json +0 -5
  47. package/tsup.config.ts +0 -22
  48. package/vitest.config.ts +0 -11
  49. /package/dist/storage/{domains → db}/utils.d.ts +0 -0
package/dist/index.js CHANGED
@@ -1,132 +1,18 @@
1
1
  import { connect, Index } from '@lancedb/lancedb';
2
2
  import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
3
- import { MastraStorage, StoreOperations, LegacyEvalsStorage, TABLE_EVALS, MemoryStorage, TABLE_THREADS, TABLE_MESSAGES, resolveMessageLimit, TABLE_RESOURCES, ScoresStorage, TABLE_SCORERS, TracesStorage, TABLE_TRACES, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, ensureDate } from '@mastra/core/storage';
3
+ import { MastraStorage, createStorageErrorId, createVectorErrorId, MemoryStorage, TABLE_SCHEMAS, TABLE_THREADS, TABLE_MESSAGES, TABLE_RESOURCES, normalizePerPage, calculatePagination, ScoresStorage, SCORERS_SCHEMA, TABLE_SCORERS, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, getDefaultValue, ensureDate } from '@mastra/core/storage';
4
4
  import { MessageList } from '@mastra/core/agent';
5
+ import { MastraBase } from '@mastra/core/base';
5
6
  import { Utf8, Float64, Binary, Float32, Int32, Field, Schema } from 'apache-arrow';
7
+ import { saveScorePayloadSchema } from '@mastra/core/evals';
6
8
  import { MastraVector } from '@mastra/core/vector';
7
9
  import { BaseFilterTranslator } from '@mastra/core/vector/filter';
8
10
 
9
11
  // src/storage/index.ts
10
- var StoreLegacyEvalsLance = class extends LegacyEvalsStorage {
11
- client;
12
- constructor({ client }) {
13
- super();
14
- this.client = client;
15
- }
16
- async getEvalsByAgentName(agentName, type) {
17
- try {
18
- const table = await this.client.openTable(TABLE_EVALS);
19
- const query = table.query().where(`agent_name = '${agentName}'`);
20
- const records = await query.toArray();
21
- let filteredRecords = records;
22
- if (type === "live") {
23
- filteredRecords = records.filter((record) => record.test_info === null);
24
- } else if (type === "test") {
25
- filteredRecords = records.filter((record) => record.test_info !== null);
26
- }
27
- return filteredRecords.map((record) => {
28
- return {
29
- id: record.id,
30
- input: record.input,
31
- output: record.output,
32
- agentName: record.agent_name,
33
- metricName: record.metric_name,
34
- result: JSON.parse(record.result),
35
- instructions: record.instructions,
36
- testInfo: record.test_info ? JSON.parse(record.test_info) : null,
37
- globalRunId: record.global_run_id,
38
- runId: record.run_id,
39
- createdAt: new Date(record.created_at).toString()
40
- };
41
- });
42
- } catch (error) {
43
- throw new MastraError(
44
- {
45
- id: "LANCE_STORE_GET_EVALS_BY_AGENT_NAME_FAILED",
46
- domain: ErrorDomain.STORAGE,
47
- category: ErrorCategory.THIRD_PARTY,
48
- details: { agentName }
49
- },
50
- error
51
- );
52
- }
53
- }
54
- async getEvals(options) {
55
- try {
56
- const table = await this.client.openTable(TABLE_EVALS);
57
- const conditions = [];
58
- if (options.agentName) {
59
- conditions.push(`agent_name = '${options.agentName}'`);
60
- }
61
- if (options.type === "live") {
62
- conditions.push("length(test_info) = 0");
63
- } else if (options.type === "test") {
64
- conditions.push("length(test_info) > 0");
65
- }
66
- const startDate = options.dateRange?.start || options.fromDate;
67
- const endDate = options.dateRange?.end || options.toDate;
68
- if (startDate) {
69
- conditions.push(`\`created_at\` >= ${startDate.getTime()}`);
70
- }
71
- if (endDate) {
72
- conditions.push(`\`created_at\` <= ${endDate.getTime()}`);
73
- }
74
- let total = 0;
75
- if (conditions.length > 0) {
76
- total = await table.countRows(conditions.join(" AND "));
77
- } else {
78
- total = await table.countRows();
79
- }
80
- const query = table.query();
81
- if (conditions.length > 0) {
82
- const whereClause = conditions.join(" AND ");
83
- query.where(whereClause);
84
- }
85
- const records = await query.toArray();
86
- const evals = records.sort((a, b) => b.created_at - a.created_at).map((record) => {
87
- return {
88
- id: record.id,
89
- input: record.input,
90
- output: record.output,
91
- agentName: record.agent_name,
92
- metricName: record.metric_name,
93
- result: JSON.parse(record.result),
94
- instructions: record.instructions,
95
- testInfo: record.test_info ? JSON.parse(record.test_info) : null,
96
- globalRunId: record.global_run_id,
97
- runId: record.run_id,
98
- createdAt: new Date(record.created_at).toISOString()
99
- };
100
- });
101
- const page = options.page || 0;
102
- const perPage = options.perPage || 10;
103
- const pagedEvals = evals.slice(page * perPage, (page + 1) * perPage);
104
- return {
105
- evals: pagedEvals,
106
- total,
107
- page,
108
- perPage,
109
- hasMore: total > (page + 1) * perPage
110
- };
111
- } catch (error) {
112
- throw new MastraError(
113
- {
114
- id: "LANCE_STORE_GET_EVALS_FAILED",
115
- domain: ErrorDomain.STORAGE,
116
- category: ErrorCategory.THIRD_PARTY,
117
- details: { agentName: options.agentName ?? "" }
118
- },
119
- error
120
- );
121
- }
122
- }
123
- };
124
12
  function getPrimaryKeys(tableName) {
125
13
  let primaryId = ["id"];
126
14
  if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
127
15
  primaryId = ["workflow_name", "run_id"];
128
- } else if (tableName === TABLE_EVALS) {
129
- primaryId = ["agent_name", "metric_name", "run_id"];
130
16
  }
131
17
  return primaryId;
132
18
  }
@@ -187,7 +73,6 @@ function processResultWithTypeConversion(rawResult, tableSchema) {
187
73
  } else if (fieldTypeStr.includes("float64") && ["createdAt", "updatedAt"].includes(key)) {
188
74
  processedResult[key] = new Date(processedResult[key]);
189
75
  }
190
- console.log(key, "processedResult", processedResult);
191
76
  }
192
77
  return processedResult;
193
78
  }
@@ -205,7 +90,7 @@ async function getTableSchema({
205
90
  } catch (validationError) {
206
91
  throw new MastraError(
207
92
  {
208
- id: "STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_INVALID_ARGS",
93
+ id: createStorageErrorId("LANCE", "GET_TABLE_SCHEMA", "INVALID_ARGS"),
209
94
  domain: ErrorDomain.STORAGE,
210
95
  category: ErrorCategory.USER,
211
96
  text: validationError.message,
@@ -228,7 +113,7 @@ async function getTableSchema({
228
113
  } catch (error) {
229
114
  throw new MastraError(
230
115
  {
231
- id: "STORAGE_LANCE_STORAGE_GET_TABLE_SCHEMA_FAILED",
116
+ id: createStorageErrorId("LANCE", "GET_TABLE_SCHEMA", "FAILED"),
232
117
  domain: ErrorDomain.STORAGE,
233
118
  category: ErrorCategory.THIRD_PARTY,
234
119
  details: { tableName }
@@ -238,625 +123,503 @@ async function getTableSchema({
238
123
  }
239
124
  }
240
125
 
241
- // src/storage/domains/memory/index.ts
242
- var StoreMemoryLance = class extends MemoryStorage {
126
+ // src/storage/db/index.ts
127
+ function resolveLanceConfig(config) {
128
+ return config.client;
129
+ }
130
+ var LanceDB = class extends MastraBase {
243
131
  client;
244
- operations;
245
- constructor({ client, operations }) {
246
- super();
132
+ constructor({ client }) {
133
+ super({ name: "lance-db" });
247
134
  this.client = client;
248
- this.operations = operations;
249
135
  }
250
- async getThreadById({ threadId }) {
136
+ getDefaultValue(type) {
137
+ switch (type) {
138
+ case "text":
139
+ return "''";
140
+ case "timestamp":
141
+ return "CURRENT_TIMESTAMP";
142
+ case "integer":
143
+ case "bigint":
144
+ return "0";
145
+ case "jsonb":
146
+ return "'{}'";
147
+ case "uuid":
148
+ return "''";
149
+ default:
150
+ return getDefaultValue(type);
151
+ }
152
+ }
153
+ async hasColumn(tableName, columnName) {
154
+ const table = await this.client.openTable(tableName);
155
+ const schema = await table.schema();
156
+ return schema.fields.some((field) => field.name === columnName);
157
+ }
158
+ translateSchema(schema) {
159
+ const fields = Object.entries(schema).map(([name, column]) => {
160
+ let arrowType;
161
+ switch (column.type.toLowerCase()) {
162
+ case "text":
163
+ case "uuid":
164
+ arrowType = new Utf8();
165
+ break;
166
+ case "int":
167
+ case "integer":
168
+ arrowType = new Int32();
169
+ break;
170
+ case "bigint":
171
+ arrowType = new Float64();
172
+ break;
173
+ case "float":
174
+ arrowType = new Float32();
175
+ break;
176
+ case "jsonb":
177
+ case "json":
178
+ arrowType = new Utf8();
179
+ break;
180
+ case "binary":
181
+ arrowType = new Binary();
182
+ break;
183
+ case "timestamp":
184
+ arrowType = new Float64();
185
+ break;
186
+ default:
187
+ arrowType = new Utf8();
188
+ }
189
+ return new Field(name, arrowType, column.nullable ?? true);
190
+ });
191
+ return new Schema(fields);
192
+ }
193
+ async createTable({
194
+ tableName,
195
+ schema
196
+ }) {
251
197
  try {
252
- const thread = await this.operations.load({ tableName: TABLE_THREADS, keys: { id: threadId } });
253
- if (!thread) {
254
- return null;
198
+ if (!this.client) {
199
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
200
+ }
201
+ if (!tableName) {
202
+ throw new Error("tableName is required for createTable.");
203
+ }
204
+ if (!schema) {
205
+ throw new Error("schema is required for createTable.");
255
206
  }
256
- return {
257
- ...thread,
258
- createdAt: new Date(thread.createdAt),
259
- updatedAt: new Date(thread.updatedAt)
260
- };
261
207
  } catch (error) {
262
208
  throw new MastraError(
263
209
  {
264
- id: "LANCE_STORE_GET_THREAD_BY_ID_FAILED",
210
+ id: createStorageErrorId("LANCE", "CREATE_TABLE", "INVALID_ARGS"),
265
211
  domain: ErrorDomain.STORAGE,
266
- category: ErrorCategory.THIRD_PARTY
212
+ category: ErrorCategory.USER,
213
+ details: { tableName }
267
214
  },
268
215
  error
269
216
  );
270
217
  }
271
- }
272
- async getThreadsByResourceId({ resourceId }) {
273
218
  try {
274
- const table = await this.client.openTable(TABLE_THREADS);
275
- const query = table.query().where(`\`resourceId\` = '${resourceId}'`);
276
- const records = await query.toArray();
277
- return processResultWithTypeConversion(
278
- records,
279
- await getTableSchema({ tableName: TABLE_THREADS, client: this.client })
280
- );
219
+ const arrowSchema = this.translateSchema(schema);
220
+ await this.client.createEmptyTable(tableName, arrowSchema);
281
221
  } catch (error) {
222
+ if (error.message?.includes("already exists")) {
223
+ this.logger.debug(`Table '${tableName}' already exists, skipping create`);
224
+ return;
225
+ }
282
226
  throw new MastraError(
283
227
  {
284
- id: "LANCE_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED",
228
+ id: createStorageErrorId("LANCE", "CREATE_TABLE", "FAILED"),
285
229
  domain: ErrorDomain.STORAGE,
286
- category: ErrorCategory.THIRD_PARTY
230
+ category: ErrorCategory.THIRD_PARTY,
231
+ details: { tableName }
287
232
  },
288
233
  error
289
234
  );
290
235
  }
291
236
  }
292
- /**
293
- * Saves a thread to the database. This function doesn't overwrite existing threads.
294
- * @param thread - The thread to save
295
- * @returns The saved thread
296
- */
297
- async saveThread({ thread }) {
237
+ async dropTable({ tableName }) {
298
238
  try {
299
- const record = { ...thread, metadata: JSON.stringify(thread.metadata) };
300
- const table = await this.client.openTable(TABLE_THREADS);
301
- await table.add([record], { mode: "append" });
302
- return thread;
303
- } catch (error) {
239
+ if (!this.client) {
240
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
241
+ }
242
+ if (!tableName) {
243
+ throw new Error("tableName is required for dropTable.");
244
+ }
245
+ } catch (validationError) {
304
246
  throw new MastraError(
305
247
  {
306
- id: "LANCE_STORE_SAVE_THREAD_FAILED",
248
+ id: createStorageErrorId("LANCE", "DROP_TABLE", "INVALID_ARGS"),
307
249
  domain: ErrorDomain.STORAGE,
308
- category: ErrorCategory.THIRD_PARTY
250
+ category: ErrorCategory.USER,
251
+ text: validationError.message,
252
+ details: { tableName }
309
253
  },
310
- error
254
+ validationError
311
255
  );
312
256
  }
313
- }
314
- async updateThread({
315
- id,
316
- title,
317
- metadata
318
- }) {
319
- const maxRetries = 5;
320
- for (let attempt = 0; attempt < maxRetries; attempt++) {
321
- try {
322
- const current = await this.getThreadById({ threadId: id });
323
- if (!current) {
324
- throw new Error(`Thread with id ${id} not found`);
325
- }
326
- const mergedMetadata = { ...current.metadata, ...metadata };
327
- const record = {
328
- id,
329
- title,
330
- metadata: JSON.stringify(mergedMetadata),
331
- updatedAt: (/* @__PURE__ */ new Date()).getTime()
332
- };
333
- const table = await this.client.openTable(TABLE_THREADS);
334
- await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
335
- const updatedThread = await this.getThreadById({ threadId: id });
336
- if (!updatedThread) {
337
- throw new Error(`Failed to retrieve updated thread ${id}`);
338
- }
339
- return updatedThread;
340
- } catch (error) {
341
- if (error.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
342
- const delay = Math.pow(2, attempt) * 10;
343
- await new Promise((resolve) => setTimeout(resolve, delay));
344
- continue;
345
- }
346
- throw new MastraError(
347
- {
348
- id: "LANCE_STORE_UPDATE_THREAD_FAILED",
349
- domain: ErrorDomain.STORAGE,
350
- category: ErrorCategory.THIRD_PARTY
351
- },
352
- error
353
- );
354
- }
355
- }
356
- throw new MastraError(
357
- {
358
- id: "LANCE_STORE_UPDATE_THREAD_FAILED",
359
- domain: ErrorDomain.STORAGE,
360
- category: ErrorCategory.THIRD_PARTY
361
- },
362
- new Error("All retries exhausted")
363
- );
364
- }
365
- async deleteThread({ threadId }) {
366
257
  try {
367
- const table = await this.client.openTable(TABLE_THREADS);
368
- await table.delete(`id = '${threadId}'`);
369
- const messagesTable = await this.client.openTable(TABLE_MESSAGES);
370
- await messagesTable.delete(`thread_id = '${threadId}'`);
258
+ await this.client.dropTable(tableName);
371
259
  } catch (error) {
260
+ if (error.toString().includes("was not found") || error.message?.includes("Table not found")) {
261
+ this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
262
+ return;
263
+ }
372
264
  throw new MastraError(
373
265
  {
374
- id: "LANCE_STORE_DELETE_THREAD_FAILED",
266
+ id: createStorageErrorId("LANCE", "DROP_TABLE", "FAILED"),
375
267
  domain: ErrorDomain.STORAGE,
376
- category: ErrorCategory.THIRD_PARTY
268
+ category: ErrorCategory.THIRD_PARTY,
269
+ details: { tableName }
377
270
  },
378
271
  error
379
272
  );
380
273
  }
381
274
  }
382
- async getMessages({
383
- threadId,
384
- resourceId,
385
- selectBy,
386
- format,
387
- threadConfig
275
+ async alterTable({
276
+ tableName,
277
+ schema,
278
+ ifNotExists
388
279
  }) {
389
280
  try {
390
- if (threadConfig) {
391
- throw new Error("ThreadConfig is not supported by LanceDB storage");
392
- }
393
- const limit = resolveMessageLimit({ last: selectBy?.last, defaultLimit: Number.MAX_SAFE_INTEGER });
394
- const table = await this.client.openTable(TABLE_MESSAGES);
395
- let allRecords = [];
396
- if (selectBy?.include && selectBy.include.length > 0) {
397
- const threadIds = [...new Set(selectBy.include.map((item) => item.threadId))];
398
- for (const threadId2 of threadIds) {
399
- const threadQuery = table.query().where(`thread_id = '${threadId2}'`);
400
- let threadRecords = await threadQuery.toArray();
401
- allRecords.push(...threadRecords);
402
- }
403
- } else {
404
- let query = table.query().where(`\`thread_id\` = '${threadId}'`);
405
- allRecords = await query.toArray();
281
+ if (!this.client) {
282
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
406
283
  }
407
- allRecords.sort((a, b) => {
408
- const dateA = new Date(a.createdAt).getTime();
409
- const dateB = new Date(b.createdAt).getTime();
410
- return dateA - dateB;
411
- });
412
- if (selectBy?.include && selectBy.include.length > 0) {
413
- allRecords = this.processMessagesWithContext(allRecords, selectBy.include);
284
+ if (!tableName) {
285
+ throw new Error("tableName is required for alterTable.");
414
286
  }
415
- if (limit !== Number.MAX_SAFE_INTEGER) {
416
- allRecords = allRecords.slice(-limit);
287
+ if (!schema) {
288
+ throw new Error("schema is required for alterTable.");
417
289
  }
418
- const messages = processResultWithTypeConversion(
419
- allRecords,
420
- await getTableSchema({ tableName: TABLE_MESSAGES, client: this.client })
290
+ if (!ifNotExists || ifNotExists.length === 0) {
291
+ this.logger.debug("No columns specified to add in alterTable, skipping.");
292
+ return;
293
+ }
294
+ } catch (validationError) {
295
+ throw new MastraError(
296
+ {
297
+ id: createStorageErrorId("LANCE", "ALTER_TABLE", "INVALID_ARGS"),
298
+ domain: ErrorDomain.STORAGE,
299
+ category: ErrorCategory.USER,
300
+ text: validationError.message,
301
+ details: { tableName }
302
+ },
303
+ validationError
421
304
  );
422
- const normalized = messages.map((msg) => {
423
- const { thread_id, ...rest } = msg;
305
+ }
306
+ try {
307
+ const table = await this.client.openTable(tableName);
308
+ const currentSchema = await table.schema();
309
+ const existingFields = new Set(currentSchema.fields.map((f) => f.name));
310
+ const typeMap = {
311
+ text: "string",
312
+ integer: "int",
313
+ bigint: "bigint",
314
+ timestamp: "timestamp",
315
+ jsonb: "string",
316
+ uuid: "string"
317
+ };
318
+ const columnsToAdd = ifNotExists.filter((col) => schema[col] && !existingFields.has(col)).map((col) => {
319
+ const colDef = schema[col];
424
320
  return {
425
- ...rest,
426
- threadId: thread_id,
427
- content: typeof msg.content === "string" ? (() => {
428
- try {
429
- return JSON.parse(msg.content);
430
- } catch {
431
- return msg.content;
432
- }
433
- })() : msg.content
321
+ name: col,
322
+ valueSql: colDef?.nullable ? `cast(NULL as ${typeMap[colDef.type ?? "text"]})` : `cast(${this.getDefaultValue(colDef?.type ?? "text")} as ${typeMap[colDef?.type ?? "text"]})`
434
323
  };
435
324
  });
436
- const list = new MessageList({ threadId, resourceId }).add(normalized, "memory");
437
- if (format === "v2") return list.get.all.v2();
438
- return list.get.all.v1();
325
+ if (columnsToAdd.length > 0) {
326
+ await table.addColumns(columnsToAdd);
327
+ this.logger?.info?.(`Added columns [${columnsToAdd.map((c) => c.name).join(", ")}] to table ${tableName}`);
328
+ }
439
329
  } catch (error) {
440
330
  throw new MastraError(
441
331
  {
442
- id: "LANCE_STORE_GET_MESSAGES_FAILED",
332
+ id: createStorageErrorId("LANCE", "ALTER_TABLE", "FAILED"),
443
333
  domain: ErrorDomain.STORAGE,
444
- category: ErrorCategory.THIRD_PARTY
334
+ category: ErrorCategory.THIRD_PARTY,
335
+ details: { tableName }
445
336
  },
446
337
  error
447
338
  );
448
339
  }
449
340
  }
450
- async saveMessages(args) {
341
+ async clearTable({ tableName }) {
451
342
  try {
452
- const { messages, format = "v1" } = args;
453
- if (messages.length === 0) {
454
- return [];
455
- }
456
- const threadId = messages[0]?.threadId;
457
- if (!threadId) {
458
- throw new Error("Thread ID is required");
343
+ if (!this.client) {
344
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
459
345
  }
460
- for (const message of messages) {
461
- if (!message.id) {
462
- throw new Error("Message ID is required");
463
- }
464
- if (!message.threadId) {
465
- throw new Error("Thread ID is required for all messages");
466
- }
467
- if (message.resourceId === null || message.resourceId === void 0) {
468
- throw new Error("Resource ID cannot be null or undefined");
469
- }
470
- if (!message.content) {
471
- throw new Error("Message content is required");
472
- }
346
+ if (!tableName) {
347
+ throw new Error("tableName is required for clearTable.");
473
348
  }
474
- const transformedMessages = messages.map((message) => {
475
- const { threadId: threadId2, type, ...rest } = message;
476
- return {
477
- ...rest,
478
- thread_id: threadId2,
479
- type: type ?? "v2",
480
- content: JSON.stringify(message.content)
481
- };
482
- });
483
- const table = await this.client.openTable(TABLE_MESSAGES);
484
- await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
485
- const threadsTable = await this.client.openTable(TABLE_THREADS);
486
- const currentTime = (/* @__PURE__ */ new Date()).getTime();
487
- const updateRecord = { id: threadId, updatedAt: currentTime };
488
- await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([updateRecord]);
489
- const list = new MessageList().add(messages, "memory");
490
- if (format === `v2`) return list.get.all.v2();
491
- return list.get.all.v1();
492
- } catch (error) {
349
+ } catch (validationError) {
493
350
  throw new MastraError(
494
351
  {
495
- id: "LANCE_STORE_SAVE_MESSAGES_FAILED",
352
+ id: createStorageErrorId("LANCE", "CLEAR_TABLE", "INVALID_ARGS"),
496
353
  domain: ErrorDomain.STORAGE,
497
- category: ErrorCategory.THIRD_PARTY
354
+ category: ErrorCategory.USER,
355
+ text: validationError.message,
356
+ details: { tableName }
498
357
  },
499
- error
358
+ validationError
500
359
  );
501
360
  }
502
- }
503
- async getThreadsByResourceIdPaginated(args) {
504
361
  try {
505
- const { resourceId, page = 0, perPage = 10 } = args;
506
- const table = await this.client.openTable(TABLE_THREADS);
507
- const total = await table.countRows(`\`resourceId\` = '${resourceId}'`);
508
- const query = table.query().where(`\`resourceId\` = '${resourceId}'`);
509
- const offset = page * perPage;
510
- query.limit(perPage);
511
- if (offset > 0) {
512
- query.offset(offset);
513
- }
514
- const records = await query.toArray();
515
- records.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
516
- const schema = await getTableSchema({ tableName: TABLE_THREADS, client: this.client });
517
- const threads = records.map((record) => processResultWithTypeConversion(record, schema));
518
- return {
519
- threads,
520
- total,
521
- page,
522
- perPage,
523
- hasMore: total > (page + 1) * perPage
524
- };
362
+ const table = await this.client.openTable(tableName);
363
+ await table.delete("1=1");
525
364
  } catch (error) {
526
365
  throw new MastraError(
527
366
  {
528
- id: "LANCE_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
367
+ id: createStorageErrorId("LANCE", "CLEAR_TABLE", "FAILED"),
529
368
  domain: ErrorDomain.STORAGE,
530
- category: ErrorCategory.THIRD_PARTY
369
+ category: ErrorCategory.THIRD_PARTY,
370
+ details: { tableName }
531
371
  },
532
372
  error
533
373
  );
534
374
  }
535
375
  }
536
- /**
537
- * Processes messages to include context messages based on withPreviousMessages and withNextMessages
538
- * @param records - The sorted array of records to process
539
- * @param include - The array of include specifications with context parameters
540
- * @returns The processed array with context messages included
541
- */
542
- processMessagesWithContext(records, include) {
543
- const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
544
- if (messagesWithContext.length === 0) {
545
- return records;
546
- }
547
- const messageIndexMap = /* @__PURE__ */ new Map();
548
- records.forEach((message, index) => {
549
- messageIndexMap.set(message.id, index);
550
- });
551
- const additionalIndices = /* @__PURE__ */ new Set();
552
- for (const item of messagesWithContext) {
553
- const messageIndex = messageIndexMap.get(item.id);
554
- if (messageIndex !== void 0) {
555
- if (item.withPreviousMessages) {
556
- const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
557
- for (let i = startIdx; i < messageIndex; i++) {
558
- additionalIndices.add(i);
559
- }
560
- }
561
- if (item.withNextMessages) {
562
- const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
563
- for (let i = messageIndex + 1; i <= endIdx; i++) {
564
- additionalIndices.add(i);
565
- }
566
- }
567
- }
568
- }
569
- if (additionalIndices.size === 0) {
570
- return records;
571
- }
572
- const originalMatchIds = new Set(include.map((item) => item.id));
573
- const allIndices = /* @__PURE__ */ new Set();
574
- records.forEach((record, index) => {
575
- if (originalMatchIds.has(record.id)) {
576
- allIndices.add(index);
577
- }
578
- });
579
- additionalIndices.forEach((index) => {
580
- allIndices.add(index);
581
- });
582
- return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
583
- }
584
- async getMessagesPaginated(args) {
376
+ async insert({ tableName, record }) {
585
377
  try {
586
- const { threadId, resourceId, selectBy, format = "v1" } = args;
587
- if (!threadId) {
588
- throw new Error("Thread ID is required for getMessagesPaginated");
589
- }
590
- const page = selectBy?.pagination?.page ?? 0;
591
- const perPage = selectBy?.pagination?.perPage ?? 10;
592
- const dateRange = selectBy?.pagination?.dateRange;
593
- const fromDate = dateRange?.start;
594
- const toDate = dateRange?.end;
595
- const table = await this.client.openTable(TABLE_MESSAGES);
596
- const messages = [];
597
- if (selectBy?.include && Array.isArray(selectBy.include)) {
598
- const threadIds = [...new Set(selectBy.include.map((item) => item.threadId))];
599
- const allThreadMessages = [];
600
- for (const threadId2 of threadIds) {
601
- const threadQuery = table.query().where(`thread_id = '${threadId2}'`);
602
- let threadRecords = await threadQuery.toArray();
603
- if (fromDate) threadRecords = threadRecords.filter((m) => m.createdAt >= fromDate.getTime());
604
- if (toDate) threadRecords = threadRecords.filter((m) => m.createdAt <= toDate.getTime());
605
- allThreadMessages.push(...threadRecords);
606
- }
607
- allThreadMessages.sort((a, b) => a.createdAt - b.createdAt);
608
- const contextMessages = this.processMessagesWithContext(allThreadMessages, selectBy.include);
609
- messages.push(...contextMessages);
610
- }
611
- const conditions = [`thread_id = '${threadId}'`];
612
- if (resourceId) {
613
- conditions.push(`\`resourceId\` = '${resourceId}'`);
614
- }
615
- if (fromDate) {
616
- conditions.push(`\`createdAt\` >= ${fromDate.getTime()}`);
617
- }
618
- if (toDate) {
619
- conditions.push(`\`createdAt\` <= ${toDate.getTime()}`);
378
+ if (!this.client) {
379
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
620
380
  }
621
- let total = 0;
622
- if (conditions.length > 0) {
623
- total = await table.countRows(conditions.join(" AND "));
624
- } else {
625
- total = await table.countRows();
381
+ if (!tableName) {
382
+ throw new Error("tableName is required for insert.");
626
383
  }
627
- if (total === 0 && messages.length === 0) {
628
- return {
629
- messages: [],
630
- total: 0,
631
- page,
632
- perPage,
633
- hasMore: false
634
- };
384
+ if (!record || Object.keys(record).length === 0) {
385
+ throw new Error("record is required and cannot be empty for insert.");
635
386
  }
636
- const excludeIds = messages.map((m) => m.id);
637
- let selectedMessages = [];
638
- if (selectBy?.last && selectBy.last > 0) {
639
- const query = table.query();
640
- if (conditions.length > 0) {
641
- query.where(conditions.join(" AND "));
642
- }
643
- let records = await query.toArray();
644
- records = records.sort((a, b) => a.createdAt - b.createdAt);
645
- if (excludeIds.length > 0) {
646
- records = records.filter((m) => !excludeIds.includes(m.id));
647
- }
648
- selectedMessages = records.slice(-selectBy.last);
649
- } else {
650
- const query = table.query();
651
- if (conditions.length > 0) {
652
- query.where(conditions.join(" AND "));
653
- }
654
- let records = await query.toArray();
655
- records = records.sort((a, b) => a.createdAt - b.createdAt);
656
- if (excludeIds.length > 0) {
657
- records = records.filter((m) => !excludeIds.includes(m.id));
387
+ } catch (validationError) {
388
+ throw new MastraError(
389
+ {
390
+ id: createStorageErrorId("LANCE", "INSERT", "INVALID_ARGS"),
391
+ domain: ErrorDomain.STORAGE,
392
+ category: ErrorCategory.USER,
393
+ text: validationError.message,
394
+ details: { tableName }
395
+ },
396
+ validationError
397
+ );
398
+ }
399
+ try {
400
+ const table = await this.client.openTable(tableName);
401
+ const primaryId = getPrimaryKeys(tableName);
402
+ const processedRecord = { ...record };
403
+ for (const key in processedRecord) {
404
+ if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
405
+ this.logger.debug("Converting object to JSON string: ", processedRecord[key]);
406
+ processedRecord[key] = JSON.stringify(processedRecord[key]);
658
407
  }
659
- selectedMessages = records.slice(page * perPage, (page + 1) * perPage);
660
- }
661
- const allMessages = [...messages, ...selectedMessages];
662
- const seen = /* @__PURE__ */ new Set();
663
- const dedupedMessages = allMessages.filter((m) => {
664
- const key = `${m.id}:${m.thread_id}`;
665
- if (seen.has(key)) return false;
666
- seen.add(key);
667
- return true;
668
- });
669
- const formattedMessages = dedupedMessages.map((msg) => {
670
- const { thread_id, ...rest } = msg;
671
- return {
672
- ...rest,
673
- threadId: thread_id,
674
- content: typeof msg.content === "string" ? (() => {
675
- try {
676
- return JSON.parse(msg.content);
677
- } catch {
678
- return msg.content;
679
- }
680
- })() : msg.content
681
- };
682
- });
683
- const list = new MessageList().add(formattedMessages, "memory");
684
- return {
685
- messages: format === "v2" ? list.get.all.v2() : list.get.all.v1(),
686
- total,
687
- // Total should be the count of messages matching the filters
688
- page,
689
- perPage,
690
- hasMore: total > (page + 1) * perPage
691
- };
408
+ }
409
+ await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([processedRecord]);
692
410
  } catch (error) {
693
411
  throw new MastraError(
694
412
  {
695
- id: "LANCE_STORE_GET_MESSAGES_PAGINATED_FAILED",
413
+ id: createStorageErrorId("LANCE", "INSERT", "FAILED"),
696
414
  domain: ErrorDomain.STORAGE,
697
- category: ErrorCategory.THIRD_PARTY
415
+ category: ErrorCategory.THIRD_PARTY,
416
+ details: { tableName }
698
417
  },
699
418
  error
700
419
  );
701
420
  }
702
421
  }
703
- /**
704
- * Parse message data from LanceDB record format to MastraMessageV2 format
705
- */
706
- parseMessageData(data) {
707
- const { thread_id, ...rest } = data;
708
- return {
709
- ...rest,
710
- threadId: thread_id,
711
- content: typeof data.content === "string" ? (() => {
712
- try {
713
- return JSON.parse(data.content);
714
- } catch {
715
- return data.content;
716
- }
717
- })() : data.content,
718
- createdAt: new Date(data.createdAt),
719
- updatedAt: new Date(data.updatedAt)
720
- };
721
- }
722
- async updateMessages(args) {
723
- const { messages } = args;
724
- this.logger.debug("Updating messages", { count: messages.length });
725
- if (!messages.length) {
726
- return [];
727
- }
728
- const updatedMessages = [];
729
- const affectedThreadIds = /* @__PURE__ */ new Set();
422
+ async batchInsert({ tableName, records }) {
730
423
  try {
731
- for (const updateData of messages) {
732
- const { id, ...updates } = updateData;
733
- const existingMessage = await this.operations.load({ tableName: TABLE_MESSAGES, keys: { id } });
734
- if (!existingMessage) {
735
- this.logger.warn("Message not found for update", { id });
736
- continue;
737
- }
738
- const existingMsg = this.parseMessageData(existingMessage);
739
- const originalThreadId = existingMsg.threadId;
740
- affectedThreadIds.add(originalThreadId);
741
- const updatePayload = {};
742
- if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
743
- if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
744
- if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
745
- if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
746
- updatePayload.thread_id = updates.threadId;
747
- affectedThreadIds.add(updates.threadId);
748
- }
749
- if (updates.content) {
750
- const existingContent = existingMsg.content;
751
- let newContent = { ...existingContent };
752
- if (updates.content.metadata !== void 0) {
753
- newContent.metadata = {
754
- ...existingContent.metadata || {},
755
- ...updates.content.metadata || {}
756
- };
757
- }
758
- if (updates.content.content !== void 0) {
759
- newContent.content = updates.content.content;
760
- }
761
- if ("parts" in updates.content && updates.content.parts !== void 0) {
762
- newContent.parts = updates.content.parts;
763
- }
764
- updatePayload.content = JSON.stringify(newContent);
765
- }
766
- await this.operations.insert({ tableName: TABLE_MESSAGES, record: { id, ...updatePayload } });
767
- const updatedMessage = await this.operations.load({ tableName: TABLE_MESSAGES, keys: { id } });
768
- if (updatedMessage) {
769
- updatedMessages.push(this.parseMessageData(updatedMessage));
770
- }
424
+ if (!this.client) {
425
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
771
426
  }
772
- for (const threadId of affectedThreadIds) {
773
- await this.operations.insert({
774
- tableName: TABLE_THREADS,
775
- record: { id: threadId, updatedAt: Date.now() }
776
- });
427
+ if (!tableName) {
428
+ throw new Error("tableName is required for batchInsert.");
777
429
  }
778
- return updatedMessages;
430
+ if (!records || records.length === 0) {
431
+ throw new Error("records array is required and cannot be empty for batchInsert.");
432
+ }
433
+ } catch (validationError) {
434
+ throw new MastraError(
435
+ {
436
+ id: createStorageErrorId("LANCE", "BATCH_INSERT", "INVALID_ARGS"),
437
+ domain: ErrorDomain.STORAGE,
438
+ category: ErrorCategory.USER,
439
+ text: validationError.message,
440
+ details: { tableName }
441
+ },
442
+ validationError
443
+ );
444
+ }
445
+ try {
446
+ const table = await this.client.openTable(tableName);
447
+ const primaryId = getPrimaryKeys(tableName);
448
+ const processedRecords = records.map((record) => {
449
+ const processedRecord = { ...record };
450
+ for (const key in processedRecord) {
451
+ if (processedRecord[key] == null) continue;
452
+ if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
453
+ processedRecord[key] = JSON.stringify(processedRecord[key]);
454
+ }
455
+ }
456
+ return processedRecord;
457
+ });
458
+ await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(processedRecords);
779
459
  } catch (error) {
780
460
  throw new MastraError(
781
461
  {
782
- id: "LANCE_STORE_UPDATE_MESSAGES_FAILED",
462
+ id: createStorageErrorId("LANCE", "BATCH_INSERT", "FAILED"),
783
463
  domain: ErrorDomain.STORAGE,
784
464
  category: ErrorCategory.THIRD_PARTY,
785
- details: { count: messages.length }
465
+ details: { tableName }
786
466
  },
787
467
  error
788
468
  );
789
469
  }
790
470
  }
791
- async getResourceById({ resourceId }) {
471
+ async load({ tableName, keys }) {
792
472
  try {
793
- const resource = await this.operations.load({ tableName: TABLE_RESOURCES, keys: { id: resourceId } });
794
- if (!resource) {
473
+ if (!this.client) {
474
+ throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
475
+ }
476
+ if (!tableName) {
477
+ throw new Error("tableName is required for load.");
478
+ }
479
+ if (!keys || Object.keys(keys).length === 0) {
480
+ throw new Error("keys are required and cannot be empty for load.");
481
+ }
482
+ } catch (validationError) {
483
+ throw new MastraError(
484
+ {
485
+ id: createStorageErrorId("LANCE", "LOAD", "INVALID_ARGS"),
486
+ domain: ErrorDomain.STORAGE,
487
+ category: ErrorCategory.USER,
488
+ text: validationError.message,
489
+ details: { tableName }
490
+ },
491
+ validationError
492
+ );
493
+ }
494
+ try {
495
+ const table = await this.client.openTable(tableName);
496
+ const tableSchema = await getTableSchema({ tableName, client: this.client });
497
+ const query = table.query();
498
+ if (Object.keys(keys).length > 0) {
499
+ validateKeyTypes(keys, tableSchema);
500
+ const filterConditions = Object.entries(keys).map(([key, value]) => {
501
+ const isCamelCase = /^[a-z][a-zA-Z]*$/.test(key) && /[A-Z]/.test(key);
502
+ const quotedKey = isCamelCase ? `\`${key}\`` : key;
503
+ if (typeof value === "string") {
504
+ return `${quotedKey} = '${value}'`;
505
+ } else if (value === null) {
506
+ return `${quotedKey} IS NULL`;
507
+ } else {
508
+ return `${quotedKey} = ${value}`;
509
+ }
510
+ }).join(" AND ");
511
+ this.logger.debug("where clause generated: " + filterConditions);
512
+ query.where(filterConditions);
513
+ }
514
+ const result = await query.limit(1).toArray();
515
+ if (result.length === 0) {
516
+ this.logger.debug("No record found");
795
517
  return null;
796
518
  }
797
- let createdAt;
798
- let updatedAt;
799
- try {
800
- if (resource.createdAt instanceof Date) {
801
- createdAt = resource.createdAt;
802
- } else if (typeof resource.createdAt === "string") {
803
- createdAt = new Date(resource.createdAt);
804
- } else if (typeof resource.createdAt === "number") {
805
- createdAt = new Date(resource.createdAt);
806
- } else {
807
- createdAt = /* @__PURE__ */ new Date();
808
- }
809
- if (isNaN(createdAt.getTime())) {
810
- createdAt = /* @__PURE__ */ new Date();
519
+ return processResultWithTypeConversion(result[0], tableSchema);
520
+ } catch (error) {
521
+ if (error instanceof MastraError) throw error;
522
+ throw new MastraError(
523
+ {
524
+ id: createStorageErrorId("LANCE", "LOAD", "FAILED"),
525
+ domain: ErrorDomain.STORAGE,
526
+ category: ErrorCategory.THIRD_PARTY,
527
+ details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
528
+ },
529
+ error
530
+ );
531
+ }
532
+ }
533
+ };
534
+
535
+ // src/storage/domains/memory/index.ts
536
+ var StoreMemoryLance = class extends MemoryStorage {
537
+ client;
538
+ #db;
539
+ constructor(config) {
540
+ super();
541
+ const client = resolveLanceConfig(config);
542
+ this.client = client;
543
+ this.#db = new LanceDB({ client });
544
+ }
545
+ async init() {
546
+ await this.#db.createTable({ tableName: TABLE_THREADS, schema: TABLE_SCHEMAS[TABLE_THREADS] });
547
+ await this.#db.createTable({ tableName: TABLE_MESSAGES, schema: TABLE_SCHEMAS[TABLE_MESSAGES] });
548
+ await this.#db.createTable({ tableName: TABLE_RESOURCES, schema: TABLE_SCHEMAS[TABLE_RESOURCES] });
549
+ await this.#db.alterTable({
550
+ tableName: TABLE_MESSAGES,
551
+ schema: TABLE_SCHEMAS[TABLE_MESSAGES],
552
+ ifNotExists: ["resourceId"]
553
+ });
554
+ }
555
+ async dangerouslyClearAll() {
556
+ await this.#db.clearTable({ tableName: TABLE_THREADS });
557
+ await this.#db.clearTable({ tableName: TABLE_MESSAGES });
558
+ await this.#db.clearTable({ tableName: TABLE_RESOURCES });
559
+ }
560
+ async deleteMessages(messageIds) {
561
+ if (!messageIds || messageIds.length === 0) {
562
+ return;
563
+ }
564
+ this.logger.debug("Deleting messages", { count: messageIds.length });
565
+ try {
566
+ const threadIds = /* @__PURE__ */ new Set();
567
+ for (const messageId of messageIds) {
568
+ const message = await this.#db.load({ tableName: TABLE_MESSAGES, keys: { id: messageId } });
569
+ if (message?.thread_id) {
570
+ threadIds.add(message.thread_id);
811
571
  }
812
- } catch {
813
- createdAt = /* @__PURE__ */ new Date();
814
572
  }
815
- try {
816
- if (resource.updatedAt instanceof Date) {
817
- updatedAt = resource.updatedAt;
818
- } else if (typeof resource.updatedAt === "string") {
819
- updatedAt = new Date(resource.updatedAt);
820
- } else if (typeof resource.updatedAt === "number") {
821
- updatedAt = new Date(resource.updatedAt);
822
- } else {
823
- updatedAt = /* @__PURE__ */ new Date();
824
- }
825
- if (isNaN(updatedAt.getTime())) {
826
- updatedAt = /* @__PURE__ */ new Date();
573
+ const messagesTable = await this.client.openTable(TABLE_MESSAGES);
574
+ const idConditions = messageIds.map((id) => `id = '${this.escapeSql(id)}'`).join(" OR ");
575
+ await messagesTable.delete(idConditions);
576
+ const now = (/* @__PURE__ */ new Date()).getTime();
577
+ const threadsTable = await this.client.openTable(TABLE_THREADS);
578
+ for (const threadId of threadIds) {
579
+ const thread = await this.getThreadById({ threadId });
580
+ if (thread) {
581
+ const record = {
582
+ id: threadId,
583
+ resourceId: thread.resourceId,
584
+ title: thread.title,
585
+ metadata: JSON.stringify(thread.metadata),
586
+ createdAt: new Date(thread.createdAt).getTime(),
587
+ updatedAt: now
588
+ };
589
+ await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
827
590
  }
828
- } catch {
829
- updatedAt = /* @__PURE__ */ new Date();
830
- }
831
- let workingMemory = resource.workingMemory;
832
- if (workingMemory === null || workingMemory === void 0) {
833
- workingMemory = void 0;
834
- } else if (workingMemory === "") {
835
- workingMemory = "";
836
- } else if (typeof workingMemory === "object") {
837
- workingMemory = JSON.stringify(workingMemory);
838
591
  }
839
- let metadata = resource.metadata;
840
- if (metadata === "" || metadata === null || metadata === void 0) {
841
- metadata = void 0;
842
- } else if (typeof metadata === "string") {
843
- try {
844
- metadata = JSON.parse(metadata);
845
- } catch {
846
- metadata = metadata;
847
- }
592
+ } catch (error) {
593
+ throw new MastraError(
594
+ {
595
+ id: createStorageErrorId("LANCE", "DELETE_MESSAGES", "FAILED"),
596
+ domain: ErrorDomain.STORAGE,
597
+ category: ErrorCategory.THIRD_PARTY,
598
+ details: { count: messageIds.length }
599
+ },
600
+ error
601
+ );
602
+ }
603
+ }
604
+ // Utility to escape single quotes in SQL strings
605
+ escapeSql(str) {
606
+ return str.replace(/'/g, "''");
607
+ }
608
+ async getThreadById({ threadId }) {
609
+ try {
610
+ const thread = await this.#db.load({ tableName: TABLE_THREADS, keys: { id: threadId } });
611
+ if (!thread) {
612
+ return null;
848
613
  }
849
614
  return {
850
- ...resource,
851
- createdAt,
852
- updatedAt,
853
- workingMemory,
854
- metadata
615
+ ...thread,
616
+ createdAt: new Date(thread.createdAt),
617
+ updatedAt: new Date(thread.updatedAt)
855
618
  };
856
619
  } catch (error) {
857
620
  throw new MastraError(
858
621
  {
859
- id: "LANCE_STORE_GET_RESOURCE_BY_ID_FAILED",
622
+ id: createStorageErrorId("LANCE", "GET_THREAD_BY_ID", "FAILED"),
860
623
  domain: ErrorDomain.STORAGE,
861
624
  category: ErrorCategory.THIRD_PARTY
862
625
  },
@@ -864,23 +627,21 @@ var StoreMemoryLance = class extends MemoryStorage {
864
627
  );
865
628
  }
866
629
  }
867
- async saveResource({ resource }) {
630
+ /**
631
+ * Saves a thread to the database. This function doesn't overwrite existing threads.
632
+ * @param thread - The thread to save
633
+ * @returns The saved thread
634
+ */
635
+ async saveThread({ thread }) {
868
636
  try {
869
- const record = {
870
- ...resource,
871
- metadata: resource.metadata ? JSON.stringify(resource.metadata) : "",
872
- createdAt: resource.createdAt.getTime(),
873
- // Store as timestamp (milliseconds)
874
- updatedAt: resource.updatedAt.getTime()
875
- // Store as timestamp (milliseconds)
876
- };
877
- const table = await this.client.openTable(TABLE_RESOURCES);
637
+ const record = { ...thread, metadata: JSON.stringify(thread.metadata) };
638
+ const table = await this.client.openTable(TABLE_THREADS);
878
639
  await table.add([record], { mode: "append" });
879
- return resource;
640
+ return thread;
880
641
  } catch (error) {
881
642
  throw new MastraError(
882
643
  {
883
- id: "LANCE_STORE_SAVE_RESOURCE_FAILED",
644
+ id: createStorageErrorId("LANCE", "SAVE_THREAD", "FAILED"),
884
645
  domain: ErrorDomain.STORAGE,
885
646
  category: ErrorCategory.THIRD_PARTY
886
647
  },
@@ -888,44 +649,32 @@ var StoreMemoryLance = class extends MemoryStorage {
888
649
  );
889
650
  }
890
651
  }
891
- async updateResource({
892
- resourceId,
893
- workingMemory,
652
+ async updateThread({
653
+ id,
654
+ title,
894
655
  metadata
895
656
  }) {
896
- const maxRetries = 3;
657
+ const maxRetries = 5;
897
658
  for (let attempt = 0; attempt < maxRetries; attempt++) {
898
659
  try {
899
- const existingResource = await this.getResourceById({ resourceId });
900
- if (!existingResource) {
901
- const newResource = {
902
- id: resourceId,
903
- workingMemory,
904
- metadata: metadata || {},
905
- createdAt: /* @__PURE__ */ new Date(),
906
- updatedAt: /* @__PURE__ */ new Date()
907
- };
908
- return this.saveResource({ resource: newResource });
660
+ const current = await this.getThreadById({ threadId: id });
661
+ if (!current) {
662
+ throw new Error(`Thread with id ${id} not found`);
909
663
  }
910
- const updatedResource = {
911
- ...existingResource,
912
- workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
913
- metadata: {
914
- ...existingResource.metadata,
915
- ...metadata
916
- },
917
- updatedAt: /* @__PURE__ */ new Date()
918
- };
664
+ const mergedMetadata = { ...current.metadata, ...metadata };
919
665
  const record = {
920
- id: resourceId,
921
- workingMemory: updatedResource.workingMemory || "",
922
- metadata: updatedResource.metadata ? JSON.stringify(updatedResource.metadata) : "",
923
- updatedAt: updatedResource.updatedAt.getTime()
924
- // Store as timestamp (milliseconds)
666
+ id,
667
+ title,
668
+ metadata: JSON.stringify(mergedMetadata),
669
+ updatedAt: (/* @__PURE__ */ new Date()).getTime()
925
670
  };
926
- const table = await this.client.openTable(TABLE_RESOURCES);
671
+ const table = await this.client.openTable(TABLE_THREADS);
927
672
  await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
928
- return updatedResource;
673
+ const updatedThread = await this.getThreadById({ threadId: id });
674
+ if (!updatedThread) {
675
+ throw new Error(`Failed to retrieve updated thread ${id}`);
676
+ }
677
+ return updatedThread;
929
678
  } catch (error) {
930
679
  if (error.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
931
680
  const delay = Math.pow(2, attempt) * 10;
@@ -934,7 +683,7 @@ var StoreMemoryLance = class extends MemoryStorage {
934
683
  }
935
684
  throw new MastraError(
936
685
  {
937
- id: "LANCE_STORE_UPDATE_RESOURCE_FAILED",
686
+ id: createStorageErrorId("LANCE", "UPDATE_THREAD", "FAILED"),
938
687
  domain: ErrorDomain.STORAGE,
939
688
  category: ErrorCategory.THIRD_PARTY
940
689
  },
@@ -942,444 +691,679 @@ var StoreMemoryLance = class extends MemoryStorage {
942
691
  );
943
692
  }
944
693
  }
945
- throw new Error("Unexpected end of retry loop");
946
- }
947
- };
948
- var StoreOperationsLance = class extends StoreOperations {
949
- client;
950
- constructor({ client }) {
951
- super();
952
- this.client = client;
953
- }
954
- getDefaultValue(type) {
955
- switch (type) {
956
- case "text":
957
- return "''";
958
- case "timestamp":
959
- return "CURRENT_TIMESTAMP";
960
- case "integer":
961
- case "bigint":
962
- return "0";
963
- case "jsonb":
964
- return "'{}'";
965
- case "uuid":
966
- return "''";
967
- default:
968
- return super.getDefaultValue(type);
969
- }
970
- }
971
- async hasColumn(tableName, columnName) {
972
- const table = await this.client.openTable(tableName);
973
- const schema = await table.schema();
974
- return schema.fields.some((field) => field.name === columnName);
975
- }
976
- translateSchema(schema) {
977
- const fields = Object.entries(schema).map(([name, column]) => {
978
- let arrowType;
979
- switch (column.type.toLowerCase()) {
980
- case "text":
981
- case "uuid":
982
- arrowType = new Utf8();
983
- break;
984
- case "int":
985
- case "integer":
986
- arrowType = new Int32();
987
- break;
988
- case "bigint":
989
- arrowType = new Float64();
990
- break;
991
- case "float":
992
- arrowType = new Float32();
993
- break;
994
- case "jsonb":
995
- case "json":
996
- arrowType = new Utf8();
997
- break;
998
- case "binary":
999
- arrowType = new Binary();
1000
- break;
1001
- case "timestamp":
1002
- arrowType = new Float64();
1003
- break;
1004
- default:
1005
- arrowType = new Utf8();
1006
- }
1007
- return new Field(name, arrowType, column.nullable ?? true);
1008
- });
1009
- return new Schema(fields);
694
+ throw new MastraError(
695
+ {
696
+ id: createStorageErrorId("LANCE", "UPDATE_THREAD", "FAILED"),
697
+ domain: ErrorDomain.STORAGE,
698
+ category: ErrorCategory.THIRD_PARTY
699
+ },
700
+ new Error("All retries exhausted")
701
+ );
1010
702
  }
1011
- async createTable({
1012
- tableName,
1013
- schema
1014
- }) {
703
+ async deleteThread({ threadId }) {
1015
704
  try {
1016
- if (!this.client) {
1017
- throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1018
- }
1019
- if (!tableName) {
1020
- throw new Error("tableName is required for createTable.");
1021
- }
1022
- if (!schema) {
1023
- throw new Error("schema is required for createTable.");
1024
- }
705
+ const table = await this.client.openTable(TABLE_THREADS);
706
+ await table.delete(`id = '${threadId}'`);
707
+ const messagesTable = await this.client.openTable(TABLE_MESSAGES);
708
+ await messagesTable.delete(`thread_id = '${threadId}'`);
1025
709
  } catch (error) {
1026
710
  throw new MastraError(
1027
711
  {
1028
- id: "STORAGE_LANCE_STORAGE_CREATE_TABLE_INVALID_ARGS",
712
+ id: createStorageErrorId("LANCE", "DELETE_THREAD", "FAILED"),
1029
713
  domain: ErrorDomain.STORAGE,
1030
- category: ErrorCategory.USER,
1031
- details: { tableName }
714
+ category: ErrorCategory.THIRD_PARTY
1032
715
  },
1033
716
  error
1034
717
  );
1035
718
  }
719
+ }
720
+ normalizeMessage(message) {
721
+ const { thread_id, ...rest } = message;
722
+ return {
723
+ ...rest,
724
+ threadId: thread_id,
725
+ content: typeof message.content === "string" ? (() => {
726
+ try {
727
+ return JSON.parse(message.content);
728
+ } catch {
729
+ return message.content;
730
+ }
731
+ })() : message.content
732
+ };
733
+ }
734
+ async listMessagesById({ messageIds }) {
735
+ if (messageIds.length === 0) return { messages: [] };
1036
736
  try {
1037
- const arrowSchema = this.translateSchema(schema);
1038
- await this.client.createEmptyTable(tableName, arrowSchema);
737
+ const table = await this.client.openTable(TABLE_MESSAGES);
738
+ const quotedIds = messageIds.map((id) => `'${id}'`).join(", ");
739
+ const allRecords = await table.query().where(`id IN (${quotedIds})`).toArray();
740
+ const messages = processResultWithTypeConversion(
741
+ allRecords,
742
+ await getTableSchema({ tableName: TABLE_MESSAGES, client: this.client })
743
+ );
744
+ const list = new MessageList().add(
745
+ messages.map(this.normalizeMessage),
746
+ "memory"
747
+ );
748
+ return { messages: list.get.all.db() };
1039
749
  } catch (error) {
1040
- if (error.message?.includes("already exists")) {
1041
- this.logger.debug(`Table '${tableName}' already exists, skipping create`);
1042
- return;
1043
- }
1044
750
  throw new MastraError(
1045
751
  {
1046
- id: "STORAGE_LANCE_STORAGE_CREATE_TABLE_FAILED",
752
+ id: createStorageErrorId("LANCE", "LIST_MESSAGES_BY_ID", "FAILED"),
1047
753
  domain: ErrorDomain.STORAGE,
1048
754
  category: ErrorCategory.THIRD_PARTY,
1049
- details: { tableName }
755
+ details: {
756
+ messageIds: JSON.stringify(messageIds)
757
+ }
1050
758
  },
1051
759
  error
1052
760
  );
1053
761
  }
1054
762
  }
1055
- async dropTable({ tableName }) {
1056
- try {
1057
- if (!this.client) {
1058
- throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1059
- }
1060
- if (!tableName) {
1061
- throw new Error("tableName is required for dropTable.");
1062
- }
1063
- } catch (validationError) {
1064
- throw new MastraError(
1065
- {
1066
- id: "STORAGE_LANCE_STORAGE_DROP_TABLE_INVALID_ARGS",
1067
- domain: ErrorDomain.STORAGE,
1068
- category: ErrorCategory.USER,
1069
- text: validationError.message,
1070
- details: { tableName }
1071
- },
1072
- validationError
1073
- );
1074
- }
1075
- try {
1076
- await this.client.dropTable(tableName);
1077
- } catch (error) {
1078
- if (error.toString().includes("was not found") || error.message?.includes("Table not found")) {
1079
- this.logger.debug(`Table '${tableName}' does not exist, skipping drop`);
1080
- return;
1081
- }
763
+ async listMessages(args) {
764
+ const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
765
+ const threadIds = Array.isArray(threadId) ? threadId : [threadId];
766
+ if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) {
1082
767
  throw new MastraError(
1083
768
  {
1084
- id: "STORAGE_LANCE_STORAGE_DROP_TABLE_FAILED",
769
+ id: createStorageErrorId("LANCE", "LIST_MESSAGES", "INVALID_THREAD_ID"),
1085
770
  domain: ErrorDomain.STORAGE,
1086
771
  category: ErrorCategory.THIRD_PARTY,
1087
- details: { tableName }
772
+ details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
1088
773
  },
1089
- error
774
+ new Error("threadId must be a non-empty string or array of non-empty strings")
1090
775
  );
1091
776
  }
1092
- }
1093
- async alterTable({
1094
- tableName,
1095
- schema,
1096
- ifNotExists
1097
- }) {
777
+ const perPage = normalizePerPage(perPageInput, 40);
778
+ const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
1098
779
  try {
1099
- if (!this.client) {
1100
- throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
780
+ if (page < 0) {
781
+ throw new MastraError(
782
+ {
783
+ id: createStorageErrorId("LANCE", "LIST_MESSAGES", "INVALID_PAGE"),
784
+ domain: ErrorDomain.STORAGE,
785
+ category: ErrorCategory.USER,
786
+ details: { page }
787
+ },
788
+ new Error("page must be >= 0")
789
+ );
1101
790
  }
1102
- if (!tableName) {
1103
- throw new Error("tableName is required for alterTable.");
791
+ const { field, direction } = this.parseOrderBy(orderBy, "ASC");
792
+ const table = await this.client.openTable(TABLE_MESSAGES);
793
+ const threadCondition = threadIds.length === 1 ? `thread_id = '${this.escapeSql(threadIds[0])}'` : `thread_id IN (${threadIds.map((t) => `'${this.escapeSql(t)}'`).join(", ")})`;
794
+ const conditions = [threadCondition];
795
+ if (resourceId) {
796
+ conditions.push(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
1104
797
  }
1105
- if (!schema) {
1106
- throw new Error("schema is required for alterTable.");
798
+ if (filter?.dateRange?.start) {
799
+ const startTime = filter.dateRange.start instanceof Date ? filter.dateRange.start.getTime() : new Date(filter.dateRange.start).getTime();
800
+ conditions.push(`\`createdAt\` >= ${startTime}`);
1107
801
  }
1108
- if (!ifNotExists || ifNotExists.length === 0) {
1109
- this.logger.debug("No columns specified to add in alterTable, skipping.");
1110
- return;
802
+ if (filter?.dateRange?.end) {
803
+ const endTime = filter.dateRange.end instanceof Date ? filter.dateRange.end.getTime() : new Date(filter.dateRange.end).getTime();
804
+ conditions.push(`\`createdAt\` <= ${endTime}`);
1111
805
  }
1112
- } catch (validationError) {
1113
- throw new MastraError(
1114
- {
1115
- id: "STORAGE_LANCE_STORAGE_ALTER_TABLE_INVALID_ARGS",
1116
- domain: ErrorDomain.STORAGE,
1117
- category: ErrorCategory.USER,
1118
- text: validationError.message,
1119
- details: { tableName }
1120
- },
1121
- validationError
1122
- );
1123
- }
1124
- try {
1125
- const table = await this.client.openTable(tableName);
1126
- const currentSchema = await table.schema();
1127
- const existingFields = new Set(currentSchema.fields.map((f) => f.name));
1128
- const typeMap = {
1129
- text: "string",
1130
- integer: "int",
1131
- bigint: "bigint",
1132
- timestamp: "timestamp",
1133
- jsonb: "string",
1134
- uuid: "string"
1135
- };
1136
- const columnsToAdd = ifNotExists.filter((col) => schema[col] && !existingFields.has(col)).map((col) => {
1137
- const colDef = schema[col];
806
+ const whereClause = conditions.join(" AND ");
807
+ const total = await table.countRows(whereClause);
808
+ const query = table.query().where(whereClause);
809
+ let allRecords = await query.toArray();
810
+ allRecords.sort((a, b) => {
811
+ const aValue = field === "createdAt" ? a.createdAt : a[field];
812
+ const bValue = field === "createdAt" ? b.createdAt : b[field];
813
+ if (aValue == null && bValue == null) return 0;
814
+ if (aValue == null) return direction === "ASC" ? -1 : 1;
815
+ if (bValue == null) return direction === "ASC" ? 1 : -1;
816
+ if (typeof aValue === "string" && typeof bValue === "string") {
817
+ return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
818
+ }
819
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
820
+ });
821
+ const paginatedRecords = allRecords.slice(offset, offset + perPage);
822
+ const messages = paginatedRecords.map((row) => this.normalizeMessage(row));
823
+ if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
1138
824
  return {
1139
- name: col,
1140
- valueSql: colDef?.nullable ? `cast(NULL as ${typeMap[colDef.type ?? "text"]})` : `cast(${this.getDefaultValue(colDef?.type ?? "text")} as ${typeMap[colDef?.type ?? "text"]})`
825
+ messages: [],
826
+ total: 0,
827
+ page,
828
+ perPage: perPageForResponse,
829
+ hasMore: false
1141
830
  };
1142
- });
1143
- if (columnsToAdd.length > 0) {
1144
- await table.addColumns(columnsToAdd);
1145
- this.logger?.info?.(`Added columns [${columnsToAdd.map((c) => c.name).join(", ")}] to table ${tableName}`);
1146
831
  }
832
+ const messageIds = new Set(messages.map((m) => m.id));
833
+ if (include && include.length > 0) {
834
+ const threadIds2 = [...new Set(include.map((item) => item.threadId || threadId))];
835
+ const allThreadMessages = [];
836
+ for (const tid of threadIds2) {
837
+ const threadQuery = table.query().where(`thread_id = '${tid}'`);
838
+ let threadRecords = await threadQuery.toArray();
839
+ allThreadMessages.push(...threadRecords);
840
+ }
841
+ allThreadMessages.sort((a, b) => a.createdAt - b.createdAt);
842
+ const contextMessages = this.processMessagesWithContext(allThreadMessages, include);
843
+ const includedMessages = contextMessages.map((row) => this.normalizeMessage(row));
844
+ for (const includeMsg of includedMessages) {
845
+ if (!messageIds.has(includeMsg.id)) {
846
+ messages.push(includeMsg);
847
+ messageIds.add(includeMsg.id);
848
+ }
849
+ }
850
+ }
851
+ const list = new MessageList().add(messages, "memory");
852
+ let finalMessages = list.get.all.db();
853
+ finalMessages = finalMessages.sort((a, b) => {
854
+ const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
855
+ const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
856
+ if (aValue == null && bValue == null) return 0;
857
+ if (aValue == null) return direction === "ASC" ? -1 : 1;
858
+ if (bValue == null) return direction === "ASC" ? 1 : -1;
859
+ if (typeof aValue === "string" && typeof bValue === "string") {
860
+ return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
861
+ }
862
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
863
+ });
864
+ const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
865
+ const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
866
+ const fetchedAll = perPageInput === false || allThreadMessagesReturned;
867
+ const hasMore = !fetchedAll && offset + perPage < total;
868
+ return {
869
+ messages: finalMessages,
870
+ total,
871
+ page,
872
+ perPage: perPageForResponse,
873
+ hasMore
874
+ };
1147
875
  } catch (error) {
1148
- throw new MastraError(
876
+ const mastraError = new MastraError(
1149
877
  {
1150
- id: "STORAGE_LANCE_STORAGE_ALTER_TABLE_FAILED",
878
+ id: createStorageErrorId("LANCE", "LIST_MESSAGES", "FAILED"),
1151
879
  domain: ErrorDomain.STORAGE,
1152
880
  category: ErrorCategory.THIRD_PARTY,
1153
- details: { tableName }
881
+ details: {
882
+ threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
883
+ resourceId: resourceId ?? ""
884
+ }
1154
885
  },
1155
886
  error
1156
887
  );
888
+ this.logger?.error?.(mastraError.toString());
889
+ this.logger?.trackException?.(mastraError);
890
+ return {
891
+ messages: [],
892
+ total: 0,
893
+ page,
894
+ perPage: perPageForResponse,
895
+ hasMore: false
896
+ };
1157
897
  }
1158
898
  }
1159
- async clearTable({ tableName }) {
899
+ async saveMessages(args) {
1160
900
  try {
1161
- if (!this.client) {
1162
- throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
901
+ const { messages } = args;
902
+ if (messages.length === 0) {
903
+ return { messages: [] };
1163
904
  }
1164
- if (!tableName) {
1165
- throw new Error("tableName is required for clearTable.");
905
+ const threadId = messages[0]?.threadId;
906
+ if (!threadId) {
907
+ throw new Error("Thread ID is required");
1166
908
  }
1167
- } catch (validationError) {
909
+ for (const message of messages) {
910
+ if (!message.id) {
911
+ throw new Error("Message ID is required");
912
+ }
913
+ if (!message.threadId) {
914
+ throw new Error("Thread ID is required for all messages");
915
+ }
916
+ if (message.resourceId === null || message.resourceId === void 0) {
917
+ throw new Error("Resource ID cannot be null or undefined");
918
+ }
919
+ if (!message.content) {
920
+ throw new Error("Message content is required");
921
+ }
922
+ }
923
+ const transformedMessages = messages.map((message) => {
924
+ const { threadId: threadId2, type, ...rest } = message;
925
+ return {
926
+ ...rest,
927
+ thread_id: threadId2,
928
+ type: type ?? "v2",
929
+ content: JSON.stringify(message.content)
930
+ };
931
+ });
932
+ const table = await this.client.openTable(TABLE_MESSAGES);
933
+ await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(transformedMessages);
934
+ const threadsTable = await this.client.openTable(TABLE_THREADS);
935
+ const currentTime = (/* @__PURE__ */ new Date()).getTime();
936
+ const updateRecord = { id: threadId, updatedAt: currentTime };
937
+ await threadsTable.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([updateRecord]);
938
+ const list = new MessageList().add(messages, "memory");
939
+ return { messages: list.get.all.db() };
940
+ } catch (error) {
1168
941
  throw new MastraError(
1169
942
  {
1170
- id: "STORAGE_LANCE_STORAGE_CLEAR_TABLE_INVALID_ARGS",
943
+ id: createStorageErrorId("LANCE", "SAVE_MESSAGES", "FAILED"),
1171
944
  domain: ErrorDomain.STORAGE,
1172
- category: ErrorCategory.USER,
1173
- text: validationError.message,
1174
- details: { tableName }
945
+ category: ErrorCategory.THIRD_PARTY
1175
946
  },
1176
- validationError
947
+ error
1177
948
  );
1178
949
  }
950
+ }
951
+ async listThreadsByResourceId(args) {
1179
952
  try {
1180
- const table = await this.client.openTable(tableName);
1181
- await table.delete("1=1");
953
+ const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
954
+ const perPage = normalizePerPage(perPageInput, 100);
955
+ if (page < 0) {
956
+ throw new MastraError(
957
+ {
958
+ id: createStorageErrorId("LANCE", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
959
+ domain: ErrorDomain.STORAGE,
960
+ category: ErrorCategory.USER,
961
+ details: { page }
962
+ },
963
+ new Error("page must be >= 0")
964
+ );
965
+ }
966
+ const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
967
+ const { field, direction } = this.parseOrderBy(orderBy);
968
+ const table = await this.client.openTable(TABLE_THREADS);
969
+ const total = await table.countRows(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
970
+ const query = table.query().where(`\`resourceId\` = '${this.escapeSql(resourceId)}'`);
971
+ const records = await query.toArray();
972
+ records.sort((a, b) => {
973
+ const aValue = ["createdAt", "updatedAt"].includes(field) ? new Date(a[field]).getTime() : a[field];
974
+ const bValue = ["createdAt", "updatedAt"].includes(field) ? new Date(b[field]).getTime() : b[field];
975
+ if (aValue == null && bValue == null) return 0;
976
+ if (aValue == null) return direction === "ASC" ? -1 : 1;
977
+ if (bValue == null) return direction === "ASC" ? 1 : -1;
978
+ if (typeof aValue === "string" && typeof bValue === "string") {
979
+ return direction === "ASC" ? aValue.localeCompare(bValue) : bValue.localeCompare(aValue);
980
+ }
981
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
982
+ });
983
+ const paginatedRecords = records.slice(offset, offset + perPage);
984
+ const schema = await getTableSchema({ tableName: TABLE_THREADS, client: this.client });
985
+ const threads = paginatedRecords.map(
986
+ (record) => processResultWithTypeConversion(record, schema)
987
+ );
988
+ return {
989
+ threads,
990
+ total,
991
+ page,
992
+ perPage: perPageForResponse,
993
+ hasMore: offset + perPage < total
994
+ };
1182
995
  } catch (error) {
1183
996
  throw new MastraError(
1184
997
  {
1185
- id: "STORAGE_LANCE_STORAGE_CLEAR_TABLE_FAILED",
998
+ id: createStorageErrorId("LANCE", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
1186
999
  domain: ErrorDomain.STORAGE,
1187
- category: ErrorCategory.THIRD_PARTY,
1188
- details: { tableName }
1000
+ category: ErrorCategory.THIRD_PARTY
1189
1001
  },
1190
1002
  error
1191
1003
  );
1192
1004
  }
1193
1005
  }
1194
- async insert({ tableName, record }) {
1195
- try {
1196
- if (!this.client) {
1197
- throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1198
- }
1199
- if (!tableName) {
1200
- throw new Error("tableName is required for insert.");
1006
+ /**
1007
+ * Processes messages to include context messages based on withPreviousMessages and withNextMessages
1008
+ * @param records - The sorted array of records to process
1009
+ * @param include - The array of include specifications with context parameters
1010
+ * @returns The processed array with context messages included
1011
+ */
1012
+ processMessagesWithContext(records, include) {
1013
+ const messagesWithContext = include.filter((item) => item.withPreviousMessages || item.withNextMessages);
1014
+ if (messagesWithContext.length === 0) {
1015
+ return records;
1016
+ }
1017
+ const messageIndexMap = /* @__PURE__ */ new Map();
1018
+ records.forEach((message, index) => {
1019
+ messageIndexMap.set(message.id, index);
1020
+ });
1021
+ const additionalIndices = /* @__PURE__ */ new Set();
1022
+ for (const item of messagesWithContext) {
1023
+ const messageIndex = messageIndexMap.get(item.id);
1024
+ if (messageIndex !== void 0) {
1025
+ if (item.withPreviousMessages) {
1026
+ const startIdx = Math.max(0, messageIndex - item.withPreviousMessages);
1027
+ for (let i = startIdx; i < messageIndex; i++) {
1028
+ additionalIndices.add(i);
1029
+ }
1030
+ }
1031
+ if (item.withNextMessages) {
1032
+ const endIdx = Math.min(records.length - 1, messageIndex + item.withNextMessages);
1033
+ for (let i = messageIndex + 1; i <= endIdx; i++) {
1034
+ additionalIndices.add(i);
1035
+ }
1036
+ }
1201
1037
  }
1202
- if (!record || Object.keys(record).length === 0) {
1203
- throw new Error("record is required and cannot be empty for insert.");
1038
+ }
1039
+ if (additionalIndices.size === 0) {
1040
+ return records;
1041
+ }
1042
+ const originalMatchIds = new Set(include.map((item) => item.id));
1043
+ const allIndices = /* @__PURE__ */ new Set();
1044
+ records.forEach((record, index) => {
1045
+ if (originalMatchIds.has(record.id)) {
1046
+ allIndices.add(index);
1204
1047
  }
1205
- } catch (validationError) {
1206
- throw new MastraError(
1207
- {
1208
- id: "STORAGE_LANCE_STORAGE_INSERT_INVALID_ARGS",
1209
- domain: ErrorDomain.STORAGE,
1210
- category: ErrorCategory.USER,
1211
- text: validationError.message,
1212
- details: { tableName }
1213
- },
1214
- validationError
1215
- );
1048
+ });
1049
+ additionalIndices.forEach((index) => {
1050
+ allIndices.add(index);
1051
+ });
1052
+ return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
1053
+ }
1054
+ /**
1055
+ * Parse message data from LanceDB record format to MastraDBMessage format
1056
+ */
1057
+ parseMessageData(data) {
1058
+ const { thread_id, ...rest } = data;
1059
+ return {
1060
+ ...rest,
1061
+ threadId: thread_id,
1062
+ content: typeof data.content === "string" ? (() => {
1063
+ try {
1064
+ return JSON.parse(data.content);
1065
+ } catch {
1066
+ return data.content;
1067
+ }
1068
+ })() : data.content,
1069
+ createdAt: new Date(data.createdAt),
1070
+ updatedAt: new Date(data.updatedAt)
1071
+ };
1072
+ }
1073
+ async updateMessages(args) {
1074
+ const { messages } = args;
1075
+ this.logger.debug("Updating messages", { count: messages.length });
1076
+ if (!messages.length) {
1077
+ return [];
1216
1078
  }
1079
+ const updatedMessages = [];
1080
+ const affectedThreadIds = /* @__PURE__ */ new Set();
1217
1081
  try {
1218
- const table = await this.client.openTable(tableName);
1219
- const primaryId = getPrimaryKeys(tableName);
1220
- const processedRecord = { ...record };
1221
- for (const key in processedRecord) {
1222
- if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
1223
- this.logger.debug("Converting object to JSON string: ", processedRecord[key]);
1224
- processedRecord[key] = JSON.stringify(processedRecord[key]);
1082
+ for (const updateData of messages) {
1083
+ const { id, ...updates } = updateData;
1084
+ const existingMessage = await this.#db.load({ tableName: TABLE_MESSAGES, keys: { id } });
1085
+ if (!existingMessage) {
1086
+ this.logger.warn("Message not found for update", { id });
1087
+ continue;
1088
+ }
1089
+ const existingMsg = this.parseMessageData(existingMessage);
1090
+ const originalThreadId = existingMsg.threadId;
1091
+ affectedThreadIds.add(originalThreadId);
1092
+ const updatePayload = {};
1093
+ if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
1094
+ if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
1095
+ if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
1096
+ if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
1097
+ updatePayload.thread_id = updates.threadId;
1098
+ affectedThreadIds.add(updates.threadId);
1099
+ }
1100
+ if (updates.content) {
1101
+ const existingContent = existingMsg.content;
1102
+ let newContent = { ...existingContent };
1103
+ if (updates.content.metadata !== void 0) {
1104
+ newContent.metadata = {
1105
+ ...existingContent.metadata || {},
1106
+ ...updates.content.metadata || {}
1107
+ };
1108
+ }
1109
+ if (updates.content.content !== void 0) {
1110
+ newContent.content = updates.content.content;
1111
+ }
1112
+ if ("parts" in updates.content && updates.content.parts !== void 0) {
1113
+ newContent.parts = updates.content.parts;
1114
+ }
1115
+ updatePayload.content = JSON.stringify(newContent);
1116
+ }
1117
+ await this.#db.insert({ tableName: TABLE_MESSAGES, record: { id, ...updatePayload } });
1118
+ const updatedMessage = await this.#db.load({ tableName: TABLE_MESSAGES, keys: { id } });
1119
+ if (updatedMessage) {
1120
+ updatedMessages.push(this.parseMessageData(updatedMessage));
1225
1121
  }
1226
1122
  }
1227
- console.log(await table.schema());
1228
- await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([processedRecord]);
1123
+ for (const threadId of affectedThreadIds) {
1124
+ await this.#db.insert({
1125
+ tableName: TABLE_THREADS,
1126
+ record: { id: threadId, updatedAt: Date.now() }
1127
+ });
1128
+ }
1129
+ return updatedMessages;
1229
1130
  } catch (error) {
1230
1131
  throw new MastraError(
1231
1132
  {
1232
- id: "STORAGE_LANCE_STORAGE_INSERT_FAILED",
1133
+ id: createStorageErrorId("LANCE", "UPDATE_MESSAGES", "FAILED"),
1233
1134
  domain: ErrorDomain.STORAGE,
1234
1135
  category: ErrorCategory.THIRD_PARTY,
1235
- details: { tableName }
1136
+ details: { count: messages.length }
1236
1137
  },
1237
1138
  error
1238
1139
  );
1239
1140
  }
1240
1141
  }
1241
- async batchInsert({ tableName, records }) {
1142
+ async getResourceById({ resourceId }) {
1242
1143
  try {
1243
- if (!this.client) {
1244
- throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1144
+ const resource = await this.#db.load({ tableName: TABLE_RESOURCES, keys: { id: resourceId } });
1145
+ if (!resource) {
1146
+ return null;
1245
1147
  }
1246
- if (!tableName) {
1247
- throw new Error("tableName is required for batchInsert.");
1148
+ let createdAt;
1149
+ let updatedAt;
1150
+ try {
1151
+ if (resource.createdAt instanceof Date) {
1152
+ createdAt = resource.createdAt;
1153
+ } else if (typeof resource.createdAt === "string") {
1154
+ createdAt = new Date(resource.createdAt);
1155
+ } else if (typeof resource.createdAt === "number") {
1156
+ createdAt = new Date(resource.createdAt);
1157
+ } else {
1158
+ createdAt = /* @__PURE__ */ new Date();
1159
+ }
1160
+ if (isNaN(createdAt.getTime())) {
1161
+ createdAt = /* @__PURE__ */ new Date();
1162
+ }
1163
+ } catch {
1164
+ createdAt = /* @__PURE__ */ new Date();
1248
1165
  }
1249
- if (!records || records.length === 0) {
1250
- throw new Error("records array is required and cannot be empty for batchInsert.");
1166
+ try {
1167
+ if (resource.updatedAt instanceof Date) {
1168
+ updatedAt = resource.updatedAt;
1169
+ } else if (typeof resource.updatedAt === "string") {
1170
+ updatedAt = new Date(resource.updatedAt);
1171
+ } else if (typeof resource.updatedAt === "number") {
1172
+ updatedAt = new Date(resource.updatedAt);
1173
+ } else {
1174
+ updatedAt = /* @__PURE__ */ new Date();
1175
+ }
1176
+ if (isNaN(updatedAt.getTime())) {
1177
+ updatedAt = /* @__PURE__ */ new Date();
1178
+ }
1179
+ } catch {
1180
+ updatedAt = /* @__PURE__ */ new Date();
1181
+ }
1182
+ let workingMemory = resource.workingMemory;
1183
+ if (workingMemory === null || workingMemory === void 0) {
1184
+ workingMemory = void 0;
1185
+ } else if (workingMemory === "") {
1186
+ workingMemory = "";
1187
+ } else if (typeof workingMemory === "object") {
1188
+ workingMemory = JSON.stringify(workingMemory);
1189
+ }
1190
+ let metadata = resource.metadata;
1191
+ if (metadata === "" || metadata === null || metadata === void 0) {
1192
+ metadata = void 0;
1193
+ } else if (typeof metadata === "string") {
1194
+ try {
1195
+ metadata = JSON.parse(metadata);
1196
+ } catch {
1197
+ metadata = metadata;
1198
+ }
1251
1199
  }
1252
- } catch (validationError) {
1200
+ return {
1201
+ ...resource,
1202
+ createdAt,
1203
+ updatedAt,
1204
+ workingMemory,
1205
+ metadata
1206
+ };
1207
+ } catch (error) {
1253
1208
  throw new MastraError(
1254
1209
  {
1255
- id: "STORAGE_LANCE_STORAGE_BATCH_INSERT_INVALID_ARGS",
1210
+ id: createStorageErrorId("LANCE", "GET_RESOURCE_BY_ID", "FAILED"),
1256
1211
  domain: ErrorDomain.STORAGE,
1257
- category: ErrorCategory.USER,
1258
- text: validationError.message,
1259
- details: { tableName }
1212
+ category: ErrorCategory.THIRD_PARTY
1260
1213
  },
1261
- validationError
1214
+ error
1262
1215
  );
1263
1216
  }
1217
+ }
1218
+ async saveResource({ resource }) {
1264
1219
  try {
1265
- const table = await this.client.openTable(tableName);
1266
- const primaryId = getPrimaryKeys(tableName);
1267
- const processedRecords = records.map((record) => {
1268
- const processedRecord = { ...record };
1269
- for (const key in processedRecord) {
1270
- if (processedRecord[key] == null) continue;
1271
- if (processedRecord[key] !== null && typeof processedRecord[key] === "object" && !(processedRecord[key] instanceof Date)) {
1272
- processedRecord[key] = JSON.stringify(processedRecord[key]);
1273
- }
1274
- }
1275
- return processedRecord;
1276
- });
1277
- console.log(processedRecords);
1278
- await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(processedRecords);
1220
+ const record = {
1221
+ ...resource,
1222
+ metadata: resource.metadata ? JSON.stringify(resource.metadata) : "",
1223
+ createdAt: resource.createdAt.getTime(),
1224
+ // Store as timestamp (milliseconds)
1225
+ updatedAt: resource.updatedAt.getTime()
1226
+ // Store as timestamp (milliseconds)
1227
+ };
1228
+ const table = await this.client.openTable(TABLE_RESOURCES);
1229
+ await table.add([record], { mode: "append" });
1230
+ return resource;
1279
1231
  } catch (error) {
1280
1232
  throw new MastraError(
1281
1233
  {
1282
- id: "STORAGE_LANCE_STORAGE_BATCH_INSERT_FAILED",
1234
+ id: createStorageErrorId("LANCE", "SAVE_RESOURCE", "FAILED"),
1283
1235
  domain: ErrorDomain.STORAGE,
1284
- category: ErrorCategory.THIRD_PARTY,
1285
- details: { tableName }
1236
+ category: ErrorCategory.THIRD_PARTY
1286
1237
  },
1287
1238
  error
1288
1239
  );
1289
1240
  }
1290
1241
  }
1291
- async load({ tableName, keys }) {
1292
- try {
1293
- if (!this.client) {
1294
- throw new Error("LanceDB client not initialized. Call LanceStorage.create() first.");
1295
- }
1296
- if (!tableName) {
1297
- throw new Error("tableName is required for load.");
1298
- }
1299
- if (!keys || Object.keys(keys).length === 0) {
1300
- throw new Error("keys are required and cannot be empty for load.");
1242
+ async updateResource({
1243
+ resourceId,
1244
+ workingMemory,
1245
+ metadata
1246
+ }) {
1247
+ const maxRetries = 3;
1248
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
1249
+ try {
1250
+ const existingResource = await this.getResourceById({ resourceId });
1251
+ if (!existingResource) {
1252
+ const newResource = {
1253
+ id: resourceId,
1254
+ workingMemory,
1255
+ metadata: metadata || {},
1256
+ createdAt: /* @__PURE__ */ new Date(),
1257
+ updatedAt: /* @__PURE__ */ new Date()
1258
+ };
1259
+ return this.saveResource({ resource: newResource });
1260
+ }
1261
+ const updatedResource = {
1262
+ ...existingResource,
1263
+ workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
1264
+ metadata: {
1265
+ ...existingResource.metadata,
1266
+ ...metadata
1267
+ },
1268
+ updatedAt: /* @__PURE__ */ new Date()
1269
+ };
1270
+ const record = {
1271
+ id: resourceId,
1272
+ workingMemory: updatedResource.workingMemory || "",
1273
+ metadata: updatedResource.metadata ? JSON.stringify(updatedResource.metadata) : "",
1274
+ updatedAt: updatedResource.updatedAt.getTime()
1275
+ // Store as timestamp (milliseconds)
1276
+ };
1277
+ const table = await this.client.openTable(TABLE_RESOURCES);
1278
+ await table.mergeInsert("id").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
1279
+ return updatedResource;
1280
+ } catch (error) {
1281
+ if (error.message?.includes("Commit conflict") && attempt < maxRetries - 1) {
1282
+ const delay = Math.pow(2, attempt) * 10;
1283
+ await new Promise((resolve) => setTimeout(resolve, delay));
1284
+ continue;
1285
+ }
1286
+ throw new MastraError(
1287
+ {
1288
+ id: createStorageErrorId("LANCE", "UPDATE_RESOURCE", "FAILED"),
1289
+ domain: ErrorDomain.STORAGE,
1290
+ category: ErrorCategory.THIRD_PARTY
1291
+ },
1292
+ error
1293
+ );
1301
1294
  }
1302
- } catch (validationError) {
1303
- throw new MastraError(
1304
- {
1305
- id: "STORAGE_LANCE_STORAGE_LOAD_INVALID_ARGS",
1306
- domain: ErrorDomain.STORAGE,
1307
- category: ErrorCategory.USER,
1308
- text: validationError.message,
1309
- details: { tableName }
1310
- },
1311
- validationError
1312
- );
1313
1295
  }
1296
+ throw new Error("Unexpected end of retry loop");
1297
+ }
1298
+ };
1299
+ var StoreScoresLance = class extends ScoresStorage {
1300
+ client;
1301
+ #db;
1302
+ constructor(config) {
1303
+ super();
1304
+ const client = resolveLanceConfig(config);
1305
+ this.client = client;
1306
+ this.#db = new LanceDB({ client });
1307
+ }
1308
+ async init() {
1309
+ await this.#db.createTable({ tableName: TABLE_SCORERS, schema: SCORERS_SCHEMA });
1310
+ await this.#db.alterTable({
1311
+ tableName: TABLE_SCORERS,
1312
+ schema: SCORERS_SCHEMA,
1313
+ ifNotExists: ["spanId", "requestContext"]
1314
+ });
1315
+ }
1316
+ async dangerouslyClearAll() {
1317
+ await this.#db.clearTable({ tableName: TABLE_SCORERS });
1318
+ }
1319
+ async saveScore(score) {
1320
+ let validatedScore;
1314
1321
  try {
1315
- const table = await this.client.openTable(tableName);
1316
- const tableSchema = await getTableSchema({ tableName, client: this.client });
1317
- const query = table.query();
1318
- if (Object.keys(keys).length > 0) {
1319
- validateKeyTypes(keys, tableSchema);
1320
- const filterConditions = Object.entries(keys).map(([key, value]) => {
1321
- const isCamelCase = /^[a-z][a-zA-Z]*$/.test(key) && /[A-Z]/.test(key);
1322
- const quotedKey = isCamelCase ? `\`${key}\`` : key;
1323
- if (typeof value === "string") {
1324
- return `${quotedKey} = '${value}'`;
1325
- } else if (value === null) {
1326
- return `${quotedKey} IS NULL`;
1327
- } else {
1328
- return `${quotedKey} = ${value}`;
1329
- }
1330
- }).join(" AND ");
1331
- this.logger.debug("where clause generated: " + filterConditions);
1332
- query.where(filterConditions);
1333
- }
1334
- const result = await query.limit(1).toArray();
1335
- if (result.length === 0) {
1336
- this.logger.debug("No record found");
1337
- return null;
1338
- }
1339
- return processResultWithTypeConversion(result[0], tableSchema);
1322
+ validatedScore = saveScorePayloadSchema.parse(score);
1340
1323
  } catch (error) {
1341
- if (error instanceof MastraError) throw error;
1342
1324
  throw new MastraError(
1343
1325
  {
1344
- id: "STORAGE_LANCE_STORAGE_LOAD_FAILED",
1326
+ id: createStorageErrorId("LANCE", "SAVE_SCORE", "VALIDATION_FAILED"),
1327
+ text: "Failed to save score in LanceStorage",
1345
1328
  domain: ErrorDomain.STORAGE,
1346
- category: ErrorCategory.THIRD_PARTY,
1347
- details: { tableName, keyCount: Object.keys(keys).length, firstKey: Object.keys(keys)[0] ?? "" }
1329
+ category: ErrorCategory.USER,
1330
+ details: {
1331
+ scorer: score.scorer?.id ?? "unknown",
1332
+ entityId: score.entityId ?? "unknown",
1333
+ entityType: score.entityType ?? "unknown",
1334
+ traceId: score.traceId ?? "",
1335
+ spanId: score.spanId ?? ""
1336
+ }
1348
1337
  },
1349
1338
  error
1350
1339
  );
1351
1340
  }
1352
- }
1353
- };
1354
- var StoreScoresLance = class extends ScoresStorage {
1355
- client;
1356
- constructor({ client }) {
1357
- super();
1358
- this.client = client;
1359
- }
1360
- async saveScore(score) {
1341
+ const id = crypto.randomUUID();
1342
+ const now = /* @__PURE__ */ new Date();
1361
1343
  try {
1362
1344
  const table = await this.client.openTable(TABLE_SCORERS);
1363
1345
  const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1364
1346
  const allowedFields = new Set(schema.fields.map((f) => f.name));
1365
1347
  const filteredScore = {};
1366
- Object.keys(score).forEach((key) => {
1348
+ for (const key of Object.keys(validatedScore)) {
1367
1349
  if (allowedFields.has(key)) {
1368
- filteredScore[key] = score[key];
1350
+ filteredScore[key] = validatedScore[key];
1369
1351
  }
1370
- });
1352
+ }
1371
1353
  for (const key in filteredScore) {
1372
1354
  if (filteredScore[key] !== null && typeof filteredScore[key] === "object" && !(filteredScore[key] instanceof Date)) {
1373
1355
  filteredScore[key] = JSON.stringify(filteredScore[key]);
1374
1356
  }
1375
1357
  }
1376
- console.log("Saving score to LanceStorage:", filteredScore);
1358
+ filteredScore.id = id;
1359
+ filteredScore.createdAt = now;
1360
+ filteredScore.updatedAt = now;
1377
1361
  await table.add([filteredScore], { mode: "append" });
1378
- return { score };
1362
+ return { score: { ...validatedScore, id, createdAt: now, updatedAt: now } };
1379
1363
  } catch (error) {
1380
1364
  throw new MastraError(
1381
1365
  {
1382
- id: "LANCE_STORAGE_SAVE_SCORE_FAILED",
1366
+ id: createStorageErrorId("LANCE", "SAVE_SCORE", "FAILED"),
1383
1367
  text: "Failed to save score in LanceStorage",
1384
1368
  domain: ErrorDomain.STORAGE,
1385
1369
  category: ErrorCategory.THIRD_PARTY,
@@ -1395,12 +1379,11 @@ var StoreScoresLance = class extends ScoresStorage {
1395
1379
  const query = table.query().where(`id = '${id}'`).limit(1);
1396
1380
  const records = await query.toArray();
1397
1381
  if (records.length === 0) return null;
1398
- const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1399
- return processResultWithTypeConversion(records[0], schema);
1382
+ return await this.transformScoreRow(records[0]);
1400
1383
  } catch (error) {
1401
1384
  throw new MastraError(
1402
1385
  {
1403
- id: "LANCE_STORAGE_GET_SCORE_BY_ID_FAILED",
1386
+ id: createStorageErrorId("LANCE", "GET_SCORE_BY_ID", "FAILED"),
1404
1387
  text: "Failed to get score by id in LanceStorage",
1405
1388
  domain: ErrorDomain.STORAGE,
1406
1389
  category: ErrorCategory.THIRD_PARTY,
@@ -1410,34 +1393,76 @@ var StoreScoresLance = class extends ScoresStorage {
1410
1393
  );
1411
1394
  }
1412
1395
  }
1413
- async getScoresByScorerId({
1396
+ /**
1397
+ * LanceDB-specific score row transformation.
1398
+ *
1399
+ * Note: This implementation does NOT use coreTransformScoreRow because:
1400
+ * 1. LanceDB stores schema information in the table itself (requires async fetch)
1401
+ * 2. Uses processResultWithTypeConversion utility for LanceDB-specific type handling
1402
+ */
1403
+ async transformScoreRow(row) {
1404
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1405
+ const transformed = processResultWithTypeConversion(row, schema);
1406
+ return {
1407
+ ...transformed,
1408
+ createdAt: row.createdAt,
1409
+ updatedAt: row.updatedAt
1410
+ };
1411
+ }
1412
+ async listScoresByScorerId({
1414
1413
  scorerId,
1415
- pagination
1414
+ pagination,
1415
+ entityId,
1416
+ entityType,
1417
+ source
1416
1418
  }) {
1417
1419
  try {
1420
+ const { page, perPage: perPageInput } = pagination;
1421
+ const perPage = normalizePerPage(perPageInput, 100);
1422
+ const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
1418
1423
  const table = await this.client.openTable(TABLE_SCORERS);
1419
- const { page = 0, perPage = 10 } = pagination || {};
1420
- const offset = page * perPage;
1421
- const query = table.query().where(`\`scorerId\` = '${scorerId}'`).limit(perPage);
1422
- if (offset > 0) query.offset(offset);
1423
- const records = await query.toArray();
1424
- const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1425
- const scores = processResultWithTypeConversion(records, schema);
1426
- const allRecords = await table.query().where(`\`scorerId\` = '${scorerId}'`).toArray();
1424
+ let query = table.query().where(`\`scorerId\` = '${scorerId}'`);
1425
+ if (source) {
1426
+ query = query.where(`\`source\` = '${source}'`);
1427
+ }
1428
+ if (entityId) {
1429
+ query = query.where(`\`entityId\` = '${entityId}'`);
1430
+ }
1431
+ if (entityType) {
1432
+ query = query.where(`\`entityType\` = '${entityType}'`);
1433
+ }
1434
+ let totalQuery = table.query().where(`\`scorerId\` = '${scorerId}'`);
1435
+ if (source) {
1436
+ totalQuery = totalQuery.where(`\`source\` = '${source}'`);
1437
+ }
1438
+ if (entityId) {
1439
+ totalQuery = totalQuery.where(`\`entityId\` = '${entityId}'`);
1440
+ }
1441
+ if (entityType) {
1442
+ totalQuery = totalQuery.where(`\`entityType\` = '${entityType}'`);
1443
+ }
1444
+ const allRecords = await totalQuery.toArray();
1427
1445
  const total = allRecords.length;
1446
+ const end = perPageInput === false ? total : start + perPage;
1447
+ if (perPageInput !== false) {
1448
+ query = query.limit(perPage);
1449
+ if (start > 0) query = query.offset(start);
1450
+ }
1451
+ const records = await query.toArray();
1452
+ const scores = await Promise.all(records.map(async (record) => await this.transformScoreRow(record)));
1428
1453
  return {
1429
1454
  pagination: {
1430
1455
  page,
1431
- perPage,
1456
+ perPage: perPageForResponse,
1432
1457
  total,
1433
- hasMore: offset + scores.length < total
1458
+ hasMore: end < total
1434
1459
  },
1435
1460
  scores
1436
1461
  };
1437
1462
  } catch (error) {
1438
1463
  throw new MastraError(
1439
1464
  {
1440
- id: "LANCE_STORAGE_GET_SCORES_BY_SCORER_ID_FAILED",
1465
+ id: createStorageErrorId("LANCE", "LIST_SCORES_BY_SCORER_ID", "FAILED"),
1441
1466
  text: "Failed to get scores by scorerId in LanceStorage",
1442
1467
  domain: ErrorDomain.STORAGE,
1443
1468
  category: ErrorCategory.THIRD_PARTY,
@@ -1447,274 +1472,135 @@ var StoreScoresLance = class extends ScoresStorage {
1447
1472
  );
1448
1473
  }
1449
1474
  }
1450
- async getScoresByRunId({
1475
+ async listScoresByRunId({
1451
1476
  runId,
1452
1477
  pagination
1453
1478
  }) {
1454
1479
  try {
1480
+ const { page, perPage: perPageInput } = pagination;
1481
+ const perPage = normalizePerPage(perPageInput, 100);
1482
+ const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
1455
1483
  const table = await this.client.openTable(TABLE_SCORERS);
1456
- const { page = 0, perPage = 10 } = pagination || {};
1457
- const offset = page * perPage;
1458
- const query = table.query().where(`\`runId\` = '${runId}'`).limit(perPage);
1459
- if (offset > 0) query.offset(offset);
1460
- const records = await query.toArray();
1461
- const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1462
- const scores = processResultWithTypeConversion(records, schema);
1463
1484
  const allRecords = await table.query().where(`\`runId\` = '${runId}'`).toArray();
1464
1485
  const total = allRecords.length;
1465
- return {
1466
- pagination: {
1467
- page,
1468
- perPage,
1469
- total,
1470
- hasMore: offset + scores.length < total
1471
- },
1472
- scores
1473
- };
1474
- } catch (error) {
1475
- throw new MastraError(
1476
- {
1477
- id: "LANCE_STORAGE_GET_SCORES_BY_RUN_ID_FAILED",
1478
- text: "Failed to get scores by runId in LanceStorage",
1479
- domain: ErrorDomain.STORAGE,
1480
- category: ErrorCategory.THIRD_PARTY,
1481
- details: { error: error?.message }
1482
- },
1483
- error
1484
- );
1485
- }
1486
- }
1487
- async getScoresByEntityId({
1488
- entityId,
1489
- entityType,
1490
- pagination
1491
- }) {
1492
- try {
1493
- const table = await this.client.openTable(TABLE_SCORERS);
1494
- const { page = 0, perPage = 10 } = pagination || {};
1495
- const offset = page * perPage;
1496
- const query = table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).limit(perPage);
1497
- if (offset > 0) query.offset(offset);
1486
+ const end = perPageInput === false ? total : start + perPage;
1487
+ let query = table.query().where(`\`runId\` = '${runId}'`);
1488
+ if (perPageInput !== false) {
1489
+ query = query.limit(perPage);
1490
+ if (start > 0) query = query.offset(start);
1491
+ }
1498
1492
  const records = await query.toArray();
1499
- const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1500
- const scores = processResultWithTypeConversion(records, schema);
1501
- const allRecords = await table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).toArray();
1502
- const total = allRecords.length;
1493
+ const scores = await Promise.all(records.map(async (record) => await this.transformScoreRow(record)));
1503
1494
  return {
1504
1495
  pagination: {
1505
1496
  page,
1506
- perPage,
1497
+ perPage: perPageForResponse,
1507
1498
  total,
1508
- hasMore: offset + scores.length < total
1499
+ hasMore: end < total
1509
1500
  },
1510
1501
  scores
1511
- };
1512
- } catch (error) {
1513
- throw new MastraError(
1514
- {
1515
- id: "LANCE_STORAGE_GET_SCORES_BY_ENTITY_ID_FAILED",
1516
- text: "Failed to get scores by entityId and entityType in LanceStorage",
1517
- domain: ErrorDomain.STORAGE,
1518
- category: ErrorCategory.THIRD_PARTY,
1519
- details: { error: error?.message }
1520
- },
1521
- error
1522
- );
1523
- }
1524
- }
1525
- };
1526
- var StoreTracesLance = class extends TracesStorage {
1527
- client;
1528
- operations;
1529
- constructor({ client, operations }) {
1530
- super();
1531
- this.client = client;
1532
- this.operations = operations;
1533
- }
1534
- async saveTrace({ trace }) {
1535
- try {
1536
- const table = await this.client.openTable(TABLE_TRACES);
1537
- const record = {
1538
- ...trace,
1539
- attributes: JSON.stringify(trace.attributes),
1540
- status: JSON.stringify(trace.status),
1541
- events: JSON.stringify(trace.events),
1542
- links: JSON.stringify(trace.links),
1543
- other: JSON.stringify(trace.other)
1544
- };
1545
- await table.add([record], { mode: "append" });
1546
- return trace;
1547
- } catch (error) {
1548
- throw new MastraError(
1549
- {
1550
- id: "LANCE_STORE_SAVE_TRACE_FAILED",
1551
- domain: ErrorDomain.STORAGE,
1552
- category: ErrorCategory.THIRD_PARTY
1553
- },
1554
- error
1555
- );
1556
- }
1557
- }
1558
- async getTraceById({ traceId }) {
1559
- try {
1560
- const table = await this.client.openTable(TABLE_TRACES);
1561
- const query = table.query().where(`id = '${traceId}'`);
1562
- const records = await query.toArray();
1563
- return records[0];
1502
+ };
1564
1503
  } catch (error) {
1565
1504
  throw new MastraError(
1566
1505
  {
1567
- id: "LANCE_STORE_GET_TRACE_BY_ID_FAILED",
1506
+ id: createStorageErrorId("LANCE", "LIST_SCORES_BY_RUN_ID", "FAILED"),
1507
+ text: "Failed to get scores by runId in LanceStorage",
1568
1508
  domain: ErrorDomain.STORAGE,
1569
- category: ErrorCategory.THIRD_PARTY
1509
+ category: ErrorCategory.THIRD_PARTY,
1510
+ details: { error: error?.message }
1570
1511
  },
1571
1512
  error
1572
1513
  );
1573
1514
  }
1574
1515
  }
1575
- async getTraces({
1576
- name,
1577
- scope,
1578
- page = 1,
1579
- perPage = 10,
1580
- attributes
1516
+ async listScoresByEntityId({
1517
+ entityId,
1518
+ entityType,
1519
+ pagination
1581
1520
  }) {
1582
1521
  try {
1583
- const table = await this.client.openTable(TABLE_TRACES);
1584
- const query = table.query();
1585
- if (name) {
1586
- query.where(`name = '${name}'`);
1587
- }
1588
- if (scope) {
1589
- query.where(`scope = '${scope}'`);
1590
- }
1591
- if (attributes) {
1592
- query.where(`attributes = '${JSON.stringify(attributes)}'`);
1593
- }
1594
- const offset = (page - 1) * perPage;
1595
- query.limit(perPage);
1596
- if (offset > 0) {
1597
- query.offset(offset);
1522
+ const { page, perPage: perPageInput } = pagination;
1523
+ const perPage = normalizePerPage(perPageInput, 100);
1524
+ const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
1525
+ const table = await this.client.openTable(TABLE_SCORERS);
1526
+ const allRecords = await table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`).toArray();
1527
+ const total = allRecords.length;
1528
+ const end = perPageInput === false ? total : start + perPage;
1529
+ let query = table.query().where(`\`entityId\` = '${entityId}' AND \`entityType\` = '${entityType}'`);
1530
+ if (perPageInput !== false) {
1531
+ query = query.limit(perPage);
1532
+ if (start > 0) query = query.offset(start);
1598
1533
  }
1599
1534
  const records = await query.toArray();
1600
- return records.map((record) => {
1601
- const processed = {
1602
- ...record,
1603
- attributes: record.attributes ? JSON.parse(record.attributes) : {},
1604
- status: record.status ? JSON.parse(record.status) : {},
1605
- events: record.events ? JSON.parse(record.events) : [],
1606
- links: record.links ? JSON.parse(record.links) : [],
1607
- other: record.other ? JSON.parse(record.other) : {},
1608
- startTime: new Date(record.startTime),
1609
- endTime: new Date(record.endTime),
1610
- createdAt: new Date(record.createdAt)
1611
- };
1612
- if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
1613
- processed.parentSpanId = "";
1614
- } else {
1615
- processed.parentSpanId = String(processed.parentSpanId);
1616
- }
1617
- return processed;
1618
- });
1535
+ const scores = await Promise.all(records.map(async (record) => await this.transformScoreRow(record)));
1536
+ return {
1537
+ pagination: {
1538
+ page,
1539
+ perPage: perPageForResponse,
1540
+ total,
1541
+ hasMore: end < total
1542
+ },
1543
+ scores
1544
+ };
1619
1545
  } catch (error) {
1620
1546
  throw new MastraError(
1621
1547
  {
1622
- id: "LANCE_STORE_GET_TRACES_FAILED",
1548
+ id: createStorageErrorId("LANCE", "LIST_SCORES_BY_ENTITY_ID", "FAILED"),
1549
+ text: "Failed to get scores by entityId and entityType in LanceStorage",
1623
1550
  domain: ErrorDomain.STORAGE,
1624
1551
  category: ErrorCategory.THIRD_PARTY,
1625
- details: { name: name ?? "", scope: scope ?? "" }
1552
+ details: { error: error?.message }
1626
1553
  },
1627
1554
  error
1628
1555
  );
1629
1556
  }
1630
1557
  }
1631
- async getTracesPaginated(args) {
1558
+ async listScoresBySpan({
1559
+ traceId,
1560
+ spanId,
1561
+ pagination
1562
+ }) {
1632
1563
  try {
1633
- const table = await this.client.openTable(TABLE_TRACES);
1634
- const query = table.query();
1635
- const conditions = [];
1636
- if (args.name) {
1637
- conditions.push(`name = '${args.name}'`);
1638
- }
1639
- if (args.scope) {
1640
- conditions.push(`scope = '${args.scope}'`);
1641
- }
1642
- if (args.attributes) {
1643
- const attributesStr = JSON.stringify(args.attributes);
1644
- conditions.push(`attributes LIKE '%${attributesStr.replace(/"/g, '\\"')}%'`);
1645
- }
1646
- if (args.dateRange?.start) {
1647
- conditions.push(`\`createdAt\` >= ${args.dateRange.start.getTime()}`);
1648
- }
1649
- if (args.dateRange?.end) {
1650
- conditions.push(`\`createdAt\` <= ${args.dateRange.end.getTime()}`);
1651
- }
1652
- if (conditions.length > 0) {
1653
- const whereClause = conditions.join(" AND ");
1654
- query.where(whereClause);
1655
- }
1656
- let total = 0;
1657
- if (conditions.length > 0) {
1658
- const countQuery = table.query().where(conditions.join(" AND "));
1659
- const allRecords = await countQuery.toArray();
1660
- total = allRecords.length;
1661
- } else {
1662
- total = await table.countRows();
1663
- }
1664
- const page = args.page || 0;
1665
- const perPage = args.perPage || 10;
1666
- const offset = page * perPage;
1667
- query.limit(perPage);
1668
- if (offset > 0) {
1669
- query.offset(offset);
1564
+ const { page, perPage: perPageInput } = pagination;
1565
+ const perPage = normalizePerPage(perPageInput, 100);
1566
+ const { offset: start, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
1567
+ const table = await this.client.openTable(TABLE_SCORERS);
1568
+ const allRecords = await table.query().where(`\`traceId\` = '${traceId}' AND \`spanId\` = '${spanId}'`).toArray();
1569
+ const total = allRecords.length;
1570
+ const end = perPageInput === false ? total : start + perPage;
1571
+ let query = table.query().where(`\`traceId\` = '${traceId}' AND \`spanId\` = '${spanId}'`);
1572
+ if (perPageInput !== false) {
1573
+ query = query.limit(perPage);
1574
+ if (start > 0) query = query.offset(start);
1670
1575
  }
1671
1576
  const records = await query.toArray();
1672
- const traces = records.map((record) => {
1673
- const processed = {
1674
- ...record,
1675
- attributes: record.attributes ? JSON.parse(record.attributes) : {},
1676
- status: record.status ? JSON.parse(record.status) : {},
1677
- events: record.events ? JSON.parse(record.events) : [],
1678
- links: record.links ? JSON.parse(record.links) : [],
1679
- other: record.other ? JSON.parse(record.other) : {},
1680
- startTime: new Date(record.startTime),
1681
- endTime: new Date(record.endTime),
1682
- createdAt: new Date(record.createdAt)
1683
- };
1684
- if (processed.parentSpanId === null || processed.parentSpanId === void 0) {
1685
- processed.parentSpanId = "";
1686
- } else {
1687
- processed.parentSpanId = String(processed.parentSpanId);
1688
- }
1689
- return processed;
1690
- });
1577
+ const scores = await Promise.all(records.map(async (record) => await this.transformScoreRow(record)));
1691
1578
  return {
1692
- traces,
1693
- total,
1694
- page,
1695
- perPage,
1696
- hasMore: total > (page + 1) * perPage
1579
+ pagination: {
1580
+ page,
1581
+ perPage: perPageForResponse,
1582
+ total,
1583
+ hasMore: end < total
1584
+ },
1585
+ scores
1697
1586
  };
1698
1587
  } catch (error) {
1699
1588
  throw new MastraError(
1700
1589
  {
1701
- id: "LANCE_STORE_GET_TRACES_PAGINATED_FAILED",
1590
+ id: createStorageErrorId("LANCE", "LIST_SCORES_BY_SPAN", "FAILED"),
1591
+ text: "Failed to get scores by traceId and spanId in LanceStorage",
1702
1592
  domain: ErrorDomain.STORAGE,
1703
1593
  category: ErrorCategory.THIRD_PARTY,
1704
- details: { name: args.name ?? "", scope: args.scope ?? "" }
1594
+ details: { error: error?.message }
1705
1595
  },
1706
1596
  error
1707
1597
  );
1708
1598
  }
1709
1599
  }
1710
- async batchTraceInsert({ records }) {
1711
- this.logger.debug("Batch inserting traces", { count: records.length });
1712
- await this.operations.batchInsert({
1713
- tableName: TABLE_TRACES,
1714
- records
1715
- });
1716
- }
1717
1600
  };
1601
+ function escapeSql(str) {
1602
+ return str.replace(/'/g, "''");
1603
+ }
1718
1604
  function parseWorkflowRun(row) {
1719
1605
  let parsedSnapshot = row.snapshot;
1720
1606
  if (typeof parsedSnapshot === "string") {
@@ -1735,38 +1621,104 @@ function parseWorkflowRun(row) {
1735
1621
  }
1736
1622
  var StoreWorkflowsLance = class extends WorkflowsStorage {
1737
1623
  client;
1738
- constructor({ client }) {
1624
+ #db;
1625
+ constructor(config) {
1739
1626
  super();
1627
+ const client = resolveLanceConfig(config);
1740
1628
  this.client = client;
1629
+ this.#db = new LanceDB({ client });
1630
+ }
1631
+ async init() {
1632
+ const schema = TABLE_SCHEMAS[TABLE_WORKFLOW_SNAPSHOT];
1633
+ await this.#db.createTable({ tableName: TABLE_WORKFLOW_SNAPSHOT, schema });
1634
+ await this.#db.alterTable({
1635
+ tableName: TABLE_WORKFLOW_SNAPSHOT,
1636
+ schema,
1637
+ ifNotExists: ["resourceId"]
1638
+ });
1639
+ }
1640
+ async dangerouslyClearAll() {
1641
+ await this.#db.clearTable({ tableName: TABLE_WORKFLOW_SNAPSHOT });
1642
+ }
1643
+ async updateWorkflowResults({
1644
+ workflowName,
1645
+ runId,
1646
+ stepId,
1647
+ result,
1648
+ requestContext
1649
+ }) {
1650
+ let snapshot = await this.loadWorkflowSnapshot({ workflowName, runId });
1651
+ if (!snapshot) {
1652
+ snapshot = {
1653
+ context: {},
1654
+ activePaths: [],
1655
+ timestamp: Date.now(),
1656
+ suspendedPaths: {},
1657
+ activeStepsPath: {},
1658
+ resumeLabels: {},
1659
+ serializedStepGraph: [],
1660
+ status: "pending",
1661
+ value: {},
1662
+ waitingPaths: {},
1663
+ runId,
1664
+ requestContext: {}
1665
+ };
1666
+ }
1667
+ snapshot.context[stepId] = result;
1668
+ snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
1669
+ await this.persistWorkflowSnapshot({ workflowName, runId, snapshot });
1670
+ return snapshot.context;
1671
+ }
1672
+ async updateWorkflowState({
1673
+ workflowName,
1674
+ runId,
1675
+ opts
1676
+ }) {
1677
+ const snapshot = await this.loadWorkflowSnapshot({ workflowName, runId });
1678
+ if (!snapshot) {
1679
+ return void 0;
1680
+ }
1681
+ if (!snapshot.context) {
1682
+ throw new Error(`Snapshot not found for runId ${runId}`);
1683
+ }
1684
+ const updatedSnapshot = { ...snapshot, ...opts };
1685
+ await this.persistWorkflowSnapshot({ workflowName, runId, snapshot: updatedSnapshot });
1686
+ return updatedSnapshot;
1741
1687
  }
1742
1688
  async persistWorkflowSnapshot({
1743
1689
  workflowName,
1744
1690
  runId,
1745
- snapshot
1691
+ resourceId,
1692
+ snapshot,
1693
+ createdAt,
1694
+ updatedAt
1746
1695
  }) {
1747
1696
  try {
1748
1697
  const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1749
- const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
1698
+ const query = table.query().where(`workflow_name = '${escapeSql(workflowName)}' AND run_id = '${escapeSql(runId)}'`);
1750
1699
  const records = await query.toArray();
1751
- let createdAt;
1752
- const now = Date.now();
1700
+ let createdAtValue;
1701
+ const now = createdAt?.getTime() ?? Date.now();
1753
1702
  if (records.length > 0) {
1754
- createdAt = records[0].createdAt ?? now;
1703
+ createdAtValue = records[0].createdAt ?? now;
1755
1704
  } else {
1756
- createdAt = now;
1705
+ createdAtValue = now;
1757
1706
  }
1707
+ const { status, value, ...rest } = snapshot;
1758
1708
  const record = {
1759
1709
  workflow_name: workflowName,
1760
1710
  run_id: runId,
1761
- snapshot: JSON.stringify(snapshot),
1762
- createdAt,
1763
- updatedAt: now
1711
+ resourceId,
1712
+ snapshot: JSON.stringify({ status, value, ...rest }),
1713
+ // this is to ensure status is always just before value, for when querying the db by status
1714
+ createdAt: createdAtValue,
1715
+ updatedAt: updatedAt ?? now
1764
1716
  };
1765
1717
  await table.mergeInsert(["workflow_name", "run_id"]).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([record]);
1766
1718
  } catch (error) {
1767
1719
  throw new MastraError(
1768
1720
  {
1769
- id: "LANCE_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
1721
+ id: createStorageErrorId("LANCE", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
1770
1722
  domain: ErrorDomain.STORAGE,
1771
1723
  category: ErrorCategory.THIRD_PARTY,
1772
1724
  details: { workflowName, runId }
@@ -1781,13 +1733,13 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
1781
1733
  }) {
1782
1734
  try {
1783
1735
  const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1784
- const query = table.query().where(`workflow_name = '${workflowName}' AND run_id = '${runId}'`);
1736
+ const query = table.query().where(`workflow_name = '${escapeSql(workflowName)}' AND run_id = '${escapeSql(runId)}'`);
1785
1737
  const records = await query.toArray();
1786
1738
  return records.length > 0 ? JSON.parse(records[0].snapshot) : null;
1787
1739
  } catch (error) {
1788
1740
  throw new MastraError(
1789
1741
  {
1790
- id: "LANCE_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
1742
+ id: createStorageErrorId("LANCE", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
1791
1743
  domain: ErrorDomain.STORAGE,
1792
1744
  category: ErrorCategory.THIRD_PARTY,
1793
1745
  details: { workflowName, runId }
@@ -1799,9 +1751,9 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
1799
1751
  async getWorkflowRunById(args) {
1800
1752
  try {
1801
1753
  const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1802
- let whereClause = `run_id = '${args.runId}'`;
1754
+ let whereClause = `run_id = '${escapeSql(args.runId)}'`;
1803
1755
  if (args.workflowName) {
1804
- whereClause += ` AND workflow_name = '${args.workflowName}'`;
1756
+ whereClause += ` AND workflow_name = '${escapeSql(args.workflowName)}'`;
1805
1757
  }
1806
1758
  const query = table.query().where(whereClause);
1807
1759
  const records = await query.toArray();
@@ -1811,7 +1763,7 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
1811
1763
  } catch (error) {
1812
1764
  throw new MastraError(
1813
1765
  {
1814
- id: "LANCE_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
1766
+ id: createStorageErrorId("LANCE", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
1815
1767
  domain: ErrorDomain.STORAGE,
1816
1768
  category: ErrorCategory.THIRD_PARTY,
1817
1769
  details: { runId: args.runId, workflowName: args.workflowName ?? "" }
@@ -1820,16 +1772,37 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
1820
1772
  );
1821
1773
  }
1822
1774
  }
1823
- async getWorkflowRuns(args) {
1775
+ async deleteWorkflowRunById({ runId, workflowName }) {
1776
+ try {
1777
+ const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1778
+ const whereClause = `run_id = '${escapeSql(runId)}' AND workflow_name = '${escapeSql(workflowName)}'`;
1779
+ await table.delete(whereClause);
1780
+ } catch (error) {
1781
+ throw new MastraError(
1782
+ {
1783
+ id: createStorageErrorId("LANCE", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
1784
+ domain: ErrorDomain.STORAGE,
1785
+ category: ErrorCategory.THIRD_PARTY,
1786
+ details: { runId, workflowName }
1787
+ },
1788
+ error
1789
+ );
1790
+ }
1791
+ }
1792
+ async listWorkflowRuns(args) {
1824
1793
  try {
1825
1794
  const table = await this.client.openTable(TABLE_WORKFLOW_SNAPSHOT);
1826
1795
  let query = table.query();
1827
1796
  const conditions = [];
1828
1797
  if (args?.workflowName) {
1829
- conditions.push(`workflow_name = '${args.workflowName.replace(/'/g, "''")}'`);
1798
+ conditions.push(`workflow_name = '${escapeSql(args.workflowName)}'`);
1799
+ }
1800
+ if (args?.status) {
1801
+ const escapedStatus = args.status.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/%/g, "\\%").replace(/_/g, "\\_");
1802
+ conditions.push(`\`snapshot\` LIKE '%"status":"${escapedStatus}","value"%'`);
1830
1803
  }
1831
1804
  if (args?.resourceId) {
1832
- conditions.push(`\`resourceId\` = '${args.resourceId}'`);
1805
+ conditions.push(`\`resourceId\` = '${escapeSql(args.resourceId)}'`);
1833
1806
  }
1834
1807
  if (args?.fromDate instanceof Date) {
1835
1808
  conditions.push(`\`createdAt\` >= ${args.fromDate.getTime()}`);
@@ -1844,11 +1817,22 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
1844
1817
  } else {
1845
1818
  total = await table.countRows();
1846
1819
  }
1847
- if (args?.limit) {
1848
- query.limit(args.limit);
1849
- }
1850
- if (args?.offset) {
1851
- query.offset(args.offset);
1820
+ if (args?.perPage !== void 0 && args?.page !== void 0) {
1821
+ const normalizedPerPage = normalizePerPage(args.perPage, Number.MAX_SAFE_INTEGER);
1822
+ if (args.page < 0 || !Number.isInteger(args.page)) {
1823
+ throw new MastraError(
1824
+ {
1825
+ id: createStorageErrorId("LANCE", "LIST_WORKFLOW_RUNS", "INVALID_PAGINATION"),
1826
+ domain: ErrorDomain.STORAGE,
1827
+ category: ErrorCategory.USER,
1828
+ details: { page: args.page, perPage: args.perPage }
1829
+ },
1830
+ new Error(`Invalid pagination parameters: page=${args.page}, perPage=${args.perPage}`)
1831
+ );
1832
+ }
1833
+ const offset = args.page * normalizedPerPage;
1834
+ query.limit(normalizedPerPage);
1835
+ query.offset(offset);
1852
1836
  }
1853
1837
  const records = await query.toArray();
1854
1838
  return {
@@ -1858,10 +1842,10 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
1858
1842
  } catch (error) {
1859
1843
  throw new MastraError(
1860
1844
  {
1861
- id: "LANCE_STORE_GET_WORKFLOW_RUNS_FAILED",
1845
+ id: createStorageErrorId("LANCE", "LIST_WORKFLOW_RUNS", "FAILED"),
1862
1846
  domain: ErrorDomain.STORAGE,
1863
1847
  category: ErrorCategory.THIRD_PARTY,
1864
- details: { namespace: args?.namespace ?? "", workflowName: args?.workflowName ?? "" }
1848
+ details: { resourceId: args?.resourceId ?? "", workflowName: args?.workflowName ?? "" }
1865
1849
  },
1866
1850
  error
1867
1851
  );
@@ -1875,48 +1859,52 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
1875
1859
  lanceClient;
1876
1860
  /**
1877
1861
  * Creates a new instance of LanceStorage
1862
+ * @param id The unique identifier for this storage instance
1863
+ * @param name The name for this storage instance
1878
1864
  * @param uri The URI to connect to LanceDB
1879
- * @param options connection options
1865
+ * @param connectionOptions connection options for LanceDB
1866
+ * @param storageOptions storage options including disableInit
1880
1867
  *
1881
1868
  * Usage:
1882
1869
  *
1883
1870
  * Connect to a local database
1884
1871
  * ```ts
1885
- * const store = await LanceStorage.create('/path/to/db');
1872
+ * const store = await LanceStorage.create('my-storage-id', 'MyStorage', '/path/to/db');
1886
1873
  * ```
1887
1874
  *
1888
1875
  * Connect to a LanceDB cloud database
1889
1876
  * ```ts
1890
- * const store = await LanceStorage.create('db://host:port');
1877
+ * const store = await LanceStorage.create('my-storage-id', 'MyStorage', 'db://host:port');
1891
1878
  * ```
1892
1879
  *
1893
1880
  * Connect to a cloud database
1894
1881
  * ```ts
1895
- * const store = await LanceStorage.create('s3://bucket/db', { storageOptions: { timeout: '60s' } });
1882
+ * const store = await LanceStorage.create('my-storage-id', 'MyStorage', 's3://bucket/db', { storageOptions: { timeout: '60s' } });
1883
+ * ```
1884
+ *
1885
+ * Disable auto-init for runtime (after CI/CD has run migrations)
1886
+ * ```ts
1887
+ * const store = await LanceStorage.create('my-storage-id', 'MyStorage', '/path/to/db', undefined, { disableInit: true });
1896
1888
  * ```
1897
1889
  */
1898
- static async create(name, uri, options) {
1899
- const instance = new _LanceStorage(name);
1890
+ static async create(id, name, uri, connectionOptions, storageOptions) {
1891
+ const instance = new _LanceStorage(id, name, storageOptions?.disableInit);
1900
1892
  try {
1901
- instance.lanceClient = await connect(uri, options);
1902
- const operations = new StoreOperationsLance({ client: instance.lanceClient });
1893
+ instance.lanceClient = await connect(uri, connectionOptions);
1903
1894
  instance.stores = {
1904
- operations: new StoreOperationsLance({ client: instance.lanceClient }),
1905
1895
  workflows: new StoreWorkflowsLance({ client: instance.lanceClient }),
1906
- traces: new StoreTracesLance({ client: instance.lanceClient, operations }),
1907
1896
  scores: new StoreScoresLance({ client: instance.lanceClient }),
1908
- memory: new StoreMemoryLance({ client: instance.lanceClient, operations }),
1909
- legacyEvals: new StoreLegacyEvalsLance({ client: instance.lanceClient })
1897
+ memory: new StoreMemoryLance({ client: instance.lanceClient })
1910
1898
  };
1911
1899
  return instance;
1912
1900
  } catch (e) {
1913
1901
  throw new MastraError(
1914
1902
  {
1915
- id: "STORAGE_LANCE_STORAGE_CONNECT_FAILED",
1903
+ id: createStorageErrorId("LANCE", "CONNECT", "FAILED"),
1916
1904
  domain: ErrorDomain.STORAGE,
1917
1905
  category: ErrorCategory.THIRD_PARTY,
1918
1906
  text: `Failed to connect to LanceDB: ${e.message || e}`,
1919
- details: { uri, optionsProvided: !!options }
1907
+ details: { uri, optionsProvided: !!connectionOptions }
1920
1908
  },
1921
1909
  e
1922
1910
  );
@@ -1924,54 +1912,16 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
1924
1912
  }
1925
1913
  /**
1926
1914
  * @internal
1927
- * Private constructor to enforce using the create factory method
1915
+ * Private constructor to enforce using the create factory method.
1916
+ * Note: stores is initialized in create() after the lanceClient is connected.
1928
1917
  */
1929
- constructor(name) {
1930
- super({ name });
1931
- const operations = new StoreOperationsLance({ client: this.lanceClient });
1932
- this.stores = {
1933
- operations: new StoreOperationsLance({ client: this.lanceClient }),
1934
- workflows: new StoreWorkflowsLance({ client: this.lanceClient }),
1935
- traces: new StoreTracesLance({ client: this.lanceClient, operations }),
1936
- scores: new StoreScoresLance({ client: this.lanceClient }),
1937
- legacyEvals: new StoreLegacyEvalsLance({ client: this.lanceClient }),
1938
- memory: new StoreMemoryLance({ client: this.lanceClient, operations })
1939
- };
1940
- }
1941
- async createTable({
1942
- tableName,
1943
- schema
1944
- }) {
1945
- return this.stores.operations.createTable({ tableName, schema });
1946
- }
1947
- async dropTable({ tableName }) {
1948
- return this.stores.operations.dropTable({ tableName });
1949
- }
1950
- async alterTable({
1951
- tableName,
1952
- schema,
1953
- ifNotExists
1954
- }) {
1955
- return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
1956
- }
1957
- async clearTable({ tableName }) {
1958
- return this.stores.operations.clearTable({ tableName });
1959
- }
1960
- async insert({ tableName, record }) {
1961
- return this.stores.operations.insert({ tableName, record });
1962
- }
1963
- async batchInsert({ tableName, records }) {
1964
- return this.stores.operations.batchInsert({ tableName, records });
1965
- }
1966
- async load({ tableName, keys }) {
1967
- return this.stores.operations.load({ tableName, keys });
1918
+ constructor(id, name, disableInit) {
1919
+ super({ id, name, disableInit });
1920
+ this.stores = {};
1968
1921
  }
1969
1922
  async getThreadById({ threadId }) {
1970
1923
  return this.stores.memory.getThreadById({ threadId });
1971
1924
  }
1972
- async getThreadsByResourceId({ resourceId }) {
1973
- return this.stores.memory.getThreadsByResourceId({ resourceId });
1974
- }
1975
1925
  /**
1976
1926
  * Saves a thread to the database. This function doesn't overwrite existing threads.
1977
1927
  * @param thread - The thread to save
@@ -1990,13 +1940,17 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
1990
1940
  async deleteThread({ threadId }) {
1991
1941
  return this.stores.memory.deleteThread({ threadId });
1992
1942
  }
1943
+ async deleteMessages(messageIds) {
1944
+ return this.stores.memory.deleteMessages(messageIds);
1945
+ }
1993
1946
  get supports() {
1994
1947
  return {
1995
1948
  selectByIncludeResourceScope: true,
1996
1949
  resourceWorkingMemory: true,
1997
1950
  hasColumn: true,
1998
1951
  createTable: true,
1999
- deleteMessages: false
1952
+ deleteMessages: true,
1953
+ listScoresBySpan: true
2000
1954
  };
2001
1955
  }
2002
1956
  async getResourceById({ resourceId }) {
@@ -2060,54 +2014,47 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
2060
2014
  });
2061
2015
  return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
2062
2016
  }
2063
- async getMessages({
2064
- threadId,
2065
- resourceId,
2066
- selectBy,
2067
- format,
2068
- threadConfig
2069
- }) {
2070
- return this.stores.memory.getMessages({ threadId, resourceId, selectBy, format, threadConfig });
2017
+ async listMessagesById({ messageIds }) {
2018
+ return this.stores.memory.listMessagesById({ messageIds });
2071
2019
  }
2072
2020
  async saveMessages(args) {
2073
2021
  return this.stores.memory.saveMessages(args);
2074
2022
  }
2075
- async getThreadsByResourceIdPaginated(args) {
2076
- return this.stores.memory.getThreadsByResourceIdPaginated(args);
2077
- }
2078
- async getMessagesPaginated(args) {
2079
- return this.stores.memory.getMessagesPaginated(args);
2080
- }
2081
2023
  async updateMessages(_args) {
2082
2024
  return this.stores.memory.updateMessages(_args);
2083
2025
  }
2084
- async getTraceById(args) {
2085
- return this.stores.traces.getTraceById(args);
2026
+ async listWorkflowRuns(args) {
2027
+ return this.stores.workflows.listWorkflowRuns(args);
2086
2028
  }
2087
- async getTraces(args) {
2088
- return this.stores.traces.getTraces(args);
2089
- }
2090
- async getTracesPaginated(args) {
2091
- return this.stores.traces.getTracesPaginated(args);
2092
- }
2093
- async getEvalsByAgentName(agentName, type) {
2094
- return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
2029
+ async getWorkflowRunById(args) {
2030
+ return this.stores.workflows.getWorkflowRunById(args);
2095
2031
  }
2096
- async getEvals(options) {
2097
- return this.stores.legacyEvals.getEvals(options);
2032
+ async deleteWorkflowRunById({ runId, workflowName }) {
2033
+ return this.stores.workflows.deleteWorkflowRunById({ runId, workflowName });
2098
2034
  }
2099
- async getWorkflowRuns(args) {
2100
- return this.stores.workflows.getWorkflowRuns(args);
2035
+ async updateWorkflowResults({
2036
+ workflowName,
2037
+ runId,
2038
+ stepId,
2039
+ result,
2040
+ requestContext
2041
+ }) {
2042
+ return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
2101
2043
  }
2102
- async getWorkflowRunById(args) {
2103
- return this.stores.workflows.getWorkflowRunById(args);
2044
+ async updateWorkflowState({
2045
+ workflowName,
2046
+ runId,
2047
+ opts
2048
+ }) {
2049
+ return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
2104
2050
  }
2105
2051
  async persistWorkflowSnapshot({
2106
2052
  workflowName,
2107
2053
  runId,
2054
+ resourceId,
2108
2055
  snapshot
2109
2056
  }) {
2110
- return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
2057
+ return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
2111
2058
  }
2112
2059
  async loadWorkflowSnapshot({
2113
2060
  workflowName,
@@ -2118,27 +2065,37 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
2118
2065
  async getScoreById({ id: _id }) {
2119
2066
  return this.stores.scores.getScoreById({ id: _id });
2120
2067
  }
2121
- async getScoresByScorerId({
2068
+ async listScoresByScorerId({
2122
2069
  scorerId,
2070
+ source,
2071
+ entityId,
2072
+ entityType,
2123
2073
  pagination
2124
2074
  }) {
2125
- return this.stores.scores.getScoresByScorerId({ scorerId, pagination });
2075
+ return this.stores.scores.listScoresByScorerId({ scorerId, source, pagination, entityId, entityType });
2126
2076
  }
2127
- async saveScore(_score) {
2128
- return this.stores.scores.saveScore(_score);
2077
+ async saveScore(score) {
2078
+ return this.stores.scores.saveScore(score);
2129
2079
  }
2130
- async getScoresByRunId({
2080
+ async listScoresByRunId({
2131
2081
  runId,
2132
2082
  pagination
2133
2083
  }) {
2134
- return this.stores.scores.getScoresByRunId({ runId, pagination });
2084
+ return this.stores.scores.listScoresByRunId({ runId, pagination });
2135
2085
  }
2136
- async getScoresByEntityId({
2086
+ async listScoresByEntityId({
2137
2087
  entityId,
2138
2088
  entityType,
2139
2089
  pagination
2140
2090
  }) {
2141
- return this.stores.scores.getScoresByEntityId({ entityId, entityType, pagination });
2091
+ return this.stores.scores.listScoresByEntityId({ entityId, entityType, pagination });
2092
+ }
2093
+ async listScoresBySpan({
2094
+ traceId,
2095
+ spanId,
2096
+ pagination
2097
+ }) {
2098
+ return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
2142
2099
  }
2143
2100
  };
2144
2101
  var LanceFilterTranslator = class extends BaseFilterTranslator {
@@ -2487,14 +2444,14 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2487
2444
  * ```
2488
2445
  */
2489
2446
  static async create(uri, options) {
2490
- const instance = new _LanceVectorStore();
2447
+ const instance = new _LanceVectorStore(options?.id || crypto.randomUUID());
2491
2448
  try {
2492
2449
  instance.lanceClient = await connect(uri, options);
2493
2450
  return instance;
2494
2451
  } catch (e) {
2495
2452
  throw new MastraError(
2496
2453
  {
2497
- id: "STORAGE_LANCE_VECTOR_CONNECT_FAILED",
2454
+ id: createVectorErrorId("LANCE", "CONNECT", "FAILED"),
2498
2455
  domain: ErrorDomain.STORAGE,
2499
2456
  category: ErrorCategory.THIRD_PARTY,
2500
2457
  details: { uri }
@@ -2507,8 +2464,8 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2507
2464
  * @internal
2508
2465
  * Private constructor to enforce using the create factory method
2509
2466
  */
2510
- constructor() {
2511
- super();
2467
+ constructor(id) {
2468
+ super({ id });
2512
2469
  }
2513
2470
  close() {
2514
2471
  if (this.lanceClient) {
@@ -2537,7 +2494,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2537
2494
  } catch (error) {
2538
2495
  throw new MastraError(
2539
2496
  {
2540
- id: "STORAGE_LANCE_VECTOR_QUERY_FAILED_INVALID_ARGS",
2497
+ id: createVectorErrorId("LANCE", "QUERY", "INVALID_ARGS"),
2541
2498
  domain: ErrorDomain.STORAGE,
2542
2499
  category: ErrorCategory.USER,
2543
2500
  text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
@@ -2585,7 +2542,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2585
2542
  } catch (error) {
2586
2543
  throw new MastraError(
2587
2544
  {
2588
- id: "STORAGE_LANCE_VECTOR_QUERY_FAILED",
2545
+ id: createVectorErrorId("LANCE", "QUERY", "FAILED"),
2589
2546
  domain: ErrorDomain.STORAGE,
2590
2547
  category: ErrorCategory.THIRD_PARTY,
2591
2548
  details: { tableName, includeVector, columnsCount: columns?.length, includeAllColumns }
@@ -2637,7 +2594,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2637
2594
  } catch (error) {
2638
2595
  throw new MastraError(
2639
2596
  {
2640
- id: "STORAGE_LANCE_VECTOR_UPSERT_FAILED_INVALID_ARGS",
2597
+ id: createVectorErrorId("LANCE", "UPSERT", "INVALID_ARGS"),
2641
2598
  domain: ErrorDomain.STORAGE,
2642
2599
  category: ErrorCategory.USER,
2643
2600
  text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
@@ -2673,7 +2630,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2673
2630
  } catch (error) {
2674
2631
  throw new MastraError(
2675
2632
  {
2676
- id: "STORAGE_LANCE_VECTOR_UPSERT_FAILED",
2633
+ id: createVectorErrorId("LANCE", "UPSERT", "FAILED"),
2677
2634
  domain: ErrorDomain.STORAGE,
2678
2635
  category: ErrorCategory.THIRD_PARTY,
2679
2636
  details: { tableName, vectorCount: vectors.length, metadataCount: metadata.length, idsCount: ids.length }
@@ -2700,7 +2657,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2700
2657
  async createTable(tableName, data, options) {
2701
2658
  if (!this.lanceClient) {
2702
2659
  throw new MastraError({
2703
- id: "STORAGE_LANCE_VECTOR_CREATE_TABLE_FAILED_INVALID_ARGS",
2660
+ id: createVectorErrorId("LANCE", "CREATE_TABLE", "INVALID_ARGS"),
2704
2661
  domain: ErrorDomain.STORAGE,
2705
2662
  category: ErrorCategory.USER,
2706
2663
  text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
@@ -2715,7 +2672,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2715
2672
  } catch (error) {
2716
2673
  throw new MastraError(
2717
2674
  {
2718
- id: "STORAGE_LANCE_VECTOR_CREATE_TABLE_FAILED",
2675
+ id: createVectorErrorId("LANCE", "CREATE_TABLE", "FAILED"),
2719
2676
  domain: ErrorDomain.STORAGE,
2720
2677
  category: ErrorCategory.THIRD_PARTY,
2721
2678
  details: { tableName }
@@ -2727,7 +2684,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2727
2684
  async listTables() {
2728
2685
  if (!this.lanceClient) {
2729
2686
  throw new MastraError({
2730
- id: "STORAGE_LANCE_VECTOR_LIST_TABLES_FAILED_INVALID_ARGS",
2687
+ id: createVectorErrorId("LANCE", "LIST_TABLES", "INVALID_ARGS"),
2731
2688
  domain: ErrorDomain.STORAGE,
2732
2689
  category: ErrorCategory.USER,
2733
2690
  text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
@@ -2739,7 +2696,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2739
2696
  } catch (error) {
2740
2697
  throw new MastraError(
2741
2698
  {
2742
- id: "STORAGE_LANCE_VECTOR_LIST_TABLES_FAILED",
2699
+ id: createVectorErrorId("LANCE", "LIST_TABLES", "FAILED"),
2743
2700
  domain: ErrorDomain.STORAGE,
2744
2701
  category: ErrorCategory.THIRD_PARTY
2745
2702
  },
@@ -2750,7 +2707,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2750
2707
  async getTableSchema(tableName) {
2751
2708
  if (!this.lanceClient) {
2752
2709
  throw new MastraError({
2753
- id: "STORAGE_LANCE_VECTOR_GET_TABLE_SCHEMA_FAILED_INVALID_ARGS",
2710
+ id: createVectorErrorId("LANCE", "GET_TABLE_SCHEMA", "INVALID_ARGS"),
2754
2711
  domain: ErrorDomain.STORAGE,
2755
2712
  category: ErrorCategory.USER,
2756
2713
  text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
@@ -2763,7 +2720,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2763
2720
  } catch (error) {
2764
2721
  throw new MastraError(
2765
2722
  {
2766
- id: "STORAGE_LANCE_VECTOR_GET_TABLE_SCHEMA_FAILED",
2723
+ id: createVectorErrorId("LANCE", "GET_TABLE_SCHEMA", "FAILED"),
2767
2724
  domain: ErrorDomain.STORAGE,
2768
2725
  category: ErrorCategory.THIRD_PARTY,
2769
2726
  details: { tableName }
@@ -2798,7 +2755,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2798
2755
  } catch (err) {
2799
2756
  throw new MastraError(
2800
2757
  {
2801
- id: "STORAGE_LANCE_VECTOR_CREATE_INDEX_FAILED_INVALID_ARGS",
2758
+ id: createVectorErrorId("LANCE", "CREATE_INDEX", "INVALID_ARGS"),
2802
2759
  domain: ErrorDomain.STORAGE,
2803
2760
  category: ErrorCategory.USER,
2804
2761
  details: { tableName: tableName || "", indexName, dimension, metric }
@@ -2843,7 +2800,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2843
2800
  } catch (error) {
2844
2801
  throw new MastraError(
2845
2802
  {
2846
- id: "STORAGE_LANCE_VECTOR_CREATE_INDEX_FAILED",
2803
+ id: createVectorErrorId("LANCE", "CREATE_INDEX", "FAILED"),
2847
2804
  domain: ErrorDomain.STORAGE,
2848
2805
  category: ErrorCategory.THIRD_PARTY,
2849
2806
  details: { tableName: tableName || "", indexName, dimension }
@@ -2855,7 +2812,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2855
2812
  async listIndexes() {
2856
2813
  if (!this.lanceClient) {
2857
2814
  throw new MastraError({
2858
- id: "STORAGE_LANCE_VECTOR_LIST_INDEXES_FAILED_INVALID_ARGS",
2815
+ id: createVectorErrorId("LANCE", "LIST_INDEXES", "INVALID_ARGS"),
2859
2816
  domain: ErrorDomain.STORAGE,
2860
2817
  category: ErrorCategory.USER,
2861
2818
  text: "LanceDB client not initialized. Use LanceVectorStore.create() to create an instance",
@@ -2874,7 +2831,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2874
2831
  } catch (error) {
2875
2832
  throw new MastraError(
2876
2833
  {
2877
- id: "STORAGE_LANCE_VECTOR_LIST_INDEXES_FAILED",
2834
+ id: createVectorErrorId("LANCE", "LIST_INDEXES", "FAILED"),
2878
2835
  domain: ErrorDomain.STORAGE,
2879
2836
  category: ErrorCategory.THIRD_PARTY
2880
2837
  },
@@ -2893,7 +2850,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2893
2850
  } catch (err) {
2894
2851
  throw new MastraError(
2895
2852
  {
2896
- id: "STORAGE_LANCE_VECTOR_DESCRIBE_INDEX_FAILED_INVALID_ARGS",
2853
+ id: createVectorErrorId("LANCE", "DESCRIBE_INDEX", "INVALID_ARGS"),
2897
2854
  domain: ErrorDomain.STORAGE,
2898
2855
  category: ErrorCategory.USER,
2899
2856
  details: { indexName }
@@ -2928,7 +2885,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2928
2885
  } catch (error) {
2929
2886
  throw new MastraError(
2930
2887
  {
2931
- id: "STORAGE_LANCE_VECTOR_DESCRIBE_INDEX_FAILED",
2888
+ id: createVectorErrorId("LANCE", "DESCRIBE_INDEX", "FAILED"),
2932
2889
  domain: ErrorDomain.STORAGE,
2933
2890
  category: ErrorCategory.THIRD_PARTY,
2934
2891
  details: { indexName }
@@ -2948,7 +2905,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2948
2905
  } catch (err) {
2949
2906
  throw new MastraError(
2950
2907
  {
2951
- id: "STORAGE_LANCE_VECTOR_DELETE_INDEX_FAILED_INVALID_ARGS",
2908
+ id: createVectorErrorId("LANCE", "DELETE_INDEX", "INVALID_ARGS"),
2952
2909
  domain: ErrorDomain.STORAGE,
2953
2910
  category: ErrorCategory.USER,
2954
2911
  details: { indexName }
@@ -2971,7 +2928,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2971
2928
  } catch (error) {
2972
2929
  throw new MastraError(
2973
2930
  {
2974
- id: "STORAGE_LANCE_VECTOR_DELETE_INDEX_FAILED",
2931
+ id: createVectorErrorId("LANCE", "DELETE_INDEX", "FAILED"),
2975
2932
  domain: ErrorDomain.STORAGE,
2976
2933
  category: ErrorCategory.THIRD_PARTY,
2977
2934
  details: { indexName }
@@ -2986,7 +2943,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2986
2943
  async deleteAllTables() {
2987
2944
  if (!this.lanceClient) {
2988
2945
  throw new MastraError({
2989
- id: "STORAGE_LANCE_VECTOR_DELETE_ALL_TABLES_FAILED_INVALID_ARGS",
2946
+ id: createVectorErrorId("LANCE", "DELETE_ALL_TABLES", "INVALID_ARGS"),
2990
2947
  domain: ErrorDomain.STORAGE,
2991
2948
  category: ErrorCategory.USER,
2992
2949
  details: { methodName: "deleteAllTables" },
@@ -2998,7 +2955,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
2998
2955
  } catch (error) {
2999
2956
  throw new MastraError(
3000
2957
  {
3001
- id: "STORAGE_LANCE_VECTOR_DELETE_ALL_TABLES_FAILED",
2958
+ id: createVectorErrorId("LANCE", "DELETE_ALL_TABLES", "FAILED"),
3002
2959
  domain: ErrorDomain.STORAGE,
3003
2960
  category: ErrorCategory.THIRD_PARTY,
3004
2961
  details: { methodName: "deleteAllTables" }
@@ -3010,7 +2967,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3010
2967
  async deleteTable(tableName) {
3011
2968
  if (!this.lanceClient) {
3012
2969
  throw new MastraError({
3013
- id: "STORAGE_LANCE_VECTOR_DELETE_TABLE_FAILED_INVALID_ARGS",
2970
+ id: createVectorErrorId("LANCE", "DELETE_TABLE", "INVALID_ARGS"),
3014
2971
  domain: ErrorDomain.STORAGE,
3015
2972
  category: ErrorCategory.USER,
3016
2973
  details: { tableName },
@@ -3022,7 +2979,7 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3022
2979
  } catch (error) {
3023
2980
  throw new MastraError(
3024
2981
  {
3025
- id: "STORAGE_LANCE_VECTOR_DELETE_TABLE_FAILED",
2982
+ id: createVectorErrorId("LANCE", "DELETE_TABLE", "FAILED"),
3026
2983
  domain: ErrorDomain.STORAGE,
3027
2984
  category: ErrorCategory.THIRD_PARTY,
3028
2985
  details: { tableName }
@@ -3031,7 +2988,44 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3031
2988
  );
3032
2989
  }
3033
2990
  }
3034
- async updateVector({ indexName, id, update }) {
2991
+ async updateVector(params) {
2992
+ const { indexName, update } = params;
2993
+ if ("id" in params && "filter" in params && params.id && params.filter) {
2994
+ throw new MastraError({
2995
+ id: createVectorErrorId("LANCE", "UPDATE_VECTOR", "MUTUALLY_EXCLUSIVE"),
2996
+ domain: ErrorDomain.STORAGE,
2997
+ category: ErrorCategory.USER,
2998
+ text: "id and filter are mutually exclusive",
2999
+ details: { indexName }
3000
+ });
3001
+ }
3002
+ if (!("id" in params || "filter" in params) || !params.id && !params.filter) {
3003
+ throw new MastraError({
3004
+ id: createVectorErrorId("LANCE", "UPDATE_VECTOR", "NO_TARGET"),
3005
+ domain: ErrorDomain.STORAGE,
3006
+ category: ErrorCategory.USER,
3007
+ text: "Either id or filter must be provided",
3008
+ details: { indexName }
3009
+ });
3010
+ }
3011
+ if ("filter" in params && params.filter && Object.keys(params.filter).length === 0) {
3012
+ throw new MastraError({
3013
+ id: createVectorErrorId("LANCE", "UPDATE_VECTOR", "EMPTY_FILTER"),
3014
+ domain: ErrorDomain.STORAGE,
3015
+ category: ErrorCategory.USER,
3016
+ text: "Cannot update with empty filter",
3017
+ details: { indexName }
3018
+ });
3019
+ }
3020
+ if (!update.vector && !update.metadata) {
3021
+ throw new MastraError({
3022
+ id: createVectorErrorId("LANCE", "UPDATE_VECTOR", "NO_PAYLOAD"),
3023
+ domain: ErrorDomain.STORAGE,
3024
+ category: ErrorCategory.USER,
3025
+ text: "No updates provided",
3026
+ details: { indexName }
3027
+ });
3028
+ }
3035
3029
  try {
3036
3030
  if (!this.lanceClient) {
3037
3031
  throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
@@ -3039,21 +3033,6 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3039
3033
  if (!indexName) {
3040
3034
  throw new Error("indexName is required");
3041
3035
  }
3042
- if (!id) {
3043
- throw new Error("id is required");
3044
- }
3045
- } catch (err) {
3046
- throw new MastraError(
3047
- {
3048
- id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED_INVALID_ARGS",
3049
- domain: ErrorDomain.STORAGE,
3050
- category: ErrorCategory.USER,
3051
- details: { indexName, id }
3052
- },
3053
- err
3054
- );
3055
- }
3056
- try {
3057
3036
  const tables = await this.lanceClient.tableNames();
3058
3037
  for (const tableName of tables) {
3059
3038
  this.logger.debug("Checking table:" + tableName);
@@ -3063,39 +3042,66 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3063
3042
  const hasColumn = schema.fields.some((field) => field.name === indexName);
3064
3043
  if (hasColumn) {
3065
3044
  this.logger.debug(`Found column ${indexName} in table ${tableName}`);
3066
- const existingRecord = await table.query().where(`id = '${id}'`).select(schema.fields.map((field) => field.name)).limit(1).toArray();
3067
- if (existingRecord.length === 0) {
3068
- throw new Error(`Record with id '${id}' not found in table ${tableName}`);
3045
+ let whereClause;
3046
+ if ("id" in params && params.id) {
3047
+ whereClause = `id = '${params.id}'`;
3048
+ } else if ("filter" in params && params.filter) {
3049
+ const translator = new LanceFilterTranslator();
3050
+ const processFilterKeys = (filter) => {
3051
+ const processedFilter = {};
3052
+ Object.entries(filter).forEach(([key, value]) => {
3053
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3054
+ Object.entries(value).forEach(([nestedKey, nestedValue]) => {
3055
+ processedFilter[`metadata_${key}_${nestedKey}`] = nestedValue;
3056
+ });
3057
+ } else {
3058
+ processedFilter[`metadata_${key}`] = value;
3059
+ }
3060
+ });
3061
+ return processedFilter;
3062
+ };
3063
+ const prefixedFilter = processFilterKeys(params.filter);
3064
+ whereClause = translator.translate(prefixedFilter) || "";
3065
+ if (!whereClause) {
3066
+ throw new Error("Failed to translate filter to SQL");
3067
+ }
3068
+ } else {
3069
+ throw new Error("Either id or filter must be provided");
3069
3070
  }
3070
- const rowData = {
3071
- id
3072
- };
3073
- Object.entries(existingRecord[0]).forEach(([key, value]) => {
3074
- if (key !== "id" && key !== "_distance") {
3075
- if (key === indexName) {
3076
- if (!update.vector) {
3077
- if (Array.isArray(value)) {
3078
- rowData[key] = [...value];
3079
- } else if (typeof value === "object" && value !== null) {
3080
- rowData[key] = Array.from(value);
3071
+ const existingRecords = await table.query().where(whereClause).select(schema.fields.map((field) => field.name)).toArray();
3072
+ if (existingRecords.length === 0) {
3073
+ this.logger.info(`No records found matching criteria in table ${tableName}`);
3074
+ return;
3075
+ }
3076
+ const updatedRecords = existingRecords.map((record) => {
3077
+ const rowData = {};
3078
+ Object.entries(record).forEach(([key, value]) => {
3079
+ if (key !== "_distance") {
3080
+ if (key === indexName) {
3081
+ if (update.vector) {
3082
+ rowData[key] = update.vector;
3081
3083
  } else {
3082
- rowData[key] = value;
3084
+ if (Array.isArray(value)) {
3085
+ rowData[key] = [...value];
3086
+ } else if (typeof value === "object" && value !== null) {
3087
+ rowData[key] = Array.from(value);
3088
+ } else {
3089
+ rowData[key] = value;
3090
+ }
3083
3091
  }
3092
+ } else {
3093
+ rowData[key] = value;
3084
3094
  }
3085
- } else {
3086
- rowData[key] = value;
3087
3095
  }
3096
+ });
3097
+ if (update.metadata) {
3098
+ Object.entries(update.metadata).forEach(([key, value]) => {
3099
+ rowData[`metadata_${key}`] = value;
3100
+ });
3088
3101
  }
3102
+ return rowData;
3089
3103
  });
3090
- if (update.vector) {
3091
- rowData[indexName] = update.vector;
3092
- }
3093
- if (update.metadata) {
3094
- Object.entries(update.metadata).forEach(([key, value]) => {
3095
- rowData[`metadata_${key}`] = value;
3096
- });
3097
- }
3098
- await table.add([rowData], { mode: "overwrite" });
3104
+ await table.add(updatedRecords, { mode: "overwrite" });
3099
3105
  return;
3100
3106
  }
3101
3107
  } catch (err) {
@@ -3105,12 +3111,19 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3105
3111
  }
3106
3112
  throw new Error(`No table found with column/index '${indexName}'`);
3107
3113
  } catch (error) {
3114
+ if (error instanceof MastraError) throw error;
3108
3115
  throw new MastraError(
3109
3116
  {
3110
- id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED",
3117
+ id: createVectorErrorId("LANCE", "UPDATE_VECTOR", "FAILED"),
3111
3118
  domain: ErrorDomain.STORAGE,
3112
3119
  category: ErrorCategory.THIRD_PARTY,
3113
- details: { indexName, id, hasVector: !!update.vector, hasMetadata: !!update.metadata }
3120
+ details: {
3121
+ indexName,
3122
+ ..."id" in params && params.id && { id: params.id },
3123
+ ..."filter" in params && params.filter && { filter: JSON.stringify(params.filter) },
3124
+ hasVector: !!update.vector,
3125
+ hasMetadata: !!update.metadata
3126
+ }
3114
3127
  },
3115
3128
  error
3116
3129
  );
@@ -3130,10 +3143,13 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3130
3143
  } catch (err) {
3131
3144
  throw new MastraError(
3132
3145
  {
3133
- id: "STORAGE_LANCE_VECTOR_DELETE_VECTOR_FAILED_INVALID_ARGS",
3146
+ id: createVectorErrorId("LANCE", "DELETE_VECTOR", "INVALID_ARGS"),
3134
3147
  domain: ErrorDomain.STORAGE,
3135
3148
  category: ErrorCategory.USER,
3136
- details: { indexName, id }
3149
+ details: {
3150
+ indexName,
3151
+ ...id && { id }
3152
+ }
3137
3153
  },
3138
3154
  err
3139
3155
  );
@@ -3160,10 +3176,13 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3160
3176
  } catch (error) {
3161
3177
  throw new MastraError(
3162
3178
  {
3163
- id: "STORAGE_LANCE_VECTOR_DELETE_VECTOR_FAILED",
3179
+ id: createVectorErrorId("LANCE", "DELETE_VECTOR", "FAILED"),
3164
3180
  domain: ErrorDomain.STORAGE,
3165
3181
  category: ErrorCategory.THIRD_PARTY,
3166
- details: { indexName, id }
3182
+ details: {
3183
+ indexName,
3184
+ ...id && { id }
3185
+ }
3167
3186
  },
3168
3187
  error
3169
3188
  );
@@ -3194,6 +3213,109 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3194
3213
  });
3195
3214
  return result;
3196
3215
  }
3216
+ async deleteVectors({ indexName, filter, ids }) {
3217
+ if (ids && filter) {
3218
+ throw new MastraError({
3219
+ id: createVectorErrorId("LANCE", "DELETE_VECTORS", "MUTUALLY_EXCLUSIVE"),
3220
+ domain: ErrorDomain.STORAGE,
3221
+ category: ErrorCategory.USER,
3222
+ text: "ids and filter are mutually exclusive",
3223
+ details: { indexName }
3224
+ });
3225
+ }
3226
+ if (!ids && !filter) {
3227
+ throw new MastraError({
3228
+ id: createVectorErrorId("LANCE", "DELETE_VECTORS", "NO_TARGET"),
3229
+ domain: ErrorDomain.STORAGE,
3230
+ category: ErrorCategory.USER,
3231
+ text: "Either filter or ids must be provided",
3232
+ details: { indexName }
3233
+ });
3234
+ }
3235
+ if (ids && ids.length === 0) {
3236
+ throw new MastraError({
3237
+ id: createVectorErrorId("LANCE", "DELETE_VECTORS", "EMPTY_IDS"),
3238
+ domain: ErrorDomain.STORAGE,
3239
+ category: ErrorCategory.USER,
3240
+ text: "Cannot delete with empty ids array",
3241
+ details: { indexName }
3242
+ });
3243
+ }
3244
+ if (filter && Object.keys(filter).length === 0) {
3245
+ throw new MastraError({
3246
+ id: createVectorErrorId("LANCE", "DELETE_VECTORS", "EMPTY_FILTER"),
3247
+ domain: ErrorDomain.STORAGE,
3248
+ category: ErrorCategory.USER,
3249
+ text: "Cannot delete with empty filter",
3250
+ details: { indexName }
3251
+ });
3252
+ }
3253
+ try {
3254
+ if (!this.lanceClient) {
3255
+ throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
3256
+ }
3257
+ if (!indexName) {
3258
+ throw new Error("indexName is required");
3259
+ }
3260
+ const tables = await this.lanceClient.tableNames();
3261
+ for (const tableName of tables) {
3262
+ this.logger.debug("Checking table:" + tableName);
3263
+ const table = await this.lanceClient.openTable(tableName);
3264
+ try {
3265
+ const schema = await table.schema();
3266
+ const hasColumn = schema.fields.some((field) => field.name === indexName);
3267
+ if (hasColumn) {
3268
+ this.logger.debug(`Found column ${indexName} in table ${tableName}`);
3269
+ if (ids) {
3270
+ const idsConditions = ids.map((id) => `id = '${id}'`).join(" OR ");
3271
+ await table.delete(idsConditions);
3272
+ } else if (filter) {
3273
+ const translator = new LanceFilterTranslator();
3274
+ const processFilterKeys = (filter2) => {
3275
+ const processedFilter = {};
3276
+ Object.entries(filter2).forEach(([key, value]) => {
3277
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3278
+ Object.entries(value).forEach(([nestedKey, nestedValue]) => {
3279
+ processedFilter[`metadata_${key}_${nestedKey}`] = nestedValue;
3280
+ });
3281
+ } else {
3282
+ processedFilter[`metadata_${key}`] = value;
3283
+ }
3284
+ });
3285
+ return processedFilter;
3286
+ };
3287
+ const prefixedFilter = processFilterKeys(filter);
3288
+ const whereClause = translator.translate(prefixedFilter);
3289
+ if (!whereClause) {
3290
+ throw new Error("Failed to translate filter to SQL");
3291
+ }
3292
+ await table.delete(whereClause);
3293
+ }
3294
+ return;
3295
+ }
3296
+ } catch (err) {
3297
+ this.logger.error(`Error checking schema for table ${tableName}:` + err);
3298
+ continue;
3299
+ }
3300
+ }
3301
+ throw new Error(`No table found with column/index '${indexName}'`);
3302
+ } catch (error) {
3303
+ if (error instanceof MastraError) throw error;
3304
+ throw new MastraError(
3305
+ {
3306
+ id: createVectorErrorId("LANCE", "DELETE_VECTORS", "FAILED"),
3307
+ domain: ErrorDomain.STORAGE,
3308
+ category: ErrorCategory.THIRD_PARTY,
3309
+ details: {
3310
+ indexName,
3311
+ ...filter && { filter: JSON.stringify(filter) },
3312
+ ...ids && { idsCount: ids.length }
3313
+ }
3314
+ },
3315
+ error
3316
+ );
3317
+ }
3318
+ }
3197
3319
  };
3198
3320
 
3199
3321
  export { LanceStorage, LanceVectorStore };