@mastra/lance 0.0.0-new-scorer-api-20250801075530 → 0.0.0-partial-response-backport-20251204204441

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +505 -3
  2. package/README.md +3 -3
  3. package/dist/index.cjs +418 -84
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.js +418 -84
  7. package/dist/index.js.map +1 -1
  8. package/dist/storage/domains/memory/index.d.ts +10 -1
  9. package/dist/storage/domains/memory/index.d.ts.map +1 -1
  10. package/dist/storage/domains/operations/index.d.ts.map +1 -1
  11. package/dist/storage/domains/scores/index.d.ts +13 -2
  12. package/dist/storage/domains/scores/index.d.ts.map +1 -1
  13. package/dist/storage/domains/traces/index.d.ts +1 -1
  14. package/dist/storage/domains/utils.d.ts.map +1 -1
  15. package/dist/storage/domains/workflows/index.d.ts +23 -11
  16. package/dist/storage/domains/workflows/index.d.ts.map +1 -1
  17. package/dist/storage/index.d.ts +45 -13
  18. package/dist/storage/index.d.ts.map +1 -1
  19. package/dist/vector/filter.d.ts +5 -5
  20. package/dist/vector/index.d.ts +5 -4
  21. package/dist/vector/index.d.ts.map +1 -1
  22. package/package.json +29 -8
  23. package/eslint.config.js +0 -6
  24. package/src/index.ts +0 -2
  25. package/src/storage/domains/legacy-evals/index.ts +0 -156
  26. package/src/storage/domains/memory/index.ts +0 -947
  27. package/src/storage/domains/operations/index.ts +0 -489
  28. package/src/storage/domains/scores/index.ts +0 -221
  29. package/src/storage/domains/traces/index.ts +0 -212
  30. package/src/storage/domains/utils.ts +0 -158
  31. package/src/storage/domains/workflows/index.ts +0 -207
  32. package/src/storage/index.test.ts +0 -10
  33. package/src/storage/index.ts +0 -442
  34. package/src/vector/filter.test.ts +0 -295
  35. package/src/vector/filter.ts +0 -443
  36. package/src/vector/index.test.ts +0 -1493
  37. package/src/vector/index.ts +0 -941
  38. package/src/vector/types.ts +0 -16
  39. package/tsconfig.build.json +0 -9
  40. package/tsconfig.json +0 -5
  41. package/tsup.config.ts +0 -22
  42. package/vitest.config.ts +0 -11
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
3
3
  import { MastraStorage, StoreOperations, LegacyEvalsStorage, TABLE_EVALS, MemoryStorage, TABLE_THREADS, TABLE_MESSAGES, resolveMessageLimit, TABLE_RESOURCES, ScoresStorage, TABLE_SCORERS, TracesStorage, TABLE_TRACES, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT, ensureDate } from '@mastra/core/storage';
4
4
  import { MessageList } from '@mastra/core/agent';
5
5
  import { Utf8, Float64, Binary, Float32, Int32, Field, Schema } from 'apache-arrow';
6
+ import { saveScorePayloadSchema } from '@mastra/core/scores';
6
7
  import { MastraVector } from '@mastra/core/vector';
7
8
  import { BaseFilterTranslator } from '@mastra/core/vector/filter';
8
9
 
@@ -59,9 +60,9 @@ var StoreLegacyEvalsLance = class extends LegacyEvalsStorage {
59
60
  conditions.push(`agent_name = '${options.agentName}'`);
60
61
  }
61
62
  if (options.type === "live") {
62
- conditions.push("length(test_info) = 0");
63
+ conditions.push("test_info IS NULL");
63
64
  } else if (options.type === "test") {
64
- conditions.push("length(test_info) > 0");
65
+ conditions.push("test_info IS NOT NULL");
65
66
  }
66
67
  const startDate = options.dateRange?.start || options.fromDate;
67
68
  const endDate = options.dateRange?.end || options.toDate;
@@ -187,7 +188,6 @@ function processResultWithTypeConversion(rawResult, tableSchema) {
187
188
  } else if (fieldTypeStr.includes("float64") && ["createdAt", "updatedAt"].includes(key)) {
188
189
  processedResult[key] = new Date(processedResult[key]);
189
190
  }
190
- console.log(key, "processedResult", processedResult);
191
191
  }
192
192
  return processedResult;
193
193
  }
@@ -379,6 +379,20 @@ var StoreMemoryLance = class extends MemoryStorage {
379
379
  );
380
380
  }
