@mastra/mongodb 0.12.0 → 0.12.1

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.js CHANGED
@@ -3,8 +3,8 @@ import { MastraVector } from '@mastra/core/vector';
3
3
  import { MongoClient } from 'mongodb';
4
4
  import { v4 } from 'uuid';
5
5
  import { BaseFilterTranslator } from '@mastra/core/vector/filter';
6
+ import { MastraStorage, StoreOperations, TABLE_SCHEMAS, safelyParseJSON, MemoryStorage, TABLE_MESSAGES, resolveMessageLimit, TABLE_THREADS, TABLE_RESOURCES, TracesStorage, TABLE_TRACES, LegacyEvalsStorage, TABLE_EVALS, ScoresStorage, TABLE_SCORERS, WorkflowsStorage, TABLE_WORKFLOW_SNAPSHOT } from '@mastra/core/storage';
6
7
  import { MessageList } from '@mastra/core/agent';
7
- import { MastraStorage, TABLE_THREADS, TABLE_MESSAGES, TABLE_TRACES, TABLE_WORKFLOW_SNAPSHOT, TABLE_EVALS } from '@mastra/core/storage';
8
8
 
9
9
  // src/vector/index.ts
10
10
  var MongoDBFilterTranslator = class extends BaseFilterTranslator {
@@ -187,12 +187,25 @@ var MongoDBVector = class extends MastraVector {
187
187
  path: embeddingField,
188
188
  numDimensions,
189
189
  similarity: mongoMetric
190
+ },
191
+ {
192
+ type: "filter",
193
+ path: "_id"
190
194
  }
191
195
  ]
192
196
  },
193
197
  name: indexNameInternal,
194
198
  type: "vectorSearch"
195
199
  });
