@mastra/lance 0.0.0-remove-unused-model-providers-api-20251030210744 → 0.0.0-remove-ai-peer-dep-from-evals-20260105220639

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