381
381
  }
382
+ normalizeMessage(message) {
383
+ const { thread_id, ...rest } = message;
384
+ return {
385
+ ...rest,
386
+ threadId: thread_id,
387
+ content: typeof message.content === "string" ? (() => {
388
+ try {
389
+ return JSON.parse(message.content);
390
+ } catch {
391
+ return message.content;
392
+ }
393
+ })() : message.content
394
+ };
395
+ }
382
396
  async getMessages({
383
397
  threadId,
384
398
  resourceId,
@@ -387,6 +401,7 @@ var StoreMemoryLance = class extends MemoryStorage {
387
401
  threadConfig
388
402
  }) {
389
403
  try {
404
+ if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
390
405
  if (threadConfig) {
391
406
  throw new Error("ThreadConfig is not supported by LanceDB storage");
392
407
  }
@@ -419,21 +434,7 @@ var StoreMemoryLance = class extends MemoryStorage {
419
434
  allRecords,
420
435
  await getTableSchema({ tableName: TABLE_MESSAGES, client: this.client })
421
436
  );
422
- const normalized = messages.map((msg) => {
423
- const { thread_id, ...rest } = msg;
424
- return {
425
- ...rest,
426
- threadId: thread_id,
427
- content: typeof msg.content === "string" ? (() => {
428
- try {
429
- return JSON.parse(msg.content);
430
- } catch {
431
- return msg.content;
432
- }
433
- })() : msg.content
434
- };
435
- });
436
- const list = new MessageList({ threadId, resourceId }).add(normalized, "memory");
437
+ const list = new MessageList({ threadId, resourceId }).add(messages.map(this.normalizeMessage), "memory");
437
438
  if (format === "v2") return list.get.all.v2();
438
439
  return list.get.all.v1();
439
440
  } catch (error) {
@@ -441,7 +442,41 @@ var StoreMemoryLance = class extends MemoryStorage {
441
442
  {
442
443
  id: "LANCE_STORE_GET_MESSAGES_FAILED",
443
444
  domain: ErrorDomain.STORAGE,
444
- category: ErrorCategory.THIRD_PARTY
445
+ category: ErrorCategory.THIRD_PARTY,
446
+ details: {
447
+ threadId,
448
+ resourceId: resourceId ?? ""
449
+ }
450
+ },
451
+ error
452
+ );
453
+ }
454
+ }
455
+ async getMessagesById({
456
+ messageIds,
457
+ format
458
+ }) {
459
+ if (messageIds.length === 0) return [];
460
+ try {
461
+ const table = await this.client.openTable(TABLE_MESSAGES);
462
+ const quotedIds = messageIds.map((id) => `'${id}'`).join(", ");
463
+ const allRecords = await table.query().where(`id IN (${quotedIds})`).toArray();
464
+ const messages = processResultWithTypeConversion(
465
+ allRecords,
466
+ await getTableSchema({ tableName: TABLE_MESSAGES, client: this.client })
467
+ );
468
+ const list = new MessageList().add(messages.map(this.normalizeMessage), "memory");
469
+ if (format === `v1`) return list.get.all.v1();
470
+ return list.get.all.v2();
471
+ } catch (error) {
472
+ throw new MastraError(
473
+ {
474
+ id: "LANCE_STORE_GET_MESSAGES_BY_ID_FAILED",
475
+ domain: ErrorDomain.STORAGE,
476
+ category: ErrorCategory.THIRD_PARTY,
477
+ details: {
478
+ messageIds: JSON.stringify(messageIds)
479
+ }
445
480
  },
446
481
  error
447
482
  );
@@ -582,13 +617,11 @@ var StoreMemoryLance = class extends MemoryStorage {
582
617
  return Array.from(allIndices).sort((a, b) => a - b).map((index) => records[index]);
583
618
  }
584
619
  async getMessagesPaginated(args) {
620
+ const { threadId, resourceId, selectBy, format = "v1" } = args;
621
+ const page = selectBy?.pagination?.page ?? 0;
622
+ const perPage = selectBy?.pagination?.perPage ?? 10;
585
623
  try {
586
- const { threadId, resourceId, selectBy, format = "v1" } = args;
587
- if (!threadId) {
588
- throw new Error("Thread ID is required for getMessagesPaginated");
589
- }
590
- const page = selectBy?.pagination?.page ?? 0;
591
- const perPage = selectBy?.pagination?.perPage ?? 10;
624
+ if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
592
625
  const dateRange = selectBy?.pagination?.dateRange;
593
626
  const fromDate = dateRange?.start;
594
627
  const toDate = dateRange?.end;
@@ -690,14 +723,21 @@ var StoreMemoryLance = class extends MemoryStorage {
690
723
  hasMore: total > (page + 1) * perPage
691
724
  };
692
725
  } catch (error) {
693
- throw new MastraError(
726
+ const mastraError = new MastraError(
694
727
  {
695
728
  id: "LANCE_STORE_GET_MESSAGES_PAGINATED_FAILED",
696
729
  domain: ErrorDomain.STORAGE,
697
- category: ErrorCategory.THIRD_PARTY
730
+ category: ErrorCategory.THIRD_PARTY,
731
+ details: {
732
+ threadId,
733
+ resourceId: resourceId ?? ""
734
+ }
698
735
  },
699
736
  error
700
737
  );
738
+ this.logger?.trackException?.(mastraError);
739
+ this.logger?.error?.(mastraError.toString());
740
+ return { messages: [], total: 0, page, perPage, hasMore: false };
701
741
  }
702
742
  }
703
743
  /**
@@ -1224,7 +1264,7 @@ var StoreOperationsLance = class extends StoreOperations {
1224
1264
  processedRecord[key] = JSON.stringify(processedRecord[key]);
1225
1265
  }
1226
1266
  }
1227
- console.log(await table.schema());
1267
+ console.info(await table.schema());
1228
1268
  await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([processedRecord]);
1229
1269
  } catch (error) {
1230
1270
  throw new MastraError(
@@ -1274,7 +1314,6 @@ var StoreOperationsLance = class extends StoreOperations {
1274
1314
  }
1275
1315
  return processedRecord;
1276
1316
  });
1277
- console.log(processedRecords);
1278
1317
  await table.mergeInsert(primaryId).whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(processedRecords);
1279
1318
  } catch (error) {
1280
1319
  throw new MastraError(
@@ -1358,12 +1397,27 @@ var StoreScoresLance = class extends ScoresStorage {
1358
1397
  this.client = client;
1359
1398
  }
1360
1399
  async saveScore(score) {
1400
+ let validatedScore;
1401
+ try {
1402
+ validatedScore = saveScorePayloadSchema.parse(score);
1403
+ } catch (error) {
1404
+ throw new MastraError(
1405
+ {
1406
+ id: "LANCE_STORAGE_SAVE_SCORE_FAILED",
1407
+ text: "Failed to save score in LanceStorage",
1408
+ domain: ErrorDomain.STORAGE,
1409
+ category: ErrorCategory.THIRD_PARTY
1410
+ },
1411
+ error
1412
+ );
1413
+ }
1361
1414
  try {
1415
+ const id = crypto.randomUUID();
1362
1416
  const table = await this.client.openTable(TABLE_SCORERS);
1363
1417
  const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1364
1418
  const allowedFields = new Set(schema.fields.map((f) => f.name));
1365
1419
  const filteredScore = {};
1366
- Object.keys(score).forEach((key) => {
1420
+ Object.keys(validatedScore).forEach((key) => {
1367
1421
  if (allowedFields.has(key)) {
1368
1422
  filteredScore[key] = score[key];
1369
1423
  }
@@ -1373,7 +1427,9 @@ var StoreScoresLance = class extends ScoresStorage {
1373
1427
  filteredScore[key] = JSON.stringify(filteredScore[key]);
1374
1428
  }
1375
1429
  }
1376
- console.log("Saving score to LanceStorage:", filteredScore);
1430
+ filteredScore.createdAt = /* @__PURE__ */ new Date();
1431
+ filteredScore.updatedAt = /* @__PURE__ */ new Date();
1432
+ filteredScore.id = id;
1377
1433
  await table.add([filteredScore], { mode: "append" });
1378
1434
  return { score };
1379
1435
  } catch (error) {
@@ -1412,18 +1468,35 @@ var StoreScoresLance = class extends ScoresStorage {
1412
1468
  }
1413
1469
  async getScoresByScorerId({
1414
1470
  scorerId,
1415
- pagination
1471
+ pagination,
1472
+ entityId,
1473
+ entityType,
1474
+ source
1416
1475
  }) {
1417
1476
  try {
1418
1477
  const table = await this.client.openTable(TABLE_SCORERS);
1419
1478
  const { page = 0, perPage = 10 } = pagination || {};
1420
1479
  const offset = page * perPage;
1421
- const query = table.query().where(`\`scorerId\` = '${scorerId}'`).limit(perPage);
1480
+ let query = table.query().where(`\`scorerId\` = '${scorerId}'`);
1481
+ if (source) {
1482
+ query = query.where(`\`source\` = '${source}'`);
1483
+ }
1484
+ if (entityId) {
1485
+ query = query.where(`\`entityId\` = '${entityId}'`);
1486
+ }
1487
+ if (entityType) {
1488
+ query = query.where(`\`entityType\` = '${entityType}'`);
1489
+ }
1490
+ query = query.limit(perPage);
1422
1491
  if (offset > 0) query.offset(offset);
1423
1492
  const records = await query.toArray();
1424
1493
  const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1425
1494
  const scores = processResultWithTypeConversion(records, schema);
1426
- const allRecords = await table.query().where(`\`scorerId\` = '${scorerId}'`).toArray();
1495
+ let totalQuery = table.query().where(`\`scorerId\` = '${scorerId}'`);
1496
+ if (source) {
1497
+ totalQuery = totalQuery.where(`\`source\` = '${source}'`);
1498
+ }
1499
+ const allRecords = await totalQuery.toArray();
1427
1500
  const total = allRecords.length;
1428
1501
  return {
1429
1502
  pagination: {
@@ -1522,6 +1595,44 @@ var StoreScoresLance = class extends ScoresStorage {
1522
1595
  );
1523
1596
  }
1524
1597
  }
1598
+ async getScoresBySpan({
1599
+ traceId,
1600
+ spanId,
1601
+ pagination
1602
+ }) {
1603
+ try {
1604
+ const table = await this.client.openTable(TABLE_SCORERS);
1605
+ const { page = 0, perPage = 10 } = pagination || {};
1606
+ const offset = page * perPage;
1607
+ const query = table.query().where(`\`traceId\` = '${traceId}' AND \`spanId\` = '${spanId}'`).limit(perPage);
1608
+ if (offset > 0) query.offset(offset);
1609
+ const records = await query.toArray();
1610
+ const schema = await getTableSchema({ tableName: TABLE_SCORERS, client: this.client });
1611
+ const scores = processResultWithTypeConversion(records, schema);
1612
+ const allRecords = await table.query().where(`\`traceId\` = '${traceId}' AND \`spanId\` = '${spanId}'`).toArray();
1613
+ const total = allRecords.length;
1614
+ return {
1615
+ pagination: {
1616
+ page,
1617
+ perPage,
1618
+ total,
1619
+ hasMore: offset + scores.length < total
1620
+ },
1621
+ scores
1622
+ };
1623
+ } catch (error) {
1624
+ throw new MastraError(
1625
+ {
1626
+ id: "LANCE_STORAGE_GET_SCORES_BY_SPAN_FAILED",
1627
+ text: "Failed to get scores by traceId and spanId in LanceStorage",
1628
+ domain: ErrorDomain.STORAGE,
1629
+ category: ErrorCategory.THIRD_PARTY,
1630
+ details: { error: error?.message }
1631
+ },
1632
+ error
1633
+ );
1634
+ }
1635
+ }
1525
1636
  };
1526
1637
  var StoreTracesLance = class extends TracesStorage {
1527
1638
  client;
@@ -1739,9 +1850,26 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
1739
1850
  super();
1740
1851
  this.client = client;
1741
1852
  }
1853
+ updateWorkflowResults({
1854
+ // workflowName,
1855
+ // runId,
1856
+ // stepId,
1857
+ // result,
1858
+ // runtimeContext,
1859
+ }) {
1860
+ throw new Error("Method not implemented.");
1861
+ }
1862
+ updateWorkflowState({
1863
+ // workflowName,
1864
+ // runId,
1865
+ // opts,
1866
+ }) {
1867
+ throw new Error("Method not implemented.");
1868
+ }
1742
1869
  async persistWorkflowSnapshot({
1743
1870
  workflowName,
1744
1871
  runId,
1872
+ resourceId,
1745
1873
  snapshot
1746
1874
  }) {
1747
1875
  try {
@@ -1755,10 +1883,13 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
1755
1883
  } else {
1756
1884
  createdAt = now;
1757
1885
  }
1886
+ const { status, value, ...rest } = snapshot;
1758
1887
  const record = {
1759
1888
  workflow_name: workflowName,
1760
1889
  run_id: runId,
1761
- snapshot: JSON.stringify(snapshot),
1890
+ resourceId,
1891
+ snapshot: JSON.stringify({ status, value, ...rest }),
1892
+ // this is to ensure status is always just before value, for when querying the db by status
1762
1893
  createdAt,
1763
1894
  updatedAt: now
1764
1895
  };
@@ -1828,6 +1959,10 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
1828
1959
  if (args?.workflowName) {
1829
1960
  conditions.push(`workflow_name = '${args.workflowName.replace(/'/g, "''")}'`);
1830
1961
  }
1962
+ if (args?.status) {
1963
+ const escapedStatus = args.status.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/%/g, "\\%").replace(/_/g, "\\_");
1964
+ conditions.push(`\`snapshot\` LIKE '%"status":"${escapedStatus}","value"%'`);
1965
+ }
1831
1966
  if (args?.resourceId) {
1832
1967
  conditions.push(`\`resourceId\` = '${args.resourceId}'`);
1833
1968
  }
@@ -1861,7 +1996,7 @@ var StoreWorkflowsLance = class extends WorkflowsStorage {
1861
1996
  id: "LANCE_STORE_GET_WORKFLOW_RUNS_FAILED",
1862
1997
  domain: ErrorDomain.STORAGE,
1863
1998
  category: ErrorCategory.THIRD_PARTY,
1864
- details: { namespace: args?.namespace ?? "", workflowName: args?.workflowName ?? "" }
1999
+ details: { resourceId: args?.resourceId ?? "", workflowName: args?.workflowName ?? "" }
1865
2000
  },
1866
2001
  error
1867
2002
  );
@@ -1996,7 +2131,8 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
1996
2131
  resourceWorkingMemory: true,
1997
2132
  hasColumn: true,
1998
2133
  createTable: true,
1999
- deleteMessages: false
2134
+ deleteMessages: false,
2135
+ getScoresBySpan: true
2000
2136
  };
2001
2137
  }
2002
2138
  async getResourceById({ resourceId }) {
@@ -2069,6 +2205,12 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
2069
2205
  }) {
2070
2206
  return this.stores.memory.getMessages({ threadId, resourceId, selectBy, format, threadConfig });
2071
2207
  }
2208
+ async getMessagesById({
2209
+ messageIds,
2210
+ format
2211
+ }) {
2212
+ return this.stores.memory.getMessagesById({ messageIds, format });
2213
+ }
2072
2214
  async saveMessages(args) {
2073
2215
  return this.stores.memory.saveMessages(args);
2074
2216
  }
@@ -2102,12 +2244,29 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
2102
2244
  async getWorkflowRunById(args) {
2103
2245
  return this.stores.workflows.getWorkflowRunById(args);
2104
2246
  }
2247
+ async updateWorkflowResults({
2248
+ workflowName,
2249
+ runId,
2250
+ stepId,
2251
+ result,
2252
+ runtimeContext
2253
+ }) {
2254
+ return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, runtimeContext });
2255
+ }
2256
+ async updateWorkflowState({
2257
+ workflowName,
2258
+ runId,
2259
+ opts
2260
+ }) {
2261
+ return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
2262
+ }
2105
2263
  async persistWorkflowSnapshot({
2106
2264
  workflowName,
2107
2265
  runId,
2266
+ resourceId,
2108
2267
  snapshot
2109
2268
  }) {
2110
- return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
2269
+ return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
2111
2270
  }
