@mastra/dynamodb 0.0.0-share-agent-metadata-with-cloud-20250718123411 → 0.0.0-span-scorring-test-20251124132129

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 (51) hide show
  1. package/CHANGELOG.md +1484 -0
  2. package/README.md +0 -4
  3. package/dist/entities/eval.d.ts +102 -0
  4. package/dist/entities/eval.d.ts.map +1 -0
  5. package/dist/entities/index.d.ts +761 -0
  6. package/dist/entities/index.d.ts.map +1 -0
  7. package/dist/entities/message.d.ts +100 -0
  8. package/dist/entities/message.d.ts.map +1 -0
  9. package/dist/entities/resource.d.ts +54 -0
  10. package/dist/entities/resource.d.ts.map +1 -0
  11. package/dist/entities/score.d.ts +244 -0
  12. package/dist/entities/score.d.ts.map +1 -0
  13. package/dist/entities/thread.d.ts +69 -0
  14. package/dist/entities/thread.d.ts.map +1 -0
  15. package/dist/entities/trace.d.ts +127 -0
  16. package/dist/entities/trace.d.ts.map +1 -0
  17. package/dist/entities/utils.d.ts +21 -0
  18. package/dist/entities/utils.d.ts.map +1 -0
  19. package/dist/entities/workflow-snapshot.d.ts +74 -0
  20. package/dist/entities/workflow-snapshot.d.ts.map +1 -0
  21. package/dist/index.cjs +1754 -566
  22. package/dist/index.cjs.map +1 -0
  23. package/dist/index.d.ts +2 -2
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +1755 -567
  26. package/dist/index.js.map +1 -0
  27. package/dist/storage/domains/memory/index.d.ts +61 -0
  28. package/dist/storage/domains/memory/index.d.ts.map +1 -0
  29. package/dist/storage/domains/operations/index.d.ts +69 -0
  30. package/dist/storage/domains/operations/index.d.ts.map +1 -0
  31. package/dist/storage/domains/score/index.d.ts +51 -0
  32. package/dist/storage/domains/score/index.d.ts.map +1 -0
  33. package/dist/storage/domains/workflows/index.d.ts +44 -0
  34. package/dist/storage/domains/workflows/index.d.ts.map +1 -0
  35. package/dist/storage/index.d.ts +204 -0
  36. package/dist/storage/index.d.ts.map +1 -0
  37. package/package.json +31 -18
  38. package/dist/_tsup-dts-rollup.d.cts +0 -1160
  39. package/dist/_tsup-dts-rollup.d.ts +0 -1160
  40. package/dist/index.d.cts +0 -2
  41. package/src/entities/eval.ts +0 -102
  42. package/src/entities/index.ts +0 -23
  43. package/src/entities/message.ts +0 -143
  44. package/src/entities/thread.ts +0 -66
  45. package/src/entities/trace.ts +0 -129
  46. package/src/entities/utils.ts +0 -51
  47. package/src/entities/workflow-snapshot.ts +0 -56
  48. package/src/index.ts +0 -1
  49. package/src/storage/docker-compose.yml +0 -16
  50. package/src/storage/index.test.ts +0 -1483
  51. package/src/storage/index.ts +0 -1383
package/dist/index.cjs CHANGED
@@ -2,10 +2,11 @@
2
2
 
3
3
  var clientDynamodb = require('@aws-sdk/client-dynamodb');
4
4
  var libDynamodb = require('@aws-sdk/lib-dynamodb');
5
- var agent = require('@mastra/core/agent');
6
5
  var error = require('@mastra/core/error');
7
6
  var storage = require('@mastra/core/storage');
8
7
  var electrodb = require('electrodb');
8
+ var agent = require('@mastra/core/agent');
9
+ var evals = require('@mastra/core/evals');
9
10
 
10
11
  // src/storage/index.ts
11
12
 
@@ -296,9 +297,9 @@ var messageEntity = new electrodb.Entity({
296
297
  }
297
298
  }
298
299
  });