200
+ await collection.createSearchIndex({
201
+ definition: {
202
+ mappings: {
203
+ dynamic: true
204
+ }
205
+ },
206
+ name: `${indexName}_search_index`,
207
+ type: "search"
208
+ });
196
209
  } catch (error) {
197
210
  if (error.codeName !== "IndexAlreadyExists") {
198
211
  throw new MastraError(
@@ -319,18 +332,21 @@ var MongoDBVector = class extends MastraVector {
319
332
  } else if (Object.keys(documentMongoFilter).length > 0) {
320
333
  combinedFilter = documentMongoFilter;
321
334
  }
335
+ const vectorSearch = {
336
+ index: indexNameInternal,
337
+ queryVector,
338
+ path: this.embeddingFieldName,
339
+ numCandidates: 100,
340
+ limit: topK
341
+ };
342
+ if (Object.keys(combinedFilter).length > 0) {
343
+ const candidateIds = await collection.aggregate([{ $match: combinedFilter }, { $project: { _id: 1 } }]).map((doc) => doc._id).toArray();
344
+ vectorSearch.filter = { _id: { $in: candidateIds } };
345
+ }
322
346
  const pipeline = [
323
347
  {
324
- $vectorSearch: {
325
- index: indexNameInternal,
326
- queryVector,
327
- path: this.embeddingFieldName,
328
- numCandidates: 100,
329
- limit: topK
330
- }
348
+ $vectorSearch: vectorSearch
331
349
  },
332
- // Apply the filter using $match stage
333
- ...Object.keys(combinedFilter).length > 0 ? [{ $match: combinedFilter }] : [],
334
350
  {
335
351
  $set: { score: { $meta: "vectorSearchScore" } }
336
352
  },
@@ -548,200 +564,713 @@ var MongoDBVector = class extends MastraVector {
548
564
  return translator.translate(filter);
549
565
  }
550
566
  };
551
- function safelyParseJSON(jsonString) {
552
- try {
553
- return JSON.parse(jsonString);
554
- } catch {
555
- return {};
556
- }
557
- }
558
- var MongoDBStore = class extends MastraStorage {
559
- #isConnected = false;
567
+ var MongoDBConnector = class _MongoDBConnector {
560
568
  #client;
561
- #db;
562
569
  #dbName;
563
- constructor(config) {
564
- super({ name: "MongoDBStore" });
570
+ #handler;
571
+ #isConnected;
572
+ #db;
573
+ constructor(options) {
574
+ this.#client = options.client;
575
+ this.#dbName = options.dbName;
576
+ this.#handler = options.handler;
565
577
  this.#isConnected = false;
566
- try {
567
- if (!config.url?.trim().length) {
568
- throw new Error(
569
- "MongoDBStore: url must be provided and cannot be empty. Passing an empty string may cause fallback to local MongoDB defaults."
570
- );
571
- }
572
- if (!config.dbName?.trim().length) {
573
- throw new Error(
574
- "MongoDBStore: dbName must be provided and cannot be empty. Passing an empty string may cause fallback to local MongoDB defaults."
575
- );
576
- }
577
- } catch (error) {
578
- throw new MastraError(
579
- {
580
- id: "STORAGE_MONGODB_STORE_CONSTRUCTOR_FAILED",
581
- domain: ErrorDomain.STORAGE,
582
- category: ErrorCategory.USER,
583
- details: { url: config.url, dbName: config.dbName }
584
- },
585
- error
578
+ }
579
+ static fromDatabaseConfig(config) {
580
+ if (!config.url?.trim().length) {
581
+ throw new Error(
582
+ "MongoDBStore: url must be provided and cannot be empty. Passing an empty string may cause fallback to local MongoDB defaults."
583
+ );
584
+ }
585
+ if (!config.dbName?.trim().length) {
586
+ throw new Error(
587
+ "MongoDBStore: dbName must be provided and cannot be empty. Passing an empty string may cause fallback to local MongoDB defaults."
586
588
  );
587
589
  }
588
- this.#dbName = config.dbName;
589
- this.#client = new MongoClient(config.url, config.options);
590
+ return new _MongoDBConnector({
591
+ client: new MongoClient(config.url, config.options),
592
+ dbName: config.dbName,
593
+ handler: void 0
594
+ });
595
+ }
596
+ static fromConnectionHandler(handler) {
597
+ return new _MongoDBConnector({
598
+ client: void 0,
599
+ dbName: void 0,
600
+ handler
601
+ });
590
602
  }
591
603
  async getConnection() {
592
- if (this.#isConnected) {
604
+ if (this.#client) {
605
+ if (this.#isConnected && this.#db) {
606
+ return this.#db;
607
+ }
608
+ await this.#client.connect();
609
+ this.#db = this.#client.db(this.#dbName);
610
+ this.#isConnected = true;
593
611
  return this.#db;
594
612
  }
595
- await this.#client.connect();
596
- this.#db = this.#client.db(this.#dbName);
597
- this.#isConnected = true;
598
- return this.#db;
613
+ throw new Error("MongoDBStore: client cannot be empty. Check your MongoDBConnector configuration.");
599
614
  }
600
615
  async getCollection(collectionName) {
616
+ if (this.#handler) {
617
+ return this.#handler.getCollection(collectionName);
618
+ }
601
619
  const db = await this.getConnection();
602
620
  return db.collection(collectionName);
603
621
  }
604
- async createTable() {
605
- }
606
- /**
607
- * No-op: This backend is schemaless and does not require schema changes.
608
- * @param tableName Name of the table
609
- * @param schema Schema of the table
610
- * @param ifNotExists Array of column names to add if they don't exist
611
- */
612
- async alterTable(_args) {
622
+ async close() {
623
+ if (this.#client) {
624
+ await this.#client.close();
625
+ this.#isConnected = false;
626
+ return;
627
+ }
628
+ if (this.#handler) {
629
+ await this.#handler.close();
630
+ }
613
631
  }
614
- async clearTable({ tableName }) {
632
+ };
633
+ function transformEvalRow(row) {
634
+ let testInfoValue = null;
635
+ if (row.test_info) {
615
636
  try {
616
- const collection = await this.getCollection(tableName);
617
- await collection.deleteMany({});
618
- } catch (error) {
619
- if (error instanceof Error) {
620
- const matstraError = new MastraError(
621
- {
622
- id: "STORAGE_MONGODB_STORE_CLEAR_TABLE_FAILED",
623
- domain: ErrorDomain.STORAGE,
624
- category: ErrorCategory.THIRD_PARTY,
625
- details: { tableName }
626
- },
627
- error
628
- );
629
- this.logger.error(matstraError.message);
630
- this.logger?.trackException(matstraError);
631
- }
637
+ testInfoValue = typeof row.test_info === "string" ? safelyParseJSON(row.test_info) : row.test_info;
638
+ } catch (e) {
639
+ console.warn("Failed to parse test_info:", e);
632
640
  }
633
641
  }
634
- async insert({ tableName, record }) {
642
+ let resultValue;
643
+ try {
644
+ resultValue = typeof row.result === "string" ? safelyParseJSON(row.result) : row.result;
645
+ } catch (e) {
646
+ console.warn("Failed to parse result:", e);
647
+ throw new Error("Invalid result format");
648
+ }
649
+ return {
650
+ agentName: row.agent_name,
651
+ input: row.input,
652
+ output: row.output,
653
+ result: resultValue,
654
+ metricName: row.metric_name,
655
+ instructions: row.instructions,
656
+ testInfo: testInfoValue,
657
+ globalRunId: row.global_run_id,
658
+ runId: row.run_id,
659
+ createdAt: row.createdAt
660
+ };
661
+ }
662
+ var LegacyEvalsMongoDB = class extends LegacyEvalsStorage {
663
+ operations;
664
+ constructor({ operations }) {
665
+ super();
666
+ this.operations = operations;
667
+ }
668
+ /** @deprecated use getEvals instead */
669
+ async getEvalsByAgentName(agentName, type) {
635
670
  try {
636
- const collection = await this.getCollection(tableName);
637
- await collection.insertOne(record);
671
+ const query = {
672
+ agent_name: agentName
673
+ };
674
+ if (type === "test") {
675
+ query["test_info"] = { $ne: null };
676
+ }
677
+ if (type === "live") {
678
+ query["test_info"] = null;
679
+ }
680
+ const collection = await this.operations.getCollection(TABLE_EVALS);
681
+ const documents = await collection.find(query).sort({ created_at: "desc" }).toArray();
682
+ const result = documents.map((row) => transformEvalRow(row));
683
+ return result.filter((row) => {
684
+ if (type === "live") {
685
+ return !Boolean(row.testInfo?.testPath);
686
+ }
687
+ if (type === "test") {
688
+ return row.testInfo?.testPath !== null;
689
+ }
690
+ return true;
691
+ });
638
692
  } catch (error) {
639
- if (error instanceof Error) {
640
- const matstraError = new MastraError(
641
- {
642
- id: "STORAGE_MONGODB_STORE_INSERT_FAILED",
643
- domain: ErrorDomain.STORAGE,
644
- category: ErrorCategory.THIRD_PARTY,
645
- details: { tableName }
646
- },
647
- error
648
- );
649
- this.logger.error(matstraError.message);
650
- this.logger?.trackException(matstraError);
693
+ if (error instanceof Error && error.message.includes("no such table")) {
694
+ return [];
651
695
  }
696
+ throw new MastraError(
697
+ {
698
+ id: "STORAGE_MONGODB_STORE_GET_EVALS_BY_AGENT_NAME_FAILED",
699
+ domain: ErrorDomain.STORAGE,
700
+ category: ErrorCategory.THIRD_PARTY,
701
+ details: { agentName }
702
+ },
703
+ error
704
+ );
652
705
  }
653
706
  }
654
- async batchInsert({ tableName, records }) {
655
- if (!records.length) {
656
- return;
707
+ async getEvals(options = {}) {
708
+ const { agentName, type, page = 0, perPage = 100, dateRange } = options;
709
+ const fromDate = dateRange?.start;
710
+ const toDate = dateRange?.end;
711
+ const currentOffset = page * perPage;
712
+ const query = {};
713
+ if (agentName) {
714
+ query["agent_name"] = agentName;
715
+ }
716
+ if (type === "test") {
717
+ query["test_info"] = { $ne: null };
718
+ } else if (type === "live") {
719
+ query["test_info"] = null;
720
+ }
721
+ if (fromDate || toDate) {
722
+ query["createdAt"] = {};
723
+ if (fromDate) {
724
+ query["createdAt"]["$gte"] = fromDate;
725
+ }
726
+ if (toDate) {
727
+ query["createdAt"]["$lte"] = toDate;
728
+ }
657
729
  }
658
730
  try {
659
- const collection = await this.getCollection(tableName);
660
- await collection.insertMany(records);
731
+ const collection = await this.operations.getCollection(TABLE_EVALS);
732
+ let total = 0;
733
+ if (page === 0 || perPage < 1e3) {
734
+ total = await collection.countDocuments(query);
735
+ }
736
+ if (total === 0) {
737
+ return {
738
+ evals: [],
739
+ total: 0,
740
+ page,
741
+ perPage,
742
+ hasMore: false
743
+ };
744
+ }
745
+ const documents = await collection.find(query).sort({ created_at: "desc" }).skip(currentOffset).limit(perPage).toArray();
746
+ const evals = documents.map((row) => transformEvalRow(row));
747
+ const filteredEvals = evals.filter((row) => {
748
+ if (type === "live") {
749
+ return !Boolean(row.testInfo?.testPath);
750
+ }
751
+ if (type === "test") {
752
+ return row.testInfo?.testPath !== null;
753
+ }
754
+ return true;
755
+ });
756
+ const hasMore = currentOffset + filteredEvals.length < total;
757
+ return {
758
+ evals: filteredEvals,
759
+ total,
760
+ page,
761
+ perPage,
762
+ hasMore
763
+ };
661
764
  } catch (error) {
662
765
  throw new MastraError(
663
766
  {
664
- id: "STORAGE_MONGODB_STORE_BATCH_INSERT_FAILED",
767
+ id: "STORAGE_MONGODB_STORE_GET_EVALS_FAILED",
665
768
  domain: ErrorDomain.STORAGE,
666
769
  category: ErrorCategory.THIRD_PARTY,
667
- details: { tableName }
770
+ details: {
771
+ agentName: agentName || "all",
772
+ type: type || "all",
773
+ page,
774
+ perPage
775
+ }
668
776
  },
669
777
  error
670
778
  );
671
779
  }
672
780
  }
673
- async load({ tableName, keys }) {
674
- this.logger.info(`Loading ${tableName} with keys ${JSON.stringify(keys)}`);
781
+ };
782
+
783
+ // src/storage/domains/utils.ts
784
+ function formatDateForMongoDB(date) {
785
+ return typeof date === "string" ? new Date(date) : date;
786
+ }
787
+
788
+ // src/storage/domains/memory/index.ts
789
+ var MemoryStorageMongoDB = class extends MemoryStorage {
790
+ operations;
791
+ constructor({ operations }) {
792
+ super();
793
+ this.operations = operations;
794
+ }
795
+ parseRow(row) {
796
+ let content = row.content;
797
+ if (typeof content === "string") {
798
+ try {
799
+ content = JSON.parse(content);
800
+ } catch {
801
+ }
802
+ }
803
+ const result = {
804
+ id: row.id,
805
+ content,
806
+ role: row.role,
807
+ createdAt: formatDateForMongoDB(row.createdAt),
808
+ threadId: row.thread_id,
809
+ resourceId: row.resourceId
810
+ };
811
+ if (row.type && row.type !== "v2") result.type = row.type;
812
+ return result;
813
+ }
814
+ async _getIncludedMessages({
815
+ threadId,
816
+ selectBy
817
+ }) {
818
+ const include = selectBy?.include;
819
+ if (!include) return null;
820
+ const collection = await this.operations.getCollection(TABLE_MESSAGES);
821
+ const includedMessages = [];
822
+ for (const inc of include) {
823
+ const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
824
+ const searchThreadId = inc.threadId || threadId;
825
+ const allMessages = await collection.find({ thread_id: searchThreadId }).sort({ createdAt: 1 }).toArray();
826
+ const targetIndex = allMessages.findIndex((msg) => msg.id === id);
827
+ if (targetIndex === -1) continue;
828
+ const startIndex = Math.max(0, targetIndex - withPreviousMessages);
829
+ const endIndex = Math.min(allMessages.length - 1, targetIndex + withNextMessages);
830
+ for (let i = startIndex; i <= endIndex; i++) {
831
+ includedMessages.push(allMessages[i]);
832
+ }
833
+ }
834
+ const seen = /* @__PURE__ */ new Set();
835
+ const dedupedMessages = includedMessages.filter((msg) => {
836
+ if (seen.has(msg.id)) return false;
837
+ seen.add(msg.id);
838
+ return true;
839
+ });
840
+ return dedupedMessages.map((row) => this.parseRow(row));
841
+ }
842
+ async getMessages({
843
+ threadId,
844
+ selectBy,
845
+ format
846
+ }) {
675
847
  try {
676
- const collection = await this.getCollection(tableName);
677
- return await collection.find(keys).toArray();
848
+ const messages = [];
849
+ const limit = resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
850
+ if (selectBy?.include?.length) {
851
+ const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
852
+ if (includeMessages) {
853
+ messages.push(...includeMessages);
854
+ }
855
+ }
856
+ const excludeIds = messages.map((m) => m.id);
857
+ const collection = await this.operations.getCollection(TABLE_MESSAGES);
858
+ const query = { thread_id: threadId };
859
+ if (excludeIds.length > 0) {
860
+ query.id = { $nin: excludeIds };
861
+ }
862
+ if (limit > 0) {
863
+ const remainingMessages = await collection.find(query).sort({ createdAt: -1 }).limit(limit).toArray();
864
+ messages.push(...remainingMessages.map((row) => this.parseRow(row)));
865
+ }
866
+ messages.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
867
+ const list = new MessageList().add(messages, "memory");
868
+ if (format === "v2") return list.get.all.v2();
869
+ return list.get.all.v1();
678
870
  } catch (error) {
679
871
  throw new MastraError(
680
872
  {
681
- id: "STORAGE_MONGODB_STORE_LOAD_FAILED",
873
+ id: "MONGODB_STORE_GET_MESSAGES_FAILED",
682
874
  domain: ErrorDomain.STORAGE,
683
875
  category: ErrorCategory.THIRD_PARTY,
684
- details: { tableName }
876
+ details: { threadId }
685
877
  },
686
878
  error
687
879
  );
688
880
  }
689
881
  }
690
- async getThreadById({ threadId }) {
882
+ async getMessagesPaginated(args) {
883
+ const { threadId, format, selectBy } = args;
884
+ const { page = 0, perPage: perPageInput, dateRange } = selectBy?.pagination || {};
885
+ const perPage = perPageInput !== void 0 ? perPageInput : resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
886
+ const fromDate = dateRange?.start;
887
+ const toDate = dateRange?.end;
888
+ const messages = [];
889
+ if (selectBy?.include?.length) {
890
+ try {
891
+ const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
892
+ if (includeMessages) {
893
+ messages.push(...includeMessages);
894
+ }
895
+ } catch (error) {
896
+ throw new MastraError(
897
+ {
898
+ id: "MONGODB_STORE_GET_MESSAGES_PAGINATED_GET_INCLUDE_MESSAGES_FAILED",
899
+ domain: ErrorDomain.STORAGE,
900
+ category: ErrorCategory.THIRD_PARTY,
901
+ details: { threadId }
902
+ },
903
+ error
904
+ );
905
+ }
906
+ }
691
907
  try {
692
- const collection = await this.getCollection(TABLE_THREADS);
693
- const result = await collection.findOne({ id: threadId });
694
- if (!result) {
695
- return null;
908
+ const currentOffset = page * perPage;
909
+ const collection = await this.operations.getCollection(TABLE_MESSAGES);
910
+ const query = { thread_id: threadId };
911
+ if (fromDate) {
912
+ query.createdAt = { ...query.createdAt, $gte: fromDate };
913
+ }
914
+ if (toDate) {
915
+ query.createdAt = { ...query.createdAt, $lte: toDate };
916
+ }
917
+ const total = await collection.countDocuments(query);
918
+ if (total === 0 && messages.length === 0) {
919
+ return {
920
+ messages: [],
921
+ total: 0,
922
+ page,
923
+ perPage,
924
+ hasMore: false
925
+ };
926
+ }
927
+ const excludeIds = messages.map((m) => m.id);
928
+ if (excludeIds.length > 0) {
929
+ query.id = { $nin: excludeIds };
696
930
  }
931
+ const dataResult = await collection.find(query).sort({ createdAt: -1 }).skip(currentOffset).limit(perPage).toArray();
932
+ messages.push(...dataResult.map((row) => this.parseRow(row)));
933
+ const messagesToReturn = format === "v1" ? new MessageList().add(messages, "memory").get.all.v1() : new MessageList().add(messages, "memory").get.all.v2();
697
934
  return {
698
- ...result,
699
- metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
935
+ messages: messagesToReturn,
936
+ total,
937
+ page,
938
+ perPage,
939
+ hasMore: (page + 1) * perPage < total
700
940
  };
701
941
  } catch (error) {
702
- throw new MastraError(
942
+ const mastraError = new MastraError(
703
943
  {
704
- id: "STORAGE_MONGODB_STORE_GET_THREAD_BY_ID_FAILED",
944
+ id: "MONGODB_STORE_GET_MESSAGES_PAGINATED_FAILED",
705
945
  domain: ErrorDomain.STORAGE,
706
946
  category: ErrorCategory.THIRD_PARTY,
707
947
  details: { threadId }
708
948
  },
709
949
  error
710
950
  );
951
+ this.logger?.trackException?.(mastraError);
952
+ this.logger?.error?.(mastraError.toString());
953
+ return { messages: [], total: 0, page, perPage, hasMore: false };
711
954
  }
712
955
  }
713
- async getThreadsByResourceId({ resourceId }) {
956
+ async saveMessages({
957
+ messages,
958
+ format
959
+ }) {
960
+ if (messages.length === 0) return messages;
714
961
  try {
715
- const collection = await this.getCollection(TABLE_THREADS);
716
- const results = await collection.find({ resourceId }).toArray();
717
- if (!results.length) {
718
- return [];
962
+ const threadId = messages[0]?.threadId;
963
+ if (!threadId) {
964
+ throw new Error("Thread ID is required");
719
965
  }
720
- return results.map((result) => ({
721
- ...result,
722
- metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
723
- }));
966
+ const collection = await this.operations.getCollection(TABLE_MESSAGES);
967
+ const threadsCollection = await this.operations.getCollection(TABLE_THREADS);
968
+ const messagesToInsert = messages.map((message) => {
969
+ const time = message.createdAt || /* @__PURE__ */ new Date();
970
+ if (!message.threadId) {
971
+ throw new Error(
972
+ "Expected to find a threadId for message, but couldn't find one. An unexpected error has occurred."
973
+ );
974
+ }
975
+ if (!message.resourceId) {
976
+ throw new Error(
977
+ "Expected to find a resourceId for message, but couldn't find one. An unexpected error has occurred."
978
+ );
979
+ }
980
+ return {
981
+ updateOne: {
982
+ filter: { id: message.id },
983
+ update: {
984
+ $set: {
985
+ id: message.id,
986
+ thread_id: message.threadId,
987
+ content: typeof message.content === "object" ? JSON.stringify(message.content) : message.content,
988
+ role: message.role,
989
+ type: message.type || "v2",
990
+ createdAt: formatDateForMongoDB(time),
991
+ resourceId: message.resourceId
992
+ }
993
+ },
994
+ upsert: true
995
+ }
996
+ };
997
+ });
998
+ await Promise.all([
999
+ collection.bulkWrite(messagesToInsert),
1000
+ threadsCollection.updateOne({ id: threadId }, { $set: { updatedAt: /* @__PURE__ */ new Date() } })
1001
+ ]);
1002
+ const list = new MessageList().add(messages, "memory");
1003
+ if (format === "v2") return list.get.all.v2();
1004
+ return list.get.all.v1();
724
1005
  } catch (error) {
725
1006
  throw new MastraError(
726
1007
  {
727
- id: "STORAGE_MONGODB_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED",
1008
+ id: "MONGODB_STORE_SAVE_MESSAGES_FAILED",
728
1009
  domain: ErrorDomain.STORAGE,
729
- category: ErrorCategory.THIRD_PARTY,
730
- details: { resourceId }
1010
+ category: ErrorCategory.THIRD_PARTY
731
1011
  },
732
1012
  error
733
1013
  );
734
1014
  }
735
1015
  }
736
- async saveThread({ thread }) {
737
- try {
738
- const collection = await this.getCollection(TABLE_THREADS);
739
- await collection.updateOne(
740
- { id: thread.id },
741
- {
1016
+ async updateMessages({
1017
+ messages
1018
+ }) {
1019
+ if (messages.length === 0) {
1020
+ return [];
1021
+ }
1022
+ const messageIds = messages.map((m) => m.id);
1023
+ const collection = await this.operations.getCollection(TABLE_MESSAGES);
1024
+ const existingMessages = await collection.find({ id: { $in: messageIds } }).toArray();
1025
+ const existingMessagesParsed = existingMessages.map((msg) => this.parseRow(msg));
1026
+ if (existingMessagesParsed.length === 0) {
1027
+ return [];
1028
+ }
1029
+ const threadIdsToUpdate = /* @__PURE__ */ new Set();
1030
+ const bulkOps = [];
1031
+ for (const existingMessage of existingMessagesParsed) {
1032
+ const updatePayload = messages.find((m) => m.id === existingMessage.id);
1033
+ if (!updatePayload) continue;
1034
+ const { id, ...fieldsToUpdate } = updatePayload;
1035
+ if (Object.keys(fieldsToUpdate).length === 0) continue;
1036
+ threadIdsToUpdate.add(existingMessage.threadId);
1037
+ if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
1038
+ threadIdsToUpdate.add(updatePayload.threadId);
1039
+ }
1040
+ const updateDoc = {};
1041
+ const updatableFields = { ...fieldsToUpdate };
1042
+ if (updatableFields.content) {
1043
+ const newContent = {
1044
+ ...existingMessage.content,
1045
+ ...updatableFields.content,
1046
+ // Deep merge metadata if it exists on both
1047
+ ...existingMessage.content?.metadata && updatableFields.content.metadata ? {
1048
+ metadata: {
1049
+ ...existingMessage.content.metadata,
1050
+ ...updatableFields.content.metadata
1051
+ }
1052
+ } : {}
1053
+ };
1054
+ updateDoc.content = JSON.stringify(newContent);
1055
+ delete updatableFields.content;
1056
+ }
1057
+ for (const key in updatableFields) {
1058
+ if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
1059
+ const dbKey = key === "threadId" ? "thread_id" : key;
1060
+ let value = updatableFields[key];
1061
+ if (typeof value === "object" && value !== null) {
1062
+ value = JSON.stringify(value);
1063
+ }
1064
+ updateDoc[dbKey] = value;
1065
+ }
1066
+ }
1067
+ if (Object.keys(updateDoc).length > 0) {
1068
+ bulkOps.push({
1069
+ updateOne: {
1070
+ filter: { id },
1071
+ update: { $set: updateDoc }
1072
+ }
1073
+ });
1074
+ }
1075
+ }
1076
+ if (bulkOps.length > 0) {
1077
+ await collection.bulkWrite(bulkOps);
1078
+ }
1079
+ if (threadIdsToUpdate.size > 0) {
1080
+ const threadsCollection = await this.operations.getCollection(TABLE_THREADS);
1081
+ await threadsCollection.updateMany(
1082
+ { id: { $in: Array.from(threadIdsToUpdate) } },
1083
+ { $set: { updatedAt: /* @__PURE__ */ new Date() } }
1084
+ );
1085
+ }
1086
+ const updatedMessages = await collection.find({ id: { $in: messageIds } }).toArray();
1087
+ return updatedMessages.map((row) => this.parseRow(row));
1088
+ }
1089
+ async getResourceById({ resourceId }) {
1090
+ try {
1091
+ const collection = await this.operations.getCollection(TABLE_RESOURCES);
1092
+ const result = await collection.findOne({ id: resourceId });
1093
+ if (!result) {
1094
+ return null;
1095
+ }
1096
+ return {
1097
+ id: result.id,
1098
+ workingMemory: result.workingMemory || "",
1099
+ metadata: typeof result.metadata === "string" ? safelyParseJSON(result.metadata) : result.metadata,
1100
+ createdAt: formatDateForMongoDB(result.createdAt),
1101
+ updatedAt: formatDateForMongoDB(result.updatedAt)
1102
+ };
1103
+ } catch (error) {
1104
+ throw new MastraError(
1105
+ {
1106
+ id: "STORAGE_MONGODB_STORE_GET_RESOURCE_BY_ID_FAILED",
1107
+ domain: ErrorDomain.STORAGE,
1108
+ category: ErrorCategory.THIRD_PARTY,
1109
+ details: { resourceId }
1110
+ },
1111
+ error
1112
+ );
1113
+ }
1114
+ }
1115
+ async saveResource({ resource }) {
1116
+ try {
1117
+ const collection = await this.operations.getCollection(TABLE_RESOURCES);
1118
+ await collection.updateOne(
1119
+ { id: resource.id },
1120
+ {
1121
+ $set: {
1122
+ ...resource,
1123
+ metadata: JSON.stringify(resource.metadata)
1124
+ }
1125
+ },
1126
+ { upsert: true }
1127
+ );
1128
+ return resource;
1129
+ } catch (error) {
1130
+ throw new MastraError(
1131
+ {
1132
+ id: "STORAGE_MONGODB_STORE_SAVE_RESOURCE_FAILED",
1133
+ domain: ErrorDomain.STORAGE,
1134
+ category: ErrorCategory.THIRD_PARTY,
1135
+ details: { resourceId: resource.id }
1136
+ },
1137
+ error
1138
+ );
1139
+ }
1140
+ }
1141
+ async updateResource({
1142
+ resourceId,
1143
+ workingMemory,
1144
+ metadata
1145
+ }) {
1146
+ try {
1147
+ const existingResource = await this.getResourceById({ resourceId });
1148
+ if (!existingResource) {
1149
+ const newResource = {
1150
+ id: resourceId,
1151
+ workingMemory: workingMemory || "",
1152
+ metadata: metadata || {},
1153
+ createdAt: /* @__PURE__ */ new Date(),
1154
+ updatedAt: /* @__PURE__ */ new Date()
1155
+ };
1156
+ return this.saveResource({ resource: newResource });
1157
+ }
1158
+ const updatedResource = {
1159
+ ...existingResource,
1160
+ workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
1161
+ metadata: metadata ? { ...existingResource.metadata, ...metadata } : existingResource.metadata,
1162
+ updatedAt: /* @__PURE__ */ new Date()
1163
+ };
1164
+ const collection = await this.operations.getCollection(TABLE_RESOURCES);
1165
+ const updateDoc = { updatedAt: updatedResource.updatedAt };
1166
+ if (workingMemory !== void 0) {
1167
+ updateDoc.workingMemory = workingMemory;
1168
+ }
1169
+ if (metadata) {
1170
+ updateDoc.metadata = JSON.stringify(updatedResource.metadata);
1171
+ }
1172
+ await collection.updateOne({ id: resourceId }, { $set: updateDoc });
1173
+ return updatedResource;
1174
+ } catch (error) {
1175
+ throw new MastraError(
1176
+ {
1177
+ id: "STORAGE_MONGODB_STORE_UPDATE_RESOURCE_FAILED",
1178
+ domain: ErrorDomain.STORAGE,
1179
+ category: ErrorCategory.THIRD_PARTY,
1180
+ details: { resourceId }
1181
+ },
1182
+ error
1183
+ );
1184
+ }
1185
+ }
1186
+ async getThreadById({ threadId }) {
1187
+ try {
1188
+ const collection = await this.operations.getCollection(TABLE_THREADS);
1189
+ const result = await collection.findOne({ id: threadId });
1190
+ if (!result) {
1191
+ return null;
1192
+ }
1193
+ return {
1194
+ ...result,
1195
+ metadata: typeof result.metadata === "string" ? safelyParseJSON(result.metadata) : result.metadata
1196
+ };
1197
+ } catch (error) {
1198
+ throw new MastraError(
1199
+ {
1200
+ id: "STORAGE_MONGODB_STORE_GET_THREAD_BY_ID_FAILED",
1201
+ domain: ErrorDomain.STORAGE,
1202
+ category: ErrorCategory.THIRD_PARTY,
1203
+ details: { threadId }
1204
+ },
1205
+ error
1206
+ );
1207
+ }
1208
+ }
1209
+ async getThreadsByResourceId({ resourceId }) {
1210
+ try {
1211
+ const collection = await this.operations.getCollection(TABLE_THREADS);
1212
+ const results = await collection.find({ resourceId }).toArray();
1213
+ if (!results.length) {
1214
+ return [];
1215
+ }
1216
+ return results.map((result) => ({
1217
+ ...result,
1218
+ metadata: typeof result.metadata === "string" ? safelyParseJSON(result.metadata) : result.metadata
1219
+ }));
1220
+ } catch (error) {
1221
+ throw new MastraError(
1222
+ {
1223
+ id: "STORAGE_MONGODB_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED",
1224
+ domain: ErrorDomain.STORAGE,
1225
+ category: ErrorCategory.THIRD_PARTY,
1226
+ details: { resourceId }
1227
+ },
1228
+ error
1229
+ );
1230
+ }
1231
+ }
1232
+ async getThreadsByResourceIdPaginated(args) {
1233
+ try {
1234
+ const { resourceId, page, perPage } = args;
1235
+ const collection = await this.operations.getCollection(TABLE_THREADS);
1236
+ const query = { resourceId };
1237
+ const total = await collection.countDocuments(query);
1238
+ const threads = await collection.find(query).sort({ updatedAt: -1 }).skip(page * perPage).limit(perPage).toArray();
1239
+ return {
1240
+ threads: threads.map((thread) => ({
1241
+ id: thread.id,
1242
+ title: thread.title,
1243
+ resourceId: thread.resourceId,
1244
+ createdAt: formatDateForMongoDB(thread.createdAt),
1245
+ updatedAt: formatDateForMongoDB(thread.updatedAt),
1246
+ metadata: thread.metadata || {}
1247
+ })),
1248
+ total,
1249
+ page,
1250
+ perPage,
1251
+ hasMore: (page + 1) * perPage < total
1252
+ };
1253
+ } catch (error) {
1254
+ throw new MastraError(
1255
+ {
1256
+ id: "MONGODB_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
1257
+ domain: ErrorDomain.STORAGE,
1258
+ category: ErrorCategory.THIRD_PARTY,
1259
+ details: { resourceId: args.resourceId }
1260
+ },
1261
+ error
1262
+ );
1263
+ }
1264
+ }
1265
+ async saveThread({ thread }) {
1266
+ try {
1267
+ const collection = await this.operations.getCollection(TABLE_THREADS);
1268
+ await collection.updateOne(
1269
+ { id: thread.id },
1270
+ {
742
1271
  $set: {
743
1272
  ...thread,
744
- metadata: JSON.stringify(thread.metadata)
1273
+ metadata: thread.metadata
745
1274
  }
746
1275
  },
747
1276
  { upsert: true }
@@ -770,7 +1299,7 @@ var MongoDBStore = class extends MastraStorage {
770
1299
  id: "STORAGE_MONGODB_STORE_UPDATE_THREAD_NOT_FOUND",
771
1300
  domain: ErrorDomain.STORAGE,
772
1301
  category: ErrorCategory.THIRD_PARTY,
773
- details: { threadId: id },
1302
+ details: { threadId: id, status: 404 },
774
1303
  text: `Thread ${id} not found`
775
1304
  });
776
1305
  }
@@ -783,13 +1312,13 @@ var MongoDBStore = class extends MastraStorage {
783
1312
  }
784
1313
  };
785
1314
  try {
786
- const collection = await this.getCollection(TABLE_THREADS);
1315
+ const collection = await this.operations.getCollection(TABLE_THREADS);
787
1316
  await collection.updateOne(
788
1317
  { id },
789
1318
  {
790
1319
  $set: {
791
1320
  title,
792
- metadata: JSON.stringify(updatedThread.metadata)
1321
+ metadata: updatedThread.metadata
793
1322
  }
794
1323
  }
795
1324
  );
@@ -808,9 +1337,9 @@ var MongoDBStore = class extends MastraStorage {
808
1337
  }
809
1338
  async deleteThread({ threadId }) {
810
1339
  try {
811
- const collectionMessages = await this.getCollection(TABLE_MESSAGES);
1340
+ const collectionMessages = await this.operations.getCollection(TABLE_MESSAGES);
812
1341
  await collectionMessages.deleteMany({ thread_id: threadId });
813
- const collectionThreads = await this.getCollection(TABLE_THREADS);
1342
+ const collectionThreads = await this.operations.getCollection(TABLE_THREADS);
814
1343
  await collectionThreads.deleteOne({ id: threadId });
815
1344
  } catch (error) {
816
1345
  throw new MastraError(
@@ -824,124 +1353,461 @@ var MongoDBStore = class extends MastraStorage {
824
1353
  );
825
1354
  }
826
1355
  }
827
- async getMessages({
828
- threadId,
829
- selectBy,
830
- format
831
- }) {
1356
+ };
1357
+ var StoreOperationsMongoDB = class extends StoreOperations {
1358
+ #connector;
1359
+ constructor(config) {
1360
+ super();
1361
+ this.#connector = config.connector;
1362
+ }
1363
+ async getCollection(collectionName) {
1364
+ return this.#connector.getCollection(collectionName);
1365
+ }
1366
+ async hasColumn(_table, _column) {
1367
+ return true;
1368
+ }
1369
+ async createTable() {
1370
+ }
1371
+ async alterTable(_args) {
1372
+ }
1373
+ async clearTable({ tableName }) {
1374
+ try {
1375
+ const collection = await this.getCollection(tableName);
1376
+ await collection.deleteMany({});
1377
+ } catch (error) {
1378
+ if (error instanceof Error) {
1379
+ const matstraError = new MastraError(
1380
+ {
1381
+ id: "STORAGE_MONGODB_STORE_CLEAR_TABLE_FAILED",
1382
+ domain: ErrorDomain.STORAGE,
1383
+ category: ErrorCategory.THIRD_PARTY,
1384
+ details: { tableName }
1385
+ },
1386
+ error
1387
+ );
1388
+ this.logger.error(matstraError.message);
1389
+ this.logger?.trackException(matstraError);
1390
+ }
1391
+ }
1392
+ }
1393
+ async dropTable({ tableName }) {
832
1394
  try {
833
- const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
834
- const include = selectBy?.include || [];
835
- let messages = [];
836
- let allMessages = [];
837
- const collection = await this.getCollection(TABLE_MESSAGES);
838
- allMessages = (await collection.find({ thread_id: threadId }).sort({ createdAt: -1 }).toArray()).map(
839
- (row) => this.parseRow(row)
1395
+ const collection = await this.getCollection(tableName);
1396
+ await collection.drop();
1397
+ } catch (error) {
1398
+ if (error instanceof Error && error.message.includes("ns not found")) {
1399
+ return;
1400
+ }
1401
+ throw new MastraError(
1402
+ {
1403
+ id: "MONGODB_STORE_DROP_TABLE_FAILED",
1404
+ domain: ErrorDomain.STORAGE,
1405
+ category: ErrorCategory.THIRD_PARTY,
1406
+ details: { tableName }
1407
+ },
1408
+ error
840
1409
  );
841
- if (include.length) {
842
- const idToIndex = /* @__PURE__ */ new Map();
843
- allMessages.forEach((msg, idx) => {
844
- idToIndex.set(msg.id, idx);
845
- });
846
- const selectedIndexes = /* @__PURE__ */ new Set();
847
- for (const inc of include) {
848
- const idx = idToIndex.get(inc.id);
849
- if (idx === void 0) continue;
850
- for (let i = 1; i <= (inc.withPreviousMessages || 0); i++) {
851
- if (idx + i < allMessages.length) selectedIndexes.add(idx + i);
852
- }
853
- selectedIndexes.add(idx);
854
- for (let i = 1; i <= (inc.withNextMessages || 0); i++) {
855
- if (idx - i >= 0) selectedIndexes.add(idx - i);
1410
+ }
1411
+ }
1412
+ async insert({ tableName, record }) {
1413
+ try {
1414
+ const collection = await this.getCollection(tableName);
1415
+ const schema = TABLE_SCHEMAS[tableName];
1416
+ const recordToInsert = Object.fromEntries(
1417
+ Object.entries(schema).map(([key, value]) => {
1418
+ if (value.type === "jsonb" && record[key] && typeof record[key] === "string") {
1419
+ return [key, safelyParseJSON(record[key])];
856
1420
  }
857
- }
858
- messages.push(
859
- ...Array.from(selectedIndexes).map((i) => allMessages[i]).filter((m) => !!m)
1421
+ return [key, record[key]];
1422
+ })
1423
+ );
1424
+ await collection.insertOne(recordToInsert);
1425
+ } catch (error) {
1426
+ if (error instanceof Error) {
1427
+ const matstraError = new MastraError(
1428
+ {
1429
+ id: "STORAGE_MONGODB_STORE_INSERT_FAILED",
1430
+ domain: ErrorDomain.STORAGE,
1431
+ category: ErrorCategory.THIRD_PARTY,
1432
+ details: { tableName }
1433
+ },
1434
+ error
860
1435
  );
1436
+ this.logger.error(matstraError.message);
1437
+ this.logger?.trackException(matstraError);
861
1438
  }
862
- const excludeIds = new Set(messages.map((m) => m.id));
863
- for (const msg of allMessages) {
864
- if (messages.length >= limit) break;
865
- if (!excludeIds.has(msg.id)) {
866
- messages.push(msg);
867
- }
1439
+ }
1440
+ }
1441
+ async batchInsert({ tableName, records }) {
1442
+ if (!records.length) {
1443
+ return;
1444
+ }
1445
+ try {
1446
+ const collection = await this.getCollection(tableName);
1447
+ await collection.insertMany(records);
1448
+ } catch (error) {
1449
+ throw new MastraError(
1450
+ {
1451
+ id: "STORAGE_MONGODB_STORE_BATCH_INSERT_FAILED",
1452
+ domain: ErrorDomain.STORAGE,
1453
+ category: ErrorCategory.THIRD_PARTY,
1454
+ details: { tableName }
1455
+ },
1456
+ error
1457
+ );
1458
+ }
1459
+ }
1460
+ async load({ tableName, keys }) {
1461
+ this.logger.info(`Loading ${tableName} with keys ${JSON.stringify(keys)}`);
1462
+ try {
1463
+ const collection = await this.getCollection(tableName);
1464
+ return await collection.find(keys).toArray();
1465
+ } catch (error) {
1466
+ throw new MastraError(
1467
+ {
1468
+ id: "STORAGE_MONGODB_STORE_LOAD_FAILED",
1469
+ domain: ErrorDomain.STORAGE,
1470
+ category: ErrorCategory.THIRD_PARTY,
1471
+ details: { tableName }
1472
+ },
1473
+ error
1474
+ );
1475
+ }
1476
+ }
1477
+ };
1478
+ function transformScoreRow(row) {
1479
+ let scorerValue = null;
1480
+ if (row.scorer) {
1481
+ try {
1482
+ scorerValue = typeof row.scorer === "string" ? safelyParseJSON(row.scorer) : row.scorer;
1483
+ } catch (e) {
1484
+ console.warn("Failed to parse scorer:", e);
1485
+ }
1486
+ }
1487
+ let extractStepResultValue = null;
1488
+ if (row.extractStepResult) {
1489
+ try {
1490
+ extractStepResultValue = typeof row.extractStepResult === "string" ? safelyParseJSON(row.extractStepResult) : row.extractStepResult;
1491
+ } catch (e) {
1492
+ console.warn("Failed to parse extractStepResult:", e);
1493
+ }
1494
+ }
1495
+ let analyzeStepResultValue = null;
1496
+ if (row.analyzeStepResult) {
1497
+ try {
1498
+ analyzeStepResultValue = typeof row.analyzeStepResult === "string" ? safelyParseJSON(row.analyzeStepResult) : row.analyzeStepResult;
1499
+ } catch (e) {
1500
+ console.warn("Failed to parse analyzeStepResult:", e);
1501
+ }
1502
+ }
1503
+ let inputValue = null;
1504
+ if (row.input) {
1505
+ try {
1506
+ inputValue = typeof row.input === "string" ? safelyParseJSON(row.input) : row.input;
1507
+ } catch (e) {
1508
+ console.warn("Failed to parse input:", e);
1509
+ }
1510
+ }
1511
+ let outputValue = null;
1512
+ if (row.output) {
1513
+ try {
1514
+ outputValue = typeof row.output === "string" ? safelyParseJSON(row.output) : row.output;
1515
+ } catch (e) {
1516
+ console.warn("Failed to parse output:", e);
1517
+ }
1518
+ }
1519
+ let entityValue = null;
1520
+ if (row.entity) {
1521
+ try {
1522
+ entityValue = typeof row.entity === "string" ? safelyParseJSON(row.entity) : row.entity;
1523
+ } catch (e) {
1524
+ console.warn("Failed to parse entity:", e);
1525
+ }
1526
+ }
1527
+ let runtimeContextValue = null;
1528
+ if (row.runtimeContext) {
1529
+ try {
1530
+ runtimeContextValue = typeof row.runtimeContext === "string" ? safelyParseJSON(row.runtimeContext) : row.runtimeContext;
1531
+ } catch (e) {
1532
+ console.warn("Failed to parse runtimeContext:", e);
1533
+ }
1534
+ }
1535
+ return {
1536
+ id: row.id,
1537
+ entityId: row.entityId,
1538
+ entityType: row.entityType,
1539
+ scorerId: row.scorerId,
1540
+ traceId: row.traceId,
1541
+ runId: row.runId,
1542
+ scorer: scorerValue,
1543
+ extractStepResult: extractStepResultValue,
1544
+ analyzeStepResult: analyzeStepResultValue,
1545
+ score: row.score,
1546
+ reason: row.reason,
1547
+ extractPrompt: row.extractPrompt,
1548
+ analyzePrompt: row.analyzePrompt,
1549
+ reasonPrompt: row.reasonPrompt,
1550
+ input: inputValue,
1551
+ output: outputValue,
1552
+ additionalContext: row.additionalContext,
1553
+ runtimeContext: runtimeContextValue,
1554
+ entity: entityValue,
1555
+ source: row.source,
1556
+ resourceId: row.resourceId,
1557
+ threadId: row.threadId,
1558
+ createdAt: new Date(row.createdAt),
1559
+ updatedAt: new Date(row.updatedAt)
1560
+ };
1561
+ }
1562
+ var ScoresStorageMongoDB = class extends ScoresStorage {
1563
+ operations;
1564
+ constructor({ operations }) {
1565
+ super();
1566
+ this.operations = operations;
1567
+ }
1568
+ async getScoreById({ id }) {
1569
+ try {
1570
+ const collection = await this.operations.getCollection(TABLE_SCORERS);
1571
+ const document = await collection.findOne({ id });
1572
+ if (!document) {
1573
+ return null;
868
1574
  }
869
- messages.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
870
- const list = new MessageList().add(messages.slice(0, limit), "memory");
871
- if (format === `v2`) return list.get.all.v2();
872
- return list.get.all.v1();
1575
+ return transformScoreRow(document);
873
1576
  } catch (error) {
874
1577
  throw new MastraError(
875
1578
  {
876
- id: "STORAGE_MONGODB_STORE_GET_MESSAGES_FAILED",
1579
+ id: "STORAGE_MONGODB_STORE_GET_SCORE_BY_ID_FAILED",
877
1580
  domain: ErrorDomain.STORAGE,
878
1581
  category: ErrorCategory.THIRD_PARTY,
879
- details: { threadId }
1582
+ details: { id }
880
1583
  },
881
1584
  error
882
1585
  );
883
1586
  }
884
1587
  }
885
- async saveMessages({
886
- messages,
887
- format
1588
+ async saveScore(score) {
1589
+ try {
1590
+ const now = /* @__PURE__ */ new Date();
1591
+ const scoreId = `score-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1592
+ const scoreData = {
1593
+ id: scoreId,
1594
+ entityId: score.entityId,
1595
+ entityType: score.entityType,
1596
+ scorerId: score.scorerId,
1597
+ traceId: score.traceId || "",
1598
+ runId: score.runId,
1599
+ scorer: typeof score.scorer === "string" ? score.scorer : JSON.stringify(score.scorer),
1600
+ extractStepResult: typeof score.extractStepResult === "string" ? score.extractStepResult : JSON.stringify(score.extractStepResult),
1601
+ analyzeStepResult: typeof score.analyzeStepResult === "string" ? score.analyzeStepResult : JSON.stringify(score.analyzeStepResult),
1602
+ score: score.score,
1603
+ reason: score.reason,
1604
+ extractPrompt: score.extractPrompt,
1605
+ analyzePrompt: score.analyzePrompt,
1606
+ reasonPrompt: score.reasonPrompt,
1607
+ input: typeof score.input === "string" ? score.input : JSON.stringify(score.input),
1608
+ output: typeof score.output === "string" ? score.output : JSON.stringify(score.output),
1609
+ additionalContext: score.additionalContext,
1610
+ runtimeContext: typeof score.runtimeContext === "string" ? score.runtimeContext : JSON.stringify(score.runtimeContext),
1611
+ entity: typeof score.entity === "string" ? score.entity : JSON.stringify(score.entity),
1612
+ source: score.source,
1613
+ resourceId: score.resourceId || "",
1614
+ threadId: score.threadId || "",
1615
+ createdAt: now,
1616
+ updatedAt: now
1617
+ };
1618
+ const collection = await this.operations.getCollection(TABLE_SCORERS);
1619
+ await collection.insertOne(scoreData);
1620
+ const savedScore = {
1621
+ ...score,
1622
+ id: scoreId,
1623
+ createdAt: now,
1624
+ updatedAt: now
1625
+ };
1626
+ return { score: savedScore };
1627
+ } catch (error) {
1628
+ throw new MastraError(
1629
+ {
1630
+ id: "STORAGE_MONGODB_STORE_SAVE_SCORE_FAILED",
1631
+ domain: ErrorDomain.STORAGE,
1632
+ category: ErrorCategory.THIRD_PARTY,
1633
+ details: { scorerId: score.scorerId, runId: score.runId }
1634
+ },
1635
+ error
1636
+ );
1637
+ }
1638
+ }
1639
+ async getScoresByScorerId({
1640
+ scorerId,
1641
+ pagination,
1642
+ entityId,
1643
+ entityType
888
1644
  }) {
889
- if (!messages.length) {
890
- return messages;
1645
+ try {
1646
+ const query = { scorerId };
1647
+ if (entityId) {
1648
+ query.entityId = entityId;
1649
+ }
1650
+ if (entityType) {
1651
+ query.entityType = entityType;
1652
+ }
1653
+ const collection = await this.operations.getCollection(TABLE_SCORERS);
1654
+ const total = await collection.countDocuments(query);
1655
+ const currentOffset = pagination.page * pagination.perPage;
1656
+ if (total === 0) {
1657
+ return {
1658
+ scores: [],
1659
+ pagination: {
1660
+ total: 0,
1661
+ page: pagination.page,
1662
+ perPage: pagination.perPage,
1663
+ hasMore: false
1664
+ }
1665
+ };
1666
+ }
1667
+ const documents = await collection.find(query).sort({ createdAt: "desc" }).skip(currentOffset).limit(pagination.perPage).toArray();
1668
+ const scores = documents.map((row) => transformScoreRow(row));
1669
+ const hasMore = currentOffset + scores.length < total;
1670
+ return {
1671
+ scores,
1672
+ pagination: {
1673
+ total,
1674
+ page: pagination.page,
1675
+ perPage: pagination.perPage,
1676
+ hasMore
1677
+ }
1678
+ };
1679
+ } catch (error) {
1680
+ throw new MastraError(
1681
+ {
1682
+ id: "STORAGE_MONGODB_STORE_GET_SCORES_BY_SCORER_ID_FAILED",
1683
+ domain: ErrorDomain.STORAGE,
1684
+ category: ErrorCategory.THIRD_PARTY,
1685
+ details: { scorerId, page: pagination.page, perPage: pagination.perPage }
1686
+ },
1687
+ error
1688
+ );
891
1689
  }
892
- const threadId = messages[0]?.threadId;
893
- if (!threadId) {
894
- this.logger.error("Thread ID is required to save messages");
895
- throw new Error("Thread ID is required");
1690
+ }
1691
+ async getScoresByRunId({
1692
+ runId,
1693
+ pagination
1694
+ }) {
1695
+ try {
1696
+ const collection = await this.operations.getCollection(TABLE_SCORERS);
1697
+ const total = await collection.countDocuments({ runId });
1698
+ const currentOffset = pagination.page * pagination.perPage;
1699
+ if (total === 0) {
1700
+ return {
1701
+ scores: [],
1702
+ pagination: {
1703
+ total: 0,
1704
+ page: pagination.page,
1705
+ perPage: pagination.perPage,
1706
+ hasMore: false
1707
+ }
1708
+ };
1709
+ }
1710
+ const documents = await collection.find({ runId }).sort({ createdAt: "desc" }).skip(currentOffset).limit(pagination.perPage).toArray();
1711
+ const scores = documents.map((row) => transformScoreRow(row));
1712
+ const hasMore = currentOffset + scores.length < total;
1713
+ return {
1714
+ scores,
1715
+ pagination: {
1716
+ total,
1717
+ page: pagination.page,
1718
+ perPage: pagination.perPage,
1719
+ hasMore
1720
+ }
1721
+ };
1722
+ } catch (error) {
1723
+ throw new MastraError(
1724
+ {
1725
+ id: "STORAGE_MONGODB_STORE_GET_SCORES_BY_RUN_ID_FAILED",
1726
+ domain: ErrorDomain.STORAGE,
1727
+ category: ErrorCategory.THIRD_PARTY,
1728
+ details: { runId, page: pagination.page, perPage: pagination.perPage }
1729
+ },
1730
+ error
1731
+ );
896
1732
  }
1733
+ }
1734
+ async getScoresByEntityId({
1735
+ entityId,
1736
+ entityType,
1737
+ pagination
1738
+ }) {
897
1739
  try {
898
- const messagesToInsert = messages.map((message) => {
899
- const time = message.createdAt || /* @__PURE__ */ new Date();
1740
+ const collection = await this.operations.getCollection(TABLE_SCORERS);
1741
+ const total = await collection.countDocuments({ entityId, entityType });
1742
+ const currentOffset = pagination.page * pagination.perPage;
1743
+ if (total === 0) {
900
1744
  return {
901
- id: message.id,
902
- thread_id: threadId,
903
- content: typeof message.content === "string" ? message.content : JSON.stringify(message.content),
904
- role: message.role,
905
- type: message.type,
906
- resourceId: message.resourceId,
907
- createdAt: time instanceof Date ? time.toISOString() : time
1745
+ scores: [],
1746
+ pagination: {
1747
+ total: 0,
1748
+ page: pagination.page,
1749
+ perPage: pagination.perPage,
1750
+ hasMore: false
1751
+ }
908
1752
  };
909
- });
910
- const collection = await this.getCollection(TABLE_MESSAGES);
911
- const threadsCollection = await this.getCollection(TABLE_THREADS);
912
- await Promise.all([
913
- collection.bulkWrite(
914
- messagesToInsert.map((msg) => ({
915
- updateOne: {
916
- filter: { id: msg.id },
917
- update: { $set: msg },
918
- upsert: true
919
- }
920
- }))
921
- ),
922
- threadsCollection.updateOne({ id: threadId }, { $set: { updatedAt: /* @__PURE__ */ new Date() } })
923
- ]);
924
- const list = new MessageList().add(messages, "memory");
925
- if (format === `v2`) return list.get.all.v2();
926
- return list.get.all.v1();
1753
+ }
1754
+ const documents = await collection.find({ entityId, entityType }).sort({ createdAt: "desc" }).skip(currentOffset).limit(pagination.perPage).toArray();
1755
+ const scores = documents.map((row) => transformScoreRow(row));
1756
+ const hasMore = currentOffset + scores.length < total;
1757
+ return {
1758
+ scores,
1759
+ pagination: {
1760
+ total,
1761
+ page: pagination.page,
1762
+ perPage: pagination.perPage,
1763
+ hasMore
1764
+ }
1765
+ };
1766
+ } catch (error) {
1767
+ throw new MastraError(
1768
+ {
1769
+ id: "STORAGE_MONGODB_STORE_GET_SCORES_BY_ENTITY_ID_FAILED",
1770
+ domain: ErrorDomain.STORAGE,
1771
+ category: ErrorCategory.THIRD_PARTY,
1772
+ details: { entityId, entityType, page: pagination.page, perPage: pagination.perPage }
1773
+ },
1774
+ error
1775
+ );
1776
+ }
1777
+ }
1778
+ };
1779
+ var TracesStorageMongoDB = class extends TracesStorage {
1780
+ operations;
1781
+ constructor({ operations }) {
1782
+ super();
1783
+ this.operations = operations;
1784
+ }
1785
+ async getTraces(args) {
1786
+ if (args.fromDate || args.toDate) {
1787
+ args.dateRange = {
1788
+ start: args.fromDate,
1789
+ end: args.toDate
1790
+ };
1791
+ }
1792
+ try {
1793
+ const result = await this.getTracesPaginated(args);
1794
+ return result.traces;
927
1795
  } catch (error) {
928
- this.logger.error("Failed to save messages in database: " + error?.message);
929
- throw error;
930
- }
931
- }
932
- async getTraces({
933
- name,
934
- scope,
935
- page,
936
- perPage,
937
- attributes,
938
- filters
939
- } = {
940
- page: 0,
941
- perPage: 100
942
- }) {
943
- const limit = perPage;
944
- const offset = page * perPage;
1796
+ throw new MastraError(
1797
+ {
1798
+ id: "STORAGE_MONGODB_STORE_GET_TRACES_FAILED",
1799
+ domain: ErrorDomain.STORAGE,
1800
+ category: ErrorCategory.THIRD_PARTY
1801
+ },
1802
+ error
1803
+ );
1804
+ }
1805
+ }
1806
+ async getTracesPaginated(args) {
1807
+ const { name, scope, page = 0, perPage = 100, attributes, filters, dateRange } = args;
1808
+ const fromDate = dateRange?.start;
1809
+ const toDate = dateRange?.end;
1810
+ const currentOffset = page * perPage;
945
1811
  const query = {};
946
1812
  if (name) {
947
1813
  query["name"] = new RegExp(name);
@@ -951,7 +1817,7 @@ var MongoDBStore = class extends MastraStorage {
951
1817
  }
952
1818
  if (attributes) {
953
1819
  query["$and"] = Object.entries(attributes).map(([key, value]) => ({
954
- attributes: new RegExp(`"${key}":"${value}"`)
1820
+ [`attributes.${key}`]: value
955
1821
  }));
956
1822
  }
957
1823
  if (filters) {
@@ -959,12 +1825,31 @@ var MongoDBStore = class extends MastraStorage {
959
1825
  query[key] = value;
960
1826
  });
961
1827
  }
1828
+ if (fromDate || toDate) {
1829
+ query["createdAt"] = {};
1830
+ if (fromDate) {
1831
+ query["createdAt"]["$gte"] = fromDate;
1832
+ }
1833
+ if (toDate) {
1834
+ query["createdAt"]["$lte"] = toDate;
1835
+ }
1836
+ }
962
1837
  try {
963
- const collection = await this.getCollection(TABLE_TRACES);
1838
+ const collection = await this.operations.getCollection(TABLE_TRACES);
1839
+ const total = await collection.countDocuments(query);
1840
+ if (total === 0) {
1841
+ return {
1842
+ traces: [],
1843
+ total: 0,
1844
+ page,
1845
+ perPage,
1846
+ hasMore: false
1847
+ };
1848
+ }
964
1849
  const result = await collection.find(query, {
965
1850
  sort: { startTime: -1 }
966
- }).limit(limit).skip(offset).toArray();
967
- return result.map((row) => ({
1851
+ }).limit(perPage).skip(currentOffset).toArray();
1852
+ const traces = result.map((row) => ({
968
1853
  id: row.id,
969
1854
  parentSpanId: row.parentSpanId,
970
1855
  traceId: row.traceId,
@@ -980,10 +1865,17 @@ var MongoDBStore = class extends MastraStorage {
980
1865
  other: safelyParseJSON(row.other),
981
1866
  createdAt: row.createdAt
982
1867
  }));
1868
+ return {
1869
+ traces,
1870
+ total,
1871
+ page,
1872
+ perPage,
1873
+ hasMore: currentOffset + traces.length < total
1874
+ };
983
1875
  } catch (error) {
984
1876
  throw new MastraError(
985
1877
  {
986
- id: "STORAGE_MONGODB_STORE_GET_TRACES_FAILED",
1878
+ id: "STORAGE_MONGODB_STORE_GET_TRACES_PAGINATED_FAILED",
987
1879
  domain: ErrorDomain.STORAGE,
988
1880
  category: ErrorCategory.THIRD_PARTY
989
1881
  },
@@ -991,106 +1883,19 @@ var MongoDBStore = class extends MastraStorage {
991
1883
  );
992
1884
  }
993
1885
  }
994
- async getWorkflowRuns({
995
- workflowName,
996
- fromDate,
997
- toDate,
998
- limit,
999
- offset
1000
- } = {}) {
1001
- const query = {};
1002
- if (workflowName) {
1003
- query["workflow_name"] = workflowName;
1004
- }
1005
- if (fromDate || toDate) {
1006
- query["createdAt"] = {};
1007
- if (fromDate) {
1008
- query["createdAt"]["$gte"] = fromDate;
1009
- }
1010
- if (toDate) {
1011
- query["createdAt"]["$lte"] = toDate;
1012
- }
1013
- }
1014
- try {
1015
- const collection = await this.getCollection(TABLE_WORKFLOW_SNAPSHOT);
1016
- let total = 0;
1017
- if (limit !== void 0 && offset !== void 0) {
1018
- total = await collection.countDocuments(query);
1019
- }
1020
- const request = collection.find(query).sort({ createdAt: "desc" });
1021
- if (limit) {
1022
- request.limit(limit);
1023
- }
1024
- if (offset) {
1025
- request.skip(offset);
1026
- }
1027
- const result = await request.toArray();
1028
- const runs = result.map((row) => {
1029
- let parsedSnapshot = row.snapshot;
1030
- if (typeof parsedSnapshot === "string") {
1031
- try {
1032
- parsedSnapshot = JSON.parse(row.snapshot);
1033
- } catch (e) {
1034
- console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
1035
- }
1036
- }
1037
- return {
1038
- workflowName: row.workflow_name,
1039
- runId: row.run_id,
1040
- snapshot: parsedSnapshot,
1041
- createdAt: new Date(row.createdAt),
1042
- updatedAt: new Date(row.updatedAt)
1043
- };
1044
- });
1045
- return { runs, total: total || runs.length };
1046
- } catch (error) {
1047
- throw new MastraError(
1048
- {
1049
- id: "STORAGE_MONGODB_STORE_GET_WORKFLOW_RUNS_FAILED",
1050
- domain: ErrorDomain.STORAGE,
1051
- category: ErrorCategory.THIRD_PARTY
1052
- },
1053
- error
1054
- );
1055
- }
1886
+ async batchTraceInsert({ records }) {
1887
+ this.logger.debug("Batch inserting traces", { count: records.length });
1888
+ await this.operations.batchInsert({
1889
+ tableName: TABLE_TRACES,
1890
+ records
1891
+ });
1056
1892
  }
1057
- async getEvalsByAgentName(agentName, type) {
1058
- try {
1059
- const query = {
1060
- agent_name: agentName
1061
- };
1062
- if (type === "test") {
1063
- query["test_info"] = { $ne: null };
1064
- }
1065
- if (type === "live") {
1066
- query["test_info"] = null;
1067
- }
1068
- const collection = await this.getCollection(TABLE_EVALS);
1069
- const documents = await collection.find(query).sort({ created_at: "desc" }).toArray();
1070
- const result = documents.map((row) => this.transformEvalRow(row));
1071
- return result.filter((row) => {
1072
- if (type === "live") {
1073
- return !Boolean(row.testInfo?.testPath);
1074
- }
1075
- if (type === "test") {
1076
- return row.testInfo?.testPath !== null;
1077
- }
1078
- return true;
1079
- });
1080
- } catch (error) {
1081
- if (error instanceof Error && error.message.includes("no such table")) {
1082
- return [];
1083
- }
1084
- throw new MastraError(
1085
- {
1086
- id: "STORAGE_MONGODB_STORE_GET_EVALS_BY_AGENT_NAME_FAILED",
1087
- domain: ErrorDomain.STORAGE,
1088
- category: ErrorCategory.THIRD_PARTY,
1089
- details: { agentName }
1090
- },
1091
- error
1092
- );
1093
- }
1893
+ };
1894
+ var WorkflowsStorageMongoDB = class extends WorkflowsStorage {
1895
+ operations;
1896
+ constructor({ operations }) {
1897
+ super();
1898
+ this.operations = operations;
1094
1899
  }
1095
1900
  async persistWorkflowSnapshot({
1096
1901
  workflowName,
@@ -1098,17 +1903,16 @@ var MongoDBStore = class extends MastraStorage {
1098
1903
  snapshot
1099
1904
  }) {
1100
1905
  try {
1101
- const now = (/* @__PURE__ */ new Date()).toISOString();
1102
- const collection = await this.getCollection(TABLE_WORKFLOW_SNAPSHOT);
1906
+ const collection = await this.operations.getCollection(TABLE_WORKFLOW_SNAPSHOT);
1103
1907
  await collection.updateOne(
1104
1908
  { workflow_name: workflowName, run_id: runId },
1105
1909
  {
1106
1910
  $set: {
1107
- snapshot: JSON.stringify(snapshot),
1108
- updatedAt: now
1109
- },
1110
- $setOnInsert: {
1111
- createdAt: now
1911
+ workflow_name: workflowName,
1912
+ run_id: runId,
1913
+ snapshot,
1914
+ createdAt: /* @__PURE__ */ new Date(),
1915
+ updatedAt: /* @__PURE__ */ new Date()
1112
1916
  }
1113
1917
  },
1114
1918
  { upsert: true }
@@ -1130,7 +1934,7 @@ var MongoDBStore = class extends MastraStorage {
1130
1934
  runId
1131
1935
  }) {
1132
1936
  try {
1133
- const result = await this.load({
1937
+ const result = await this.operations.load({
1134
1938
  tableName: TABLE_WORKFLOW_SNAPSHOT,
1135
1939
  keys: {
1136
1940
  workflow_name: workflowName,
@@ -1140,7 +1944,7 @@ var MongoDBStore = class extends MastraStorage {
1140
1944
  if (!result?.length) {
1141
1945
  return null;
1142
1946
  }
1143
- return JSON.parse(result[0].snapshot);
1947
+ return typeof result[0].snapshot === "string" ? safelyParseJSON(result[0].snapshot) : result[0].snapshot;
1144
1948
  } catch (error) {
1145
1949
  throw new MastraError(
1146
1950
  {
@@ -1153,19 +1957,63 @@ var MongoDBStore = class extends MastraStorage {
1153
1957
  );
1154
1958
  }
1155
1959
  }
1156
- async getWorkflowRunById({
1157
- runId,
1158
- workflowName
1159
- }) {
1960
+ async getWorkflowRuns(args) {
1961
+ const options = args || {};
1962
+ try {
1963
+ const query = {};
1964
+ if (options.workflowName) {
1965
+ query["workflow_name"] = options.workflowName;
1966
+ }
1967
+ if (options.fromDate) {
1968
+ query["createdAt"] = { $gte: options.fromDate };
1969
+ }
1970
+ if (options.toDate) {
1971
+ if (query["createdAt"]) {
1972
+ query["createdAt"].$lte = options.toDate;
1973
+ } else {
1974
+ query["createdAt"] = { $lte: options.toDate };
1975
+ }
1976
+ }
1977
+ if (options.resourceId) {
1978
+ query["resourceId"] = options.resourceId;
1979
+ }
1980
+ const collection = await this.operations.getCollection(TABLE_WORKFLOW_SNAPSHOT);
1981
+ const total = await collection.countDocuments(query);
1982
+ let cursor = collection.find(query).sort({ createdAt: -1 });
1983
+ if (options.offset) {
1984
+ cursor = cursor.skip(options.offset);
1985
+ }
1986
+ if (options.limit) {
1987
+ cursor = cursor.limit(options.limit);
1988
+ }
1989
+ const results = await cursor.toArray();
1990
+ const runs = results.map((row) => this.parseWorkflowRun(row));
1991
+ return {
1992
+ runs,
1993
+ total
1994
+ };
1995
+ } catch (error) {
1996
+ throw new MastraError(
1997
+ {
1998
+ id: "STORAGE_MONGODB_STORE_GET_WORKFLOW_RUNS_FAILED",
1999
+ domain: ErrorDomain.STORAGE,
2000
+ category: ErrorCategory.THIRD_PARTY,
2001
+ details: { workflowName: options.workflowName || "unknown" }
2002
+ },
2003
+ error
2004
+ );
2005
+ }
2006
+ }
2007
+ async getWorkflowRunById(args) {
1160
2008
  try {
1161
2009
  const query = {};
1162
- if (runId) {
1163
- query["run_id"] = runId;
2010
+ if (args.runId) {
2011
+ query["run_id"] = args.runId;
1164
2012
  }
1165
- if (workflowName) {
1166
- query["workflow_name"] = workflowName;
2013
+ if (args.workflowName) {
2014
+ query["workflow_name"] = args.workflowName;
1167
2015
  }
1168
- const collection = await this.getCollection(TABLE_WORKFLOW_SNAPSHOT);
2016
+ const collection = await this.operations.getCollection(TABLE_WORKFLOW_SNAPSHOT);
1169
2017
  const result = await collection.findOne(query);
1170
2018
  if (!result) {
1171
2019
  return null;
@@ -1177,7 +2025,7 @@ var MongoDBStore = class extends MastraStorage {
1177
2025
  id: "STORAGE_MONGODB_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
1178
2026
  domain: ErrorDomain.STORAGE,
1179
2027
  category: ErrorCategory.THIRD_PARTY,
1180
- details: { runId }
2028
+ details: { runId: args.runId }
1181
2029
  },
1182
2030
  error
1183
2031
  );
@@ -1187,7 +2035,7 @@ var MongoDBStore = class extends MastraStorage {
1187
2035
  let parsedSnapshot = row.snapshot;
1188
2036
  if (typeof parsedSnapshot === "string") {
1189
2037
  try {
1190
- parsedSnapshot = JSON.parse(row.snapshot);
2038
+ parsedSnapshot = typeof row.snapshot === "string" ? safelyParseJSON(row.snapshot) : row.snapshot;
1191
2039
  } catch (e) {
1192
2040
  console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
1193
2041
  }
@@ -1196,85 +2044,187 @@ var MongoDBStore = class extends MastraStorage {
1196
2044
  workflowName: row.workflow_name,
1197
2045
  runId: row.run_id,
1198
2046
  snapshot: parsedSnapshot,
1199
- createdAt: row.createdAt,
1200
- updatedAt: row.updatedAt,
2047
+ createdAt: new Date(row.createdAt),
2048
+ updatedAt: new Date(row.updatedAt),
1201
2049
  resourceId: row.resourceId
1202
2050
  };
1203
2051
  }
1204
- parseRow(row) {
1205
- let content = row.content;
1206
- try {
1207
- content = JSON.parse(row.content);
1208
- } catch {
1209
- }
2052
+ };
2053
+
2054
+ // src/storage/index.ts
2055
+ var MongoDBStore = class extends MastraStorage {
2056
+ #connector;
2057
+ stores;
2058
+ get supports() {
1210
2059
  return {
1211
- id: row.id,
1212
- content,
1213
- role: row.role,
1214
- type: row.type,
1215
- createdAt: new Date(row.createdAt),
1216
- threadId: row.thread_id,
1217
- resourceId: row.resourceId
2060
+ selectByIncludeResourceScope: true,
2061
+ resourceWorkingMemory: true,
2062
+ hasColumn: false,
2063
+ createTable: false
1218
2064
  };
1219
2065
  }
1220
- transformEvalRow(row) {
1221
- let testInfoValue = null;
1222
- if (row.test_info) {
1223
- try {
1224
- testInfoValue = typeof row.test_info === "string" ? JSON.parse(row.test_info) : row.test_info;
1225
- } catch (e) {
1226
- console.warn("Failed to parse test_info:", e);
2066
+ constructor(config) {
2067
+ super({ name: "MongoDBStore" });
2068
+ this.stores = {};
2069
+ try {
2070
+ if ("connectorHandler" in config) {
2071
+ this.#connector = MongoDBConnector.fromConnectionHandler(config.connectorHandler);
2072
+ return;
1227
2073
  }
2074
+ } catch (error) {
2075
+ throw new MastraError(
2076
+ {
2077
+ id: "STORAGE_MONGODB_STORE_CONSTRUCTOR_FAILED",
2078
+ domain: ErrorDomain.STORAGE,
2079
+ category: ErrorCategory.USER,
2080
+ details: { connectionHandler: true }
2081
+ },
2082
+ error
2083
+ );
1228
2084
  }
1229
- const resultValue = JSON.parse(row.result);
1230
- if (!resultValue || typeof resultValue !== "object" || !("score" in resultValue)) {
1231
- throw new MastraError({
1232
- id: "STORAGE_MONGODB_STORE_INVALID_METRIC_FORMAT",
1233
- text: `Invalid MetricResult format: ${JSON.stringify(resultValue)}`,
1234
- domain: ErrorDomain.STORAGE,
1235
- category: ErrorCategory.USER
2085
+ try {
2086
+ this.#connector = MongoDBConnector.fromDatabaseConfig({
2087
+ options: config.options,
2088
+ url: config.url,
2089
+ dbName: config.dbName
1236
2090
  });
2091
+ } catch (error) {
2092
+ throw new MastraError(
2093
+ {
2094
+ id: "STORAGE_MONGODB_STORE_CONSTRUCTOR_FAILED",
2095
+ domain: ErrorDomain.STORAGE,
2096
+ category: ErrorCategory.USER,
2097
+ details: { url: config?.url, dbName: config?.dbName }
2098
+ },
2099
+ error
2100
+ );
1237
2101
  }
1238
- return {
1239
- input: row.input,
1240
- output: row.output,
1241
- result: resultValue,
1242
- agentName: row.agent_name,
1243
- metricName: row.metric_name,
1244
- instructions: row.instructions,
1245
- testInfo: testInfoValue,
1246
- globalRunId: row.global_run_id,
1247
- runId: row.run_id,
1248
- createdAt: row.created_at
2102
+ const operations = new StoreOperationsMongoDB({
2103
+ connector: this.#connector
2104
+ });
2105
+ const memory = new MemoryStorageMongoDB({
2106
+ operations
2107
+ });
2108
+ const traces = new TracesStorageMongoDB({
2109
+ operations
2110
+ });
2111
+ const legacyEvals = new LegacyEvalsMongoDB({
2112
+ operations
2113
+ });
2114
+ const scores = new ScoresStorageMongoDB({
2115
+ operations
2116
+ });
2117
+ const workflows = new WorkflowsStorageMongoDB({
2118
+ operations
2119
+ });
2120
+ this.stores = {
2121
+ operations,
2122
+ memory,
2123
+ traces,
2124
+ legacyEvals,
2125
+ scores,
2126
+ workflows
1249
2127
  };
1250
2128
  }
1251
- async getTracesPaginated(_args) {
1252
- throw new MastraError({
1253
- id: "STORAGE_MONGODB_STORE_GET_TRACES_PAGINATED_FAILED",
1254
- domain: ErrorDomain.STORAGE,
1255
- category: ErrorCategory.THIRD_PARTY,
1256
- text: "Method not implemented."
1257
- });
2129
+ async createTable({
2130
+ tableName,
2131
+ schema
2132
+ }) {
2133
+ return this.stores.operations.createTable({ tableName, schema });
2134
+ }
2135
+ async alterTable(_args) {
2136
+ return this.stores.operations.alterTable(_args);
2137
+ }
2138
+ async dropTable({ tableName }) {
2139
+ return this.stores.operations.dropTable({ tableName });
2140
+ }
2141
+ async clearTable({ tableName }) {
2142
+ return this.stores.operations.clearTable({ tableName });
2143
+ }
2144
+ async insert({ tableName, record }) {
2145
+ return this.stores.operations.insert({ tableName, record });
2146
+ }
2147
+ async batchInsert({ tableName, records }) {
2148
+ return this.stores.operations.batchInsert({ tableName, records });
2149
+ }
2150
+ async load({ tableName, keys }) {
2151
+ return this.stores.operations.load({ tableName, keys });
2152
+ }
2153
+ async getThreadById({ threadId }) {
2154
+ return this.stores.memory.getThreadById({ threadId });
2155
+ }
2156
+ async getThreadsByResourceId({ resourceId }) {
2157
+ return this.stores.memory.getThreadsByResourceId({ resourceId });
2158
+ }
2159
+ async saveThread({ thread }) {
2160
+ return this.stores.memory.saveThread({ thread });
2161
+ }
2162
+ async updateThread({
2163
+ id,
2164
+ title,
2165
+ metadata
2166
+ }) {
2167
+ return this.stores.memory.updateThread({ id, title, metadata });
2168
+ }
2169
+ async deleteThread({ threadId }) {
2170
+ return this.stores.memory.deleteThread({ threadId });
2171
+ }
2172
+ async getMessages({
2173
+ threadId,
2174
+ selectBy,
2175
+ format
2176
+ }) {
2177
+ return this.stores.memory.getMessages({ threadId, selectBy, format });
2178
+ }
2179
+ async saveMessages(args) {
2180
+ return this.stores.memory.saveMessages(args);
1258
2181
  }
1259
2182
  async getThreadsByResourceIdPaginated(_args) {
1260
- throw new MastraError({
1261
- id: "STORAGE_MONGODB_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
1262
- domain: ErrorDomain.STORAGE,
1263
- category: ErrorCategory.THIRD_PARTY,
1264
- text: "Method not implemented."
1265
- });
2183
+ return this.stores.memory.getThreadsByResourceIdPaginated(_args);
1266
2184
  }
1267
2185
  async getMessagesPaginated(_args) {
1268
- throw new MastraError({
1269
- id: "STORAGE_MONGODB_STORE_GET_MESSAGES_PAGINATED_FAILED",
1270
- domain: ErrorDomain.STORAGE,
1271
- category: ErrorCategory.THIRD_PARTY,
1272
- text: "Method not implemented."
1273
- });
2186
+ return this.stores.memory.getMessagesPaginated(_args);
2187
+ }
2188
+ async updateMessages(_args) {
2189
+ return this.stores.memory.updateMessages(_args);
2190
+ }
2191
+ async getTraces(args) {
2192
+ return this.stores.traces.getTraces(args);
2193
+ }
2194
+ async getTracesPaginated(args) {
2195
+ return this.stores.traces.getTracesPaginated(args);
2196
+ }
2197
+ async getWorkflowRuns(args) {
2198
+ return this.stores.workflows.getWorkflowRuns(args);
2199
+ }
2200
+ async getEvals(options = {}) {
2201
+ return this.stores.legacyEvals.getEvals(options);
2202
+ }
2203
+ async getEvalsByAgentName(agentName, type) {
2204
+ return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
2205
+ }
2206
+ async persistWorkflowSnapshot({
2207
+ workflowName,
2208
+ runId,
2209
+ snapshot
2210
+ }) {
2211
+ return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
2212
+ }
2213
+ async loadWorkflowSnapshot({
2214
+ workflowName,
2215
+ runId
2216
+ }) {
2217
+ return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
2218
+ }
2219
+ async getWorkflowRunById({
2220
+ runId,
2221
+ workflowName
2222
+ }) {
2223
+ return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
1274
2224
  }
1275
2225
  async close() {
1276
2226
  try {
1277
- await this.#client.close();
2227
+ await this.#connector.close();
1278
2228
  } catch (error) {
1279
2229
  throw new MastraError(
1280
2230
  {
@@ -1286,9 +2236,55 @@ var MongoDBStore = class extends MastraStorage {
1286
2236
  );
1287
2237
  }
1288
2238
  }
1289
- async updateMessages(_args) {
1290
- this.logger.error("updateMessages is not yet implemented in MongoDBStore");
1291
- throw new Error("Method not implemented");
2239
+ /**
2240
+ * SCORERS
2241
+ */
2242
+ async getScoreById({ id }) {
2243
+ return this.stores.scores.getScoreById({ id });
2244
+ }
2245
+ async saveScore(score) {
2246
+ return this.stores.scores.saveScore(score);
2247
+ }
2248
+ async getScoresByRunId({
2249
+ runId,
2250
+ pagination
2251
+ }) {
2252
+ return this.stores.scores.getScoresByRunId({ runId, pagination });
2253
+ }
2254
+ async getScoresByEntityId({
2255
+ entityId,
2256
+ entityType,
2257
+ pagination
2258
+ }) {
2259
+ return this.stores.scores.getScoresByEntityId({ entityId, entityType, pagination });
2260
+ }
2261
+ async getScoresByScorerId({
2262
+ scorerId,
2263
+ pagination,
2264
+ entityId,
2265
+ entityType
2266
+ }) {
2267
+ return this.stores.scores.getScoresByScorerId({ scorerId, pagination, entityId, entityType });
2268
+ }
2269
+ /**
2270
+ * RESOURCES
2271
+ */
2272
+ async getResourceById({ resourceId }) {
2273
+ return this.stores.memory.getResourceById({ resourceId });
2274
+ }
2275
+ async saveResource({ resource }) {
2276
+ return this.stores.memory.saveResource({ resource });
2277
+ }
2278
+ async updateResource({
2279
+ resourceId,
2280
+ workingMemory,
2281
+ metadata
2282
+ }) {
2283
+ return this.stores.memory.updateResource({
2284
+ resourceId,
2285
+ workingMemory,
2286
+ metadata
2287
+ });
1292
2288
  }
1293
2289
  };
1294
2290