2112
2271
  async loadWorkflowSnapshot({
2113
2272
  workflowName,
@@ -2120,9 +2279,12 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
2120
2279
  }
2121
2280
  async getScoresByScorerId({
2122
2281
  scorerId,
2282
+ source,
2283
+ entityId,
2284
+ entityType,
2123
2285
  pagination
2124
2286
  }) {
2125
- return this.stores.scores.getScoresByScorerId({ scorerId, pagination });
2287
+ return this.stores.scores.getScoresByScorerId({ scorerId, source, pagination, entityId, entityType });
2126
2288
  }
2127
2289
  async saveScore(_score) {
2128
2290
  return this.stores.scores.saveScore(_score);
@@ -2140,6 +2302,13 @@ var LanceStorage = class _LanceStorage extends MastraStorage {
2140
2302
  }) {
2141
2303
  return this.stores.scores.getScoresByEntityId({ entityId, entityType, pagination });
2142
2304
  }
2305
+ async getScoresBySpan({
2306
+ traceId,
2307
+ spanId,
2308
+ pagination
2309
+ }) {
2310
+ return this.stores.scores.getScoresBySpan({ traceId, spanId, pagination });
2311
+ }
2143
2312
  };
2144
2313
  var LanceFilterTranslator = class extends BaseFilterTranslator {
2145
2314
  translate(filter) {
@@ -3031,7 +3200,44 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3031
3200
  );
3032
3201
  }