299
- var threadEntity = new electrodb.Entity({
300
+ var resourceEntity = new electrodb.Entity({
300
301
  model: {
301
- entity: "thread",
302
+ entity: "resource",
302
303
  version: "1",
303
304
  service: "mastra"
304
305
  },
@@ -312,25 +313,21 @@ var threadEntity = new electrodb.Entity({
312
313
  type: "string",
313
314
  required: true
314
315
  },
315
- resourceId: {
316
- type: "string",
317
- required: true
318
- },
319
- title: {
316
+ workingMemory: {
320
317
  type: "string",
321
- required: true
318
+ required: false
322
319
  },
323
320
  metadata: {
324
321
  type: "string",
325
322
  required: false,
326
- // Stringify metadata object on set if it's not already a string
323
+ // Stringify content object on set if it's not already a string
327
324
  set: (value) => {
328
325
  if (value && typeof value !== "string") {
329
326
  return JSON.stringify(value);
330
327
  }
331
328
  return value;
332
329
  },
333
- // Parse JSON string to object on get
330
+ // Parse JSON string to object on get ONLY if it looks like JSON
334
331
  get: (value) => {
335
332
  if (value && typeof value === "string") {
336
333
  try {
@@ -348,18 +345,13 @@ var threadEntity = new electrodb.Entity({
348
345
  indexes: {
349
346
  primary: {
350
347
  pk: { field: "pk", composite: ["entity", "id"] },
351
- sk: { field: "sk", composite: ["id"] }
352
- },
353
- byResource: {
354
- index: "gsi1",
355
- pk: { field: "gsi1pk", composite: ["entity", "resourceId"] },
356
- sk: { field: "gsi1sk", composite: ["createdAt"] }
348
+ sk: { field: "sk", composite: ["entity"] }
357
349
  }
358
350
  }
359
351
  });
360
- var traceEntity = new electrodb.Entity({
352
+ var scoreEntity = new electrodb.Entity({
361
353
  model: {
362
- entity: "trace",
354
+ entity: "score",
363
355
  version: "1",
364
356
  service: "mastra"
365
357
  },
@@ -373,123 +365,315 @@ var traceEntity = new electrodb.Entity({
373
365
  type: "string",
374
366
  required: true
375
367
  },
376
- parentSpanId: {
368
+ scorerId: {
369
+ type: "string",
370
+ required: true
371
+ },
372
+ traceId: {
377
373
  type: "string",
378
374
  required: false
379
375
  },
380
- name: {
376
+ spanId: {
381
377
  type: "string",
382
- required: true
378
+ required: false
383
379
  },
384
- traceId: {
380
+ runId: {
385
381
  type: "string",
386
382
  required: true
387
383
  },
388
- scope: {
384
+ scorer: {
389
385
  type: "string",
390
- required: true
386
+ required: true,
387
+ set: (value) => {
388
+ if (value && typeof value !== "string") {
389
+ return JSON.stringify(value);
390
+ }
391
+ return value;
392
+ },
393
+ get: (value) => {
394
+ if (value && typeof value === "string") {
395
+ try {
396
+ if (value.startsWith("{") || value.startsWith("[")) {
397
+ return JSON.parse(value);
398
+ }
399
+ } catch {
400
+ return value;
401
+ }
402
+ }
403
+ return value;
404
+ }
391
405
  },
392
- kind: {
406
+ extractStepResult: {
407
+ type: "string",
408
+ required: false,
409
+ set: (value) => {
410
+ if (value && typeof value !== "string") {
411
+ return JSON.stringify(value);
412
+ }
413
+ return value;
414
+ },
415
+ get: (value) => {
416
+ if (value && typeof value === "string") {
417
+ try {
418
+ if (value.startsWith("{") || value.startsWith("[")) {
419
+ return JSON.parse(value);
420
+ }
421
+ } catch {
422
+ return value;
423
+ }
424
+ }
425
+ return value;
426
+ }
427
+ },
428
+ preprocessStepResult: {
429
+ type: "string",
430
+ required: false,
431
+ set: (value) => {
432
+ if (value && typeof value !== "string") {
433
+ return JSON.stringify(value);
434
+ }
435
+ return value;
436
+ },
437
+ get: (value) => {
438
+ if (value && typeof value === "string") {
439
+ try {
440
+ if (value.startsWith("{") || value.startsWith("[")) {
441
+ return JSON.parse(value);
442
+ }
443
+ } catch {
444
+ return value;
445
+ }
446
+ }
447
+ return value;
448
+ }
449
+ },
450
+ analyzeStepResult: {
451
+ type: "string",
452
+ required: false,
453
+ set: (value) => {
454
+ if (value && typeof value !== "string") {
455
+ return JSON.stringify(value);
456
+ }
457
+ return value;
458
+ },
459
+ get: (value) => {
460
+ if (value && typeof value === "string") {
461
+ try {
462
+ if (value.startsWith("{") || value.startsWith("[")) {
463
+ return JSON.parse(value);
464
+ }
465
+ } catch {
466
+ return value;
467
+ }
468
+ }
469
+ return value;
470
+ }
471
+ },
472
+ score: {
393
473
  type: "number",
394
474
  required: true
395
475
  },
396
- attributes: {
476
+ reason: {
397
477
  type: "string",
398
- // JSON stringified
399
- required: false,
400
- // Stringify object on set
478
+ required: false
479
+ },
480
+ extractPrompt: {
481
+ type: "string",
482
+ required: false
483
+ },
484
+ analyzePrompt: {
485
+ type: "string",
486
+ required: false
487
+ },
488
+ // Deprecated in favor of generateReasonPrompt
489
+ reasonPrompt: {
490
+ type: "string",
491
+ required: false
492
+ },
493
+ generateScorePrompt: {
494
+ type: "string",
495
+ required: false
496
+ },
497
+ generateReasonPrompt: {
498
+ type: "string",
499
+ required: false
500
+ },
501
+ input: {
502
+ type: "string",
503
+ required: true,
401
504
  set: (value) => {
402
505
  if (value && typeof value !== "string") {
403
506
  return JSON.stringify(value);
404
507
  }
405
508
  return value;
406
509
  },
407
- // Parse JSON string to object on get
408
510
  get: (value) => {
409
- return value ? JSON.parse(value) : value;
511
+ if (value && typeof value === "string") {
512
+ try {
513
+ if (value.startsWith("{") || value.startsWith("[")) {
514
+ return JSON.parse(value);
515
+ }
516
+ } catch {
517
+ return value;
518
+ }
519
+ }
520
+ return value;
410
521
  }
411
522
  },
412
- status: {
523
+ output: {
524
+ type: "string",
525
+ required: true,
526
+ set: (value) => {
527
+ if (value && typeof value !== "string") {
528
+ return JSON.stringify(value);
529
+ }
530
+ return value;
531
+ },
532
+ get: (value) => {
533
+ if (value && typeof value === "string") {
534
+ try {
535
+ if (value.startsWith("{") || value.startsWith("[")) {
536
+ return JSON.parse(value);
537
+ }
538
+ } catch {
539
+ return value;
540
+ }
541
+ }
542
+ return value;
543
+ }
544
+ },
545
+ additionalContext: {
413
546
  type: "string",
414
- // JSON stringified
415
547
  required: false,
416
- // Stringify object on set
417
548
  set: (value) => {
418
549
  if (value && typeof value !== "string") {
419
550
  return JSON.stringify(value);
420
551
  }
421
552
  return value;
422
553
  },
423
- // Parse JSON string to object on get
424
554
  get: (value) => {
555
+ if (value && typeof value === "string") {
556
+ try {
557
+ if (value.startsWith("{") || value.startsWith("[")) {
558
+ return JSON.parse(value);
559
+ }
560
+ } catch {
561
+ return value;
562
+ }
563
+ }
425
564
  return value;
426
565
  }
427
566
  },
428
- events: {
567
+ requestContext: {
429
568
  type: "string",
430
- // JSON stringified
431
569
  required: false,
432
- // Stringify object on set
433
570
  set: (value) => {
434
571
  if (value && typeof value !== "string") {
435
572
  return JSON.stringify(value);
436
573
  }
437
574
  return value;
438
575
  },
439
- // Parse JSON string to object on get
440
576
  get: (value) => {
577
+ if (value && typeof value === "string") {
578
+ try {
579
+ if (value.startsWith("{") || value.startsWith("[")) {
580
+ return JSON.parse(value);
581
+ }
582
+ } catch {
583
+ return value;
584
+ }
585
+ }
441
586
  return value;
442
587
  }
443
588
  },
444
- links: {
589
+ entityType: {
590
+ type: "string",
591
+ required: false
592
+ },
593
+ entityData: {
445
594
  type: "string",
446
- // JSON stringified
447
595
  required: false,
448
- // Stringify object on set
449
596
  set: (value) => {
450
597
  if (value && typeof value !== "string") {
451
598
  return JSON.stringify(value);
452
599
  }
453
600
  return value;
454
601
  },
455
- // Parse JSON string to object on get
456
602
  get: (value) => {
603
+ if (value && typeof value === "string") {
604
+ try {
605
+ if (value.startsWith("{") || value.startsWith("[")) {
606
+ return JSON.parse(value);
607
+ }
608
+ } catch {
609
+ return value;
610
+ }
611
+ }
457
612
  return value;
458
613
  }
459
614
  },
460
- other: {
615
+ entityId: {
461
616
  type: "string",
462
617
  required: false
463
618
  },
464
- startTime: {
465
- type: "number",
619
+ source: {
620
+ type: "string",
466
621
  required: true
467
622
  },
468
- endTime: {
469
- type: "number",
470
- required: true
623
+ resourceId: {
624
+ type: "string",
625
+ required: false
626
+ },
627
+ threadId: {
628
+ type: "string",
629
+ required: false
471
630
  }
472
631
  },
473
632
  indexes: {
474
633
  primary: {
475
634
  pk: { field: "pk", composite: ["entity", "id"] },
476
- sk: { field: "sk", composite: [] }
635
+ sk: { field: "sk", composite: ["entity"] }
477
636
  },
478
- byName: {
637
+ byScorer: {
479
638
  index: "gsi1",
480
- pk: { field: "gsi1pk", composite: ["entity", "name"] },
481
- sk: { field: "gsi1sk", composite: ["startTime"] }
639
+ pk: { field: "gsi1pk", composite: ["entity", "scorerId"] },
640
+ sk: { field: "gsi1sk", composite: ["createdAt"] }
482
641
  },
483
- byScope: {
642
+ byRun: {
484
643
  index: "gsi2",
485
- pk: { field: "gsi2pk", composite: ["entity", "scope"] },
486
- sk: { field: "gsi2sk", composite: ["startTime"] }
644
+ pk: { field: "gsi2pk", composite: ["entity", "runId"] },
645
+ sk: { field: "gsi2sk", composite: ["createdAt"] }
646
+ },
647
+ byTrace: {
648
+ index: "gsi3",
649
+ pk: { field: "gsi3pk", composite: ["entity", "traceId"] },
650
+ sk: { field: "gsi3sk", composite: ["createdAt"] }
651
+ },
652
+ byEntityData: {
653
+ index: "gsi4",
654
+ pk: { field: "gsi4pk", composite: ["entity", "entityId"] },
655
+ sk: { field: "gsi4sk", composite: ["createdAt"] }
656
+ },
657
+ byResource: {
658
+ index: "gsi5",
659
+ pk: { field: "gsi5pk", composite: ["entity", "resourceId"] },
660
+ sk: { field: "gsi5sk", composite: ["createdAt"] }
661
+ },
662
+ byThread: {
663
+ index: "gsi6",
664
+ pk: { field: "gsi6pk", composite: ["entity", "threadId"] },
665
+ sk: { field: "gsi6sk", composite: ["createdAt"] }
666
+ },
667
+ bySpan: {
668
+ index: "gsi7",
669
+ pk: { field: "gsi7pk", composite: ["entity", "traceId", "spanId"] },
670
+ sk: { field: "gsi7sk", composite: ["createdAt"] }
487
671
  }
488
672
  }
489
673
  });
490
- var workflowSnapshotEntity = new electrodb.Entity({
674
+ var threadEntity = new electrodb.Entity({
491
675
  model: {
492
- entity: "workflow_snapshot",
676
+ entity: "thread",
493
677
  version: "1",
494
678
  service: "mastra"
495
679
  },
@@ -499,11 +683,202 @@ var workflowSnapshotEntity = new electrodb.Entity({
499
683
  required: true
500
684
  },
501
685
  ...baseAttributes,
502
- workflow_name: {
686
+ id: {
503
687
  type: "string",
504
688
  required: true
505
689
  },
506
- run_id: {
690
+ resourceId: {
691
+ type: "string",
692
+ required: true
693
+ },
694
+ title: {
695
+ type: "string",
696
+ required: true
697
+ },
698
+ metadata: {
699
+ type: "string",
700
+ required: false,
701
+ // Stringify metadata object on set if it's not already a string
702
+ set: (value) => {
703
+ if (value && typeof value !== "string") {
704
+ return JSON.stringify(value);
705
+ }
706
+ return value;
707
+ },
708
+ // Parse JSON string to object on get
709
+ get: (value) => {
710
+ if (value && typeof value === "string") {
711
+ try {
712
+ if (value.startsWith("{") || value.startsWith("[")) {
713
+ return JSON.parse(value);
714
+ }
715
+ } catch {
716
+ return value;
717
+ }
718
+ }
719
+ return value;
720
+ }
721
+ }
722
+ },
723
+ indexes: {
724
+ primary: {
725
+ pk: { field: "pk", composite: ["entity", "id"] },
726
+ sk: { field: "sk", composite: ["id"] }
727
+ },
728
+ byResource: {
729
+ index: "gsi1",
730
+ pk: { field: "gsi1pk", composite: ["entity", "resourceId"] },
731
+ sk: { field: "gsi1sk", composite: ["createdAt"] }
732
+ }
733
+ }
734
+ });
735
+ var traceEntity = new electrodb.Entity({
736
+ model: {
737
+ entity: "trace",
738
+ version: "1",
739
+ service: "mastra"
740
+ },
741
+ attributes: {
742
+ entity: {
743
+ type: "string",
744
+ required: true
745
+ },
746
+ ...baseAttributes,
747
+ id: {
748
+ type: "string",
749
+ required: true
750
+ },
751
+ parentSpanId: {
752
+ type: "string",
753
+ required: false
754
+ },
755
+ name: {
756
+ type: "string",
757
+ required: true
758
+ },
759
+ traceId: {
760
+ type: "string",
761
+ required: true
762
+ },
763
+ scope: {
764
+ type: "string",
765
+ required: true
766
+ },
767
+ kind: {
768
+ type: "number",
769
+ required: true
770
+ },
771
+ attributes: {
772
+ type: "string",
773
+ // JSON stringified
774
+ required: false,
775
+ // Stringify object on set
776
+ set: (value) => {
777
+ if (value && typeof value !== "string") {
778
+ return JSON.stringify(value);
779
+ }
780
+ return value;
781
+ },
782
+ // Parse JSON string to object on get
783
+ get: (value) => {
784
+ return value ? JSON.parse(value) : value;
785
+ }
786
+ },
787
+ status: {
788
+ type: "string",
789
+ // JSON stringified
790
+ required: false,
791
+ // Stringify object on set
792
+ set: (value) => {
793
+ if (value && typeof value !== "string") {
794
+ return JSON.stringify(value);
795
+ }
796
+ return value;
797
+ },
798
+ // Parse JSON string to object on get
799
+ get: (value) => {
800
+ return value;
801
+ }
802
+ },
803
+ events: {
804
+ type: "string",
805
+ // JSON stringified
806
+ required: false,
807
+ // Stringify object on set
808
+ set: (value) => {
809
+ if (value && typeof value !== "string") {
810
+ return JSON.stringify(value);
811
+ }
812
+ return value;
813
+ },
814
+ // Parse JSON string to object on get
815
+ get: (value) => {
816
+ return value;
817
+ }
818
+ },
819
+ links: {
820
+ type: "string",
821
+ // JSON stringified
822
+ required: false,
823
+ // Stringify object on set
824
+ set: (value) => {
825
+ if (value && typeof value !== "string") {
826
+ return JSON.stringify(value);
827
+ }
828
+ return value;
829
+ },
830
+ // Parse JSON string to object on get
831
+ get: (value) => {
832
+ return value;
833
+ }
834
+ },
835
+ other: {
836
+ type: "string",
837
+ required: false
838
+ },
839
+ startTime: {
840
+ type: "number",
841
+ required: true
842
+ },
843
+ endTime: {
844
+ type: "number",
845
+ required: true
846
+ }
847
+ },
848
+ indexes: {
849
+ primary: {
850
+ pk: { field: "pk", composite: ["entity", "id"] },
851
+ sk: { field: "sk", composite: [] }
852
+ },
853
+ byName: {
854
+ index: "gsi1",
855
+ pk: { field: "gsi1pk", composite: ["entity", "name"] },
856
+ sk: { field: "gsi1sk", composite: ["startTime"] }
857
+ },
858
+ byScope: {
859
+ index: "gsi2",
860
+ pk: { field: "gsi2pk", composite: ["entity", "scope"] },
861
+ sk: { field: "gsi2sk", composite: ["startTime"] }
862
+ }
863
+ }
864
+ });
865
+ var workflowSnapshotEntity = new electrodb.Entity({
866
+ model: {
867
+ entity: "workflow_snapshot",
868
+ version: "1",
869
+ service: "mastra"
870
+ },
871
+ attributes: {
872
+ entity: {
873
+ type: "string",
874
+ required: true
875
+ },
876
+ ...baseAttributes,
877
+ workflow_name: {
878
+ type: "string",
879
+ required: true
880
+ },
881
+ run_id: {
507
882
  type: "string",
508
883
  required: true
509
884
  },
@@ -550,7 +925,9 @@ function getElectroDbService(client, tableName) {
550
925
  message: messageEntity,
551
926
  eval: evalEntity,
552
927
  trace: traceEntity,
553
- workflowSnapshot: workflowSnapshotEntity
928
+ workflow_snapshot: workflowSnapshotEntity,
929
+ resource: resourceEntity,
930
+ score: scoreEntity
554
931
  },
555
932
  {
556
933
  client,
@@ -558,76 +935,771 @@ function getElectroDbService(client, tableName) {
558
935
  }
559
936
  );
560
937
  }
561
-
562
- // src/storage/index.ts
563
- var DynamoDBStore = class extends storage.MastraStorage {
564
- tableName;
565
- client;
938
+ var MemoryStorageDynamoDB = class extends storage.MemoryStorage {
566
939
  service;
567
- hasInitialized = null;
568
- constructor({ name, config }) {
569
- super({ name });
940
+ constructor({ service }) {
941
+ super();
942
+ this.service = service;
943
+ }
944
+ // Helper function to parse message data (handle JSON fields)
945
+ parseMessageData(data) {
946
+ return {
947
+ ...data,
948
+ // Ensure dates are Date objects if needed (ElectroDB might return strings)
949
+ createdAt: data.createdAt ? new Date(data.createdAt) : void 0,
950
+ updatedAt: data.updatedAt ? new Date(data.updatedAt) : void 0
951
+ // Other fields like content, toolCallArgs etc. are assumed to be correctly
952
+ // transformed by the ElectroDB entity getters.
953
+ };
954
+ }
955
+ // Helper function to transform and sort threads
956
+ transformAndSortThreads(rawThreads, field, direction) {
957
+ return rawThreads.map((data) => ({
958
+ ...data,
959
+ // Convert date strings back to Date objects for consistency
960
+ createdAt: typeof data.createdAt === "string" ? new Date(data.createdAt) : data.createdAt,
961
+ updatedAt: typeof data.updatedAt === "string" ? new Date(data.updatedAt) : data.updatedAt
962
+ })).sort((a, b) => {
963
+ const fieldA = field === "createdAt" ? a.createdAt : a.updatedAt;
964
+ const fieldB = field === "createdAt" ? b.createdAt : b.updatedAt;
965
+ const comparison = fieldA.getTime() - fieldB.getTime();
966
+ return direction === "DESC" ? -comparison : comparison;
967
+ });
968
+ }
969
+ async getThreadById({ threadId }) {
970
+ this.logger.debug("Getting thread by ID", { threadId });
570
971
  try {
571
- if (!config.tableName || typeof config.tableName !== "string" || config.tableName.trim() === "") {
572
- throw new Error("DynamoDBStore: config.tableName must be provided and cannot be empty.");
573
- }
574
- if (!/^[a-zA-Z0-9_.-]{3,255}$/.test(config.tableName)) {
575
- throw new Error(
576
- `DynamoDBStore: config.tableName "${config.tableName}" contains invalid characters or is not between 3 and 255 characters long.`
577
- );
972
+ const result = await this.service.entities.thread.get({ entity: "thread", id: threadId }).go();
973
+ if (!result.data) {
974
+ return null;
578
975
  }
579
- const dynamoClient = new clientDynamodb.DynamoDBClient({
580
- region: config.region || "us-east-1",
581
- endpoint: config.endpoint,
582
- credentials: config.credentials
583
- });
584
- this.tableName = config.tableName;
585
- this.client = libDynamodb.DynamoDBDocumentClient.from(dynamoClient);
586
- this.service = getElectroDbService(this.client, this.tableName);
976
+ const data = result.data;
977
+ return {
978
+ ...data,
979
+ // Convert date strings back to Date objects for consistency
980
+ createdAt: typeof data.createdAt === "string" ? new Date(data.createdAt) : data.createdAt,
981
+ updatedAt: typeof data.updatedAt === "string" ? new Date(data.updatedAt) : data.updatedAt
982
+ // metadata: data.metadata ? JSON.parse(data.metadata) : undefined, // REMOVED by AI
983
+ // metadata is already transformed by the entity's getter
984
+ };
587
985
  } catch (error$1) {
588
986
  throw new error.MastraError(
589
987
  {
590
- id: "STORAGE_DYNAMODB_STORE_CONSTRUCTOR_FAILED",
988
+ id: "STORAGE_DYNAMODB_STORE_GET_THREAD_BY_ID_FAILED",
591
989
  domain: error.ErrorDomain.STORAGE,
592
- category: error.ErrorCategory.USER
990
+ category: error.ErrorCategory.THIRD_PARTY,
991
+ details: { threadId }
593
992
  },
594
993
  error$1
595
994
  );
596
995
  }
597
996
  }
598
- /**
599
- * This method is modified for DynamoDB with ElectroDB single-table design.
600
- * It assumes the table is created and managed externally via CDK/CloudFormation.
601
- *
602
- * This implementation only validates that the required table exists and is accessible.
603
- * No table creation is attempted - we simply check if we can access the table.
604
- */
605
- async createTable({ tableName }) {
606
- this.logger.debug("Validating access to externally managed table", { tableName, physicalTable: this.tableName });
997
+ async saveThread({ thread }) {
998
+ this.logger.debug("Saving thread", { threadId: thread.id });
999
+ const now = /* @__PURE__ */ new Date();
1000
+ const threadData = {
1001
+ entity: "thread",
1002
+ id: thread.id,
1003
+ resourceId: thread.resourceId,
1004
+ title: thread.title || `Thread ${thread.id}`,
1005
+ createdAt: thread.createdAt?.toISOString() || now.toISOString(),
1006
+ updatedAt: thread.updatedAt?.toISOString() || now.toISOString(),
1007
+ metadata: thread.metadata ? JSON.stringify(thread.metadata) : void 0
1008
+ };
607
1009
  try {
608
- const tableExists = await this.validateTableExists();
609
- if (!tableExists) {
610
- this.logger.error(
611
- `Table ${this.tableName} does not exist or is not accessible. It should be created via CDK/CloudFormation.`
612
- );
613
- throw new Error(
614
- `Table ${this.tableName} does not exist or is not accessible. Ensure it's created via CDK/CloudFormation before using this store.`
1010
+ await this.service.entities.thread.upsert(threadData).go();
1011
+ return {
1012
+ id: thread.id,
1013
+ resourceId: thread.resourceId,
1014
+ title: threadData.title,
1015
+ createdAt: thread.createdAt || now,
1016
+ updatedAt: thread.updatedAt || now,
1017
+ metadata: thread.metadata
1018
+ };
1019
+ } catch (error$1) {
1020
+ throw new error.MastraError(
1021
+ {
1022
+ id: "STORAGE_DYNAMODB_STORE_SAVE_THREAD_FAILED",
1023
+ domain: error.ErrorDomain.STORAGE,
1024
+ category: error.ErrorCategory.THIRD_PARTY,
1025
+ details: { threadId: thread.id }
1026
+ },
1027
+ error$1
1028
+ );
1029
+ }
1030
+ }
1031
+ async updateThread({
1032
+ id,
1033
+ title,
1034
+ metadata
1035
+ }) {
1036
+ this.logger.debug("Updating thread", { threadId: id });
1037
+ try {
1038
+ const existingThread = await this.getThreadById({ threadId: id });
1039
+ if (!existingThread) {
1040
+ throw new Error(`Thread not found: ${id}`);
1041
+ }
1042
+ const now = /* @__PURE__ */ new Date();
1043
+ const updateData = {
1044
+ updatedAt: now.toISOString()
1045
+ };
1046
+ if (title) {
1047
+ updateData.title = title;
1048
+ }
1049
+ if (metadata) {
1050
+ const existingMetadata = existingThread.metadata ? typeof existingThread.metadata === "string" ? JSON.parse(existingThread.metadata) : existingThread.metadata : {};
1051
+ const mergedMetadata = { ...existingMetadata, ...metadata };
1052
+ updateData.metadata = JSON.stringify(mergedMetadata);
1053
+ }
1054
+ await this.service.entities.thread.update({ entity: "thread", id }).set(updateData).go();
1055
+ return {
1056
+ ...existingThread,
1057
+ title: title || existingThread.title,
1058
+ metadata: metadata ? { ...existingThread.metadata, ...metadata } : existingThread.metadata,
1059
+ updatedAt: now
1060
+ };
1061
+ } catch (error$1) {
1062
+ throw new error.MastraError(
1063
+ {
1064
+ id: "STORAGE_DYNAMODB_STORE_UPDATE_THREAD_FAILED",
1065
+ domain: error.ErrorDomain.STORAGE,
1066
+ category: error.ErrorCategory.THIRD_PARTY,
1067
+ details: { threadId: id }
1068
+ },
1069
+ error$1
1070
+ );
1071
+ }
1072
+ }
1073
+ async deleteThread({ threadId }) {
1074
+ this.logger.debug("Deleting thread", { threadId });
1075
+ try {
1076
+ const { messages } = await this.listMessages({ threadId, perPage: false });
1077
+ if (messages.length > 0) {
1078
+ const batchSize = 25;
1079
+ for (let i = 0; i < messages.length; i += batchSize) {
1080
+ const batch = messages.slice(i, i + batchSize);
1081
+ await Promise.all(
1082
+ batch.map(
1083
+ (message) => this.service.entities.message.delete({
1084
+ entity: "message",
1085
+ id: message.id,
1086
+ threadId: message.threadId
1087
+ }).go()
1088
+ )
1089
+ );
1090
+ }
1091
+ }
1092
+ await this.service.entities.thread.delete({ entity: "thread", id: threadId }).go();
1093
+ } catch (error$1) {
1094
+ throw new error.MastraError(
1095
+ {
1096
+ id: "STORAGE_DYNAMODB_STORE_DELETE_THREAD_FAILED",
1097
+ domain: error.ErrorDomain.STORAGE,
1098
+ category: error.ErrorCategory.THIRD_PARTY,
1099
+ details: { threadId }
1100
+ },
1101
+ error$1
1102
+ );
1103
+ }
1104
+ }
1105
+ async listMessagesById({ messageIds }) {
1106
+ this.logger.debug("Getting messages by ID", { messageIds });
1107
+ if (messageIds.length === 0) return { messages: [] };
1108
+ try {
1109
+ const results = await Promise.all(
1110
+ messageIds.map((id) => this.service.entities.message.query.primary({ entity: "message", id }).go())
1111
+ );
1112
+ const data = results.map((result) => result.data).flat(1);
1113
+ let parsedMessages = data.map((data2) => this.parseMessageData(data2)).filter((msg) => "content" in msg);
1114
+ const uniqueMessages = parsedMessages.filter(
1115
+ (message, index, self) => index === self.findIndex((m) => m.id === message.id)
1116
+ );
1117
+ const list = new agent.MessageList().add(uniqueMessages, "memory");
1118
+ return { messages: list.get.all.db() };
1119
+ } catch (error$1) {
1120
+ throw new error.MastraError(
1121
+ {
1122
+ id: "STORAGE_DYNAMODB_STORE_LIST_MESSAGES_BY_ID_FAILED",
1123
+ domain: error.ErrorDomain.STORAGE,
1124
+ category: error.ErrorCategory.THIRD_PARTY,
1125
+ details: { messageIds: JSON.stringify(messageIds) }
1126
+ },
1127
+ error$1
1128
+ );
1129
+ }
1130
+ }
1131
+ async listMessages(args) {
1132
+ const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
1133
+ if (!threadId.trim()) {
1134
+ throw new error.MastraError(
1135
+ {
1136
+ id: "STORAGE_DYNAMODB_LIST_MESSAGES_INVALID_THREAD_ID",
1137
+ domain: error.ErrorDomain.STORAGE,
1138
+ category: error.ErrorCategory.THIRD_PARTY,
1139
+ details: { threadId }
1140
+ },
1141
+ new Error("threadId must be a non-empty string")
1142
+ );
1143
+ }
1144
+ const perPage = storage.normalizePerPage(perPageInput, 40);
1145
+ const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1146
+ try {
1147
+ if (page < 0) {
1148
+ throw new error.MastraError(
1149
+ {
1150
+ id: "STORAGE_DYNAMODB_LIST_MESSAGES_INVALID_PAGE",
1151
+ domain: error.ErrorDomain.STORAGE,
1152
+ category: error.ErrorCategory.USER,
1153
+ details: { page }
1154
+ },
1155
+ new Error("page must be >= 0")
615
1156
  );
616
1157
  }
617
- this.logger.debug(`Table ${this.tableName} exists and is accessible`);
1158
+ const { field, direction } = this.parseOrderBy(orderBy, "ASC");
1159
+ this.logger.debug("Getting messages with listMessages", {
1160
+ threadId,
1161
+ resourceId,
1162
+ perPageInput,
1163
+ offset,
1164
+ perPage,
1165
+ page,
1166
+ field,
1167
+ direction
1168
+ });
1169
+ const query = this.service.entities.message.query.byThread({ entity: "message", threadId });
1170
+ const results = await query.go();
1171
+ let allThreadMessages = results.data.map((data) => this.parseMessageData(data)).filter((msg) => "content" in msg && typeof msg.content === "object");
1172
+ if (resourceId) {
1173
+ allThreadMessages = allThreadMessages.filter((msg) => msg.resourceId === resourceId);
1174
+ }
1175
+ if (filter?.dateRange) {
1176
+ const dateRange = filter.dateRange;
1177
+ allThreadMessages = allThreadMessages.filter((msg) => {
1178
+ const createdAt = new Date(msg.createdAt).getTime();
1179
+ if (dateRange.start) {
1180
+ const startTime = dateRange.start instanceof Date ? dateRange.start.getTime() : new Date(dateRange.start).getTime();
1181
+ if (createdAt < startTime) return false;
1182
+ }
1183
+ if (dateRange.end) {
1184
+ const endTime = dateRange.end instanceof Date ? dateRange.end.getTime() : new Date(dateRange.end).getTime();
1185
+ if (createdAt > endTime) return false;
1186
+ }
1187
+ return true;
1188
+ });
1189
+ }
1190
+ allThreadMessages.sort((a, b) => {
1191
+ const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
1192
+ const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
1193
+ if (aValue === bValue) {
1194
+ return a.id.localeCompare(b.id);
1195
+ }
1196
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
1197
+ });
1198
+ const total = allThreadMessages.length;
1199
+ const paginatedMessages = allThreadMessages.slice(offset, offset + perPage);
1200
+ const paginatedCount = paginatedMessages.length;
1201
+ if (total === 0 && paginatedCount === 0 && (!include || include.length === 0)) {
1202
+ return {
1203
+ messages: [],
1204
+ total: 0,
1205
+ page,
1206
+ perPage: perPageForResponse,
1207
+ hasMore: false
1208
+ };
1209
+ }
1210
+ const messageIds = new Set(paginatedMessages.map((m) => m.id));
1211
+ let includeMessages = [];
1212
+ if (include && include.length > 0) {
1213
+ const selectBy = { include };
1214
+ includeMessages = await this._getIncludedMessages(threadId, selectBy);
1215
+ for (const includeMsg of includeMessages) {
1216
+ if (!messageIds.has(includeMsg.id)) {
1217
+ paginatedMessages.push(includeMsg);
1218
+ messageIds.add(includeMsg.id);
1219
+ }
1220
+ }
1221
+ }
1222
+ const list = new agent.MessageList().add(paginatedMessages, "memory");
1223
+ let finalMessages = list.get.all.db();
1224
+ finalMessages = finalMessages.sort((a, b) => {
1225
+ const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
1226
+ const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
1227
+ if (aValue === bValue) {
1228
+ return a.id.localeCompare(b.id);
1229
+ }
1230
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
1231
+ });
1232
+ const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
1233
+ const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
1234
+ let hasMore = false;
1235
+ if (perPageInput !== false && !allThreadMessagesReturned) {
1236
+ hasMore = offset + paginatedCount < total;
1237
+ }
1238
+ return {
1239
+ messages: finalMessages,
1240
+ total,
1241
+ page,
1242
+ perPage: perPageForResponse,
1243
+ hasMore
1244
+ };
1245
+ } catch (error$1) {
1246
+ const mastraError = new error.MastraError(
1247
+ {
1248
+ id: "STORAGE_DYNAMODB_STORE_LIST_MESSAGES_FAILED",
1249
+ domain: error.ErrorDomain.STORAGE,
1250
+ category: error.ErrorCategory.THIRD_PARTY,
1251
+ details: {
1252
+ threadId,
1253
+ resourceId: resourceId ?? ""
1254
+ }
1255
+ },
1256
+ error$1
1257
+ );
1258
+ this.logger?.error?.(mastraError.toString());
1259
+ this.logger?.trackException?.(mastraError);
1260
+ return {
1261
+ messages: [],
1262
+ total: 0,
1263
+ page,
1264
+ perPage: perPageForResponse,
1265
+ hasMore: false
1266
+ };
1267
+ }
1268
+ }
1269
+ async saveMessages(args) {
1270
+ const { messages } = args;
1271
+ this.logger.debug("Saving messages", { count: messages.length });
1272
+ if (!messages.length) {
1273
+ return { messages: [] };
1274
+ }
1275
+ const threadId = messages[0]?.threadId;
1276
+ if (!threadId) {
1277
+ throw new Error("Thread ID is required");
1278
+ }
1279
+ const messagesToSave = messages.map((msg) => {
1280
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1281
+ return {
1282
+ entity: "message",
1283
+ // Add entity type
1284
+ id: msg.id,
1285
+ threadId: msg.threadId,
1286
+ role: msg.role,
1287
+ type: msg.type,
1288
+ resourceId: msg.resourceId,
1289
+ // Ensure complex fields are stringified if not handled by attribute setters
1290
+ content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content),
1291
+ toolCallArgs: `toolCallArgs` in msg && msg.toolCallArgs ? JSON.stringify(msg.toolCallArgs) : void 0,
1292
+ toolCallIds: `toolCallIds` in msg && msg.toolCallIds ? JSON.stringify(msg.toolCallIds) : void 0,
1293
+ toolNames: `toolNames` in msg && msg.toolNames ? JSON.stringify(msg.toolNames) : void 0,
1294
+ createdAt: msg.createdAt instanceof Date ? msg.createdAt.toISOString() : msg.createdAt || now,
1295
+ updatedAt: now
1296
+ // Add updatedAt
1297
+ };
1298
+ });
1299
+ try {
1300
+ const savedMessageIds = [];
1301
+ for (const messageData of messagesToSave) {
1302
+ if (!messageData.entity) {
1303
+ this.logger.error("Missing entity property in message data for create", { messageData });
1304
+ throw new Error("Internal error: Missing entity property during saveMessages");
1305
+ }
1306
+ try {
1307
+ await this.service.entities.message.put(messageData).go();
1308
+ savedMessageIds.push(messageData.id);
1309
+ } catch (error) {
1310
+ for (const savedId of savedMessageIds) {
1311
+ try {
1312
+ await this.service.entities.message.delete({ entity: "message", id: savedId }).go();
1313
+ } catch (rollbackError) {
1314
+ this.logger.error("Failed to rollback message during save error", {
1315
+ messageId: savedId,
1316
+ error: rollbackError
1317
+ });
1318
+ }
1319
+ }
1320
+ throw error;
1321
+ }
1322
+ }
1323
+ await this.service.entities.thread.update({ entity: "thread", id: threadId }).set({
1324
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1325
+ }).go();
1326
+ const list = new agent.MessageList().add(messages, "memory");
1327
+ return { messages: list.get.all.db() };
618
1328
  } catch (error$1) {
619
- this.logger.error("Error validating table access", { tableName: this.tableName, error: error$1 });
620
1329
  throw new error.MastraError(
621
1330
  {
622
- id: "STORAGE_DYNAMODB_STORE_VALIDATE_TABLE_ACCESS_FAILED",
1331
+ id: "STORAGE_DYNAMODB_STORE_SAVE_MESSAGES_FAILED",
623
1332
  domain: error.ErrorDomain.STORAGE,
624
1333
  category: error.ErrorCategory.THIRD_PARTY,
625
- details: { tableName: this.tableName }
1334
+ details: { count: messages.length }
1335
+ },
1336
+ error$1
1337
+ );
1338
+ }
1339
+ }
1340
+ async listThreadsByResourceId(args) {
1341
+ const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
1342
+ const perPage = storage.normalizePerPage(perPageInput, 100);
1343
+ if (page < 0) {
1344
+ throw new error.MastraError(
1345
+ {
1346
+ id: "STORAGE_DYNAMODB_LIST_THREADS_BY_RESOURCE_ID_INVALID_PAGE",
1347
+ domain: error.ErrorDomain.STORAGE,
1348
+ category: error.ErrorCategory.USER,
1349
+ details: { page }
1350
+ },
1351
+ new Error("page must be >= 0")
1352
+ );
1353
+ }
1354
+ const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1355
+ const { field, direction } = this.parseOrderBy(orderBy);
1356
+ this.logger.debug("Getting threads by resource ID with pagination", {
1357
+ resourceId,
1358
+ page,
1359
+ perPage,
1360
+ field,
1361
+ direction
1362
+ });
1363
+ try {
1364
+ const query = this.service.entities.thread.query.byResource({ entity: "thread", resourceId });
1365
+ const results = await query.go();
1366
+ const allThreads = this.transformAndSortThreads(results.data, field, direction);
1367
+ const endIndex = offset + perPage;
1368
+ const paginatedThreads = allThreads.slice(offset, endIndex);
1369
+ const total = allThreads.length;
1370
+ const hasMore = offset + perPage < total;
1371
+ return {
1372
+ threads: paginatedThreads,
1373
+ total,
1374
+ page,
1375
+ perPage: perPageForResponse,
1376
+ hasMore
1377
+ };
1378
+ } catch (error$1) {
1379
+ throw new error.MastraError(
1380
+ {
1381
+ id: "DYNAMODB_STORAGE_LIST_THREADS_BY_RESOURCE_ID_FAILED",
1382
+ domain: error.ErrorDomain.STORAGE,
1383
+ category: error.ErrorCategory.THIRD_PARTY,
1384
+ details: { resourceId, page, perPage }
1385
+ },
1386
+ error$1
1387
+ );
1388
+ }
1389
+ }
1390
+ // Helper method to get included messages with context
1391
+ async _getIncludedMessages(threadId, selectBy) {
1392
+ if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
1393
+ if (!selectBy?.include?.length) {
1394
+ return [];
1395
+ }
1396
+ const includeMessages = [];
1397
+ for (const includeItem of selectBy.include) {
1398
+ try {
1399
+ const { id, threadId: targetThreadId, withPreviousMessages = 0, withNextMessages = 0 } = includeItem;
1400
+ const searchThreadId = targetThreadId || threadId;
1401
+ this.logger.debug("Getting included messages for", {
1402
+ id,
1403
+ targetThreadId,
1404
+ searchThreadId,
1405
+ withPreviousMessages,
1406
+ withNextMessages
1407
+ });
1408
+ const query = this.service.entities.message.query.byThread({ entity: "message", threadId: searchThreadId });
1409
+ const results = await query.go();
1410
+ const allMessages = results.data.map((data) => this.parseMessageData(data)).filter((msg) => "content" in msg && typeof msg.content === "object");
1411
+ this.logger.debug("Found messages in thread", {
1412
+ threadId: searchThreadId,
1413
+ messageCount: allMessages.length,
1414
+ messageIds: allMessages.map((m) => m.id)
1415
+ });
1416
+ allMessages.sort((a, b) => {
1417
+ const timeA = a.createdAt.getTime();
1418
+ const timeB = b.createdAt.getTime();
1419
+ if (timeA === timeB) {
1420
+ return a.id.localeCompare(b.id);
1421
+ }
1422
+ return timeA - timeB;
1423
+ });
1424
+ const targetIndex = allMessages.findIndex((msg) => msg.id === id);
1425
+ if (targetIndex === -1) {
1426
+ this.logger.warn("Target message not found", { id, threadId: searchThreadId });
1427
+ continue;
1428
+ }
1429
+ this.logger.debug("Found target message at index", { id, targetIndex, totalMessages: allMessages.length });
1430
+ const startIndex = Math.max(0, targetIndex - withPreviousMessages);
1431
+ const endIndex = Math.min(allMessages.length, targetIndex + withNextMessages + 1);
1432
+ const contextMessages = allMessages.slice(startIndex, endIndex);
1433
+ this.logger.debug("Context messages", {
1434
+ startIndex,
1435
+ endIndex,
1436
+ contextCount: contextMessages.length,
1437
+ contextIds: contextMessages.map((m) => m.id)
1438
+ });
1439
+ includeMessages.push(...contextMessages);
1440
+ } catch (error) {
1441
+ this.logger.warn("Failed to get included message", { messageId: includeItem.id, error });
1442
+ }
1443
+ }
1444
+ this.logger.debug("Total included messages", {
1445
+ count: includeMessages.length,
1446
+ ids: includeMessages.map((m) => m.id)
1447
+ });
1448
+ return includeMessages;
1449
+ }
1450
+ async updateMessages(args) {
1451
+ const { messages } = args;
1452
+ this.logger.debug("Updating messages", { count: messages.length });
1453
+ if (!messages.length) {
1454
+ return [];
1455
+ }
1456
+ const updatedMessages = [];
1457
+ const affectedThreadIds = /* @__PURE__ */ new Set();
1458
+ try {
1459
+ for (const updateData of messages) {
1460
+ const { id, ...updates } = updateData;
1461
+ const existingMessage = await this.service.entities.message.get({ entity: "message", id }).go();
1462
+ if (!existingMessage.data) {
1463
+ this.logger.warn("Message not found for update", { id });
1464
+ continue;
1465
+ }
1466
+ const existingMsg = this.parseMessageData(existingMessage.data);
1467
+ const originalThreadId = existingMsg.threadId;
1468
+ affectedThreadIds.add(originalThreadId);
1469
+ const updatePayload = {
1470
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1471
+ };
1472
+ if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
1473
+ if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
1474
+ if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
1475
+ if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
1476
+ updatePayload.threadId = updates.threadId;
1477
+ affectedThreadIds.add(updates.threadId);
1478
+ }
1479
+ if (updates.content) {
1480
+ const existingContent = existingMsg.content;
1481
+ let newContent = { ...existingContent };
1482
+ if (updates.content.metadata !== void 0) {
1483
+ newContent.metadata = {
1484
+ ...existingContent.metadata || {},
1485
+ ...updates.content.metadata || {}
1486
+ };
1487
+ }
1488
+ if (updates.content.content !== void 0) {
1489
+ newContent.content = updates.content.content;
1490
+ }
1491
+ if ("parts" in updates.content && updates.content.parts !== void 0) {
1492
+ newContent.parts = updates.content.parts;
1493
+ }
1494
+ updatePayload.content = JSON.stringify(newContent);
1495
+ }
1496
+ await this.service.entities.message.update({ entity: "message", id }).set(updatePayload).go();
1497
+ const updatedMessage = await this.service.entities.message.get({ entity: "message", id }).go();
1498
+ if (updatedMessage.data) {
1499
+ updatedMessages.push(this.parseMessageData(updatedMessage.data));
1500
+ }
1501
+ }
1502
+ for (const threadId of affectedThreadIds) {
1503
+ await this.service.entities.thread.update({ entity: "thread", id: threadId }).set({
1504
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1505
+ }).go();
1506
+ }
1507
+ return updatedMessages;
1508
+ } catch (error$1) {
1509
+ throw new error.MastraError(
1510
+ {
1511
+ id: "STORAGE_DYNAMODB_STORE_UPDATE_MESSAGES_FAILED",
1512
+ domain: error.ErrorDomain.STORAGE,
1513
+ category: error.ErrorCategory.THIRD_PARTY,
1514
+ details: { count: messages.length }
1515
+ },
1516
+ error$1
1517
+ );
1518
+ }
1519
+ }
1520
+ async getResourceById({ resourceId }) {
1521
+ this.logger.debug("Getting resource by ID", { resourceId });
1522
+ try {
1523
+ const result = await this.service.entities.resource.get({ entity: "resource", id: resourceId }).go();
1524
+ if (!result.data) {
1525
+ return null;
1526
+ }
1527
+ const data = result.data;
1528
+ return {
1529
+ ...data,
1530
+ // Convert date strings back to Date objects for consistency
1531
+ createdAt: typeof data.createdAt === "string" ? new Date(data.createdAt) : data.createdAt,
1532
+ updatedAt: typeof data.updatedAt === "string" ? new Date(data.updatedAt) : data.updatedAt,
1533
+ // Ensure workingMemory is always returned as a string, regardless of automatic parsing
1534
+ workingMemory: typeof data.workingMemory === "object" ? JSON.stringify(data.workingMemory) : data.workingMemory
1535
+ // metadata is already transformed by the entity's getter
1536
+ };
1537
+ } catch (error$1) {
1538
+ throw new error.MastraError(
1539
+ {
1540
+ id: "STORAGE_DYNAMODB_STORE_GET_RESOURCE_BY_ID_FAILED",
1541
+ domain: error.ErrorDomain.STORAGE,
1542
+ category: error.ErrorCategory.THIRD_PARTY,
1543
+ details: { resourceId }
1544
+ },
1545
+ error$1
1546
+ );
1547
+ }
1548
+ }
1549
+ async saveResource({ resource }) {
1550
+ this.logger.debug("Saving resource", { resourceId: resource.id });
1551
+ const now = /* @__PURE__ */ new Date();
1552
+ const resourceData = {
1553
+ entity: "resource",
1554
+ id: resource.id,
1555
+ workingMemory: resource.workingMemory,
1556
+ metadata: resource.metadata ? JSON.stringify(resource.metadata) : void 0,
1557
+ createdAt: resource.createdAt?.toISOString() || now.toISOString(),
1558
+ updatedAt: now.toISOString()
1559
+ };
1560
+ try {
1561
+ await this.service.entities.resource.upsert(resourceData).go();
1562
+ return {
1563
+ id: resource.id,
1564
+ workingMemory: resource.workingMemory,
1565
+ metadata: resource.metadata,
1566
+ createdAt: resource.createdAt || now,
1567
+ updatedAt: now
1568
+ };
1569
+ } catch (error$1) {
1570
+ throw new error.MastraError(
1571
+ {
1572
+ id: "STORAGE_DYNAMODB_STORE_SAVE_RESOURCE_FAILED",
1573
+ domain: error.ErrorDomain.STORAGE,
1574
+ category: error.ErrorCategory.THIRD_PARTY,
1575
+ details: { resourceId: resource.id }
626
1576
  },
627
1577
  error$1
628
1578
  );
629
1579
  }
630
1580
  }
1581
+ async updateResource({
1582
+ resourceId,
1583
+ workingMemory,
1584
+ metadata
1585
+ }) {
1586
+ this.logger.debug("Updating resource", { resourceId });
1587
+ try {
1588
+ const existingResource = await this.getResourceById({ resourceId });
1589
+ if (!existingResource) {
1590
+ const newResource = {
1591
+ id: resourceId,
1592
+ workingMemory,
1593
+ metadata: metadata || {},
1594
+ createdAt: /* @__PURE__ */ new Date(),
1595
+ updatedAt: /* @__PURE__ */ new Date()
1596
+ };
1597
+ return this.saveResource({ resource: newResource });
1598
+ }
1599
+ const now = /* @__PURE__ */ new Date();
1600
+ const updateData = {
1601
+ updatedAt: now.toISOString()
1602
+ };
1603
+ if (workingMemory !== void 0) {
1604
+ updateData.workingMemory = workingMemory;
1605
+ }
1606
+ if (metadata) {
1607
+ const existingMetadata = existingResource.metadata || {};
1608
+ const mergedMetadata = { ...existingMetadata, ...metadata };
1609
+ updateData.metadata = JSON.stringify(mergedMetadata);
1610
+ }
1611
+ await this.service.entities.resource.update({ entity: "resource", id: resourceId }).set(updateData).go();
1612
+ return {
1613
+ ...existingResource,
1614
+ workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
1615
+ metadata: metadata ? { ...existingResource.metadata, ...metadata } : existingResource.metadata,
1616
+ updatedAt: now
1617
+ };
1618
+ } catch (error$1) {
1619
+ throw new error.MastraError(
1620
+ {
1621
+ id: "STORAGE_DYNAMODB_STORE_UPDATE_RESOURCE_FAILED",
1622
+ domain: error.ErrorDomain.STORAGE,
1623
+ category: error.ErrorCategory.THIRD_PARTY,
1624
+ details: { resourceId }
1625
+ },
1626
+ error$1
1627
+ );
1628
+ }
1629
+ }
1630
+ };
1631
+ var StoreOperationsDynamoDB = class extends storage.StoreOperations {
1632
+ client;
1633
+ tableName;
1634
+ service;
1635
+ constructor({
1636
+ service,
1637
+ tableName,
1638
+ client
1639
+ }) {
1640
+ super();
1641
+ this.service = service;
1642
+ this.client = client;
1643
+ this.tableName = tableName;
1644
+ }
1645
+ async hasColumn() {
1646
+ return true;
1647
+ }
1648
+ async dropTable() {
1649
+ }
1650
+ // Helper methods for entity/table mapping
1651
+ getEntityNameForTable(tableName) {
1652
+ const mapping = {
1653
+ [storage.TABLE_THREADS]: "thread",
1654
+ [storage.TABLE_MESSAGES]: "message",
1655
+ [storage.TABLE_WORKFLOW_SNAPSHOT]: "workflow_snapshot",
1656
+ [storage.TABLE_SCORERS]: "score",
1657
+ [storage.TABLE_TRACES]: "trace",
1658
+ [storage.TABLE_RESOURCES]: "resource",
1659
+ [storage.TABLE_SPANS]: "ai_span"
1660
+ };
1661
+ return mapping[tableName] || null;
1662
+ }
1663
+ /**
1664
+ * Pre-processes a record to ensure Date objects are converted to ISO strings
1665
+ * This is necessary because ElectroDB validation happens before setters are applied
1666
+ */
1667
+ preprocessRecord(record) {
1668
+ const processed = { ...record };
1669
+ if (processed.createdAt instanceof Date) {
1670
+ processed.createdAt = processed.createdAt.toISOString();
1671
+ }
1672
+ if (processed.updatedAt instanceof Date) {
1673
+ processed.updatedAt = processed.updatedAt.toISOString();
1674
+ }
1675
+ if (processed.created_at instanceof Date) {
1676
+ processed.created_at = processed.created_at.toISOString();
1677
+ }
1678
+ if (processed.result && typeof processed.result === "object") {
1679
+ processed.result = JSON.stringify(processed.result);
1680
+ }
1681
+ if (processed.test_info && typeof processed.test_info === "object") {
1682
+ processed.test_info = JSON.stringify(processed.test_info);
1683
+ } else if (processed.test_info === void 0 || processed.test_info === null) {
1684
+ delete processed.test_info;
1685
+ }
1686
+ if (processed.snapshot && typeof processed.snapshot === "object") {
1687
+ processed.snapshot = JSON.stringify(processed.snapshot);
1688
+ }
1689
+ if (processed.attributes && typeof processed.attributes === "object") {
1690
+ processed.attributes = JSON.stringify(processed.attributes);
1691
+ }
1692
+ if (processed.status && typeof processed.status === "object") {
1693
+ processed.status = JSON.stringify(processed.status);
1694
+ }
1695
+ if (processed.events && typeof processed.events === "object") {
1696
+ processed.events = JSON.stringify(processed.events);
1697
+ }
1698
+ if (processed.links && typeof processed.links === "object") {
1699
+ processed.links = JSON.stringify(processed.links);
1700
+ }
1701
+ return processed;
1702
+ }
631
1703
  /**
632
1704
  * Validates that the required DynamoDB table exists and is accessible.
633
1705
  * This does not check the table structure - it assumes the table
@@ -646,7 +1718,40 @@ var DynamoDBStore = class extends storage.MastraStorage {
646
1718
  }
647
1719
  throw new error.MastraError(
648
1720
  {
649
- id: "STORAGE_DYNAMODB_STORE_VALIDATE_TABLE_EXISTS_FAILED",
1721
+ id: "STORAGE_DYNAMODB_STORE_VALIDATE_TABLE_EXISTS_FAILED",
1722
+ domain: error.ErrorDomain.STORAGE,
1723
+ category: error.ErrorCategory.THIRD_PARTY,
1724
+ details: { tableName: this.tableName }
1725
+ },
1726
+ error$1
1727
+ );
1728
+ }
1729
+ }
1730
+ /**
1731
+ * This method is modified for DynamoDB with ElectroDB single-table design.
1732
+ * It assumes the table is created and managed externally via CDK/CloudFormation.
1733
+ *
1734
+ * This implementation only validates that the required table exists and is accessible.
1735
+ * No table creation is attempted - we simply check if we can access the table.
1736
+ */
1737
+ async createTable({ tableName }) {
1738
+ this.logger.debug("Validating access to externally managed table", { tableName, physicalTable: this.tableName });
1739
+ try {
1740
+ const tableExists = await this.validateTableExists();
1741
+ if (!tableExists) {
1742
+ this.logger.error(
1743
+ `Table ${this.tableName} does not exist or is not accessible. It should be created via CDK/CloudFormation.`
1744
+ );
1745
+ throw new Error(
1746
+ `Table ${this.tableName} does not exist or is not accessible. Ensure it's created via CDK/CloudFormation before using this store.`
1747
+ );
1748
+ }
1749
+ this.logger.debug(`Table ${this.tableName} exists and is accessible`);
1750
+ } catch (error$1) {
1751
+ this.logger.error("Error validating table access", { tableName: this.tableName, error: error$1 });
1752
+ throw new error.MastraError(
1753
+ {
1754
+ id: "STORAGE_DYNAMODB_STORE_VALIDATE_TABLE_ACCESS_FAILED",
650
1755
  domain: error.ErrorDomain.STORAGE,
651
1756
  category: error.ErrorCategory.THIRD_PARTY,
652
1757
  details: { tableName: this.tableName }
@@ -655,63 +1760,33 @@ var DynamoDBStore = class extends storage.MastraStorage {
655
1760
  );
656
1761
  }
657
1762
  }
658
- /**
659
- * Initialize storage, validating the externally managed table is accessible.
660
- * For the single-table design, we only validate once that we can access
661
- * the table that was created via CDK/CloudFormation.
662
- */
663
- async init() {
664
- if (this.hasInitialized === null) {
665
- this.hasInitialized = this._performInitializationAndStore();
1763
+ async insert({ tableName, record }) {
1764
+ this.logger.debug("DynamoDB insert called", { tableName });
1765
+ const entityName = this.getEntityNameForTable(tableName);
1766
+ if (!entityName || !this.service.entities[entityName]) {
1767
+ throw new error.MastraError({
1768
+ id: "STORAGE_DYNAMODB_STORE_INSERT_INVALID_ARGS",
1769
+ domain: error.ErrorDomain.STORAGE,
1770
+ category: error.ErrorCategory.USER,
1771
+ text: "No entity defined for tableName",
1772
+ details: { tableName }
1773
+ });
666
1774
  }
667
1775
  try {
668
- await this.hasInitialized;
1776
+ const dataToSave = { entity: entityName, ...this.preprocessRecord(record) };
1777
+ await this.service.entities[entityName].create(dataToSave).go();
669
1778
  } catch (error$1) {
670
1779
  throw new error.MastraError(
671
1780
  {
672
- id: "STORAGE_DYNAMODB_STORE_INIT_FAILED",
1781
+ id: "STORAGE_DYNAMODB_STORE_INSERT_FAILED",
673
1782
  domain: error.ErrorDomain.STORAGE,
674
1783
  category: error.ErrorCategory.THIRD_PARTY,
675
- details: { tableName: this.tableName }
1784
+ details: { tableName }
676
1785
  },
677
1786
  error$1
678
1787
  );
679
1788
  }
680
1789
  }
681
- /**
682
- * Performs the actual table validation and stores the promise.
683
- * Handles resetting the stored promise on failure to allow retries.
684
- */
685
- _performInitializationAndStore() {
686
- return this.validateTableExists().then((exists) => {
687
- if (!exists) {
688
- throw new Error(
689
- `Table ${this.tableName} does not exist or is not accessible. Ensure it's created via CDK/CloudFormation before using this store.`
690
- );
691
- }
692
- return true;
693
- }).catch((err) => {
694
- this.hasInitialized = null;
695
- throw err;
696
- });
697
- }
698
- /**
699
- * Pre-processes a record to ensure Date objects are converted to ISO strings
700
- * This is necessary because ElectroDB validation happens before setters are applied
701
- */
702
- preprocessRecord(record) {
703
- const processed = { ...record };
704
- if (processed.createdAt instanceof Date) {
705
- processed.createdAt = processed.createdAt.toISOString();
706
- }
707
- if (processed.updatedAt instanceof Date) {
708
- processed.updatedAt = processed.updatedAt.toISOString();
709
- }
710
- if (processed.created_at instanceof Date) {
711
- processed.created_at = processed.created_at.toISOString();
712
- }
713
- return processed;
714
- }
715
1790
  async alterTable(_args) {
716
1791
  }
717
1792
  /**
@@ -747,10 +1822,10 @@ var DynamoDBStore = class extends storage.MastraStorage {
747
1822
  if (!item.id) throw new Error(`Missing required key 'id' for entity 'message'`);
748
1823
  key.id = item.id;
749
1824
  break;
750
- case "workflowSnapshot":
1825
+ case "workflow_snapshot":
751
1826
  if (!item.workflow_name)
752
- throw new Error(`Missing required key 'workflow_name' for entity 'workflowSnapshot'`);
753
- if (!item.run_id) throw new Error(`Missing required key 'run_id' for entity 'workflowSnapshot'`);
1827
+ throw new Error(`Missing required key 'workflow_name' for entity 'workflow_snapshot'`);
1828
+ if (!item.run_id) throw new Error(`Missing required key 'run_id' for entity 'workflow_snapshot'`);
754
1829
  key.workflow_name = item.workflow_name;
755
1830
  key.run_id = item.run_id;
756
1831
  break;
@@ -762,6 +1837,14 @@ var DynamoDBStore = class extends storage.MastraStorage {
762
1837
  if (!item.id) throw new Error(`Missing required key 'id' for entity 'trace'`);
763
1838
  key.id = item.id;
764
1839
  break;
1840
+ case "score":
1841
+ if (!item.id) throw new Error(`Missing required key 'id' for entity 'score'`);
1842
+ key.id = item.id;
1843
+ break;
1844
+ case "resource":
1845
+ if (!item.id) throw new Error(`Missing required key 'id' for entity 'resource'`);
1846
+ key.id = item.id;
1847
+ break;
765
1848
  default:
766
1849
  this.logger.warn(`Unknown entity type encountered during clearTable: ${entityName}`);
767
1850
  throw new Error(`Cannot construct delete key for unknown entity type: ${entityName}`);
@@ -786,46 +1869,10 @@ var DynamoDBStore = class extends storage.MastraStorage {
786
1869
  );
787
1870
  }
788
1871
  }
789
- /**
790
- * Insert a record into the specified "table" (entity)
791
- */
792
- async insert({
793
- tableName,
794
- record
795
- }) {
796
- this.logger.debug("DynamoDB insert called", { tableName });
797
- const entityName = this.getEntityNameForTable(tableName);
798
- if (!entityName || !this.service.entities[entityName]) {
799
- throw new error.MastraError({
800
- id: "STORAGE_DYNAMODB_STORE_INSERT_INVALID_ARGS",
801
- domain: error.ErrorDomain.STORAGE,
802
- category: error.ErrorCategory.USER,
803
- text: "No entity defined for tableName",
804
- details: { tableName }
805
- });
806
- }
807
- try {
808
- const dataToSave = { entity: entityName, ...this.preprocessRecord(record) };
809
- await this.service.entities[entityName].create(dataToSave).go();
810
- } catch (error$1) {
811
- throw new error.MastraError(
812
- {
813
- id: "STORAGE_DYNAMODB_STORE_INSERT_FAILED",
814
- domain: error.ErrorDomain.STORAGE,
815
- category: error.ErrorCategory.THIRD_PARTY,
816
- details: { tableName }
817
- },
818
- error$1
819
- );
820
- }
821
- }
822
1872
  /**
823
1873
  * Insert multiple records as a batch
824
1874
  */
825
- async batchInsert({
826
- tableName,
827
- records
828
- }) {
1875
+ async batchInsert({ tableName, records }) {
829
1876
  this.logger.debug("DynamoDB batchInsert called", { tableName, count: records.length });
830
1877
  const entityName = this.getEntityNameForTable(tableName);
831
1878
  if (!entityName || !this.service.entities[entityName]) {
@@ -870,10 +1917,7 @@ var DynamoDBStore = class extends storage.MastraStorage {
870
1917
  /**
871
1918
  * Load a record by its keys
872
1919
  */
873
- async load({
874
- tableName,
875
- keys
876
- }) {
1920
+ async load({ tableName, keys }) {
877
1921
  this.logger.debug("DynamoDB load called", { tableName, keys });
878
1922
  const entityName = this.getEntityNameForTable(tableName);
879
1923
  if (!entityName || !this.service.entities[entityName]) {
@@ -905,344 +1949,320 @@ var DynamoDBStore = class extends storage.MastraStorage {
905
1949
  );
906
1950
  }
907
1951
  }
908
- // Thread operations
909
- async getThreadById({ threadId }) {
910
- this.logger.debug("Getting thread by ID", { threadId });
1952
+ };
1953
+ var ScoresStorageDynamoDB = class extends storage.ScoresStorage {
1954
+ service;
1955
+ constructor({ service }) {
1956
+ super();
1957
+ this.service = service;
1958
+ }
1959
+ // Helper function to parse score data (handle JSON fields)
1960
+ parseScoreData(data) {
1961
+ return {
1962
+ ...data,
1963
+ // Convert date strings back to Date objects for consistency
1964
+ createdAt: data.createdAt ? new Date(data.createdAt) : /* @__PURE__ */ new Date(),
1965
+ updatedAt: data.updatedAt ? new Date(data.updatedAt) : /* @__PURE__ */ new Date()
1966
+ // JSON fields are already transformed by the entity's getters
1967
+ };
1968
+ }
1969
+ async getScoreById({ id }) {
1970
+ this.logger.debug("Getting score by ID", { id });
911
1971
  try {
912
- const result = await this.service.entities.thread.get({ entity: "thread", id: threadId }).go();
1972
+ const result = await this.service.entities.score.get({ entity: "score", id }).go();
913
1973
  if (!result.data) {
914
1974
  return null;
915
1975
  }
916
- const data = result.data;
917
- return {
918
- ...data,
919
- // Convert date strings back to Date objects for consistency
920
- createdAt: typeof data.createdAt === "string" ? new Date(data.createdAt) : data.createdAt,
921
- updatedAt: typeof data.updatedAt === "string" ? new Date(data.updatedAt) : data.updatedAt
922
- // metadata: data.metadata ? JSON.parse(data.metadata) : undefined, // REMOVED by AI
923
- // metadata is already transformed by the entity's getter
924
- };
1976
+ return this.parseScoreData(result.data);
925
1977
  } catch (error$1) {
926
1978
  throw new error.MastraError(
927
1979
  {
928
- id: "STORAGE_DYNAMODB_STORE_GET_THREAD_BY_ID_FAILED",
1980
+ id: "STORAGE_DYNAMODB_STORE_GET_SCORE_BY_ID_FAILED",
929
1981
  domain: error.ErrorDomain.STORAGE,
930
1982
  category: error.ErrorCategory.THIRD_PARTY,
931
- details: { threadId }
1983
+ details: { id }
932
1984
  },
933
1985
  error$1
934
1986
  );
935
1987
  }
936
1988
  }
937
- async getThreadsByResourceId({ resourceId }) {
938
- this.logger.debug("Getting threads by resource ID", { resourceId });
1989
+ async saveScore(score) {
1990
+ let validatedScore;
939
1991
  try {
940
- const result = await this.service.entities.thread.query.byResource({ entity: "thread", resourceId }).go();
941
- if (!result.data.length) {
942
- return [];
943
- }
944
- return result.data.map((data) => ({
945
- ...data,
946
- // Convert date strings back to Date objects for consistency
947
- createdAt: typeof data.createdAt === "string" ? new Date(data.createdAt) : data.createdAt,
948
- updatedAt: typeof data.updatedAt === "string" ? new Date(data.updatedAt) : data.updatedAt
949
- // metadata: data.metadata ? JSON.parse(data.metadata) : undefined, // REMOVED by AI
950
- // metadata is already transformed by the entity's getter
951
- }));
1992
+ validatedScore = evals.saveScorePayloadSchema.parse(score);
952
1993
  } catch (error$1) {
953
1994
  throw new error.MastraError(
954
1995
  {
955
- id: "STORAGE_DYNAMODB_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED",
1996
+ id: "STORAGE_DYNAMODB_STORE_SAVE_SCORE_FAILED",
956
1997
  domain: error.ErrorDomain.STORAGE,
957
- category: error.ErrorCategory.THIRD_PARTY,
958
- details: { resourceId }
1998
+ category: error.ErrorCategory.THIRD_PARTY
959
1999
  },
960
2000
  error$1
961
2001
  );
962
2002
  }
963
- }
964
- async saveThread({ thread }) {
965
- this.logger.debug("Saving thread", { threadId: thread.id });
966
2003
  const now = /* @__PURE__ */ new Date();
967
- const threadData = {
968
- entity: "thread",
969
- id: thread.id,
970
- resourceId: thread.resourceId,
971
- title: thread.title || `Thread ${thread.id}`,
972
- createdAt: thread.createdAt?.toISOString() || now.toISOString(),
973
- updatedAt: now.toISOString(),
974
- metadata: thread.metadata ? JSON.stringify(thread.metadata) : void 0
2004
+ const scoreId = `score-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
2005
+ const scoreData = {
2006
+ entity: "score",
2007
+ id: scoreId,
2008
+ scorerId: validatedScore.scorerId,
2009
+ traceId: validatedScore.traceId || "",
2010
+ spanId: validatedScore.spanId || "",
2011
+ runId: validatedScore.runId,
2012
+ scorer: typeof validatedScore.scorer === "string" ? validatedScore.scorer : JSON.stringify(validatedScore.scorer),
2013
+ preprocessStepResult: typeof validatedScore.preprocessStepResult === "string" ? validatedScore.preprocessStepResult : JSON.stringify(validatedScore.preprocessStepResult),
2014
+ analyzeStepResult: typeof validatedScore.analyzeStepResult === "string" ? validatedScore.analyzeStepResult : JSON.stringify(validatedScore.analyzeStepResult),
2015
+ score: validatedScore.score,
2016
+ reason: validatedScore.reason,
2017
+ preprocessPrompt: validatedScore.preprocessPrompt,
2018
+ generateScorePrompt: validatedScore.generateScorePrompt,
2019
+ generateReasonPrompt: validatedScore.generateReasonPrompt,
2020
+ analyzePrompt: validatedScore.analyzePrompt,
2021
+ input: typeof validatedScore.input === "string" ? validatedScore.input : JSON.stringify(validatedScore.input),
2022
+ output: typeof validatedScore.output === "string" ? validatedScore.output : JSON.stringify(validatedScore.output),
2023
+ additionalContext: typeof validatedScore.additionalContext === "string" ? validatedScore.additionalContext : JSON.stringify(validatedScore.additionalContext),
2024
+ requestContext: typeof validatedScore.requestContext === "string" ? validatedScore.requestContext : JSON.stringify(validatedScore.requestContext),
2025
+ entityType: validatedScore.entityType,
2026
+ entityData: typeof validatedScore.entity === "string" ? validatedScore.entity : JSON.stringify(validatedScore.entity),
2027
+ entityId: validatedScore.entityId,
2028
+ source: validatedScore.source,
2029
+ resourceId: validatedScore.resourceId || "",
2030
+ threadId: validatedScore.threadId || "",
2031
+ createdAt: now.toISOString(),
2032
+ updatedAt: now.toISOString()
975
2033
  };
976
2034
  try {
977
- await this.service.entities.thread.upsert(threadData).go();
978
- return {
979
- id: thread.id,
980
- resourceId: thread.resourceId,
981
- title: threadData.title,
982
- createdAt: thread.createdAt || now,
983
- updatedAt: now,
984
- metadata: thread.metadata
985
- };
986
- } catch (error$1) {
987
- throw new error.MastraError(
988
- {
989
- id: "STORAGE_DYNAMODB_STORE_SAVE_THREAD_FAILED",
990
- domain: error.ErrorDomain.STORAGE,
991
- category: error.ErrorCategory.THIRD_PARTY,
992
- details: { threadId: thread.id }
993
- },
994
- error$1
995
- );
996
- }
997
- }
998
- async updateThread({
999
- id,
1000
- title,
1001
- metadata
1002
- }) {
1003
- this.logger.debug("Updating thread", { threadId: id });
1004
- try {
1005
- const existingThread = await this.getThreadById({ threadId: id });
1006
- if (!existingThread) {
1007
- throw new Error(`Thread not found: ${id}`);
1008
- }
1009
- const now = /* @__PURE__ */ new Date();
1010
- const updateData = {
1011
- updatedAt: now.toISOString()
1012
- };
1013
- if (title) {
1014
- updateData.title = title;
1015
- }
1016
- if (metadata) {
1017
- updateData.metadata = JSON.stringify(metadata);
1018
- }
1019
- await this.service.entities.thread.update({ entity: "thread", id }).set(updateData).go();
1020
- return {
1021
- ...existingThread,
1022
- title: title || existingThread.title,
1023
- metadata: metadata || existingThread.metadata,
2035
+ await this.service.entities.score.upsert(scoreData).go();
2036
+ const savedScore = {
2037
+ ...score,
2038
+ id: scoreId,
2039
+ createdAt: now,
1024
2040
  updatedAt: now
1025
2041
  };
2042
+ return { score: savedScore };
1026
2043
  } catch (error$1) {
1027
2044
  throw new error.MastraError(
1028
2045
  {
1029
- id: "STORAGE_DYNAMODB_STORE_UPDATE_THREAD_FAILED",
1030
- domain: error.ErrorDomain.STORAGE,
1031
- category: error.ErrorCategory.THIRD_PARTY,
1032
- details: { threadId: id }
1033
- },
1034
- error$1
1035
- );
1036
- }
1037
- }
1038
- async deleteThread({ threadId }) {
1039
- this.logger.debug("Deleting thread", { threadId });
1040
- try {
1041
- await this.service.entities.thread.delete({ entity: "thread", id: threadId }).go();
1042
- } catch (error$1) {
1043
- throw new error.MastraError(
1044
- {
1045
- id: "STORAGE_DYNAMODB_STORE_DELETE_THREAD_FAILED",
2046
+ id: "STORAGE_DYNAMODB_STORE_SAVE_SCORE_FAILED",
1046
2047
  domain: error.ErrorDomain.STORAGE,
1047
2048
  category: error.ErrorCategory.THIRD_PARTY,
1048
- details: { threadId }
2049
+ details: { scorerId: score.scorerId, runId: score.runId }
1049
2050
  },
1050
2051
  error$1
1051
2052
  );
1052
2053
  }
1053
2054
  }
1054
- async getMessages({
1055
- threadId,
1056
- resourceId,
1057
- selectBy,
1058
- format
2055
+ async listScoresByScorerId({
2056
+ scorerId,
2057
+ pagination,
2058
+ entityId,
2059
+ entityType,
2060
+ source
1059
2061
  }) {
1060
- this.logger.debug("Getting messages", { threadId, selectBy });
1061
2062
  try {
1062
- const query = this.service.entities.message.query.byThread({ entity: "message", threadId });
1063
- const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: Number.MAX_SAFE_INTEGER });
1064
- if (limit !== Number.MAX_SAFE_INTEGER) {
1065
- const results2 = await query.go({ limit, order: "desc" });
1066
- const list2 = new agent.MessageList({ threadId, resourceId }).add(
1067
- results2.data.map((data) => this.parseMessageData(data)),
1068
- "memory"
1069
- );
1070
- if (format === `v2`) return list2.get.all.v2();
1071
- return list2.get.all.v1();
1072
- }
2063
+ const query = this.service.entities.score.query.byScorer({ entity: "score", scorerId });
1073
2064
  const results = await query.go();
1074
- const list = new agent.MessageList({ threadId, resourceId }).add(
1075
- results.data.map((data) => this.parseMessageData(data)),
1076
- "memory"
1077
- );
1078
- if (format === `v2`) return list.get.all.v2();
1079
- return list.get.all.v1();
1080
- } catch (error$1) {
1081
- throw new error.MastraError(
1082
- {
1083
- id: "STORAGE_DYNAMODB_STORE_GET_MESSAGES_FAILED",
1084
- domain: error.ErrorDomain.STORAGE,
1085
- category: error.ErrorCategory.THIRD_PARTY,
1086
- details: { threadId }
1087
- },
1088
- error$1
1089
- );
1090
- }
1091
- }
1092
- async saveMessages(args) {
1093
- const { messages, format = "v1" } = args;
1094
- this.logger.debug("Saving messages", { count: messages.length });
1095
- if (!messages.length) {
1096
- return [];
1097
- }
1098
- const threadId = messages[0]?.threadId;
1099
- if (!threadId) {
1100
- throw new Error("Thread ID is required");
1101
- }
1102
- const messagesToSave = messages.map((msg) => {
1103
- const now = (/* @__PURE__ */ new Date()).toISOString();
1104
- return {
1105
- entity: "message",
1106
- // Add entity type
1107
- id: msg.id,
1108
- threadId: msg.threadId,
1109
- role: msg.role,
1110
- type: msg.type,
1111
- resourceId: msg.resourceId,
1112
- // Ensure complex fields are stringified if not handled by attribute setters
1113
- content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content),
1114
- toolCallArgs: `toolCallArgs` in msg && msg.toolCallArgs ? JSON.stringify(msg.toolCallArgs) : void 0,
1115
- toolCallIds: `toolCallIds` in msg && msg.toolCallIds ? JSON.stringify(msg.toolCallIds) : void 0,
1116
- toolNames: `toolNames` in msg && msg.toolNames ? JSON.stringify(msg.toolNames) : void 0,
1117
- createdAt: msg.createdAt instanceof Date ? msg.createdAt.toISOString() : msg.createdAt || now,
1118
- updatedAt: now
1119
- // Add updatedAt
2065
+ let allScores = results.data.map((data) => this.parseScoreData(data));
2066
+ if (entityId) {
2067
+ allScores = allScores.filter((score) => score.entityId === entityId);
2068
+ }
2069
+ if (entityType) {
2070
+ allScores = allScores.filter((score) => score.entityType === entityType);
2071
+ }
2072
+ if (source) {
2073
+ allScores = allScores.filter((score) => score.source === source);
2074
+ }
2075
+ allScores.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
2076
+ const { page, perPage: perPageInput } = pagination;
2077
+ const perPage = storage.normalizePerPage(perPageInput, Number.MAX_SAFE_INTEGER);
2078
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
2079
+ const total = allScores.length;
2080
+ const end = perPageInput === false ? allScores.length : start + perPage;
2081
+ const paginatedScores = allScores.slice(start, end);
2082
+ return {
2083
+ scores: paginatedScores,
2084
+ pagination: {
2085
+ total,
2086
+ page,
2087
+ perPage: perPageForResponse,
2088
+ hasMore: end < total
2089
+ }
1120
2090
  };
1121
- });
1122
- try {
1123
- const batchSize = 25;
1124
- const batches = [];
1125
- for (let i = 0; i < messagesToSave.length; i += batchSize) {
1126
- const batch = messagesToSave.slice(i, i + batchSize);
1127
- batches.push(batch);
1128
- }
1129
- await Promise.all([
1130
- // Process message batches
1131
- ...batches.map(async (batch) => {
1132
- for (const messageData of batch) {
1133
- if (!messageData.entity) {
1134
- this.logger.error("Missing entity property in message data for create", { messageData });
1135
- throw new Error("Internal error: Missing entity property during saveMessages");
1136
- }
1137
- await this.service.entities.message.put(messageData).go();
1138
- }
1139
- }),
1140
- // Update thread's updatedAt timestamp
1141
- this.service.entities.thread.update({ entity: "thread", id: threadId }).set({
1142
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1143
- }).go()
1144
- ]);
1145
- const list = new agent.MessageList().add(messages, "memory");
1146
- if (format === `v1`) return list.get.all.v1();
1147
- return list.get.all.v2();
1148
2091
  } catch (error$1) {
1149
2092
  throw new error.MastraError(
1150
2093
  {
1151
- id: "STORAGE_DYNAMODB_STORE_SAVE_MESSAGES_FAILED",
2094
+ id: "STORAGE_DYNAMODB_STORE_GET_SCORES_BY_SCORER_ID_FAILED",
1152
2095
  domain: error.ErrorDomain.STORAGE,
1153
2096
  category: error.ErrorCategory.THIRD_PARTY,
1154
- details: { count: messages.length }
2097
+ details: {
2098
+ scorerId: scorerId || "",
2099
+ entityId: entityId || "",
2100
+ entityType: entityType || "",
2101
+ source: source || "",
2102
+ page: pagination.page,
2103
+ perPage: pagination.perPage
2104
+ }
1155
2105
  },
1156
2106
  error$1
1157
2107
  );
1158
2108
  }
1159
2109
  }
1160
- // Helper function to parse message data (handle JSON fields)
1161
- parseMessageData(data) {
1162
- return {
1163
- ...data,
1164
- // Ensure dates are Date objects if needed (ElectroDB might return strings)
1165
- createdAt: data.createdAt ? new Date(data.createdAt) : void 0,
1166
- updatedAt: data.updatedAt ? new Date(data.updatedAt) : void 0
1167
- // Other fields like content, toolCallArgs etc. are assumed to be correctly
1168
- // transformed by the ElectroDB entity getters.
1169
- };
1170
- }
1171
- // Trace operations
1172
- async getTraces(args) {
1173
- const { name, scope, page, perPage } = args;
1174
- this.logger.debug("Getting traces", { name, scope, page, perPage });
2110
+ async listScoresByRunId({
2111
+ runId,
2112
+ pagination
2113
+ }) {
2114
+ this.logger.debug("Getting scores by run ID", { runId, pagination });
1175
2115
  try {
1176
- let query;
1177
- if (name) {
1178
- query = this.service.entities.trace.query.byName({ entity: "trace", name });
1179
- } else if (scope) {
1180
- query = this.service.entities.trace.query.byScope({ entity: "trace", scope });
1181
- } else {
1182
- this.logger.warn("Performing a scan operation on traces - consider using a more specific query");
1183
- query = this.service.entities.trace.scan;
1184
- }
1185
- let items = [];
1186
- let cursor = null;
1187
- let pagesFetched = 0;
1188
- const startPage = page > 0 ? page : 1;
1189
- do {
1190
- const results = await query.go({ cursor, limit: perPage });
1191
- pagesFetched++;
1192
- if (pagesFetched === startPage) {
1193
- items = results.data;
1194
- break;
1195
- }
1196
- cursor = results.cursor;
1197
- if (!cursor && results.data.length > 0 && pagesFetched < startPage) {
1198
- break;
2116
+ const query = this.service.entities.score.query.byRun({ entity: "score", runId });
2117
+ const results = await query.go();
2118
+ const allScores = results.data.map((data) => this.parseScoreData(data));
2119
+ allScores.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
2120
+ const { page, perPage: perPageInput } = pagination;
2121
+ const perPage = storage.normalizePerPage(perPageInput, Number.MAX_SAFE_INTEGER);
2122
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
2123
+ const total = allScores.length;
2124
+ const end = perPageInput === false ? allScores.length : start + perPage;
2125
+ const paginatedScores = allScores.slice(start, end);
2126
+ return {
2127
+ scores: paginatedScores,
2128
+ pagination: {
2129
+ total,
2130
+ page,
2131
+ perPage: perPageForResponse,
2132
+ hasMore: end < total
1199
2133
  }
1200
- } while (cursor && pagesFetched < startPage);
1201
- return items;
2134
+ };
1202
2135
  } catch (error$1) {
1203
2136
  throw new error.MastraError(
1204
2137
  {
1205
- id: "STORAGE_DYNAMODB_STORE_GET_TRACES_FAILED",
2138
+ id: "STORAGE_DYNAMODB_STORE_GET_SCORES_BY_RUN_ID_FAILED",
1206
2139
  domain: error.ErrorDomain.STORAGE,
1207
- category: error.ErrorCategory.THIRD_PARTY
2140
+ category: error.ErrorCategory.THIRD_PARTY,
2141
+ details: { runId, page: pagination.page, perPage: pagination.perPage }
1208
2142
  },
1209
2143
  error$1
1210
2144
  );
1211
2145
  }
1212
2146
  }
1213
- async batchTraceInsert({ records }) {
1214
- this.logger.debug("Batch inserting traces", { count: records.length });
1215
- if (!records.length) {
1216
- return;
2147
+ async listScoresByEntityId({
2148
+ entityId,
2149
+ entityType,
2150
+ pagination
2151
+ }) {
2152
+ this.logger.debug("Getting scores by entity ID", { entityId, entityType, pagination });
2153
+ try {
2154
+ const query = this.service.entities.score.query.byEntityData({ entity: "score", entityId });
2155
+ const results = await query.go();
2156
+ let allScores = results.data.map((data) => this.parseScoreData(data));
2157
+ allScores = allScores.filter((score) => score.entityType === entityType);
2158
+ allScores.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
2159
+ const { page, perPage: perPageInput } = pagination;
2160
+ const perPage = storage.normalizePerPage(perPageInput, Number.MAX_SAFE_INTEGER);
2161
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
2162
+ const total = allScores.length;
2163
+ const end = perPageInput === false ? allScores.length : start + perPage;
2164
+ const paginatedScores = allScores.slice(start, end);
2165
+ return {
2166
+ scores: paginatedScores,
2167
+ pagination: {
2168
+ total,
2169
+ page,
2170
+ perPage: perPageForResponse,
2171
+ hasMore: end < total
2172
+ }
2173
+ };
2174
+ } catch (error$1) {
2175
+ throw new error.MastraError(
2176
+ {
2177
+ id: "STORAGE_DYNAMODB_STORE_GET_SCORES_BY_ENTITY_ID_FAILED",
2178
+ domain: error.ErrorDomain.STORAGE,
2179
+ category: error.ErrorCategory.THIRD_PARTY,
2180
+ details: { entityId, entityType, page: pagination.page, perPage: pagination.perPage }
2181
+ },
2182
+ error$1
2183
+ );
1217
2184
  }
2185
+ }
2186
+ async listScoresBySpan({
2187
+ traceId,
2188
+ spanId,
2189
+ pagination
2190
+ }) {
2191
+ this.logger.debug("Getting scores by span", { traceId, spanId, pagination });
1218
2192
  try {
1219
- const recordsToSave = records.map((rec) => ({ entity: "trace", ...rec }));
1220
- await this.batchInsert({
1221
- tableName: storage.TABLE_TRACES,
1222
- records: recordsToSave
1223
- // Pass records with 'entity' included
1224
- });
2193
+ const query = this.service.entities.score.query.bySpan({ entity: "score", traceId, spanId });
2194
+ const results = await query.go();
2195
+ const allScores = results.data.map((data) => this.parseScoreData(data));
2196
+ allScores.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
2197
+ const { page, perPage: perPageInput } = pagination;
2198
+ const perPage = storage.normalizePerPage(perPageInput, Number.MAX_SAFE_INTEGER);
2199
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
2200
+ const total = allScores.length;
2201
+ const end = perPageInput === false ? allScores.length : start + perPage;
2202
+ const paginatedScores = allScores.slice(start, end);
2203
+ return {
2204
+ scores: paginatedScores,
2205
+ pagination: {
2206
+ total,
2207
+ page,
2208
+ perPage: perPageForResponse,
2209
+ hasMore: end < total
2210
+ }
2211
+ };
1225
2212
  } catch (error$1) {
1226
2213
  throw new error.MastraError(
1227
2214
  {
1228
- id: "STORAGE_DYNAMODB_STORE_BATCH_TRACE_INSERT_FAILED",
2215
+ id: "STORAGE_DYNAMODB_STORE_GET_SCORES_BY_SPAN_FAILED",
1229
2216
  domain: error.ErrorDomain.STORAGE,
1230
2217
  category: error.ErrorCategory.THIRD_PARTY,
1231
- details: { count: records.length }
2218
+ details: { traceId, spanId, page: pagination.page, perPage: pagination.perPage }
1232
2219
  },
1233
2220
  error$1
1234
2221
  );
1235
2222
  }
1236
2223
  }
2224
+ };
2225
+ function formatWorkflowRun(snapshotData) {
2226
+ return {
2227
+ workflowName: snapshotData.workflow_name,
2228
+ runId: snapshotData.run_id,
2229
+ snapshot: snapshotData.snapshot,
2230
+ createdAt: new Date(snapshotData.createdAt),
2231
+ updatedAt: new Date(snapshotData.updatedAt),
2232
+ resourceId: snapshotData.resourceId
2233
+ };
2234
+ }
2235
+ var WorkflowStorageDynamoDB = class extends storage.WorkflowsStorage {
2236
+ service;
2237
+ constructor({ service }) {
2238
+ super();
2239
+ this.service = service;
2240
+ }
2241
+ updateWorkflowResults({
2242
+ // workflowName,
2243
+ // runId,
2244
+ // stepId,
2245
+ // result,
2246
+ // requestContext,
2247
+ }) {
2248
+ throw new Error("Method not implemented.");
2249
+ }
2250
+ updateWorkflowState({
2251
+ // workflowName,
2252
+ // runId,
2253
+ // opts,
2254
+ }) {
2255
+ throw new Error("Method not implemented.");
2256
+ }
1237
2257
  // Workflow operations
1238
2258
  async persistWorkflowSnapshot({
1239
2259
  workflowName,
1240
2260
  runId,
2261
+ resourceId,
1241
2262
  snapshot
1242
2263
  }) {
1243
2264
  this.logger.debug("Persisting workflow snapshot", { workflowName, runId });
1244
2265
  try {
1245
- const resourceId = "resourceId" in snapshot ? snapshot.resourceId : void 0;
1246
2266
  const now = (/* @__PURE__ */ new Date()).toISOString();
1247
2267
  const data = {
1248
2268
  entity: "workflow_snapshot",
@@ -1250,12 +2270,11 @@ var DynamoDBStore = class extends storage.MastraStorage {
1250
2270
  workflow_name: workflowName,
1251
2271
  run_id: runId,
1252
2272
  snapshot: JSON.stringify(snapshot),
1253
- // Stringify the snapshot object
1254
2273
  createdAt: now,
1255
2274
  updatedAt: now,
1256
2275
  resourceId
1257
2276
  };
1258
- await this.service.entities.workflowSnapshot.upsert(data).go();
2277
+ await this.service.entities.workflow_snapshot.upsert(data).go();
1259
2278
  } catch (error$1) {
1260
2279
  throw new error.MastraError(
1261
2280
  {
@@ -1274,7 +2293,7 @@ var DynamoDBStore = class extends storage.MastraStorage {
1274
2293
  }) {
1275
2294
  this.logger.debug("Loading workflow snapshot", { workflowName, runId });
1276
2295
  try {
1277
- const result = await this.service.entities.workflowSnapshot.get({
2296
+ const result = await this.service.entities.workflow_snapshot.get({
1278
2297
  entity: "workflow_snapshot",
1279
2298
  // Add entity type
1280
2299
  workflow_name: workflowName,
@@ -1296,21 +2315,34 @@ var DynamoDBStore = class extends storage.MastraStorage {
1296
2315
  );
1297
2316
  }
1298
2317
  }
1299
- async getWorkflowRuns(args) {
2318
+ async listWorkflowRuns(args) {
1300
2319
  this.logger.debug("Getting workflow runs", { args });
1301
2320
  try {
1302
- const limit = args?.limit || 10;
1303
- const offset = args?.offset || 0;
2321
+ const perPage = args?.perPage !== void 0 ? args.perPage : 10;
2322
+ const page = args?.page !== void 0 ? args.page : 0;
2323
+ if (page < 0) {
2324
+ throw new error.MastraError(
2325
+ {
2326
+ id: "DYNAMODB_STORE_INVALID_PAGE",
2327
+ domain: error.ErrorDomain.STORAGE,
2328
+ category: error.ErrorCategory.USER,
2329
+ details: { page }
2330
+ },
2331
+ new Error("page must be >= 0")
2332
+ );
2333
+ }
2334
+ const normalizedPerPage = storage.normalizePerPage(perPage, 10);
2335
+ const offset = page * normalizedPerPage;
1304
2336
  let query;
1305
2337
  if (args?.workflowName) {
1306
- query = this.service.entities.workflowSnapshot.query.primary({
2338
+ query = this.service.entities.workflow_snapshot.query.primary({
1307
2339
  entity: "workflow_snapshot",
1308
2340
  // Add entity type
1309
2341
  workflow_name: args.workflowName
1310
2342
  });
1311
2343
  } else {
1312
2344
  this.logger.warn("Performing a scan operation on workflow snapshots - consider using a more specific query");
1313
- query = this.service.entities.workflowSnapshot.scan;
2345
+ query = this.service.entities.workflow_snapshot.scan;
1314
2346
  }
1315
2347
  const allMatchingSnapshots = [];
1316
2348
  let cursor = null;
@@ -1322,6 +2354,11 @@ var DynamoDBStore = class extends storage.MastraStorage {
1322
2354
  });
1323
2355
  if (pageResults.data && pageResults.data.length > 0) {
1324
2356
  let pageFilteredData = pageResults.data;
2357
+ if (args?.status) {
2358
+ pageFilteredData = pageFilteredData.filter((snapshot) => {
2359
+ return snapshot.snapshot.status === args.status;
2360
+ });
2361
+ }
1325
2362
  if (args?.fromDate || args?.toDate) {
1326
2363
  pageFilteredData = pageFilteredData.filter((snapshot) => {
1327
2364
  const createdAt = new Date(snapshot.createdAt);
@@ -1347,8 +2384,8 @@ var DynamoDBStore = class extends storage.MastraStorage {
1347
2384
  return { runs: [], total: 0 };
1348
2385
  }
1349
2386
  const total = allMatchingSnapshots.length;
1350
- const paginatedData = allMatchingSnapshots.slice(offset, offset + limit);
1351
- const runs = paginatedData.map((snapshot) => this.formatWorkflowRun(snapshot));
2387
+ const paginatedData = allMatchingSnapshots.slice(offset, offset + normalizedPerPage);
2388
+ const runs = paginatedData.map((snapshot) => formatWorkflowRun(snapshot));
1352
2389
  return {
1353
2390
  runs,
1354
2391
  total
@@ -1356,7 +2393,7 @@ var DynamoDBStore = class extends storage.MastraStorage {
1356
2393
  } catch (error$1) {
1357
2394
  throw new error.MastraError(
1358
2395
  {
1359
- id: "STORAGE_DYNAMODB_STORE_GET_WORKFLOW_RUNS_FAILED",
2396
+ id: "STORAGE_DYNAMODB_STORE_LIST_WORKFLOW_RUNS_FAILED",
1360
2397
  domain: error.ErrorDomain.STORAGE,
1361
2398
  category: error.ErrorCategory.THIRD_PARTY,
1362
2399
  details: { workflowName: args?.workflowName || "", resourceId: args?.resourceId || "" }
@@ -1371,7 +2408,7 @@ var DynamoDBStore = class extends storage.MastraStorage {
1371
2408
  try {
1372
2409
  if (workflowName) {
1373
2410
  this.logger.debug("WorkflowName provided, using direct GET operation.");
1374
- const result2 = await this.service.entities.workflowSnapshot.get({
2411
+ const result2 = await this.service.entities.workflow_snapshot.get({
1375
2412
  entity: "workflow_snapshot",
1376
2413
  // Entity type for PK
1377
2414
  workflow_name: workflowName,
@@ -1393,7 +2430,7 @@ var DynamoDBStore = class extends storage.MastraStorage {
1393
2430
  this.logger.debug(
1394
2431
  'WorkflowName not provided. Attempting to find workflow run by runId using GSI. Ensure GSI (e.g., "byRunId") is defined on the workflowSnapshot entity with run_id as its key and provisioned in DynamoDB.'
1395
2432
  );
1396
- const result = await this.service.entities.workflowSnapshot.query.gsi2({ entity: "workflow_snapshot", run_id: runId }).go();
2433
+ const result = await this.service.entities.workflow_snapshot.query.gsi2({ entity: "workflow_snapshot", run_id: runId }).go();
1397
2434
  const matchingRunDbItem = result.data && result.data.length > 0 ? result.data[0] : null;
1398
2435
  if (!matchingRunDbItem) {
1399
2436
  return null;
@@ -1419,121 +2456,232 @@ var DynamoDBStore = class extends storage.MastraStorage {
1419
2456
  );
1420
2457
  }
1421
2458
  }
1422
- // Helper function to format workflow run
1423
- formatWorkflowRun(snapshotData) {
1424
- return {
1425
- workflowName: snapshotData.workflow_name,
1426
- runId: snapshotData.run_id,
1427
- snapshot: snapshotData.snapshot,
1428
- createdAt: new Date(snapshotData.createdAt),
1429
- updatedAt: new Date(snapshotData.updatedAt),
1430
- resourceId: snapshotData.resourceId
1431
- };
2459
+ };
2460
+
2461
+ // src/storage/index.ts
2462
+ var DynamoDBStore = class extends storage.MastraStorage {
2463
+ tableName;
2464
+ client;
2465
+ service;
2466
+ hasInitialized = null;
2467
+ stores;
2468
+ constructor({ name, config }) {
2469
+ super({ id: config.id, name });
2470
+ try {
2471
+ if (!config.tableName || typeof config.tableName !== "string" || config.tableName.trim() === "") {
2472
+ throw new Error("DynamoDBStore: config.tableName must be provided and cannot be empty.");
2473
+ }
2474
+ if (!/^[a-zA-Z0-9_.-]{3,255}$/.test(config.tableName)) {
2475
+ throw new Error(
2476
+ `DynamoDBStore: config.tableName "${config.tableName}" contains invalid characters or is not between 3 and 255 characters long.`
2477
+ );
2478
+ }
2479
+ const dynamoClient = new clientDynamodb.DynamoDBClient({
2480
+ region: config.region || "us-east-1",
2481
+ endpoint: config.endpoint,
2482
+ credentials: config.credentials
2483
+ });
2484
+ this.tableName = config.tableName;
2485
+ this.client = libDynamodb.DynamoDBDocumentClient.from(dynamoClient);
2486
+ this.service = getElectroDbService(this.client, this.tableName);
2487
+ const operations = new StoreOperationsDynamoDB({
2488
+ service: this.service,
2489
+ tableName: this.tableName,
2490
+ client: this.client
2491
+ });
2492
+ const workflows = new WorkflowStorageDynamoDB({ service: this.service });
2493
+ const memory = new MemoryStorageDynamoDB({ service: this.service });
2494
+ const scores = new ScoresStorageDynamoDB({ service: this.service });
2495
+ this.stores = {
2496
+ operations,
2497
+ workflows,
2498
+ memory,
2499
+ scores
2500
+ };
2501
+ } catch (error$1) {
2502
+ throw new error.MastraError(
2503
+ {
2504
+ id: "STORAGE_DYNAMODB_STORE_CONSTRUCTOR_FAILED",
2505
+ domain: error.ErrorDomain.STORAGE,
2506
+ category: error.ErrorCategory.USER
2507
+ },
2508
+ error$1
2509
+ );
2510
+ }
1432
2511
  }
1433
- // Helper methods for entity/table mapping
1434
- getEntityNameForTable(tableName) {
1435
- const mapping = {
1436
- [storage.TABLE_THREADS]: "thread",
1437
- [storage.TABLE_MESSAGES]: "message",
1438
- [storage.TABLE_WORKFLOW_SNAPSHOT]: "workflowSnapshot",
1439
- [storage.TABLE_EVALS]: "eval",
1440
- [storage.TABLE_TRACES]: "trace"
2512
+ get supports() {
2513
+ return {
2514
+ selectByIncludeResourceScope: true,
2515
+ resourceWorkingMemory: true,
2516
+ hasColumn: false,
2517
+ createTable: false,
2518
+ deleteMessages: false,
2519
+ listScoresBySpan: true
1441
2520
  };
1442
- return mapping[tableName] || null;
1443
2521
  }
1444
- // Eval operations
1445
- async getEvalsByAgentName(agentName, type) {
1446
- this.logger.debug("Getting evals for agent", { agentName, type });
2522
+ /**
2523
+ * Validates that the required DynamoDB table exists and is accessible.
2524
+ * This does not check the table structure - it assumes the table
2525
+ * was created with the correct structure via CDK/CloudFormation.
2526
+ */
2527
+ async validateTableExists() {
1447
2528
  try {
1448
- const query = this.service.entities.eval.query.byAgent({ entity: "eval", agent_name: agentName });
1449
- const results = await query.go({ order: "desc", limit: 100 });
1450
- if (!results.data.length) {
1451
- return [];
1452
- }
1453
- let filteredData = results.data;
1454
- if (type) {
1455
- filteredData = filteredData.filter((evalRecord) => {
1456
- try {
1457
- const testInfo = evalRecord.test_info && typeof evalRecord.test_info === "string" ? JSON.parse(evalRecord.test_info) : void 0;
1458
- if (type === "test" && !testInfo) {
1459
- return false;
1460
- }
1461
- if (type === "live" && testInfo) {
1462
- return false;
1463
- }
1464
- } catch (e) {
1465
- this.logger.warn("Failed to parse test_info during filtering", { record: evalRecord, error: e });
1466
- }
1467
- return true;
1468
- });
1469
- }
1470
- return filteredData.map((evalRecord) => {
1471
- try {
1472
- return {
1473
- input: evalRecord.input,
1474
- output: evalRecord.output,
1475
- // Safely parse result and test_info
1476
- result: evalRecord.result && typeof evalRecord.result === "string" ? JSON.parse(evalRecord.result) : void 0,
1477
- agentName: evalRecord.agent_name,
1478
- createdAt: evalRecord.created_at,
1479
- // Keep as string from DDB?
1480
- metricName: evalRecord.metric_name,
1481
- instructions: evalRecord.instructions,
1482
- runId: evalRecord.run_id,
1483
- globalRunId: evalRecord.global_run_id,
1484
- testInfo: evalRecord.test_info && typeof evalRecord.test_info === "string" ? JSON.parse(evalRecord.test_info) : void 0
1485
- };
1486
- } catch (parseError) {
1487
- this.logger.error("Failed to parse eval record", { record: evalRecord, error: parseError });
1488
- return {
1489
- agentName: evalRecord.agent_name,
1490
- createdAt: evalRecord.created_at,
1491
- runId: evalRecord.run_id,
1492
- globalRunId: evalRecord.global_run_id
1493
- };
1494
- }
2529
+ const command = new clientDynamodb.DescribeTableCommand({
2530
+ TableName: this.tableName
1495
2531
  });
2532
+ await this.client.send(command);
2533
+ return true;
1496
2534
  } catch (error$1) {
2535
+ if (error$1.name === "ResourceNotFoundException") {
2536
+ return false;
2537
+ }
1497
2538
  throw new error.MastraError(
1498
2539
  {
1499
- id: "STORAGE_DYNAMODB_STORE_GET_EVALS_BY_AGENT_NAME_FAILED",
2540
+ id: "STORAGE_DYNAMODB_STORE_VALIDATE_TABLE_EXISTS_FAILED",
1500
2541
  domain: error.ErrorDomain.STORAGE,
1501
2542
  category: error.ErrorCategory.THIRD_PARTY,
1502
- details: { agentName }
2543
+ details: { tableName: this.tableName }
1503
2544
  },
1504
2545
  error$1
1505
2546
  );
1506
2547
  }
1507
2548
  }
1508
- async getTracesPaginated(_args) {
1509
- throw new error.MastraError(
1510
- {
1511
- id: "STORAGE_DYNAMODB_STORE_GET_TRACES_PAGINATED_FAILED",
1512
- domain: error.ErrorDomain.STORAGE,
1513
- category: error.ErrorCategory.THIRD_PARTY
1514
- },
1515
- new Error("Method not implemented.")
1516
- );
2549
+ /**
2550
+ * Initialize storage, validating the externally managed table is accessible.
2551
+ * For the single-table design, we only validate once that we can access
2552
+ * the table that was created via CDK/CloudFormation.
2553
+ */
2554
+ async init() {
2555
+ if (this.hasInitialized === null) {
2556
+ this.hasInitialized = this._performInitializationAndStore();
2557
+ }
2558
+ try {
2559
+ await this.hasInitialized;
2560
+ } catch (error$1) {
2561
+ throw new error.MastraError(
2562
+ {
2563
+ id: "STORAGE_DYNAMODB_STORE_INIT_FAILED",
2564
+ domain: error.ErrorDomain.STORAGE,
2565
+ category: error.ErrorCategory.THIRD_PARTY,
2566
+ details: { tableName: this.tableName }
2567
+ },
2568
+ error$1
2569
+ );
2570
+ }
1517
2571
  }
1518
- async getThreadsByResourceIdPaginated(_args) {
1519
- throw new error.MastraError(
1520
- {
1521
- id: "STORAGE_DYNAMODB_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
1522
- domain: error.ErrorDomain.STORAGE,
1523
- category: error.ErrorCategory.THIRD_PARTY
1524
- },
1525
- new Error("Method not implemented.")
1526
- );
2572
+ /**
2573
+ * Performs the actual table validation and stores the promise.
2574
+ * Handles resetting the stored promise on failure to allow retries.
2575
+ */
2576
+ _performInitializationAndStore() {
2577
+ return this.validateTableExists().then((exists) => {
2578
+ if (!exists) {
2579
+ throw new Error(
2580
+ `Table ${this.tableName} does not exist or is not accessible. Ensure it's created via CDK/CloudFormation before using this store.`
2581
+ );
2582
+ }
2583
+ return true;
2584
+ }).catch((err) => {
2585
+ this.hasInitialized = null;
2586
+ throw err;
2587
+ });
1527
2588
  }
1528
- async getMessagesPaginated(_args) {
1529
- throw new error.MastraError(
1530
- {
1531
- id: "STORAGE_DYNAMODB_STORE_GET_MESSAGES_PAGINATED_FAILED",
1532
- domain: error.ErrorDomain.STORAGE,
1533
- category: error.ErrorCategory.THIRD_PARTY
1534
- },
1535
- new Error("Method not implemented.")
1536
- );
2589
+ async createTable({ tableName, schema }) {
2590
+ return this.stores.operations.createTable({ tableName, schema });
2591
+ }
2592
+ async alterTable(_args) {
2593
+ return this.stores.operations.alterTable(_args);
2594
+ }
2595
+ async clearTable({ tableName }) {
2596
+ return this.stores.operations.clearTable({ tableName });
2597
+ }
2598
+ async dropTable({ tableName }) {
2599
+ return this.stores.operations.dropTable({ tableName });
2600
+ }
2601
+ async insert({ tableName, record }) {
2602
+ return this.stores.operations.insert({ tableName, record });
2603
+ }
2604
+ async batchInsert({ tableName, records }) {
2605
+ return this.stores.operations.batchInsert({ tableName, records });
2606
+ }
2607
+ async load({ tableName, keys }) {
2608
+ return this.stores.operations.load({ tableName, keys });
2609
+ }
2610
+ // Thread operations
2611
+ async getThreadById({ threadId }) {
2612
+ return this.stores.memory.getThreadById({ threadId });
2613
+ }
2614
+ async saveThread({ thread }) {
2615
+ return this.stores.memory.saveThread({ thread });
2616
+ }
2617
+ async updateThread({
2618
+ id,
2619
+ title,
2620
+ metadata
2621
+ }) {
2622
+ return this.stores.memory.updateThread({ id, title, metadata });
2623
+ }
2624
+ async deleteThread({ threadId }) {
2625
+ return this.stores.memory.deleteThread({ threadId });
2626
+ }
2627
+ async listMessagesById(args) {
2628
+ return this.stores.memory.listMessagesById(args);
2629
+ }
2630
+ async saveMessages(args) {
2631
+ return this.stores.memory.saveMessages(args);
2632
+ }
2633
+ async updateMessages(_args) {
2634
+ return this.stores.memory.updateMessages(_args);
2635
+ }
2636
+ // Workflow operations
2637
+ async updateWorkflowResults({
2638
+ workflowName,
2639
+ runId,
2640
+ stepId,
2641
+ result,
2642
+ requestContext
2643
+ }) {
2644
+ return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
2645
+ }
2646
+ async updateWorkflowState({
2647
+ workflowName,
2648
+ runId,
2649
+ opts
2650
+ }) {
2651
+ return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
2652
+ }
2653
+ async persistWorkflowSnapshot({
2654
+ workflowName,
2655
+ runId,
2656
+ resourceId,
2657
+ snapshot
2658
+ }) {
2659
+ return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
2660
+ }
2661
+ async loadWorkflowSnapshot({
2662
+ workflowName,
2663
+ runId
2664
+ }) {
2665
+ return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
2666
+ }
2667
+ async listWorkflowRuns(args) {
2668
+ return this.stores.workflows.listWorkflowRuns(args);
2669
+ }
2670
+ async getWorkflowRunById(args) {
2671
+ return this.stores.workflows.getWorkflowRunById(args);
2672
+ }
2673
+ async getResourceById({ resourceId }) {
2674
+ return this.stores.memory.getResourceById({ resourceId });
2675
+ }
2676
+ async saveResource({ resource }) {
2677
+ return this.stores.memory.saveResource({ resource });
2678
+ }
2679
+ async updateResource({
2680
+ resourceId,
2681
+ workingMemory,
2682
+ metadata
2683
+ }) {
2684
+ return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
1537
2685
  }
1538
2686
  /**
1539
2687
  * Closes the DynamoDB client connection and cleans up resources.
@@ -1555,10 +2703,50 @@ var DynamoDBStore = class extends storage.MastraStorage {
1555
2703
  );
1556
2704
  }
1557
2705
  }
1558
- async updateMessages(_args) {
1559
- this.logger.error("updateMessages is not yet implemented in DynamoDBStore");
1560
- throw new Error("Method not implemented");
2706
+ /**
2707
+ * SCORERS - Not implemented
2708
+ */
2709
+ async getScoreById({ id: _id }) {
2710
+ return this.stores.scores.getScoreById({ id: _id });
2711
+ }
2712
+ async saveScore(_score) {
2713
+ return this.stores.scores.saveScore(_score);
2714
+ }
2715
+ async listScoresByRunId({
2716
+ runId: _runId,
2717
+ pagination: _pagination
2718
+ }) {
2719
+ return this.stores.scores.listScoresByRunId({ runId: _runId, pagination: _pagination });
2720
+ }
2721
+ async listScoresByEntityId({
2722
+ entityId: _entityId,
2723
+ entityType: _entityType,
2724
+ pagination: _pagination
2725
+ }) {
2726
+ return this.stores.scores.listScoresByEntityId({
2727
+ entityId: _entityId,
2728
+ entityType: _entityType,
2729
+ pagination: _pagination
2730
+ });
2731
+ }
2732
+ async listScoresByScorerId({
2733
+ scorerId,
2734
+ source,
2735
+ entityId,
2736
+ entityType,
2737
+ pagination
2738
+ }) {
2739
+ return this.stores.scores.listScoresByScorerId({ scorerId, source, entityId, entityType, pagination });
2740
+ }
2741
+ async listScoresBySpan({
2742
+ traceId,
2743
+ spanId,
2744
+ pagination
2745
+ }) {
2746
+ return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
1561
2747
  }
1562
2748
  };
1563
2749
 
1564
2750
  exports.DynamoDBStore = DynamoDBStore;
2751
+ //# sourceMappingURL=index.cjs.map
2752
+ //# sourceMappingURL=index.cjs.map