3033
3202
  }
3034
- async updateVector({ indexName, id, update }) {
3203
+ async updateVector(params) {
3204
+ const { indexName, update } = params;
3205
+ if ("id" in params && "filter" in params && params.id && params.filter) {
3206
+ throw new MastraError({
3207
+ id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
3208
+ domain: ErrorDomain.STORAGE,
3209
+ category: ErrorCategory.USER,
3210
+ text: "id and filter are mutually exclusive",
3211
+ details: { indexName }
3212
+ });
3213
+ }
3214
+ if (!("id" in params || "filter" in params) || !params.id && !params.filter) {
3215
+ throw new MastraError({
3216
+ id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
3217
+ domain: ErrorDomain.STORAGE,
3218
+ category: ErrorCategory.USER,
3219
+ text: "Either id or filter must be provided",
3220
+ details: { indexName }
3221
+ });
3222
+ }
3223
+ if ("filter" in params && params.filter && Object.keys(params.filter).length === 0) {
3224
+ throw new MastraError({
3225
+ id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
3226
+ domain: ErrorDomain.STORAGE,
3227
+ category: ErrorCategory.USER,
3228
+ text: "Cannot update with empty filter",
3229
+ details: { indexName }
3230
+ });
3231
+ }
3232
+ if (!update.vector && !update.metadata) {
3233
+ throw new MastraError({
3234
+ id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_INVALID_ARGS",
3235
+ domain: ErrorDomain.STORAGE,
3236
+ category: ErrorCategory.USER,
3237
+ text: "No updates provided",
3238
+ details: { indexName }
3239
+ });
3240
+ }
3035
3241
  try {
3036
3242
  if (!this.lanceClient) {
3037
3243
  throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
@@ -3039,21 +3245,6 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3039
3245
  if (!indexName) {
3040
3246
  throw new Error("indexName is required");
3041
3247
  }
3042
- if (!id) {
3043
- throw new Error("id is required");
3044
- }
3045
- } catch (err) {
3046
- throw new MastraError(
3047
- {
3048
- id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED_INVALID_ARGS",
3049
- domain: ErrorDomain.STORAGE,
3050
- category: ErrorCategory.USER,
3051
- details: { indexName, id }
3052
- },
3053
- err
3054
- );
3055
- }
3056
- try {
3057
3248
  const tables = await this.lanceClient.tableNames();
3058
3249
  for (const tableName of tables) {
3059
3250
  this.logger.debug("Checking table:" + tableName);
@@ -3063,39 +3254,66 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3063
3254
  const hasColumn = schema.fields.some((field) => field.name === indexName);
3064
3255
  if (hasColumn) {
3065
3256
  this.logger.debug(`Found column ${indexName} in table ${tableName}`);
3066
- const existingRecord = await table.query().where(`id = '${id}'`).select(schema.fields.map((field) => field.name)).limit(1).toArray();
3067
- if (existingRecord.length === 0) {
3068
- throw new Error(`Record with id '${id}' not found in table ${tableName}`);
3257
+ let whereClause;
3258
+ if ("id" in params && params.id) {
3259
+ whereClause = `id = '${params.id}'`;
3260
+ } else if ("filter" in params && params.filter) {
3261
+ const translator = new LanceFilterTranslator();
3262
+ const processFilterKeys = (filter) => {
3263
+ const processedFilter = {};
3264
+ Object.entries(filter).forEach(([key, value]) => {
3265
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3266
+ Object.entries(value).forEach(([nestedKey, nestedValue]) => {
3267
+ processedFilter[`metadata_${key}_${nestedKey}`] = nestedValue;
3268
+ });
3269
+ } else {
3270
+ processedFilter[`metadata_${key}`] = value;
3271
+ }
3272
+ });
3273
+ return processedFilter;
3274
+ };
3275
+ const prefixedFilter = processFilterKeys(params.filter);
3276
+ whereClause = translator.translate(prefixedFilter) || "";
3277
+ if (!whereClause) {
3278
+ throw new Error("Failed to translate filter to SQL");
3279
+ }
3280
+ } else {
3281
+ throw new Error("Either id or filter must be provided");
3069
3282
  }
3070
- const rowData = {
3071
- id
3072
- };
3073
- Object.entries(existingRecord[0]).forEach(([key, value]) => {
3074
- if (key !== "id" && key !== "_distance") {
3075
- if (key === indexName) {
3076
- if (!update.vector) {
3077
- if (Array.isArray(value)) {
3078
- rowData[key] = [...value];
3079
- } else if (typeof value === "object" && value !== null) {
3080
- rowData[key] = Array.from(value);
3283
+ const existingRecords = await table.query().where(whereClause).select(schema.fields.map((field) => field.name)).toArray();
3284
+ if (existingRecords.length === 0) {
3285
+ this.logger.info(`No records found matching criteria in table ${tableName}`);
3286
+ return;
3287
+ }
3288
+ const updatedRecords = existingRecords.map((record) => {
3289
+ const rowData = {};
3290
+ Object.entries(record).forEach(([key, value]) => {
3291
+ if (key !== "_distance") {
3292
+ if (key === indexName) {
3293
+ if (update.vector) {
3294
+ rowData[key] = update.vector;
3081
3295
  } else {
3082
- rowData[key] = value;
3296
+ if (Array.isArray(value)) {
3297
+ rowData[key] = [...value];
3298
+ } else if (typeof value === "object" && value !== null) {
3299
+ rowData[key] = Array.from(value);
3300
+ } else {
3301
+ rowData[key] = value;
3302
+ }
3083
3303
  }
3304
+ } else {
3305
+ rowData[key] = value;
3084
3306
  }
3085
- } else {
3086
- rowData[key] = value;
3087
3307
  }
3308
+ });
3309
+ if (update.metadata) {
3310
+ Object.entries(update.metadata).forEach(([key, value]) => {
3311
+ rowData[`metadata_${key}`] = value;
3312
+ });
3088
3313
  }
3314
+ return rowData;
3089
3315
  });
3090
- if (update.vector) {
3091
- rowData[indexName] = update.vector;
3092
- }
3093
- if (update.metadata) {
3094
- Object.entries(update.metadata).forEach(([key, value]) => {
3095
- rowData[`metadata_${key}`] = value;
3096
- });
3097
- }
3098
- await table.add([rowData], { mode: "overwrite" });
3316
+ await table.add(updatedRecords, { mode: "overwrite" });
3099
3317
  return;
3100
3318
  }
3101
3319
  } catch (err) {
@@ -3105,12 +3323,19 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3105
3323
  }
3106
3324
  throw new Error(`No table found with column/index '${indexName}'`);
3107
3325
  } catch (error) {
3326
+ if (error instanceof MastraError) throw error;
3108
3327
  throw new MastraError(
3109
3328
  {
3110
3329
  id: "STORAGE_LANCE_VECTOR_UPDATE_VECTOR_FAILED",
3111
3330
  domain: ErrorDomain.STORAGE,
3112
3331
  category: ErrorCategory.THIRD_PARTY,
3113
- details: { indexName, id, hasVector: !!update.vector, hasMetadata: !!update.metadata }
3332
+ details: {
3333
+ indexName,
3334
+ ..."id" in params && params.id && { id: params.id },
3335
+ ..."filter" in params && params.filter && { filter: JSON.stringify(params.filter) },
3336
+ hasVector: !!update.vector,
3337
+ hasMetadata: !!update.metadata
3338
+ }
3114
3339
  },
3115
3340
  error
3116
3341
  );
@@ -3133,7 +3358,10 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3133
3358
  id: "STORAGE_LANCE_VECTOR_DELETE_VECTOR_FAILED_INVALID_ARGS",
3134
3359
  domain: ErrorDomain.STORAGE,
3135
3360
  category: ErrorCategory.USER,
3136
- details: { indexName, id }
3361
+ details: {
3362
+ indexName,
3363
+ ...id && { id }
3364
+ }
3137
3365
  },
3138
3366
  err
3139
3367
  );
@@ -3163,7 +3391,10 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3163
3391
  id: "STORAGE_LANCE_VECTOR_DELETE_VECTOR_FAILED",
3164
3392
  domain: ErrorDomain.STORAGE,
3165
3393
  category: ErrorCategory.THIRD_PARTY,
3166
- details: { indexName, id }
3394
+ details: {
3395
+ indexName,
3396
+ ...id && { id }
3397
+ }
3167
3398
  },
3168
3399
  error
3169
3400
  );
@@ -3194,6 +3425,109 @@ var LanceVectorStore = class _LanceVectorStore extends MastraVector {
3194
3425
  });
3195
3426
  return result;
3196
3427
  }
3428
+ async deleteVectors({ indexName, filter, ids }) {
3429
+ if (ids && filter) {
3430
+ throw new MastraError({
3431
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_INVALID_ARGS",
3432
+ domain: ErrorDomain.STORAGE,
3433
+ category: ErrorCategory.USER,
3434
+ text: "ids and filter are mutually exclusive",
3435
+ details: { indexName }
3436
+ });
3437
+ }
3438
+ if (!ids && !filter) {
3439
+ throw new MastraError({
3440
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_INVALID_ARGS",
3441
+ domain: ErrorDomain.STORAGE,
3442
+ category: ErrorCategory.USER,
3443
+ text: "Either filter or ids must be provided",
3444
+ details: { indexName }
3445
+ });
3446
+ }
3447
+ if (ids && ids.length === 0) {
3448
+ throw new MastraError({
3449
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_INVALID_ARGS",
3450
+ domain: ErrorDomain.STORAGE,
3451
+ category: ErrorCategory.USER,
3452
+ text: "Cannot delete with empty ids array",
3453
+ details: { indexName }
3454
+ });
3455
+ }
3456
+ if (filter && Object.keys(filter).length === 0) {
3457
+ throw new MastraError({
3458
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_INVALID_ARGS",
3459
+ domain: ErrorDomain.STORAGE,
3460
+ category: ErrorCategory.USER,
3461
+ text: "Cannot delete with empty filter",
3462
+ details: { indexName }
3463
+ });
3464
+ }
3465
+ try {
3466
+ if (!this.lanceClient) {
3467
+ throw new Error("LanceDB client not initialized. Use LanceVectorStore.create() to create an instance");
3468
+ }
3469
+ if (!indexName) {
3470
+ throw new Error("indexName is required");
3471
+ }
3472
+ const tables = await this.lanceClient.tableNames();
3473
+ for (const tableName of tables) {
3474
+ this.logger.debug("Checking table:" + tableName);
3475
+ const table = await this.lanceClient.openTable(tableName);
3476
+ try {
3477
+ const schema = await table.schema();
3478
+ const hasColumn = schema.fields.some((field) => field.name === indexName);
3479
+ if (hasColumn) {
3480
+ this.logger.debug(`Found column ${indexName} in table ${tableName}`);
3481
+ if (ids) {
3482
+ const idsConditions = ids.map((id) => `id = '${id}'`).join(" OR ");
3483
+ await table.delete(idsConditions);
3484
+ } else if (filter) {
3485
+ const translator = new LanceFilterTranslator();
3486
+ const processFilterKeys = (filter2) => {
3487
+ const processedFilter = {};
3488
+ Object.entries(filter2).forEach(([key, value]) => {
3489
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3490
+ Object.entries(value).forEach(([nestedKey, nestedValue]) => {
3491
+ processedFilter[`metadata_${key}_${nestedKey}`] = nestedValue;
3492
+ });
3493
+ } else {
3494
+ processedFilter[`metadata_${key}`] = value;
3495
+ }
3496
+ });
3497
+ return processedFilter;
3498
+ };
3499
+ const prefixedFilter = processFilterKeys(filter);
3500
+ const whereClause = translator.translate(prefixedFilter);
3501
+ if (!whereClause) {
3502
+ throw new Error("Failed to translate filter to SQL");
3503
+ }
3504
+ await table.delete(whereClause);
3505
+ }
3506
+ return;
3507
+ }
3508
+ } catch (err) {
3509
+ this.logger.error(`Error checking schema for table ${tableName}:` + err);
3510
+ continue;
3511
+ }
3512
+ }
3513
+ throw new Error(`No table found with column/index '${indexName}'`);
3514
+ } catch (error) {
3515
+ if (error instanceof MastraError) throw error;
3516
+ throw new MastraError(
3517
+ {
3518
+ id: "STORAGE_LANCE_VECTOR_DELETE_VECTORS_FAILED",
3519
+ domain: ErrorDomain.STORAGE,
3520
+ category: ErrorCategory.THIRD_PARTY,
3521
+ details: {
3522
+ indexName,
3523
+ ...filter && { filter: JSON.stringify(filter) },
3524
+ ...ids && { idsCount: ids.length }
3525
+ }
3526
+ },
3527
+ error
3528
+ );
3529
+ }
3530
+ }
3197
3531
  };
3198
3532
 
3199
3533
  export { LanceStorage, LanceVectorStore };