@mastra/dynamodb 0.0.0-pass-headers-for-create-mastra-client-20250530010057 → 0.0.0-pgvector-index-fix-20250905222058

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 (52) hide show
  1. package/CHANGELOG.md +864 -0
  2. package/LICENSE.md +11 -42
  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 +746 -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 +229 -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 +2296 -447
  22. package/dist/index.cjs.map +1 -0
  23. package/dist/index.d.ts +2 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +2299 -450
  26. package/dist/index.js.map +1 -0
  27. package/dist/storage/domains/legacy-evals/index.d.ts +19 -0
  28. package/dist/storage/domains/legacy-evals/index.d.ts.map +1 -0
  29. package/dist/storage/domains/memory/index.d.ts +89 -0
  30. package/dist/storage/domains/memory/index.d.ts.map +1 -0
  31. package/dist/storage/domains/operations/index.d.ts +69 -0
  32. package/dist/storage/domains/operations/index.d.ts.map +1 -0
  33. package/dist/storage/domains/score/index.d.ts +43 -0
  34. package/dist/storage/domains/score/index.d.ts.map +1 -0
  35. package/dist/storage/domains/traces/index.d.ts +28 -0
  36. package/dist/storage/domains/traces/index.d.ts.map +1 -0
  37. package/dist/storage/domains/workflows/index.d.ts +50 -0
  38. package/dist/storage/domains/workflows/index.d.ts.map +1 -0
  39. package/dist/storage/index.d.ts +249 -0
  40. package/dist/storage/index.d.ts.map +1 -0
  41. package/package.json +43 -19
  42. package/src/entities/eval.ts +0 -102
  43. package/src/entities/index.ts +0 -23
  44. package/src/entities/message.ts +0 -143
  45. package/src/entities/thread.ts +0 -66
  46. package/src/entities/trace.ts +0 -129
  47. package/src/entities/utils.ts +0 -51
  48. package/src/entities/workflow-snapshot.ts +0 -56
  49. package/src/index.ts +0 -1
  50. package/src/storage/docker-compose.yml +0 -16
  51. package/src/storage/index.test.ts +0 -1053
  52. package/src/storage/index.ts +0 -1059
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { DynamoDBClient, DescribeTableCommand } from '@aws-sdk/client-dynamodb';
2
2
  import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
3
- import { MessageList } from '@mastra/core/agent';
4
- import { MastraStorage, TABLE_TRACES, TABLE_EVALS, TABLE_WORKFLOW_SNAPSHOT, TABLE_MESSAGES, TABLE_THREADS } from '@mastra/core/storage';
3
+ import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
4
+ import { MastraStorage, StoreOperations, TracesStorage, TABLE_TRACES, WorkflowsStorage, MemoryStorage, resolveMessageLimit, ScoresStorage, LegacyEvalsStorage, TABLE_AI_SPANS, TABLE_RESOURCES, TABLE_SCORERS, TABLE_EVALS, TABLE_WORKFLOW_SNAPSHOT, TABLE_MESSAGES, TABLE_THREADS } from '@mastra/core/storage';
5
5
  import { Entity, Service } from 'electrodb';
6
+ import { MessageList } from '@mastra/core/agent';
6
7
 
7
8
  // src/storage/index.ts
8
9
 
@@ -293,9 +294,9 @@ var messageEntity = new Entity({
293
294
  }
294
295
  }
295
296
  });
296
- var threadEntity = new Entity({
297
+ var resourceEntity = new Entity({
297
298
  model: {
298
- entity: "thread",
299
+ entity: "resource",
299
300
  version: "1",
300
301
  service: "mastra"
301
302
  },
@@ -309,25 +310,21 @@ var threadEntity = new Entity({
309
310
  type: "string",
310
311
  required: true
311
312
  },
312
- resourceId: {
313
- type: "string",
314
- required: true
315
- },
316
- title: {
313
+ workingMemory: {
317
314
  type: "string",
318
- required: true
315
+ required: false
319
316
  },
320
317
  metadata: {
321
318
  type: "string",
322
319
  required: false,
323
- // Stringify metadata object on set if it's not already a string
320
+ // Stringify content object on set if it's not already a string
324
321
  set: (value) => {
325
322
  if (value && typeof value !== "string") {
326
323
  return JSON.stringify(value);
327
324
  }
328
325
  return value;
329
326
  },
330
- // Parse JSON string to object on get
327
+ // Parse JSON string to object on get ONLY if it looks like JSON
331
328
  get: (value) => {
332
329
  if (value && typeof value === "string") {
333
330
  try {
@@ -345,18 +342,13 @@ var threadEntity = new Entity({
345
342
  indexes: {
346
343
  primary: {
347
344
  pk: { field: "pk", composite: ["entity", "id"] },
348
- sk: { field: "sk", composite: ["id"] }
349
- },
350
- byResource: {
351
- index: "gsi1",
352
- pk: { field: "gsi1pk", composite: ["entity", "resourceId"] },
353
- sk: { field: "gsi1sk", composite: ["createdAt"] }
345
+ sk: { field: "sk", composite: ["entity"] }
354
346
  }
355
347
  }
356
348
  });
357
- var traceEntity = new Entity({
349
+ var scoreEntity = new Entity({
358
350
  model: {
359
- entity: "trace",
351
+ entity: "score",
360
352
  version: "1",
361
353
  service: "mastra"
362
354
  },
@@ -370,123 +362,306 @@ var traceEntity = new Entity({
370
362
  type: "string",
371
363
  required: true
372
364
  },
373
- parentSpanId: {
365
+ scorerId: {
366
+ type: "string",
367
+ required: true
368
+ },
369
+ traceId: {
374
370
  type: "string",
375
371
  required: false
376
372
  },
377
- name: {
373
+ runId: {
378
374
  type: "string",
379
375
  required: true
380
376
  },
381
- traceId: {
377
+ scorer: {
382
378
  type: "string",
383
- required: true
379
+ required: true,
380
+ set: (value) => {
381
+ if (value && typeof value !== "string") {
382
+ return JSON.stringify(value);
383
+ }
384
+ return value;
385
+ },
386
+ get: (value) => {
387
+ if (value && typeof value === "string") {
388
+ try {
389
+ if (value.startsWith("{") || value.startsWith("[")) {
390
+ return JSON.parse(value);
391
+ }
392
+ } catch {
393
+ return value;
394
+ }
395
+ }
396
+ return value;
397
+ }
384
398
  },
385
- scope: {
399
+ extractStepResult: {
386
400
  type: "string",
387
- required: true
401
+ required: false,
402
+ set: (value) => {
403
+ if (value && typeof value !== "string") {
404
+ return JSON.stringify(value);
405
+ }
406
+ return value;
407
+ },
408
+ get: (value) => {
409
+ if (value && typeof value === "string") {
410
+ try {
411
+ if (value.startsWith("{") || value.startsWith("[")) {
412
+ return JSON.parse(value);
413
+ }
414
+ } catch {
415
+ return value;
416
+ }
417
+ }
418
+ return value;
419
+ }
388
420
  },
389
- kind: {
421
+ preprocessStepResult: {
422
+ type: "string",
423
+ required: false,
424
+ set: (value) => {
425
+ if (value && typeof value !== "string") {
426
+ return JSON.stringify(value);
427
+ }
428
+ return value;
429
+ },
430
+ get: (value) => {
431
+ if (value && typeof value === "string") {
432
+ try {
433
+ if (value.startsWith("{") || value.startsWith("[")) {
434
+ return JSON.parse(value);
435
+ }
436
+ } catch {
437
+ return value;
438
+ }
439
+ }
440
+ return value;
441
+ }
442
+ },
443
+ analyzeStepResult: {
444
+ type: "string",
445
+ required: false,
446
+ set: (value) => {
447
+ if (value && typeof value !== "string") {
448
+ return JSON.stringify(value);
449
+ }
450
+ return value;
451
+ },
452
+ get: (value) => {
453
+ if (value && typeof value === "string") {
454
+ try {
455
+ if (value.startsWith("{") || value.startsWith("[")) {
456
+ return JSON.parse(value);
457
+ }
458
+ } catch {
459
+ return value;
460
+ }
461
+ }
462
+ return value;
463
+ }
464
+ },
465
+ score: {
390
466
  type: "number",
391
467
  required: true
392
468
  },
393
- attributes: {
469
+ reason: {
394
470
  type: "string",
395
- // JSON stringified
396
- required: false,
397
- // Stringify object on set
471
+ required: false
472
+ },
473
+ extractPrompt: {
474
+ type: "string",
475
+ required: false
476
+ },
477
+ analyzePrompt: {
478
+ type: "string",
479
+ required: false
480
+ },
481
+ // Deprecated in favor of generateReasonPrompt
482
+ reasonPrompt: {
483
+ type: "string",
484
+ required: false
485
+ },
486
+ generateScorePrompt: {
487
+ type: "string",
488
+ required: false
489
+ },
490
+ generateReasonPrompt: {
491
+ type: "string",
492
+ required: false
493
+ },
494
+ input: {
495
+ type: "string",
496
+ required: true,
398
497
  set: (value) => {
399
498
  if (value && typeof value !== "string") {
400
499
  return JSON.stringify(value);
401
500
  }
402
501
  return value;
403
502
  },
404
- // Parse JSON string to object on get
405
503
  get: (value) => {
406
- return value ? JSON.parse(value) : value;
504
+ if (value && typeof value === "string") {
505
+ try {
506
+ if (value.startsWith("{") || value.startsWith("[")) {
507
+ return JSON.parse(value);
508
+ }
509
+ } catch {
510
+ return value;
511
+ }
512
+ }
513
+ return value;
407
514
  }
408
515
  },
409
- status: {
516
+ output: {
517
+ type: "string",
518
+ required: true,
519
+ set: (value) => {
520
+ if (value && typeof value !== "string") {
521
+ return JSON.stringify(value);
522
+ }
523
+ return value;
524
+ },
525
+ get: (value) => {
526
+ if (value && typeof value === "string") {
527
+ try {
528
+ if (value.startsWith("{") || value.startsWith("[")) {
529
+ return JSON.parse(value);
530
+ }
531
+ } catch {
532
+ return value;
533
+ }
534
+ }
535
+ return value;
536
+ }
537
+ },
538
+ additionalContext: {
410
539
  type: "string",
411
- // JSON stringified
412
540
  required: false,
413
- // Stringify object on set
414
541
  set: (value) => {
415
542
  if (value && typeof value !== "string") {
416
543
  return JSON.stringify(value);
417
544
  }
418
545
  return value;
419
546
  },
420
- // Parse JSON string to object on get
421
547
  get: (value) => {
548
+ if (value && typeof value === "string") {
549
+ try {
550
+ if (value.startsWith("{") || value.startsWith("[")) {
551
+ return JSON.parse(value);
552
+ }
553
+ } catch {
554
+ return value;
555
+ }
556
+ }
422
557
  return value;
423
558
  }
424
559
  },
425
- events: {
560
+ runtimeContext: {
426
561
  type: "string",
427
- // JSON stringified
428
562
  required: false,
429
- // Stringify object on set
430
563
  set: (value) => {
431
564
  if (value && typeof value !== "string") {
432
565
  return JSON.stringify(value);
433
566
  }
434
567
  return value;
435
568
  },
436
- // Parse JSON string to object on get
437
569
  get: (value) => {
570
+ if (value && typeof value === "string") {
571
+ try {
572
+ if (value.startsWith("{") || value.startsWith("[")) {
573
+ return JSON.parse(value);
574
+ }
575
+ } catch {
576
+ return value;
577
+ }
578
+ }
438
579
  return value;
439
580
  }
440
581
  },
441
- links: {
582
+ entityType: {
583
+ type: "string",
584
+ required: false
585
+ },
586
+ entityData: {
442
587
  type: "string",
443
- // JSON stringified
444
588
  required: false,
445
- // Stringify object on set
446
589
  set: (value) => {
447
590
  if (value && typeof value !== "string") {
448
591
  return JSON.stringify(value);
449
592
  }
450
593
  return value;
451
594
  },
452
- // Parse JSON string to object on get
453
595
  get: (value) => {
596
+ if (value && typeof value === "string") {
597
+ try {
598
+ if (value.startsWith("{") || value.startsWith("[")) {
599
+ return JSON.parse(value);
600
+ }
601
+ } catch {
602
+ return value;
603
+ }
604
+ }
454
605
  return value;
455
606
  }
456
607
  },
457
- other: {
608
+ entityId: {
458
609
  type: "string",
459
610
  required: false
460
611
  },
461
- startTime: {
462
- type: "number",
612
+ source: {
613
+ type: "string",
463
614
  required: true
464
615
  },
465
- endTime: {
466
- type: "number",
467
- required: true
616
+ resourceId: {
617
+ type: "string",
618
+ required: false
619
+ },
620
+ threadId: {
621
+ type: "string",
622
+ required: false
468
623
  }
469
624
  },
470
625
  indexes: {
471
626
  primary: {
472
627
  pk: { field: "pk", composite: ["entity", "id"] },
473
- sk: { field: "sk", composite: [] }
628
+ sk: { field: "sk", composite: ["entity"] }
474
629
  },
475
- byName: {
630
+ byScorer: {
476
631
  index: "gsi1",
477
- pk: { field: "gsi1pk", composite: ["entity", "name"] },
478
- sk: { field: "gsi1sk", composite: ["startTime"] }
632
+ pk: { field: "gsi1pk", composite: ["entity", "scorerId"] },
633
+ sk: { field: "gsi1sk", composite: ["createdAt"] }
479
634
  },
480
- byScope: {
635
+ byRun: {
481
636
  index: "gsi2",
482
- pk: { field: "gsi2pk", composite: ["entity", "scope"] },
483
- sk: { field: "gsi2sk", composite: ["startTime"] }
637
+ pk: { field: "gsi2pk", composite: ["entity", "runId"] },
638
+ sk: { field: "gsi2sk", composite: ["createdAt"] }
639
+ },
640
+ byTrace: {
641
+ index: "gsi3",
642
+ pk: { field: "gsi3pk", composite: ["entity", "traceId"] },
643
+ sk: { field: "gsi3sk", composite: ["createdAt"] }
644
+ },
645
+ byEntityData: {
646
+ index: "gsi4",
647
+ pk: { field: "gsi4pk", composite: ["entity", "entityId"] },
648
+ sk: { field: "gsi4sk", composite: ["createdAt"] }
649
+ },
650
+ byResource: {
651
+ index: "gsi5",
652
+ pk: { field: "gsi5pk", composite: ["entity", "resourceId"] },
653
+ sk: { field: "gsi5sk", composite: ["createdAt"] }
654
+ },
655
+ byThread: {
656
+ index: "gsi6",
657
+ pk: { field: "gsi6pk", composite: ["entity", "threadId"] },
658
+ sk: { field: "gsi6sk", composite: ["createdAt"] }
484
659
  }
485
660
  }
486
661
  });
487
- var workflowSnapshotEntity = new Entity({
662
+ var threadEntity = new Entity({
488
663
  model: {
489
- entity: "workflow_snapshot",
664
+ entity: "thread",
490
665
  version: "1",
491
666
  service: "mastra"
492
667
  },
@@ -496,18 +671,209 @@ var workflowSnapshotEntity = new Entity({
496
671
  required: true
497
672
  },
498
673
  ...baseAttributes,
499
- workflow_name: {
674
+ id: {
500
675
  type: "string",
501
676
  required: true
502
677
  },
503
- run_id: {
678
+ resourceId: {
504
679
  type: "string",
505
680
  required: true
506
681
  },
507
- snapshot: {
682
+ title: {
508
683
  type: "string",
509
- // JSON stringified
510
- required: true,
684
+ required: true
685
+ },
686
+ metadata: {
687
+ type: "string",
688
+ required: false,
689
+ // Stringify metadata object on set if it's not already a string
690
+ set: (value) => {
691
+ if (value && typeof value !== "string") {
692
+ return JSON.stringify(value);
693
+ }
694
+ return value;
695
+ },
696
+ // Parse JSON string to object on get
697
+ get: (value) => {
698
+ if (value && typeof value === "string") {
699
+ try {
700
+ if (value.startsWith("{") || value.startsWith("[")) {
701
+ return JSON.parse(value);
702
+ }
703
+ } catch {
704
+ return value;
705
+ }
706
+ }
707
+ return value;
708
+ }
709
+ }
710
+ },
711
+ indexes: {
712
+ primary: {
713
+ pk: { field: "pk", composite: ["entity", "id"] },
714
+ sk: { field: "sk", composite: ["id"] }
715
+ },
716
+ byResource: {
717
+ index: "gsi1",
718
+ pk: { field: "gsi1pk", composite: ["entity", "resourceId"] },
719
+ sk: { field: "gsi1sk", composite: ["createdAt"] }
720
+ }
721
+ }
722
+ });
723
+ var traceEntity = new Entity({
724
+ model: {
725
+ entity: "trace",
726
+ version: "1",
727
+ service: "mastra"
728
+ },
729
+ attributes: {
730
+ entity: {
731
+ type: "string",
732
+ required: true
733
+ },
734
+ ...baseAttributes,
735
+ id: {
736
+ type: "string",
737
+ required: true
738
+ },
739
+ parentSpanId: {
740
+ type: "string",
741
+ required: false
742
+ },
743
+ name: {
744
+ type: "string",
745
+ required: true
746
+ },
747
+ traceId: {
748
+ type: "string",
749
+ required: true
750
+ },
751
+ scope: {
752
+ type: "string",
753
+ required: true
754
+ },
755
+ kind: {
756
+ type: "number",
757
+ required: true
758
+ },
759
+ attributes: {
760
+ type: "string",
761
+ // JSON stringified
762
+ required: false,
763
+ // Stringify object on set
764
+ set: (value) => {
765
+ if (value && typeof value !== "string") {
766
+ return JSON.stringify(value);
767
+ }
768
+ return value;
769
+ },
770
+ // Parse JSON string to object on get
771
+ get: (value) => {
772
+ return value ? JSON.parse(value) : value;
773
+ }
774
+ },
775
+ status: {
776
+ type: "string",
777
+ // JSON stringified
778
+ required: false,
779
+ // Stringify object on set
780
+ set: (value) => {
781
+ if (value && typeof value !== "string") {
782
+ return JSON.stringify(value);
783
+ }
784
+ return value;
785
+ },
786
+ // Parse JSON string to object on get
787
+ get: (value) => {
788
+ return value;
789
+ }
790
+ },
791
+ events: {
792
+ type: "string",
793
+ // JSON stringified
794
+ required: false,
795
+ // Stringify object on set
796
+ set: (value) => {
797
+ if (value && typeof value !== "string") {
798
+ return JSON.stringify(value);
799
+ }
800
+ return value;
801
+ },
802
+ // Parse JSON string to object on get
803
+ get: (value) => {
804
+ return value;
805
+ }
806
+ },
807
+ links: {
808
+ type: "string",
809
+ // JSON stringified
810
+ required: false,
811
+ // Stringify object on set
812
+ set: (value) => {
813
+ if (value && typeof value !== "string") {
814
+ return JSON.stringify(value);
815
+ }
816
+ return value;
817
+ },
818
+ // Parse JSON string to object on get
819
+ get: (value) => {
820
+ return value;
821
+ }
822
+ },
823
+ other: {
824
+ type: "string",
825
+ required: false
826
+ },
827
+ startTime: {
828
+ type: "number",
829
+ required: true
830
+ },
831
+ endTime: {
832
+ type: "number",
833
+ required: true
834
+ }
835
+ },
836
+ indexes: {
837
+ primary: {
838
+ pk: { field: "pk", composite: ["entity", "id"] },
839
+ sk: { field: "sk", composite: [] }
840
+ },
841
+ byName: {
842
+ index: "gsi1",
843
+ pk: { field: "gsi1pk", composite: ["entity", "name"] },
844
+ sk: { field: "gsi1sk", composite: ["startTime"] }
845
+ },
846
+ byScope: {
847
+ index: "gsi2",
848
+ pk: { field: "gsi2pk", composite: ["entity", "scope"] },
849
+ sk: { field: "gsi2sk", composite: ["startTime"] }
850
+ }
851
+ }
852
+ });
853
+ var workflowSnapshotEntity = new Entity({
854
+ model: {
855
+ entity: "workflow_snapshot",
856
+ version: "1",
857
+ service: "mastra"
858
+ },
859
+ attributes: {
860
+ entity: {
861
+ type: "string",
862
+ required: true
863
+ },
864
+ ...baseAttributes,
865
+ workflow_name: {
866
+ type: "string",
867
+ required: true
868
+ },
869
+ run_id: {
870
+ type: "string",
871
+ required: true
872
+ },
873
+ snapshot: {
874
+ type: "string",
875
+ // JSON stringified
876
+ required: true,
511
877
  // Stringify snapshot object on set
512
878
  set: (value) => {
513
879
  if (value && typeof value !== "string") {
@@ -547,7 +913,9 @@ function getElectroDbService(client, tableName) {
547
913
  message: messageEntity,
548
914
  eval: evalEntity,
549
915
  trace: traceEntity,
550
- workflowSnapshot: workflowSnapshotEntity
916
+ workflow_snapshot: workflowSnapshotEntity,
917
+ resource: resourceEntity,
918
+ score: scoreEntity
551
919
  },
552
920
  {
553
921
  client,
@@ -555,104 +923,1064 @@ function getElectroDbService(client, tableName) {
555
923
  }
556
924
  );
557
925
  }
558
-
559
- // src/storage/index.ts
560
- var DynamoDBStore = class extends MastraStorage {
561
- constructor({ name, config }) {
562
- super({ name });
563
- this.hasInitialized = null;
564
- if (!config.tableName || typeof config.tableName !== "string" || config.tableName.trim() === "") {
565
- throw new Error("DynamoDBStore: config.tableName must be provided and cannot be empty.");
566
- }
567
- if (!/^[a-zA-Z0-9_.-]{3,255}$/.test(config.tableName)) {
568
- throw new Error(
569
- `DynamoDBStore: config.tableName "${config.tableName}" contains invalid characters or is not between 3 and 255 characters long.`
570
- );
571
- }
572
- const dynamoClient = new DynamoDBClient({
573
- region: config.region || "us-east-1",
574
- endpoint: config.endpoint,
575
- credentials: config.credentials
576
- });
577
- this.tableName = config.tableName;
578
- this.client = DynamoDBDocumentClient.from(dynamoClient);
579
- this.service = getElectroDbService(this.client, this.tableName);
580
- }
581
- /**
582
- * This method is modified for DynamoDB with ElectroDB single-table design.
583
- * It assumes the table is created and managed externally via CDK/CloudFormation.
584
- *
585
- * This implementation only validates that the required table exists and is accessible.
586
- * No table creation is attempted - we simply check if we can access the table.
587
- */
588
- async createTable({ tableName }) {
589
- this.logger.debug("Validating access to externally managed table", { tableName, physicalTable: this.tableName });
590
- try {
591
- const tableExists = await this.validateTableExists();
592
- if (!tableExists) {
593
- this.logger.error(
594
- `Table ${this.tableName} does not exist or is not accessible. It should be created via CDK/CloudFormation.`
595
- );
596
- throw new Error(
597
- `Table ${this.tableName} does not exist or is not accessible. Ensure it's created via CDK/CloudFormation before using this store.`
598
- );
599
- }
600
- this.logger.debug(`Table ${this.tableName} exists and is accessible`);
601
- } catch (error) {
602
- this.logger.error("Error validating table access", { tableName: this.tableName, error });
603
- throw error;
604
- }
926
+ var LegacyEvalsDynamoDB = class extends LegacyEvalsStorage {
927
+ service;
928
+ tableName;
929
+ constructor({ service, tableName }) {
930
+ super();
931
+ this.service = service;
932
+ this.tableName = tableName;
605
933
  }
606
- /**
607
- * Validates that the required DynamoDB table exists and is accessible.
608
- * This does not check the table structure - it assumes the table
609
- * was created with the correct structure via CDK/CloudFormation.
610
- */
611
- async validateTableExists() {
934
+ // Eval operations
935
+ async getEvalsByAgentName(agentName, type) {
936
+ this.logger.debug("Getting evals for agent", { agentName, type });
612
937
  try {
613
- const command = new DescribeTableCommand({
614
- TableName: this.tableName
615
- });
616
- await this.client.send(command);
617
- return true;
618
- } catch (error) {
619
- if (error.name === "ResourceNotFoundException") {
620
- return false;
938
+ const query = this.service.entities.eval.query.byAgent({ entity: "eval", agent_name: agentName });
939
+ const results = await query.go({ order: "desc", limit: 100 });
940
+ if (!results.data.length) {
941
+ return [];
621
942
  }
622
- throw error;
623
- }
624
- }
625
- /**
626
- * Initialize storage, validating the externally managed table is accessible.
627
- * For the single-table design, we only validate once that we can access
628
- * the table that was created via CDK/CloudFormation.
629
- */
630
- async init() {
631
- if (this.hasInitialized === null) {
632
- this.hasInitialized = this._performInitializationAndStore();
943
+ let filteredData = results.data;
944
+ if (type) {
945
+ filteredData = filteredData.filter((evalRecord) => {
946
+ try {
947
+ const testInfo = evalRecord.test_info && typeof evalRecord.test_info === "string" ? JSON.parse(evalRecord.test_info) : void 0;
948
+ if (type === "test" && !testInfo) {
949
+ return false;
950
+ }
951
+ if (type === "live" && testInfo) {
952
+ return false;
953
+ }
954
+ } catch (e) {
955
+ this.logger.warn("Failed to parse test_info during filtering", { record: evalRecord, error: e });
956
+ }
957
+ return true;
958
+ });
959
+ }
960
+ return filteredData.map((evalRecord) => {
961
+ try {
962
+ return {
963
+ input: evalRecord.input,
964
+ output: evalRecord.output,
965
+ // Safely parse result and test_info
966
+ result: evalRecord.result && typeof evalRecord.result === "string" ? JSON.parse(evalRecord.result) : void 0,
967
+ agentName: evalRecord.agent_name,
968
+ createdAt: evalRecord.created_at,
969
+ // Keep as string from DDB?
970
+ metricName: evalRecord.metric_name,
971
+ instructions: evalRecord.instructions,
972
+ runId: evalRecord.run_id,
973
+ globalRunId: evalRecord.global_run_id,
974
+ testInfo: evalRecord.test_info && typeof evalRecord.test_info === "string" ? JSON.parse(evalRecord.test_info) : void 0
975
+ };
976
+ } catch (parseError) {
977
+ this.logger.error("Failed to parse eval record", { record: evalRecord, error: parseError });
978
+ return {
979
+ agentName: evalRecord.agent_name,
980
+ createdAt: evalRecord.created_at,
981
+ runId: evalRecord.run_id,
982
+ globalRunId: evalRecord.global_run_id
983
+ };
984
+ }
985
+ });
986
+ } catch (error) {
987
+ throw new MastraError(
988
+ {
989
+ id: "STORAGE_DYNAMODB_STORE_GET_EVALS_BY_AGENT_NAME_FAILED",
990
+ domain: ErrorDomain.STORAGE,
991
+ category: ErrorCategory.THIRD_PARTY,
992
+ details: { agentName }
993
+ },
994
+ error
995
+ );
633
996
  }
997
+ }
998
+ async getEvals(options = {}) {
999
+ const { agentName, type, page = 0, perPage = 100, dateRange } = options;
1000
+ this.logger.debug("Getting evals with pagination", { agentName, type, page, perPage, dateRange });
634
1001
  try {
635
- await this.hasInitialized;
1002
+ let query;
1003
+ if (agentName) {
1004
+ query = this.service.entities.eval.query.byAgent({ entity: "eval", agent_name: agentName });
1005
+ } else {
1006
+ query = this.service.entities.eval.query.byEntity({ entity: "eval" });
1007
+ }
1008
+ const results = await query.go({
1009
+ order: "desc",
1010
+ pages: "all"
1011
+ // Get all pages to apply filtering and pagination
1012
+ });
1013
+ if (!results.data.length) {
1014
+ return {
1015
+ evals: [],
1016
+ total: 0,
1017
+ page,
1018
+ perPage,
1019
+ hasMore: false
1020
+ };
1021
+ }
1022
+ let filteredData = results.data;
1023
+ if (type) {
1024
+ filteredData = filteredData.filter((evalRecord) => {
1025
+ try {
1026
+ const testInfo = evalRecord.test_info && typeof evalRecord.test_info === "string" ? JSON.parse(evalRecord.test_info) : void 0;
1027
+ if (type === "test" && !testInfo) {
1028
+ return false;
1029
+ }
1030
+ if (type === "live" && testInfo) {
1031
+ return false;
1032
+ }
1033
+ } catch (e) {
1034
+ this.logger.warn("Failed to parse test_info during filtering", { record: evalRecord, error: e });
1035
+ }
1036
+ return true;
1037
+ });
1038
+ }
1039
+ if (dateRange) {
1040
+ const fromDate = dateRange.start;
1041
+ const toDate = dateRange.end;
1042
+ filteredData = filteredData.filter((evalRecord) => {
1043
+ const recordDate = new Date(evalRecord.created_at);
1044
+ if (fromDate && recordDate < fromDate) {
1045
+ return false;
1046
+ }
1047
+ if (toDate && recordDate > toDate) {
1048
+ return false;
1049
+ }
1050
+ return true;
1051
+ });
1052
+ }
1053
+ const total = filteredData.length;
1054
+ const start = page * perPage;
1055
+ const end = start + perPage;
1056
+ const paginatedData = filteredData.slice(start, end);
1057
+ const evals = paginatedData.map((evalRecord) => {
1058
+ try {
1059
+ return {
1060
+ input: evalRecord.input,
1061
+ output: evalRecord.output,
1062
+ result: evalRecord.result && typeof evalRecord.result === "string" ? JSON.parse(evalRecord.result) : void 0,
1063
+ agentName: evalRecord.agent_name,
1064
+ createdAt: evalRecord.created_at,
1065
+ metricName: evalRecord.metric_name,
1066
+ instructions: evalRecord.instructions,
1067
+ runId: evalRecord.run_id,
1068
+ globalRunId: evalRecord.global_run_id,
1069
+ testInfo: evalRecord.test_info && typeof evalRecord.test_info === "string" ? JSON.parse(evalRecord.test_info) : void 0
1070
+ };
1071
+ } catch (parseError) {
1072
+ this.logger.error("Failed to parse eval record", { record: evalRecord, error: parseError });
1073
+ return {
1074
+ agentName: evalRecord.agent_name,
1075
+ createdAt: evalRecord.created_at,
1076
+ runId: evalRecord.run_id,
1077
+ globalRunId: evalRecord.global_run_id
1078
+ };
1079
+ }
1080
+ });
1081
+ const hasMore = end < total;
1082
+ return {
1083
+ evals,
1084
+ total,
1085
+ page,
1086
+ perPage,
1087
+ hasMore
1088
+ };
1089
+ } catch (error) {
1090
+ throw new MastraError(
1091
+ {
1092
+ id: "STORAGE_DYNAMODB_STORE_GET_EVALS_FAILED",
1093
+ domain: ErrorDomain.STORAGE,
1094
+ category: ErrorCategory.THIRD_PARTY,
1095
+ details: {
1096
+ agentName: agentName || "all",
1097
+ type: type || "all",
1098
+ page,
1099
+ perPage
1100
+ }
1101
+ },
1102
+ error
1103
+ );
1104
+ }
1105
+ }
1106
+ };
1107
+ var MemoryStorageDynamoDB = class extends MemoryStorage {
1108
+ service;
1109
+ constructor({ service }) {
1110
+ super();
1111
+ this.service = service;
1112
+ }
1113
+ // Helper function to parse message data (handle JSON fields)
1114
+ parseMessageData(data) {
1115
+ return {
1116
+ ...data,
1117
+ // Ensure dates are Date objects if needed (ElectroDB might return strings)
1118
+ createdAt: data.createdAt ? new Date(data.createdAt) : void 0,
1119
+ updatedAt: data.updatedAt ? new Date(data.updatedAt) : void 0
1120
+ // Other fields like content, toolCallArgs etc. are assumed to be correctly
1121
+ // transformed by the ElectroDB entity getters.
1122
+ };
1123
+ }
1124
+ // Helper function to transform and sort threads
1125
+ transformAndSortThreads(rawThreads, orderBy, sortDirection) {
1126
+ return rawThreads.map((data) => ({
1127
+ ...data,
1128
+ // Convert date strings back to Date objects for consistency
1129
+ createdAt: typeof data.createdAt === "string" ? new Date(data.createdAt) : data.createdAt,
1130
+ updatedAt: typeof data.updatedAt === "string" ? new Date(data.updatedAt) : data.updatedAt
1131
+ })).sort((a, b) => {
1132
+ const fieldA = orderBy === "createdAt" ? a.createdAt : a.updatedAt;
1133
+ const fieldB = orderBy === "createdAt" ? b.createdAt : b.updatedAt;
1134
+ const comparison = fieldA.getTime() - fieldB.getTime();
1135
+ return sortDirection === "DESC" ? -comparison : comparison;
1136
+ });
1137
+ }
1138
+ async getThreadById({ threadId }) {
1139
+ this.logger.debug("Getting thread by ID", { threadId });
1140
+ try {
1141
+ const result = await this.service.entities.thread.get({ entity: "thread", id: threadId }).go();
1142
+ if (!result.data) {
1143
+ return null;
1144
+ }
1145
+ const data = result.data;
1146
+ return {
1147
+ ...data,
1148
+ // Convert date strings back to Date objects for consistency
1149
+ createdAt: typeof data.createdAt === "string" ? new Date(data.createdAt) : data.createdAt,
1150
+ updatedAt: typeof data.updatedAt === "string" ? new Date(data.updatedAt) : data.updatedAt
1151
+ // metadata: data.metadata ? JSON.parse(data.metadata) : undefined, // REMOVED by AI
1152
+ // metadata is already transformed by the entity's getter
1153
+ };
1154
+ } catch (error) {
1155
+ throw new MastraError(
1156
+ {
1157
+ id: "STORAGE_DYNAMODB_STORE_GET_THREAD_BY_ID_FAILED",
1158
+ domain: ErrorDomain.STORAGE,
1159
+ category: ErrorCategory.THIRD_PARTY,
1160
+ details: { threadId }
1161
+ },
1162
+ error
1163
+ );
1164
+ }
1165
+ }
1166
+ /**
1167
+ * @deprecated use getThreadsByResourceIdPaginated instead for paginated results.
1168
+ */
1169
+ async getThreadsByResourceId(args) {
1170
+ const resourceId = args.resourceId;
1171
+ const orderBy = this.castThreadOrderBy(args.orderBy);
1172
+ const sortDirection = this.castThreadSortDirection(args.sortDirection);
1173
+ this.logger.debug("Getting threads by resource ID", { resourceId, orderBy, sortDirection });
1174
+ try {
1175
+ const result = await this.service.entities.thread.query.byResource({ entity: "thread", resourceId }).go();
1176
+ if (!result.data.length) {
1177
+ return [];
1178
+ }
1179
+ return this.transformAndSortThreads(result.data, orderBy, sortDirection);
1180
+ } catch (error) {
1181
+ throw new MastraError(
1182
+ {
1183
+ id: "STORAGE_DYNAMODB_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED",
1184
+ domain: ErrorDomain.STORAGE,
1185
+ category: ErrorCategory.THIRD_PARTY,
1186
+ details: { resourceId }
1187
+ },
1188
+ error
1189
+ );
1190
+ }
1191
+ }
1192
+ async saveThread({ thread }) {
1193
+ this.logger.debug("Saving thread", { threadId: thread.id });
1194
+ const now = /* @__PURE__ */ new Date();
1195
+ const threadData = {
1196
+ entity: "thread",
1197
+ id: thread.id,
1198
+ resourceId: thread.resourceId,
1199
+ title: thread.title || `Thread ${thread.id}`,
1200
+ createdAt: thread.createdAt?.toISOString() || now.toISOString(),
1201
+ updatedAt: thread.updatedAt?.toISOString() || now.toISOString(),
1202
+ metadata: thread.metadata ? JSON.stringify(thread.metadata) : void 0
1203
+ };
1204
+ try {
1205
+ await this.service.entities.thread.upsert(threadData).go();
1206
+ return {
1207
+ id: thread.id,
1208
+ resourceId: thread.resourceId,
1209
+ title: threadData.title,
1210
+ createdAt: thread.createdAt || now,
1211
+ updatedAt: now,
1212
+ metadata: thread.metadata
1213
+ };
1214
+ } catch (error) {
1215
+ throw new MastraError(
1216
+ {
1217
+ id: "STORAGE_DYNAMODB_STORE_SAVE_THREAD_FAILED",
1218
+ domain: ErrorDomain.STORAGE,
1219
+ category: ErrorCategory.THIRD_PARTY,
1220
+ details: { threadId: thread.id }
1221
+ },
1222
+ error
1223
+ );
1224
+ }
1225
+ }
1226
+ async updateThread({
1227
+ id,
1228
+ title,
1229
+ metadata
1230
+ }) {
1231
+ this.logger.debug("Updating thread", { threadId: id });
1232
+ try {
1233
+ const existingThread = await this.getThreadById({ threadId: id });
1234
+ if (!existingThread) {
1235
+ throw new Error(`Thread not found: ${id}`);
1236
+ }
1237
+ const now = /* @__PURE__ */ new Date();
1238
+ const updateData = {
1239
+ updatedAt: now.toISOString()
1240
+ };
1241
+ if (title) {
1242
+ updateData.title = title;
1243
+ }
1244
+ if (metadata) {
1245
+ const existingMetadata = existingThread.metadata ? typeof existingThread.metadata === "string" ? JSON.parse(existingThread.metadata) : existingThread.metadata : {};
1246
+ const mergedMetadata = { ...existingMetadata, ...metadata };
1247
+ updateData.metadata = JSON.stringify(mergedMetadata);
1248
+ }
1249
+ await this.service.entities.thread.update({ entity: "thread", id }).set(updateData).go();
1250
+ return {
1251
+ ...existingThread,
1252
+ title: title || existingThread.title,
1253
+ metadata: metadata ? { ...existingThread.metadata, ...metadata } : existingThread.metadata,
1254
+ updatedAt: now
1255
+ };
1256
+ } catch (error) {
1257
+ throw new MastraError(
1258
+ {
1259
+ id: "STORAGE_DYNAMODB_STORE_UPDATE_THREAD_FAILED",
1260
+ domain: ErrorDomain.STORAGE,
1261
+ category: ErrorCategory.THIRD_PARTY,
1262
+ details: { threadId: id }
1263
+ },
1264
+ error
1265
+ );
1266
+ }
1267
+ }
1268
+ async deleteThread({ threadId }) {
1269
+ this.logger.debug("Deleting thread", { threadId });
1270
+ try {
1271
+ const messages = await this.getMessages({ threadId });
1272
+ if (messages.length > 0) {
1273
+ const batchSize = 25;
1274
+ for (let i = 0; i < messages.length; i += batchSize) {
1275
+ const batch = messages.slice(i, i + batchSize);
1276
+ await Promise.all(
1277
+ batch.map(
1278
+ (message) => this.service.entities.message.delete({
1279
+ entity: "message",
1280
+ id: message.id,
1281
+ threadId: message.threadId
1282
+ }).go()
1283
+ )
1284
+ );
1285
+ }
1286
+ }
1287
+ await this.service.entities.thread.delete({ entity: "thread", id: threadId }).go();
1288
+ } catch (error) {
1289
+ throw new MastraError(
1290
+ {
1291
+ id: "STORAGE_DYNAMODB_STORE_DELETE_THREAD_FAILED",
1292
+ domain: ErrorDomain.STORAGE,
1293
+ category: ErrorCategory.THIRD_PARTY,
1294
+ details: { threadId }
1295
+ },
1296
+ error
1297
+ );
1298
+ }
1299
+ }
1300
+ async getMessages({
1301
+ threadId,
1302
+ resourceId,
1303
+ selectBy,
1304
+ format
1305
+ }) {
1306
+ this.logger.debug("Getting messages", { threadId, selectBy });
1307
+ try {
1308
+ if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
1309
+ const messages = [];
1310
+ const limit = resolveMessageLimit({ last: selectBy?.last, defaultLimit: Number.MAX_SAFE_INTEGER });
1311
+ if (selectBy?.include?.length) {
1312
+ const includeMessages = await this._getIncludedMessages(threadId, selectBy);
1313
+ if (includeMessages) {
1314
+ messages.push(...includeMessages);
1315
+ }
1316
+ }
1317
+ if (limit !== 0) {
1318
+ const query = this.service.entities.message.query.byThread({ entity: "message", threadId });
1319
+ let results;
1320
+ if (limit !== Number.MAX_SAFE_INTEGER && limit > 0) {
1321
+ results = await query.go({ limit, order: "desc" });
1322
+ results.data = results.data.reverse();
1323
+ } else {
1324
+ results = await query.go();
1325
+ }
1326
+ let allThreadMessages = results.data.map((data) => this.parseMessageData(data)).filter((msg) => "content" in msg);
1327
+ allThreadMessages.sort((a, b) => {
1328
+ const timeA = a.createdAt.getTime();
1329
+ const timeB = b.createdAt.getTime();
1330
+ if (timeA === timeB) {
1331
+ return a.id.localeCompare(b.id);
1332
+ }
1333
+ return timeA - timeB;
1334
+ });
1335
+ messages.push(...allThreadMessages);
1336
+ }
1337
+ messages.sort((a, b) => {
1338
+ const timeA = a.createdAt.getTime();
1339
+ const timeB = b.createdAt.getTime();
1340
+ if (timeA === timeB) {
1341
+ return a.id.localeCompare(b.id);
1342
+ }
1343
+ return timeA - timeB;
1344
+ });
1345
+ const uniqueMessages = messages.filter(
1346
+ (message, index, self) => index === self.findIndex((m) => m.id === message.id)
1347
+ );
1348
+ const list = new MessageList({ threadId, resourceId }).add(uniqueMessages, "memory");
1349
+ if (format === `v2`) return list.get.all.v2();
1350
+ return list.get.all.v1();
1351
+ } catch (error) {
1352
+ throw new MastraError(
1353
+ {
1354
+ id: "STORAGE_DYNAMODB_STORE_GET_MESSAGES_FAILED",
1355
+ domain: ErrorDomain.STORAGE,
1356
+ category: ErrorCategory.THIRD_PARTY,
1357
+ details: { threadId, resourceId: resourceId ?? "" }
1358
+ },
1359
+ error
1360
+ );
1361
+ }
1362
+ }
1363
+ async getMessagesById({
1364
+ messageIds,
1365
+ format
1366
+ }) {
1367
+ this.logger.debug("Getting messages by ID", { messageIds });
1368
+ if (messageIds.length === 0) return [];
1369
+ try {
1370
+ const results = await Promise.all(
1371
+ messageIds.map((id) => this.service.entities.message.query.primary({ entity: "message", id }).go())
1372
+ );
1373
+ const data = results.map((result) => result.data).flat(1);
1374
+ let parsedMessages = data.map((data2) => this.parseMessageData(data2)).filter((msg) => "content" in msg);
1375
+ const uniqueMessages = parsedMessages.filter(
1376
+ (message, index, self) => index === self.findIndex((m) => m.id === message.id)
1377
+ );
1378
+ const list = new MessageList().add(uniqueMessages, "memory");
1379
+ if (format === `v1`) return list.get.all.v1();
1380
+ return list.get.all.v2();
1381
+ } catch (error) {
1382
+ throw new MastraError(
1383
+ {
1384
+ id: "STORAGE_DYNAMODB_STORE_GET_MESSAGES_BY_ID_FAILED",
1385
+ domain: ErrorDomain.STORAGE,
1386
+ category: ErrorCategory.THIRD_PARTY,
1387
+ details: { messageIds: JSON.stringify(messageIds) }
1388
+ },
1389
+ error
1390
+ );
1391
+ }
1392
+ }
1393
+ async saveMessages(args) {
1394
+ const { messages, format = "v1" } = args;
1395
+ this.logger.debug("Saving messages", { count: messages.length });
1396
+ if (!messages.length) {
1397
+ return [];
1398
+ }
1399
+ const threadId = messages[0]?.threadId;
1400
+ if (!threadId) {
1401
+ throw new Error("Thread ID is required");
1402
+ }
1403
+ const messagesToSave = messages.map((msg) => {
1404
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1405
+ return {
1406
+ entity: "message",
1407
+ // Add entity type
1408
+ id: msg.id,
1409
+ threadId: msg.threadId,
1410
+ role: msg.role,
1411
+ type: msg.type,
1412
+ resourceId: msg.resourceId,
1413
+ // Ensure complex fields are stringified if not handled by attribute setters
1414
+ content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content),
1415
+ toolCallArgs: `toolCallArgs` in msg && msg.toolCallArgs ? JSON.stringify(msg.toolCallArgs) : void 0,
1416
+ toolCallIds: `toolCallIds` in msg && msg.toolCallIds ? JSON.stringify(msg.toolCallIds) : void 0,
1417
+ toolNames: `toolNames` in msg && msg.toolNames ? JSON.stringify(msg.toolNames) : void 0,
1418
+ createdAt: msg.createdAt instanceof Date ? msg.createdAt.toISOString() : msg.createdAt || now,
1419
+ updatedAt: now
1420
+ // Add updatedAt
1421
+ };
1422
+ });
1423
+ try {
1424
+ const savedMessageIds = [];
1425
+ for (const messageData of messagesToSave) {
1426
+ if (!messageData.entity) {
1427
+ this.logger.error("Missing entity property in message data for create", { messageData });
1428
+ throw new Error("Internal error: Missing entity property during saveMessages");
1429
+ }
1430
+ try {
1431
+ await this.service.entities.message.put(messageData).go();
1432
+ savedMessageIds.push(messageData.id);
1433
+ } catch (error) {
1434
+ for (const savedId of savedMessageIds) {
1435
+ try {
1436
+ await this.service.entities.message.delete({ entity: "message", id: savedId }).go();
1437
+ } catch (rollbackError) {
1438
+ this.logger.error("Failed to rollback message during save error", {
1439
+ messageId: savedId,
1440
+ error: rollbackError
1441
+ });
1442
+ }
1443
+ }
1444
+ throw error;
1445
+ }
1446
+ }
1447
+ await this.service.entities.thread.update({ entity: "thread", id: threadId }).set({
1448
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1449
+ }).go();
1450
+ const list = new MessageList().add(messages, "memory");
1451
+ if (format === `v1`) return list.get.all.v1();
1452
+ return list.get.all.v2();
1453
+ } catch (error) {
1454
+ throw new MastraError(
1455
+ {
1456
+ id: "STORAGE_DYNAMODB_STORE_SAVE_MESSAGES_FAILED",
1457
+ domain: ErrorDomain.STORAGE,
1458
+ category: ErrorCategory.THIRD_PARTY,
1459
+ details: { count: messages.length }
1460
+ },
1461
+ error
1462
+ );
1463
+ }
1464
+ }
1465
+ async getThreadsByResourceIdPaginated(args) {
1466
+ const { resourceId, page = 0, perPage = 100 } = args;
1467
+ const orderBy = this.castThreadOrderBy(args.orderBy);
1468
+ const sortDirection = this.castThreadSortDirection(args.sortDirection);
1469
+ this.logger.debug("Getting threads by resource ID with pagination", {
1470
+ resourceId,
1471
+ page,
1472
+ perPage,
1473
+ orderBy,
1474
+ sortDirection
1475
+ });
1476
+ try {
1477
+ const query = this.service.entities.thread.query.byResource({ entity: "thread", resourceId });
1478
+ const results = await query.go();
1479
+ const allThreads = this.transformAndSortThreads(results.data, orderBy, sortDirection);
1480
+ const startIndex = page * perPage;
1481
+ const endIndex = startIndex + perPage;
1482
+ const paginatedThreads = allThreads.slice(startIndex, endIndex);
1483
+ const total = allThreads.length;
1484
+ const hasMore = endIndex < total;
1485
+ return {
1486
+ threads: paginatedThreads,
1487
+ total,
1488
+ page,
1489
+ perPage,
1490
+ hasMore
1491
+ };
1492
+ } catch (error) {
1493
+ throw new MastraError(
1494
+ {
1495
+ id: "STORAGE_DYNAMODB_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
1496
+ domain: ErrorDomain.STORAGE,
1497
+ category: ErrorCategory.THIRD_PARTY,
1498
+ details: { resourceId, page, perPage }
1499
+ },
1500
+ error
1501
+ );
1502
+ }
1503
+ }
1504
+ async getMessagesPaginated(args) {
1505
+ const { threadId, resourceId, selectBy, format = "v1" } = args;
1506
+ const { page = 0, perPage = 40, dateRange } = selectBy?.pagination || {};
1507
+ const fromDate = dateRange?.start;
1508
+ const toDate = dateRange?.end;
1509
+ const limit = resolveMessageLimit({ last: selectBy?.last, defaultLimit: Number.MAX_SAFE_INTEGER });
1510
+ this.logger.debug("Getting messages with pagination", { threadId, page, perPage, fromDate, toDate, limit });
1511
+ try {
1512
+ if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
1513
+ let messages = [];
1514
+ if (selectBy?.include?.length) {
1515
+ const includeMessages = await this._getIncludedMessages(threadId, selectBy);
1516
+ if (includeMessages) {
1517
+ messages.push(...includeMessages);
1518
+ }
1519
+ }
1520
+ if (limit !== 0) {
1521
+ const query = this.service.entities.message.query.byThread({ entity: "message", threadId });
1522
+ let results;
1523
+ if (limit !== Number.MAX_SAFE_INTEGER && limit > 0) {
1524
+ results = await query.go({ limit, order: "desc" });
1525
+ results.data = results.data.reverse();
1526
+ } else {
1527
+ results = await query.go();
1528
+ }
1529
+ let allThreadMessages = results.data.map((data) => this.parseMessageData(data)).filter((msg) => "content" in msg);
1530
+ allThreadMessages.sort((a, b) => {
1531
+ const timeA = a.createdAt.getTime();
1532
+ const timeB = b.createdAt.getTime();
1533
+ if (timeA === timeB) {
1534
+ return a.id.localeCompare(b.id);
1535
+ }
1536
+ return timeA - timeB;
1537
+ });
1538
+ const excludeIds = messages.map((m) => m.id);
1539
+ if (excludeIds.length > 0) {
1540
+ allThreadMessages = allThreadMessages.filter((msg) => !excludeIds.includes(msg.id));
1541
+ }
1542
+ messages.push(...allThreadMessages);
1543
+ }
1544
+ messages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
1545
+ if (fromDate || toDate) {
1546
+ messages = messages.filter((msg) => {
1547
+ const createdAt = new Date(msg.createdAt).getTime();
1548
+ if (fromDate && createdAt < new Date(fromDate).getTime()) return false;
1549
+ if (toDate && createdAt > new Date(toDate).getTime()) return false;
1550
+ return true;
1551
+ });
1552
+ }
1553
+ const total = messages.length;
1554
+ const start = page * perPage;
1555
+ const end = start + perPage;
1556
+ const paginatedMessages = messages.slice(start, end);
1557
+ const hasMore = end < total;
1558
+ const list = new MessageList({ threadId, resourceId }).add(paginatedMessages, "memory");
1559
+ const finalMessages = format === "v2" ? list.get.all.v2() : list.get.all.v1();
1560
+ return {
1561
+ messages: finalMessages,
1562
+ total,
1563
+ page,
1564
+ perPage,
1565
+ hasMore
1566
+ };
636
1567
  } catch (error) {
637
- throw error;
1568
+ const mastraError = new MastraError(
1569
+ {
1570
+ id: "STORAGE_DYNAMODB_STORE_GET_MESSAGES_PAGINATED_FAILED",
1571
+ domain: ErrorDomain.STORAGE,
1572
+ category: ErrorCategory.THIRD_PARTY,
1573
+ details: { threadId, resourceId: resourceId ?? "" }
1574
+ },
1575
+ error
1576
+ );
1577
+ this.logger?.trackException?.(mastraError);
1578
+ this.logger?.error?.(mastraError.toString());
1579
+ return { messages: [], total: 0, page, perPage, hasMore: false };
1580
+ }
1581
+ }
1582
+ // Helper method to get included messages with context
1583
+ async _getIncludedMessages(threadId, selectBy) {
1584
+ if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
1585
+ if (!selectBy?.include?.length) {
1586
+ return [];
1587
+ }
1588
+ const includeMessages = [];
1589
+ for (const includeItem of selectBy.include) {
1590
+ try {
1591
+ const { id, threadId: targetThreadId, withPreviousMessages = 0, withNextMessages = 0 } = includeItem;
1592
+ const searchThreadId = targetThreadId || threadId;
1593
+ this.logger.debug("Getting included messages for", {
1594
+ id,
1595
+ targetThreadId,
1596
+ searchThreadId,
1597
+ withPreviousMessages,
1598
+ withNextMessages
1599
+ });
1600
+ const query = this.service.entities.message.query.byThread({ entity: "message", threadId: searchThreadId });
1601
+ const results = await query.go();
1602
+ const allMessages = results.data.map((data) => this.parseMessageData(data)).filter((msg) => "content" in msg && typeof msg.content === "object");
1603
+ this.logger.debug("Found messages in thread", {
1604
+ threadId: searchThreadId,
1605
+ messageCount: allMessages.length,
1606
+ messageIds: allMessages.map((m) => m.id)
1607
+ });
1608
+ allMessages.sort((a, b) => {
1609
+ const timeA = a.createdAt.getTime();
1610
+ const timeB = b.createdAt.getTime();
1611
+ if (timeA === timeB) {
1612
+ return a.id.localeCompare(b.id);
1613
+ }
1614
+ return timeA - timeB;
1615
+ });
1616
+ const targetIndex = allMessages.findIndex((msg) => msg.id === id);
1617
+ if (targetIndex === -1) {
1618
+ this.logger.warn("Target message not found", { id, threadId: searchThreadId });
1619
+ continue;
1620
+ }
1621
+ this.logger.debug("Found target message at index", { id, targetIndex, totalMessages: allMessages.length });
1622
+ const startIndex = Math.max(0, targetIndex - withPreviousMessages);
1623
+ const endIndex = Math.min(allMessages.length, targetIndex + withNextMessages + 1);
1624
+ const contextMessages = allMessages.slice(startIndex, endIndex);
1625
+ this.logger.debug("Context messages", {
1626
+ startIndex,
1627
+ endIndex,
1628
+ contextCount: contextMessages.length,
1629
+ contextIds: contextMessages.map((m) => m.id)
1630
+ });
1631
+ includeMessages.push(...contextMessages);
1632
+ } catch (error) {
1633
+ this.logger.warn("Failed to get included message", { messageId: includeItem.id, error });
1634
+ }
1635
+ }
1636
+ this.logger.debug("Total included messages", {
1637
+ count: includeMessages.length,
1638
+ ids: includeMessages.map((m) => m.id)
1639
+ });
1640
+ return includeMessages;
1641
+ }
1642
+ async updateMessages(args) {
1643
+ const { messages } = args;
1644
+ this.logger.debug("Updating messages", { count: messages.length });
1645
+ if (!messages.length) {
1646
+ return [];
1647
+ }
1648
+ const updatedMessages = [];
1649
+ const affectedThreadIds = /* @__PURE__ */ new Set();
1650
+ try {
1651
+ for (const updateData of messages) {
1652
+ const { id, ...updates } = updateData;
1653
+ const existingMessage = await this.service.entities.message.get({ entity: "message", id }).go();
1654
+ if (!existingMessage.data) {
1655
+ this.logger.warn("Message not found for update", { id });
1656
+ continue;
1657
+ }
1658
+ const existingMsg = this.parseMessageData(existingMessage.data);
1659
+ const originalThreadId = existingMsg.threadId;
1660
+ affectedThreadIds.add(originalThreadId);
1661
+ const updatePayload = {
1662
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1663
+ };
1664
+ if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
1665
+ if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
1666
+ if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
1667
+ if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
1668
+ updatePayload.threadId = updates.threadId;
1669
+ affectedThreadIds.add(updates.threadId);
1670
+ }
1671
+ if (updates.content) {
1672
+ const existingContent = existingMsg.content;
1673
+ let newContent = { ...existingContent };
1674
+ if (updates.content.metadata !== void 0) {
1675
+ newContent.metadata = {
1676
+ ...existingContent.metadata || {},
1677
+ ...updates.content.metadata || {}
1678
+ };
1679
+ }
1680
+ if (updates.content.content !== void 0) {
1681
+ newContent.content = updates.content.content;
1682
+ }
1683
+ if ("parts" in updates.content && updates.content.parts !== void 0) {
1684
+ newContent.parts = updates.content.parts;
1685
+ }
1686
+ updatePayload.content = JSON.stringify(newContent);
1687
+ }
1688
+ await this.service.entities.message.update({ entity: "message", id }).set(updatePayload).go();
1689
+ const updatedMessage = await this.service.entities.message.get({ entity: "message", id }).go();
1690
+ if (updatedMessage.data) {
1691
+ updatedMessages.push(this.parseMessageData(updatedMessage.data));
1692
+ }
1693
+ }
1694
+ for (const threadId of affectedThreadIds) {
1695
+ await this.service.entities.thread.update({ entity: "thread", id: threadId }).set({
1696
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1697
+ }).go();
1698
+ }
1699
+ return updatedMessages;
1700
+ } catch (error) {
1701
+ throw new MastraError(
1702
+ {
1703
+ id: "STORAGE_DYNAMODB_STORE_UPDATE_MESSAGES_FAILED",
1704
+ domain: ErrorDomain.STORAGE,
1705
+ category: ErrorCategory.THIRD_PARTY,
1706
+ details: { count: messages.length }
1707
+ },
1708
+ error
1709
+ );
1710
+ }
1711
+ }
1712
+ async getResourceById({ resourceId }) {
1713
+ this.logger.debug("Getting resource by ID", { resourceId });
1714
+ try {
1715
+ const result = await this.service.entities.resource.get({ entity: "resource", id: resourceId }).go();
1716
+ if (!result.data) {
1717
+ return null;
1718
+ }
1719
+ const data = result.data;
1720
+ return {
1721
+ ...data,
1722
+ // Convert date strings back to Date objects for consistency
1723
+ createdAt: typeof data.createdAt === "string" ? new Date(data.createdAt) : data.createdAt,
1724
+ updatedAt: typeof data.updatedAt === "string" ? new Date(data.updatedAt) : data.updatedAt,
1725
+ // Ensure workingMemory is always returned as a string, regardless of automatic parsing
1726
+ workingMemory: typeof data.workingMemory === "object" ? JSON.stringify(data.workingMemory) : data.workingMemory
1727
+ // metadata is already transformed by the entity's getter
1728
+ };
1729
+ } catch (error) {
1730
+ throw new MastraError(
1731
+ {
1732
+ id: "STORAGE_DYNAMODB_STORE_GET_RESOURCE_BY_ID_FAILED",
1733
+ domain: ErrorDomain.STORAGE,
1734
+ category: ErrorCategory.THIRD_PARTY,
1735
+ details: { resourceId }
1736
+ },
1737
+ error
1738
+ );
1739
+ }
1740
+ }
1741
+ async saveResource({ resource }) {
1742
+ this.logger.debug("Saving resource", { resourceId: resource.id });
1743
+ const now = /* @__PURE__ */ new Date();
1744
+ const resourceData = {
1745
+ entity: "resource",
1746
+ id: resource.id,
1747
+ workingMemory: resource.workingMemory,
1748
+ metadata: resource.metadata ? JSON.stringify(resource.metadata) : void 0,
1749
+ createdAt: resource.createdAt?.toISOString() || now.toISOString(),
1750
+ updatedAt: now.toISOString()
1751
+ };
1752
+ try {
1753
+ await this.service.entities.resource.upsert(resourceData).go();
1754
+ return {
1755
+ id: resource.id,
1756
+ workingMemory: resource.workingMemory,
1757
+ metadata: resource.metadata,
1758
+ createdAt: resource.createdAt || now,
1759
+ updatedAt: now
1760
+ };
1761
+ } catch (error) {
1762
+ throw new MastraError(
1763
+ {
1764
+ id: "STORAGE_DYNAMODB_STORE_SAVE_RESOURCE_FAILED",
1765
+ domain: ErrorDomain.STORAGE,
1766
+ category: ErrorCategory.THIRD_PARTY,
1767
+ details: { resourceId: resource.id }
1768
+ },
1769
+ error
1770
+ );
1771
+ }
1772
+ }
1773
+ async updateResource({
1774
+ resourceId,
1775
+ workingMemory,
1776
+ metadata
1777
+ }) {
1778
+ this.logger.debug("Updating resource", { resourceId });
1779
+ try {
1780
+ const existingResource = await this.getResourceById({ resourceId });
1781
+ if (!existingResource) {
1782
+ const newResource = {
1783
+ id: resourceId,
1784
+ workingMemory,
1785
+ metadata: metadata || {},
1786
+ createdAt: /* @__PURE__ */ new Date(),
1787
+ updatedAt: /* @__PURE__ */ new Date()
1788
+ };
1789
+ return this.saveResource({ resource: newResource });
1790
+ }
1791
+ const now = /* @__PURE__ */ new Date();
1792
+ const updateData = {
1793
+ updatedAt: now.toISOString()
1794
+ };
1795
+ if (workingMemory !== void 0) {
1796
+ updateData.workingMemory = workingMemory;
1797
+ }
1798
+ if (metadata) {
1799
+ const existingMetadata = existingResource.metadata || {};
1800
+ const mergedMetadata = { ...existingMetadata, ...metadata };
1801
+ updateData.metadata = JSON.stringify(mergedMetadata);
1802
+ }
1803
+ await this.service.entities.resource.update({ entity: "resource", id: resourceId }).set(updateData).go();
1804
+ return {
1805
+ ...existingResource,
1806
+ workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
1807
+ metadata: metadata ? { ...existingResource.metadata, ...metadata } : existingResource.metadata,
1808
+ updatedAt: now
1809
+ };
1810
+ } catch (error) {
1811
+ throw new MastraError(
1812
+ {
1813
+ id: "STORAGE_DYNAMODB_STORE_UPDATE_RESOURCE_FAILED",
1814
+ domain: ErrorDomain.STORAGE,
1815
+ category: ErrorCategory.THIRD_PARTY,
1816
+ details: { resourceId }
1817
+ },
1818
+ error
1819
+ );
1820
+ }
1821
+ }
1822
+ };
1823
+ var StoreOperationsDynamoDB = class extends StoreOperations {
1824
+ client;
1825
+ tableName;
1826
+ service;
1827
+ constructor({
1828
+ service,
1829
+ tableName,
1830
+ client
1831
+ }) {
1832
+ super();
1833
+ this.service = service;
1834
+ this.client = client;
1835
+ this.tableName = tableName;
1836
+ }
1837
+ async hasColumn() {
1838
+ return true;
1839
+ }
1840
+ async dropTable() {
1841
+ }
1842
+ // Helper methods for entity/table mapping
1843
+ getEntityNameForTable(tableName) {
1844
+ const mapping = {
1845
+ [TABLE_THREADS]: "thread",
1846
+ [TABLE_MESSAGES]: "message",
1847
+ [TABLE_WORKFLOW_SNAPSHOT]: "workflow_snapshot",
1848
+ [TABLE_EVALS]: "eval",
1849
+ [TABLE_SCORERS]: "score",
1850
+ [TABLE_TRACES]: "trace",
1851
+ [TABLE_RESOURCES]: "resource",
1852
+ [TABLE_AI_SPANS]: "ai_span"
1853
+ };
1854
+ return mapping[tableName] || null;
1855
+ }
1856
+ /**
1857
+ * Pre-processes a record to ensure Date objects are converted to ISO strings
1858
+ * This is necessary because ElectroDB validation happens before setters are applied
1859
+ */
1860
+ preprocessRecord(record) {
1861
+ const processed = { ...record };
1862
+ if (processed.createdAt instanceof Date) {
1863
+ processed.createdAt = processed.createdAt.toISOString();
1864
+ }
1865
+ if (processed.updatedAt instanceof Date) {
1866
+ processed.updatedAt = processed.updatedAt.toISOString();
1867
+ }
1868
+ if (processed.created_at instanceof Date) {
1869
+ processed.created_at = processed.created_at.toISOString();
1870
+ }
1871
+ if (processed.result && typeof processed.result === "object") {
1872
+ processed.result = JSON.stringify(processed.result);
1873
+ }
1874
+ if (processed.test_info && typeof processed.test_info === "object") {
1875
+ processed.test_info = JSON.stringify(processed.test_info);
1876
+ } else if (processed.test_info === void 0 || processed.test_info === null) {
1877
+ delete processed.test_info;
1878
+ }
1879
+ if (processed.snapshot && typeof processed.snapshot === "object") {
1880
+ processed.snapshot = JSON.stringify(processed.snapshot);
1881
+ }
1882
+ if (processed.attributes && typeof processed.attributes === "object") {
1883
+ processed.attributes = JSON.stringify(processed.attributes);
1884
+ }
1885
+ if (processed.status && typeof processed.status === "object") {
1886
+ processed.status = JSON.stringify(processed.status);
1887
+ }
1888
+ if (processed.events && typeof processed.events === "object") {
1889
+ processed.events = JSON.stringify(processed.events);
1890
+ }
1891
+ if (processed.links && typeof processed.links === "object") {
1892
+ processed.links = JSON.stringify(processed.links);
1893
+ }
1894
+ return processed;
1895
+ }
1896
+ /**
1897
+ * Validates that the required DynamoDB table exists and is accessible.
1898
+ * This does not check the table structure - it assumes the table
1899
+ * was created with the correct structure via CDK/CloudFormation.
1900
+ */
1901
+ async validateTableExists() {
1902
+ try {
1903
+ const command = new DescribeTableCommand({
1904
+ TableName: this.tableName
1905
+ });
1906
+ await this.client.send(command);
1907
+ return true;
1908
+ } catch (error) {
1909
+ if (error.name === "ResourceNotFoundException") {
1910
+ return false;
1911
+ }
1912
+ throw new MastraError(
1913
+ {
1914
+ id: "STORAGE_DYNAMODB_STORE_VALIDATE_TABLE_EXISTS_FAILED",
1915
+ domain: ErrorDomain.STORAGE,
1916
+ category: ErrorCategory.THIRD_PARTY,
1917
+ details: { tableName: this.tableName }
1918
+ },
1919
+ error
1920
+ );
638
1921
  }
639
1922
  }
640
1923
  /**
641
- * Performs the actual table validation and stores the promise.
642
- * Handles resetting the stored promise on failure to allow retries.
1924
+ * This method is modified for DynamoDB with ElectroDB single-table design.
1925
+ * It assumes the table is created and managed externally via CDK/CloudFormation.
1926
+ *
1927
+ * This implementation only validates that the required table exists and is accessible.
1928
+ * No table creation is attempted - we simply check if we can access the table.
643
1929
  */
644
- _performInitializationAndStore() {
645
- return this.validateTableExists().then((exists) => {
646
- if (!exists) {
1930
+ async createTable({ tableName }) {
1931
+ this.logger.debug("Validating access to externally managed table", { tableName, physicalTable: this.tableName });
1932
+ try {
1933
+ const tableExists = await this.validateTableExists();
1934
+ if (!tableExists) {
1935
+ this.logger.error(
1936
+ `Table ${this.tableName} does not exist or is not accessible. It should be created via CDK/CloudFormation.`
1937
+ );
647
1938
  throw new Error(
648
1939
  `Table ${this.tableName} does not exist or is not accessible. Ensure it's created via CDK/CloudFormation before using this store.`
649
1940
  );
650
1941
  }
651
- return true;
652
- }).catch((err) => {
653
- this.hasInitialized = null;
654
- throw err;
655
- });
1942
+ this.logger.debug(`Table ${this.tableName} exists and is accessible`);
1943
+ } catch (error) {
1944
+ this.logger.error("Error validating table access", { tableName: this.tableName, error });
1945
+ throw new MastraError(
1946
+ {
1947
+ id: "STORAGE_DYNAMODB_STORE_VALIDATE_TABLE_ACCESS_FAILED",
1948
+ domain: ErrorDomain.STORAGE,
1949
+ category: ErrorCategory.THIRD_PARTY,
1950
+ details: { tableName: this.tableName }
1951
+ },
1952
+ error
1953
+ );
1954
+ }
1955
+ }
1956
+ async insert({ tableName, record }) {
1957
+ this.logger.debug("DynamoDB insert called", { tableName });
1958
+ const entityName = this.getEntityNameForTable(tableName);
1959
+ if (!entityName || !this.service.entities[entityName]) {
1960
+ throw new MastraError({
1961
+ id: "STORAGE_DYNAMODB_STORE_INSERT_INVALID_ARGS",
1962
+ domain: ErrorDomain.STORAGE,
1963
+ category: ErrorCategory.USER,
1964
+ text: "No entity defined for tableName",
1965
+ details: { tableName }
1966
+ });
1967
+ }
1968
+ try {
1969
+ const dataToSave = { entity: entityName, ...this.preprocessRecord(record) };
1970
+ await this.service.entities[entityName].create(dataToSave).go();
1971
+ } catch (error) {
1972
+ throw new MastraError(
1973
+ {
1974
+ id: "STORAGE_DYNAMODB_STORE_INSERT_FAILED",
1975
+ domain: ErrorDomain.STORAGE,
1976
+ category: ErrorCategory.THIRD_PARTY,
1977
+ details: { tableName }
1978
+ },
1979
+ error
1980
+ );
1981
+ }
1982
+ }
1983
+ async alterTable(_args) {
656
1984
  }
657
1985
  /**
658
1986
  * Clear all items from a logical "table" (entity type)
@@ -661,7 +1989,13 @@ var DynamoDBStore = class extends MastraStorage {
661
1989
  this.logger.debug("DynamoDB clearTable called", { tableName });
662
1990
  const entityName = this.getEntityNameForTable(tableName);
663
1991
  if (!entityName || !this.service.entities[entityName]) {
664
- throw new Error(`No entity defined for ${tableName}`);
1992
+ throw new MastraError({
1993
+ id: "STORAGE_DYNAMODB_STORE_CLEAR_TABLE_INVALID_ARGS",
1994
+ domain: ErrorDomain.STORAGE,
1995
+ category: ErrorCategory.USER,
1996
+ text: "No entity defined for tableName",
1997
+ details: { tableName }
1998
+ });
665
1999
  }
666
2000
  try {
667
2001
  const result = await this.service.entities[entityName].scan.go({ pages: "all" });
@@ -681,10 +2015,10 @@ var DynamoDBStore = class extends MastraStorage {
681
2015
  if (!item.id) throw new Error(`Missing required key 'id' for entity 'message'`);
682
2016
  key.id = item.id;
683
2017
  break;
684
- case "workflowSnapshot":
2018
+ case "workflow_snapshot":
685
2019
  if (!item.workflow_name)
686
- throw new Error(`Missing required key 'workflow_name' for entity 'workflowSnapshot'`);
687
- if (!item.run_id) throw new Error(`Missing required key 'run_id' for entity 'workflowSnapshot'`);
2020
+ throw new Error(`Missing required key 'workflow_name' for entity 'workflow_snapshot'`);
2021
+ if (!item.run_id) throw new Error(`Missing required key 'run_id' for entity 'workflow_snapshot'`);
688
2022
  key.workflow_name = item.workflow_name;
689
2023
  key.run_id = item.run_id;
690
2024
  break;
@@ -696,6 +2030,10 @@ var DynamoDBStore = class extends MastraStorage {
696
2030
  if (!item.id) throw new Error(`Missing required key 'id' for entity 'trace'`);
697
2031
  key.id = item.id;
698
2032
  break;
2033
+ case "score":
2034
+ if (!item.id) throw new Error(`Missing required key 'id' for entity 'score'`);
2035
+ key.id = item.id;
2036
+ break;
699
2037
  default:
700
2038
  this.logger.warn(`Unknown entity type encountered during clearTable: ${entityName}`);
701
2039
  throw new Error(`Cannot construct delete key for unknown entity type: ${entityName}`);
@@ -709,25 +2047,15 @@ var DynamoDBStore = class extends MastraStorage {
709
2047
  }
710
2048
  this.logger.debug(`Successfully cleared all records for ${tableName}`);
711
2049
  } catch (error) {
712
- this.logger.error("Failed to clear table", { tableName, error });
713
- throw error;
714
- }
715
- }
716
- /**
717
- * Insert a record into the specified "table" (entity)
718
- */
719
- async insert({ tableName, record }) {
720
- this.logger.debug("DynamoDB insert called", { tableName });
721
- const entityName = this.getEntityNameForTable(tableName);
722
- if (!entityName || !this.service.entities[entityName]) {
723
- throw new Error(`No entity defined for ${tableName}`);
724
- }
725
- try {
726
- const dataToSave = { entity: entityName, ...record };
727
- await this.service.entities[entityName].create(dataToSave).go();
728
- } catch (error) {
729
- this.logger.error("Failed to insert record", { tableName, error });
730
- throw error;
2050
+ throw new MastraError(
2051
+ {
2052
+ id: "STORAGE_DYNAMODB_STORE_CLEAR_TABLE_FAILED",
2053
+ domain: ErrorDomain.STORAGE,
2054
+ category: ErrorCategory.THIRD_PARTY,
2055
+ details: { tableName }
2056
+ },
2057
+ error
2058
+ );
731
2059
  }
732
2060
  }
733
2061
  /**
@@ -737,9 +2065,15 @@ var DynamoDBStore = class extends MastraStorage {
737
2065
  this.logger.debug("DynamoDB batchInsert called", { tableName, count: records.length });
738
2066
  const entityName = this.getEntityNameForTable(tableName);
739
2067
  if (!entityName || !this.service.entities[entityName]) {
740
- throw new Error(`No entity defined for ${tableName}`);
2068
+ throw new MastraError({
2069
+ id: "STORAGE_DYNAMODB_STORE_BATCH_INSERT_INVALID_ARGS",
2070
+ domain: ErrorDomain.STORAGE,
2071
+ category: ErrorCategory.USER,
2072
+ text: "No entity defined for tableName",
2073
+ details: { tableName }
2074
+ });
741
2075
  }
742
- const recordsToSave = records.map((rec) => ({ entity: entityName, ...rec }));
2076
+ const recordsToSave = records.map((rec) => ({ entity: entityName, ...this.preprocessRecord(rec) }));
743
2077
  const batchSize = 25;
744
2078
  const batches = [];
745
2079
  for (let i = 0; i < recordsToSave.length; i += batchSize) {
@@ -758,8 +2092,15 @@ var DynamoDBStore = class extends MastraStorage {
758
2092
  }
759
2093
  }
760
2094
  } catch (error) {
761
- this.logger.error("Failed to batch insert records", { tableName, error });
762
- throw error;
2095
+ throw new MastraError(
2096
+ {
2097
+ id: "STORAGE_DYNAMODB_STORE_BATCH_INSERT_FAILED",
2098
+ domain: ErrorDomain.STORAGE,
2099
+ category: ErrorCategory.THIRD_PARTY,
2100
+ details: { tableName }
2101
+ },
2102
+ error
2103
+ );
763
2104
  }
764
2105
  }
765
2106
  /**
@@ -769,7 +2110,13 @@ var DynamoDBStore = class extends MastraStorage {
769
2110
  this.logger.debug("DynamoDB load called", { tableName, keys });
770
2111
  const entityName = this.getEntityNameForTable(tableName);
771
2112
  if (!entityName || !this.service.entities[entityName]) {
772
- throw new Error(`No entity defined for ${tableName}`);
2113
+ throw new MastraError({
2114
+ id: "STORAGE_DYNAMODB_STORE_LOAD_INVALID_ARGS",
2115
+ domain: ErrorDomain.STORAGE,
2116
+ category: ErrorCategory.USER,
2117
+ text: "No entity defined for tableName",
2118
+ details: { tableName }
2119
+ });
773
2120
  }
774
2121
  try {
775
2122
  const keyObject = { entity: entityName, ...keys };
@@ -780,205 +2127,243 @@ var DynamoDBStore = class extends MastraStorage {
780
2127
  let data = result.data;
781
2128
  return data;
782
2129
  } catch (error) {
783
- this.logger.error("Failed to load record", { tableName, keys, error });
784
- throw error;
2130
+ throw new MastraError(
2131
+ {
2132
+ id: "STORAGE_DYNAMODB_STORE_LOAD_FAILED",
2133
+ domain: ErrorDomain.STORAGE,
2134
+ category: ErrorCategory.THIRD_PARTY,
2135
+ details: { tableName }
2136
+ },
2137
+ error
2138
+ );
785
2139
  }
786
2140
  }
787
- // Thread operations
788
- async getThreadById({ threadId }) {
789
- this.logger.debug("Getting thread by ID", { threadId });
2141
+ };
2142
+ var ScoresStorageDynamoDB = class extends ScoresStorage {
2143
+ service;
2144
+ constructor({ service }) {
2145
+ super();
2146
+ this.service = service;
2147
+ }
2148
+ // Helper function to parse score data (handle JSON fields)
2149
+ parseScoreData(data) {
2150
+ return {
2151
+ ...data,
2152
+ // Convert date strings back to Date objects for consistency
2153
+ createdAt: data.createdAt ? new Date(data.createdAt) : /* @__PURE__ */ new Date(),
2154
+ updatedAt: data.updatedAt ? new Date(data.updatedAt) : /* @__PURE__ */ new Date()
2155
+ // JSON fields are already transformed by the entity's getters
2156
+ };
2157
+ }
2158
+ async getScoreById({ id }) {
2159
+ this.logger.debug("Getting score by ID", { id });
790
2160
  try {
791
- const result = await this.service.entities.thread.get({ entity: "thread", id: threadId }).go();
2161
+ const result = await this.service.entities.score.get({ entity: "score", id }).go();
792
2162
  if (!result.data) {
793
2163
  return null;
794
2164
  }
795
- const data = result.data;
796
- return {
797
- ...data
798
- // metadata: data.metadata ? JSON.parse(data.metadata) : undefined, // REMOVED by AI
799
- // metadata is already transformed by the entity's getter
800
- };
801
- } catch (error) {
802
- this.logger.error("Failed to get thread by ID", { threadId, error });
803
- throw error;
804
- }
805
- }
806
- async getThreadsByResourceId({ resourceId }) {
807
- this.logger.debug("Getting threads by resource ID", { resourceId });
808
- try {
809
- const result = await this.service.entities.thread.query.byResource({ entity: "thread", resourceId }).go();
810
- if (!result.data.length) {
811
- return [];
812
- }
813
- return result.data.map((data) => ({
814
- ...data
815
- // metadata: data.metadata ? JSON.parse(data.metadata) : undefined, // REMOVED by AI
816
- // metadata is already transformed by the entity's getter
817
- }));
2165
+ return this.parseScoreData(result.data);
818
2166
  } catch (error) {
819
- this.logger.error("Failed to get threads by resource ID", { resourceId, error });
820
- throw error;
2167
+ throw new MastraError(
2168
+ {
2169
+ id: "STORAGE_DYNAMODB_STORE_GET_SCORE_BY_ID_FAILED",
2170
+ domain: ErrorDomain.STORAGE,
2171
+ category: ErrorCategory.THIRD_PARTY,
2172
+ details: { id }
2173
+ },
2174
+ error
2175
+ );
821
2176
  }
822
2177
  }
823
- async saveThread({ thread }) {
824
- this.logger.debug("Saving thread", { threadId: thread.id });
2178
+ async saveScore(score) {
2179
+ this.logger.debug("Saving score", { scorerId: score.scorerId, runId: score.runId });
825
2180
  const now = /* @__PURE__ */ new Date();
826
- const threadData = {
827
- entity: "thread",
828
- id: thread.id,
829
- resourceId: thread.resourceId,
830
- title: thread.title || `Thread ${thread.id}`,
831
- createdAt: thread.createdAt?.toISOString() || now.toISOString(),
832
- updatedAt: now.toISOString(),
833
- metadata: thread.metadata ? JSON.stringify(thread.metadata) : void 0
2181
+ const scoreId = `score-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
2182
+ const scoreData = {
2183
+ entity: "score",
2184
+ id: scoreId,
2185
+ scorerId: score.scorerId,
2186
+ traceId: score.traceId || "",
2187
+ runId: score.runId,
2188
+ scorer: typeof score.scorer === "string" ? score.scorer : JSON.stringify(score.scorer),
2189
+ preprocessStepResult: typeof score.preprocessStepResult === "string" ? score.preprocessStepResult : JSON.stringify(score.preprocessStepResult),
2190
+ analyzeStepResult: typeof score.analyzeStepResult === "string" ? score.analyzeStepResult : JSON.stringify(score.analyzeStepResult),
2191
+ score: score.score,
2192
+ reason: score.reason,
2193
+ preprocessPrompt: score.preprocessPrompt,
2194
+ generateScorePrompt: score.generateScorePrompt,
2195
+ analyzePrompt: score.analyzePrompt,
2196
+ reasonPrompt: score.reasonPrompt,
2197
+ input: typeof score.input === "string" ? score.input : JSON.stringify(score.input),
2198
+ output: typeof score.output === "string" ? score.output : JSON.stringify(score.output),
2199
+ additionalContext: typeof score.additionalContext === "string" ? score.additionalContext : JSON.stringify(score.additionalContext),
2200
+ runtimeContext: typeof score.runtimeContext === "string" ? score.runtimeContext : JSON.stringify(score.runtimeContext),
2201
+ entityType: score.entityType,
2202
+ entityData: typeof score.entity === "string" ? score.entity : JSON.stringify(score.entity),
2203
+ entityId: score.entityId,
2204
+ source: score.source,
2205
+ resourceId: score.resourceId || "",
2206
+ threadId: score.threadId || "",
2207
+ createdAt: now.toISOString(),
2208
+ updatedAt: now.toISOString()
834
2209
  };
835
2210
  try {
836
- await this.service.entities.thread.create(threadData).go();
837
- return {
838
- id: thread.id,
839
- resourceId: thread.resourceId,
840
- title: threadData.title,
841
- createdAt: thread.createdAt || now,
842
- updatedAt: now,
843
- metadata: thread.metadata
2211
+ await this.service.entities.score.upsert(scoreData).go();
2212
+ const savedScore = {
2213
+ ...score,
2214
+ id: scoreId,
2215
+ createdAt: now,
2216
+ updatedAt: now
844
2217
  };
2218
+ return { score: savedScore };
845
2219
  } catch (error) {
846
- this.logger.error("Failed to save thread", { threadId: thread.id, error });
847
- throw error;
2220
+ throw new MastraError(
2221
+ {
2222
+ id: "STORAGE_DYNAMODB_STORE_SAVE_SCORE_FAILED",
2223
+ domain: ErrorDomain.STORAGE,
2224
+ category: ErrorCategory.THIRD_PARTY,
2225
+ details: { scorerId: score.scorerId, runId: score.runId }
2226
+ },
2227
+ error
2228
+ );
848
2229
  }
849
2230
  }
850
- async updateThread({
851
- id,
852
- title,
853
- metadata
2231
+ async getScoresByScorerId({
2232
+ scorerId,
2233
+ pagination,
2234
+ entityId,
2235
+ entityType,
2236
+ source
854
2237
  }) {
855
- this.logger.debug("Updating thread", { threadId: id });
856
2238
  try {
857
- const existingThread = await this.getThreadById({ threadId: id });
858
- if (!existingThread) {
859
- throw new Error(`Thread not found: ${id}`);
2239
+ const query = this.service.entities.score.query.byScorer({ entity: "score", scorerId });
2240
+ const results = await query.go();
2241
+ let allScores = results.data.map((data) => this.parseScoreData(data));
2242
+ if (entityId) {
2243
+ allScores = allScores.filter((score) => score.entityId === entityId);
860
2244
  }
861
- const now = /* @__PURE__ */ new Date();
862
- const updateData = {
863
- updatedAt: now.toISOString()
864
- };
865
- if (title) {
866
- updateData.title = title;
2245
+ if (entityType) {
2246
+ allScores = allScores.filter((score) => score.entityType === entityType);
867
2247
  }
868
- if (metadata) {
869
- updateData.metadata = JSON.stringify(metadata);
2248
+ if (source) {
2249
+ allScores = allScores.filter((score) => score.source === source);
870
2250
  }
871
- await this.service.entities.thread.update({ entity: "thread", id }).set(updateData).go();
2251
+ allScores.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
2252
+ const startIndex = pagination.page * pagination.perPage;
2253
+ const endIndex = startIndex + pagination.perPage;
2254
+ const paginatedScores = allScores.slice(startIndex, endIndex);
2255
+ const total = allScores.length;
2256
+ const hasMore = endIndex < total;
872
2257
  return {
873
- ...existingThread,
874
- title: title || existingThread.title,
875
- metadata: metadata || existingThread.metadata,
876
- updatedAt: now
2258
+ scores: paginatedScores,
2259
+ pagination: {
2260
+ total,
2261
+ page: pagination.page,
2262
+ perPage: pagination.perPage,
2263
+ hasMore
2264
+ }
877
2265
  };
878
2266
  } catch (error) {
879
- this.logger.error("Failed to update thread", { threadId: id, error });
880
- throw error;
2267
+ throw new MastraError(
2268
+ {
2269
+ id: "STORAGE_DYNAMODB_STORE_GET_SCORES_BY_SCORER_ID_FAILED",
2270
+ domain: ErrorDomain.STORAGE,
2271
+ category: ErrorCategory.THIRD_PARTY,
2272
+ details: {
2273
+ scorerId: scorerId || "",
2274
+ entityId: entityId || "",
2275
+ entityType: entityType || "",
2276
+ source: source || "",
2277
+ page: pagination.page,
2278
+ perPage: pagination.perPage
2279
+ }
2280
+ },
2281
+ error
2282
+ );
881
2283
  }
882
2284
  }
883
- async deleteThread({ threadId }) {
884
- this.logger.debug("Deleting thread", { threadId });
2285
+ async getScoresByRunId({
2286
+ runId,
2287
+ pagination
2288
+ }) {
2289
+ this.logger.debug("Getting scores by run ID", { runId, pagination });
885
2290
  try {
886
- await this.service.entities.thread.delete({ entity: "thread", id: threadId }).go();
2291
+ const query = this.service.entities.score.query.byRun({ entity: "score", runId });
2292
+ const results = await query.go();
2293
+ const allScores = results.data.map((data) => this.parseScoreData(data));
2294
+ allScores.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
2295
+ const startIndex = pagination.page * pagination.perPage;
2296
+ const endIndex = startIndex + pagination.perPage;
2297
+ const paginatedScores = allScores.slice(startIndex, endIndex);
2298
+ const total = allScores.length;
2299
+ const hasMore = endIndex < total;
2300
+ return {
2301
+ scores: paginatedScores,
2302
+ pagination: {
2303
+ total,
2304
+ page: pagination.page,
2305
+ perPage: pagination.perPage,
2306
+ hasMore
2307
+ }
2308
+ };
887
2309
  } catch (error) {
888
- this.logger.error("Failed to delete thread", { threadId, error });
889
- throw error;
2310
+ throw new MastraError(
2311
+ {
2312
+ id: "STORAGE_DYNAMODB_STORE_GET_SCORES_BY_RUN_ID_FAILED",
2313
+ domain: ErrorDomain.STORAGE,
2314
+ category: ErrorCategory.THIRD_PARTY,
2315
+ details: { runId, page: pagination.page, perPage: pagination.perPage }
2316
+ },
2317
+ error
2318
+ );
890
2319
  }
891
2320
  }
892
- async getMessages({
893
- threadId,
894
- resourceId,
895
- selectBy,
896
- format
2321
+ async getScoresByEntityId({
2322
+ entityId,
2323
+ entityType,
2324
+ pagination
897
2325
  }) {
898
- this.logger.debug("Getting messages", { threadId, selectBy });
2326
+ this.logger.debug("Getting scores by entity ID", { entityId, entityType, pagination });
899
2327
  try {
900
- const query = this.service.entities.message.query.byThread({ entity: "message", threadId });
901
- if (selectBy?.last && typeof selectBy.last === "number") {
902
- const results2 = await query.go({ limit: selectBy.last, reverse: true });
903
- const list2 = new MessageList({ threadId, resourceId }).add(
904
- results2.data.map((data) => this.parseMessageData(data)),
905
- "memory"
906
- );
907
- if (format === `v2`) return list2.get.all.mastra();
908
- return list2.get.all.v1();
909
- }
2328
+ const query = this.service.entities.score.query.byEntityData({ entity: "score", entityId });
910
2329
  const results = await query.go();
911
- const list = new MessageList({ threadId, resourceId }).add(
912
- results.data.map((data) => this.parseMessageData(data)),
913
- "memory"
914
- );
915
- if (format === `v2`) return list.get.all.mastra();
916
- return list.get.all.v1();
917
- } catch (error) {
918
- this.logger.error("Failed to get messages", { threadId, error });
919
- throw error;
920
- }
921
- }
922
- async saveMessages(args) {
923
- const { messages, format = "v1" } = args;
924
- this.logger.debug("Saving messages", { count: messages.length });
925
- if (!messages.length) {
926
- return [];
927
- }
928
- const messagesToSave = messages.map((msg) => {
929
- const now = (/* @__PURE__ */ new Date()).toISOString();
2330
+ let allScores = results.data.map((data) => this.parseScoreData(data));
2331
+ allScores = allScores.filter((score) => score.entityType === entityType);
2332
+ allScores.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
2333
+ const startIndex = pagination.page * pagination.perPage;
2334
+ const endIndex = startIndex + pagination.perPage;
2335
+ const paginatedScores = allScores.slice(startIndex, endIndex);
2336
+ const total = allScores.length;
2337
+ const hasMore = endIndex < total;
930
2338
  return {
931
- entity: "message",
932
- // Add entity type
933
- id: msg.id,
934
- threadId: msg.threadId,
935
- role: msg.role,
936
- type: msg.type,
937
- resourceId: msg.resourceId,
938
- // Ensure complex fields are stringified if not handled by attribute setters
939
- content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content),
940
- toolCallArgs: `toolCallArgs` in msg && msg.toolCallArgs ? JSON.stringify(msg.toolCallArgs) : void 0,
941
- toolCallIds: `toolCallIds` in msg && msg.toolCallIds ? JSON.stringify(msg.toolCallIds) : void 0,
942
- toolNames: `toolNames` in msg && msg.toolNames ? JSON.stringify(msg.toolNames) : void 0,
943
- createdAt: msg.createdAt instanceof Date ? msg.createdAt.toISOString() : msg.createdAt || now,
944
- updatedAt: now
945
- // Add updatedAt
946
- };
947
- });
948
- try {
949
- const batchSize = 25;
950
- const batches = [];
951
- for (let i = 0; i < messagesToSave.length; i += batchSize) {
952
- const batch = messagesToSave.slice(i, i + batchSize);
953
- batches.push(batch);
954
- }
955
- for (const batch of batches) {
956
- for (const messageData of batch) {
957
- if (!messageData.entity) {
958
- this.logger.error("Missing entity property in message data for create", { messageData });
959
- throw new Error("Internal error: Missing entity property during saveMessages");
960
- }
961
- await this.service.entities.message.create(messageData).go();
2339
+ scores: paginatedScores,
2340
+ pagination: {
2341
+ total,
2342
+ page: pagination.page,
2343
+ perPage: pagination.perPage,
2344
+ hasMore
962
2345
  }
963
- }
964
- const list = new MessageList().add(messages, "memory");
965
- if (format === `v1`) return list.get.all.v1();
966
- return list.get.all.mastra();
2346
+ };
967
2347
  } catch (error) {
968
- this.logger.error("Failed to save messages", { error });
969
- throw error;
2348
+ throw new MastraError(
2349
+ {
2350
+ id: "STORAGE_DYNAMODB_STORE_GET_SCORES_BY_ENTITY_ID_FAILED",
2351
+ domain: ErrorDomain.STORAGE,
2352
+ category: ErrorCategory.THIRD_PARTY,
2353
+ details: { entityId, entityType, page: pagination.page, perPage: pagination.perPage }
2354
+ },
2355
+ error
2356
+ );
970
2357
  }
971
2358
  }
972
- // Helper function to parse message data (handle JSON fields)
973
- parseMessageData(data) {
974
- return {
975
- ...data,
976
- // Ensure dates are Date objects if needed (ElectroDB might return strings)
977
- createdAt: data.createdAt ? new Date(data.createdAt) : void 0,
978
- updatedAt: data.updatedAt ? new Date(data.updatedAt) : void 0
979
- // Other fields like content, toolCallArgs etc. are assumed to be correctly
980
- // transformed by the ElectroDB entity getters.
981
- };
2359
+ };
2360
+ var TracesStorageDynamoDB = class extends TracesStorage {
2361
+ service;
2362
+ operations;
2363
+ constructor({ service, operations }) {
2364
+ super();
2365
+ this.service = service;
2366
+ this.operations = operations;
982
2367
  }
983
2368
  // Trace operations
984
2369
  async getTraces(args) {
@@ -1005,34 +2390,238 @@ var DynamoDBStore = class extends MastraStorage {
1005
2390
  items = results.data;
1006
2391
  break;
1007
2392
  }
1008
- cursor = results.cursor;
1009
- if (!cursor && results.data.length > 0 && pagesFetched < startPage) {
1010
- break;
2393
+ cursor = results.cursor;
2394
+ if (!cursor && results.data.length > 0 && pagesFetched < startPage) {
2395
+ break;
2396
+ }
2397
+ } while (cursor && pagesFetched < startPage);
2398
+ return items;
2399
+ } catch (error) {
2400
+ throw new MastraError(
2401
+ {
2402
+ id: "STORAGE_DYNAMODB_STORE_GET_TRACES_FAILED",
2403
+ domain: ErrorDomain.STORAGE,
2404
+ category: ErrorCategory.THIRD_PARTY
2405
+ },
2406
+ error
2407
+ );
2408
+ }
2409
+ }
2410
+ async batchTraceInsert({ records }) {
2411
+ this.logger.debug("Batch inserting traces", { count: records.length });
2412
+ if (!records.length) {
2413
+ return;
2414
+ }
2415
+ try {
2416
+ const recordsToSave = records.map((rec) => ({ entity: "trace", ...rec }));
2417
+ await this.operations.batchInsert({
2418
+ tableName: TABLE_TRACES,
2419
+ records: recordsToSave
2420
+ // Pass records with 'entity' included
2421
+ });
2422
+ } catch (error) {
2423
+ throw new MastraError(
2424
+ {
2425
+ id: "STORAGE_DYNAMODB_STORE_BATCH_TRACE_INSERT_FAILED",
2426
+ domain: ErrorDomain.STORAGE,
2427
+ category: ErrorCategory.THIRD_PARTY,
2428
+ details: { count: records.length }
2429
+ },
2430
+ error
2431
+ );
2432
+ }
2433
+ }
2434
+ async getTracesPaginated(args) {
2435
+ const { name, scope, page = 0, perPage = 100, attributes, filters, dateRange } = args;
2436
+ this.logger.debug("Getting traces with pagination", { name, scope, page, perPage, attributes, filters, dateRange });
2437
+ try {
2438
+ let query;
2439
+ if (name) {
2440
+ query = this.service.entities.trace.query.byName({ entity: "trace", name });
2441
+ } else if (scope) {
2442
+ query = this.service.entities.trace.query.byScope({ entity: "trace", scope });
2443
+ } else {
2444
+ this.logger.warn("Performing a scan operation on traces - consider using a more specific query");
2445
+ query = this.service.entities.trace.scan;
2446
+ }
2447
+ const results = await query.go({
2448
+ order: "desc",
2449
+ pages: "all"
2450
+ // Get all pages to apply filtering and pagination
2451
+ });
2452
+ if (!results.data.length) {
2453
+ return {
2454
+ traces: [],
2455
+ total: 0,
2456
+ page,
2457
+ perPage,
2458
+ hasMore: false
2459
+ };
2460
+ }
2461
+ let filteredData = results.data;
2462
+ if (attributes) {
2463
+ filteredData = filteredData.filter((item) => {
2464
+ try {
2465
+ let itemAttributes = {};
2466
+ if (item.attributes) {
2467
+ if (typeof item.attributes === "string") {
2468
+ if (item.attributes === "[object Object]") {
2469
+ itemAttributes = {};
2470
+ } else {
2471
+ try {
2472
+ itemAttributes = JSON.parse(item.attributes);
2473
+ } catch {
2474
+ itemAttributes = {};
2475
+ }
2476
+ }
2477
+ } else if (typeof item.attributes === "object") {
2478
+ itemAttributes = item.attributes;
2479
+ }
2480
+ }
2481
+ return Object.entries(attributes).every(([key, value]) => itemAttributes[key] === value);
2482
+ } catch (e) {
2483
+ this.logger.warn("Failed to parse attributes during filtering", { item, error: e });
2484
+ return false;
2485
+ }
2486
+ });
2487
+ }
2488
+ if (dateRange?.start) {
2489
+ filteredData = filteredData.filter((item) => {
2490
+ const itemDate = new Date(item.createdAt);
2491
+ return itemDate >= dateRange.start;
2492
+ });
2493
+ }
2494
+ if (dateRange?.end) {
2495
+ filteredData = filteredData.filter((item) => {
2496
+ const itemDate = new Date(item.createdAt);
2497
+ return itemDate <= dateRange.end;
2498
+ });
2499
+ }
2500
+ const total = filteredData.length;
2501
+ const start = page * perPage;
2502
+ const end = start + perPage;
2503
+ const paginatedData = filteredData.slice(start, end);
2504
+ const traces = paginatedData.map((item) => {
2505
+ let attributes2;
2506
+ if (item.attributes) {
2507
+ if (typeof item.attributes === "string") {
2508
+ if (item.attributes === "[object Object]") {
2509
+ attributes2 = void 0;
2510
+ } else {
2511
+ try {
2512
+ attributes2 = JSON.parse(item.attributes);
2513
+ } catch {
2514
+ attributes2 = void 0;
2515
+ }
2516
+ }
2517
+ } else if (typeof item.attributes === "object") {
2518
+ attributes2 = item.attributes;
2519
+ }
2520
+ }
2521
+ let status;
2522
+ if (item.status) {
2523
+ if (typeof item.status === "string") {
2524
+ try {
2525
+ status = JSON.parse(item.status);
2526
+ } catch {
2527
+ status = void 0;
2528
+ }
2529
+ } else if (typeof item.status === "object") {
2530
+ status = item.status;
2531
+ }
2532
+ }
2533
+ let events;
2534
+ if (item.events) {
2535
+ if (typeof item.events === "string") {
2536
+ try {
2537
+ events = JSON.parse(item.events);
2538
+ } catch {
2539
+ events = void 0;
2540
+ }
2541
+ } else if (Array.isArray(item.events)) {
2542
+ events = item.events;
2543
+ }
1011
2544
  }
1012
- } while (cursor && pagesFetched < startPage);
1013
- return items;
1014
- } catch (error) {
1015
- this.logger.error("Failed to get traces", { error });
1016
- throw error;
1017
- }
1018
- }
1019
- async batchTraceInsert({ records }) {
1020
- this.logger.debug("Batch inserting traces", { count: records.length });
1021
- if (!records.length) {
1022
- return;
1023
- }
1024
- try {
1025
- const recordsToSave = records.map((rec) => ({ entity: "trace", ...rec }));
1026
- await this.batchInsert({
1027
- tableName: TABLE_TRACES,
1028
- records: recordsToSave
1029
- // Pass records with 'entity' included
2545
+ let links;
2546
+ if (item.links) {
2547
+ if (typeof item.links === "string") {
2548
+ try {
2549
+ links = JSON.parse(item.links);
2550
+ } catch {
2551
+ links = void 0;
2552
+ }
2553
+ } else if (Array.isArray(item.links)) {
2554
+ links = item.links;
2555
+ }
2556
+ }
2557
+ return {
2558
+ id: item.id,
2559
+ parentSpanId: item.parentSpanId,
2560
+ name: item.name,
2561
+ traceId: item.traceId,
2562
+ scope: item.scope,
2563
+ kind: item.kind,
2564
+ attributes: attributes2,
2565
+ status,
2566
+ events,
2567
+ links,
2568
+ other: item.other,
2569
+ startTime: item.startTime,
2570
+ endTime: item.endTime,
2571
+ createdAt: item.createdAt
2572
+ };
1030
2573
  });
2574
+ return {
2575
+ traces,
2576
+ total,
2577
+ page,
2578
+ perPage,
2579
+ hasMore: end < total
2580
+ };
1031
2581
  } catch (error) {
1032
- this.logger.error("Failed to batch insert traces", { error });
1033
- throw error;
2582
+ throw new MastraError(
2583
+ {
2584
+ id: "STORAGE_DYNAMODB_STORE_GET_TRACES_PAGINATED_FAILED",
2585
+ domain: ErrorDomain.STORAGE,
2586
+ category: ErrorCategory.THIRD_PARTY
2587
+ },
2588
+ error
2589
+ );
1034
2590
  }
1035
2591
  }
2592
+ };
2593
+ function formatWorkflowRun(snapshotData) {
2594
+ return {
2595
+ workflowName: snapshotData.workflow_name,
2596
+ runId: snapshotData.run_id,
2597
+ snapshot: snapshotData.snapshot,
2598
+ createdAt: new Date(snapshotData.createdAt),
2599
+ updatedAt: new Date(snapshotData.updatedAt),
2600
+ resourceId: snapshotData.resourceId
2601
+ };
2602
+ }
2603
+ var WorkflowStorageDynamoDB = class extends WorkflowsStorage {
2604
+ service;
2605
+ constructor({ service }) {
2606
+ super();
2607
+ this.service = service;
2608
+ }
2609
+ updateWorkflowResults({
2610
+ // workflowName,
2611
+ // runId,
2612
+ // stepId,
2613
+ // result,
2614
+ // runtimeContext,
2615
+ }) {
2616
+ throw new Error("Method not implemented.");
2617
+ }
2618
+ updateWorkflowState({
2619
+ // workflowName,
2620
+ // runId,
2621
+ // opts,
2622
+ }) {
2623
+ throw new Error("Method not implemented.");
2624
+ }
1036
2625
  // Workflow operations
1037
2626
  async persistWorkflowSnapshot({
1038
2627
  workflowName,
@@ -1054,10 +2643,17 @@ var DynamoDBStore = class extends MastraStorage {
1054
2643
  updatedAt: now,
1055
2644
  resourceId
1056
2645
  };
1057
- await this.service.entities.workflowSnapshot.create(data).go();
2646
+ await this.service.entities.workflow_snapshot.upsert(data).go();
1058
2647
  } catch (error) {
1059
- this.logger.error("Failed to persist workflow snapshot", { workflowName, runId, error });
1060
- throw error;
2648
+ throw new MastraError(
2649
+ {
2650
+ id: "STORAGE_DYNAMODB_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
2651
+ domain: ErrorDomain.STORAGE,
2652
+ category: ErrorCategory.THIRD_PARTY,
2653
+ details: { workflowName, runId }
2654
+ },
2655
+ error
2656
+ );
1061
2657
  }
1062
2658
  }
1063
2659
  async loadWorkflowSnapshot({
@@ -1066,7 +2662,7 @@ var DynamoDBStore = class extends MastraStorage {
1066
2662
  }) {
1067
2663
  this.logger.debug("Loading workflow snapshot", { workflowName, runId });
1068
2664
  try {
1069
- const result = await this.service.entities.workflowSnapshot.get({
2665
+ const result = await this.service.entities.workflow_snapshot.get({
1070
2666
  entity: "workflow_snapshot",
1071
2667
  // Add entity type
1072
2668
  workflow_name: workflowName,
@@ -1077,8 +2673,15 @@ var DynamoDBStore = class extends MastraStorage {
1077
2673
  }
1078
2674
  return result.data.snapshot;
1079
2675
  } catch (error) {
1080
- this.logger.error("Failed to load workflow snapshot", { workflowName, runId, error });
1081
- throw error;
2676
+ throw new MastraError(
2677
+ {
2678
+ id: "STORAGE_DYNAMODB_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
2679
+ domain: ErrorDomain.STORAGE,
2680
+ category: ErrorCategory.THIRD_PARTY,
2681
+ details: { workflowName, runId }
2682
+ },
2683
+ error
2684
+ );
1082
2685
  }
1083
2686
  }
1084
2687
  async getWorkflowRuns(args) {
@@ -1088,14 +2691,14 @@ var DynamoDBStore = class extends MastraStorage {
1088
2691
  const offset = args?.offset || 0;
1089
2692
  let query;
1090
2693
  if (args?.workflowName) {
1091
- query = this.service.entities.workflowSnapshot.query.primary({
2694
+ query = this.service.entities.workflow_snapshot.query.primary({
1092
2695
  entity: "workflow_snapshot",
1093
2696
  // Add entity type
1094
2697
  workflow_name: args.workflowName
1095
2698
  });
1096
2699
  } else {
1097
2700
  this.logger.warn("Performing a scan operation on workflow snapshots - consider using a more specific query");
1098
- query = this.service.entities.workflowSnapshot.scan;
2701
+ query = this.service.entities.workflow_snapshot.scan;
1099
2702
  }
1100
2703
  const allMatchingSnapshots = [];
1101
2704
  let cursor = null;
@@ -1133,28 +2736,38 @@ var DynamoDBStore = class extends MastraStorage {
1133
2736
  }
1134
2737
  const total = allMatchingSnapshots.length;
1135
2738
  const paginatedData = allMatchingSnapshots.slice(offset, offset + limit);
1136
- const runs = paginatedData.map((snapshot) => this.formatWorkflowRun(snapshot));
2739
+ const runs = paginatedData.map((snapshot) => formatWorkflowRun(snapshot));
1137
2740
  return {
1138
2741
  runs,
1139
2742
  total
1140
2743
  };
1141
2744
  } catch (error) {
1142
- this.logger.error("Failed to get workflow runs", { error });
1143
- throw error;
2745
+ throw new MastraError(
2746
+ {
2747
+ id: "STORAGE_DYNAMODB_STORE_GET_WORKFLOW_RUNS_FAILED",
2748
+ domain: ErrorDomain.STORAGE,
2749
+ category: ErrorCategory.THIRD_PARTY,
2750
+ details: { workflowName: args?.workflowName || "", resourceId: args?.resourceId || "" }
2751
+ },
2752
+ error
2753
+ );
1144
2754
  }
1145
2755
  }
1146
2756
  async getWorkflowRunById(args) {
1147
2757
  const { runId, workflowName } = args;
1148
2758
  this.logger.debug("Getting workflow run by ID", { runId, workflowName });
2759
+ console.log("workflowName", workflowName);
2760
+ console.log("runId", runId);
1149
2761
  try {
1150
2762
  if (workflowName) {
1151
2763
  this.logger.debug("WorkflowName provided, using direct GET operation.");
1152
- const result2 = await this.service.entities.workflowSnapshot.get({
2764
+ const result2 = await this.service.entities.workflow_snapshot.get({
1153
2765
  entity: "workflow_snapshot",
1154
2766
  // Entity type for PK
1155
2767
  workflow_name: workflowName,
1156
2768
  run_id: runId
1157
2769
  }).go();
2770
+ console.log("result", result2);
1158
2771
  if (!result2.data) {
1159
2772
  return null;
1160
2773
  }
@@ -1171,7 +2784,7 @@ var DynamoDBStore = class extends MastraStorage {
1171
2784
  this.logger.debug(
1172
2785
  '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.'
1173
2786
  );
1174
- const result = await this.service.entities.workflowSnapshot.query.gsi2({ entity: "workflow_snapshot", run_id: runId }).go();
2787
+ const result = await this.service.entities.workflow_snapshot.query.gsi2({ entity: "workflow_snapshot", run_id: runId }).go();
1175
2788
  const matchingRunDbItem = result.data && result.data.length > 0 ? result.data[0] : null;
1176
2789
  if (!matchingRunDbItem) {
1177
2790
  return null;
@@ -1186,89 +2799,282 @@ var DynamoDBStore = class extends MastraStorage {
1186
2799
  resourceId: matchingRunDbItem.resourceId
1187
2800
  };
1188
2801
  } catch (error) {
1189
- this.logger.error("Failed to get workflow run by ID", { runId, workflowName, error });
1190
- throw error;
2802
+ throw new MastraError(
2803
+ {
2804
+ id: "STORAGE_DYNAMODB_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
2805
+ domain: ErrorDomain.STORAGE,
2806
+ category: ErrorCategory.THIRD_PARTY,
2807
+ details: { runId, workflowName: args?.workflowName || "" }
2808
+ },
2809
+ error
2810
+ );
1191
2811
  }
1192
2812
  }
1193
- // Helper function to format workflow run
1194
- formatWorkflowRun(snapshotData) {
1195
- return {
1196
- workflowName: snapshotData.workflow_name,
1197
- runId: snapshotData.run_id,
1198
- snapshot: snapshotData.snapshot,
1199
- createdAt: new Date(snapshotData.createdAt),
1200
- updatedAt: new Date(snapshotData.updatedAt),
1201
- resourceId: snapshotData.resourceId
1202
- };
2813
+ };
2814
+
2815
+ // src/storage/index.ts
2816
+ var DynamoDBStore = class extends MastraStorage {
2817
+ tableName;
2818
+ client;
2819
+ service;
2820
+ hasInitialized = null;
2821
+ stores;
2822
+ constructor({ name, config }) {
2823
+ super({ name });
2824
+ try {
2825
+ if (!config.tableName || typeof config.tableName !== "string" || config.tableName.trim() === "") {
2826
+ throw new Error("DynamoDBStore: config.tableName must be provided and cannot be empty.");
2827
+ }
2828
+ if (!/^[a-zA-Z0-9_.-]{3,255}$/.test(config.tableName)) {
2829
+ throw new Error(
2830
+ `DynamoDBStore: config.tableName "${config.tableName}" contains invalid characters or is not between 3 and 255 characters long.`
2831
+ );
2832
+ }
2833
+ const dynamoClient = new DynamoDBClient({
2834
+ region: config.region || "us-east-1",
2835
+ endpoint: config.endpoint,
2836
+ credentials: config.credentials
2837
+ });
2838
+ this.tableName = config.tableName;
2839
+ this.client = DynamoDBDocumentClient.from(dynamoClient);
2840
+ this.service = getElectroDbService(this.client, this.tableName);
2841
+ const operations = new StoreOperationsDynamoDB({
2842
+ service: this.service,
2843
+ tableName: this.tableName,
2844
+ client: this.client
2845
+ });
2846
+ const traces = new TracesStorageDynamoDB({ service: this.service, operations });
2847
+ const workflows = new WorkflowStorageDynamoDB({ service: this.service });
2848
+ const memory = new MemoryStorageDynamoDB({ service: this.service });
2849
+ const scores = new ScoresStorageDynamoDB({ service: this.service });
2850
+ this.stores = {
2851
+ operations,
2852
+ legacyEvals: new LegacyEvalsDynamoDB({ service: this.service, tableName: this.tableName }),
2853
+ traces,
2854
+ workflows,
2855
+ memory,
2856
+ scores
2857
+ };
2858
+ } catch (error) {
2859
+ throw new MastraError(
2860
+ {
2861
+ id: "STORAGE_DYNAMODB_STORE_CONSTRUCTOR_FAILED",
2862
+ domain: ErrorDomain.STORAGE,
2863
+ category: ErrorCategory.USER
2864
+ },
2865
+ error
2866
+ );
2867
+ }
1203
2868
  }
1204
- // Helper methods for entity/table mapping
1205
- getEntityNameForTable(tableName) {
1206
- const mapping = {
1207
- [TABLE_THREADS]: "thread",
1208
- [TABLE_MESSAGES]: "message",
1209
- [TABLE_WORKFLOW_SNAPSHOT]: "workflowSnapshot",
1210
- [TABLE_EVALS]: "eval",
1211
- [TABLE_TRACES]: "trace"
2869
+ get supports() {
2870
+ return {
2871
+ selectByIncludeResourceScope: true,
2872
+ resourceWorkingMemory: true,
2873
+ hasColumn: false,
2874
+ createTable: false,
2875
+ deleteMessages: false
1212
2876
  };
1213
- return mapping[tableName] || null;
1214
2877
  }
1215
- // Eval operations
1216
- async getEvalsByAgentName(agentName, type) {
1217
- this.logger.debug("Getting evals for agent", { agentName, type });
2878
+ /**
2879
+ * Validates that the required DynamoDB table exists and is accessible.
2880
+ * This does not check the table structure - it assumes the table
2881
+ * was created with the correct structure via CDK/CloudFormation.
2882
+ */
2883
+ async validateTableExists() {
1218
2884
  try {
1219
- const query = this.service.entities.eval.query.byAgent({ entity: "eval", agent_name: agentName });
1220
- const results = await query.go({ order: "desc", limit: 100 });
1221
- if (!results.data.length) {
1222
- return [];
1223
- }
1224
- let filteredData = results.data;
1225
- if (type) {
1226
- filteredData = filteredData.filter((evalRecord) => {
1227
- try {
1228
- const testInfo = evalRecord.test_info && typeof evalRecord.test_info === "string" ? JSON.parse(evalRecord.test_info) : void 0;
1229
- if (type === "test" && !testInfo) {
1230
- return false;
1231
- }
1232
- if (type === "live" && testInfo) {
1233
- return false;
1234
- }
1235
- } catch (e) {
1236
- this.logger.warn("Failed to parse test_info during filtering", { record: evalRecord, error: e });
1237
- }
1238
- return true;
1239
- });
1240
- }
1241
- return filteredData.map((evalRecord) => {
1242
- try {
1243
- return {
1244
- input: evalRecord.input,
1245
- output: evalRecord.output,
1246
- // Safely parse result and test_info
1247
- result: evalRecord.result && typeof evalRecord.result === "string" ? JSON.parse(evalRecord.result) : void 0,
1248
- agentName: evalRecord.agent_name,
1249
- createdAt: evalRecord.created_at,
1250
- // Keep as string from DDB?
1251
- metricName: evalRecord.metric_name,
1252
- instructions: evalRecord.instructions,
1253
- runId: evalRecord.run_id,
1254
- globalRunId: evalRecord.global_run_id,
1255
- testInfo: evalRecord.test_info && typeof evalRecord.test_info === "string" ? JSON.parse(evalRecord.test_info) : void 0
1256
- };
1257
- } catch (parseError) {
1258
- this.logger.error("Failed to parse eval record", { record: evalRecord, error: parseError });
1259
- return {
1260
- agentName: evalRecord.agent_name,
1261
- createdAt: evalRecord.created_at,
1262
- runId: evalRecord.run_id,
1263
- globalRunId: evalRecord.global_run_id
1264
- };
1265
- }
2885
+ const command = new DescribeTableCommand({
2886
+ TableName: this.tableName
1266
2887
  });
2888
+ await this.client.send(command);
2889
+ return true;
1267
2890
  } catch (error) {
1268
- this.logger.error("Failed to get evals by agent name", { agentName, type, error });
1269
- throw error;
2891
+ if (error.name === "ResourceNotFoundException") {
2892
+ return false;
2893
+ }
2894
+ throw new MastraError(
2895
+ {
2896
+ id: "STORAGE_DYNAMODB_STORE_VALIDATE_TABLE_EXISTS_FAILED",
2897
+ domain: ErrorDomain.STORAGE,
2898
+ category: ErrorCategory.THIRD_PARTY,
2899
+ details: { tableName: this.tableName }
2900
+ },
2901
+ error
2902
+ );
2903
+ }
2904
+ }
2905
+ /**
2906
+ * Initialize storage, validating the externally managed table is accessible.
2907
+ * For the single-table design, we only validate once that we can access
2908
+ * the table that was created via CDK/CloudFormation.
2909
+ */
2910
+ async init() {
2911
+ if (this.hasInitialized === null) {
2912
+ this.hasInitialized = this._performInitializationAndStore();
2913
+ }
2914
+ try {
2915
+ await this.hasInitialized;
2916
+ } catch (error) {
2917
+ throw new MastraError(
2918
+ {
2919
+ id: "STORAGE_DYNAMODB_STORE_INIT_FAILED",
2920
+ domain: ErrorDomain.STORAGE,
2921
+ category: ErrorCategory.THIRD_PARTY,
2922
+ details: { tableName: this.tableName }
2923
+ },
2924
+ error
2925
+ );
1270
2926
  }
1271
2927
  }
2928
+ /**
2929
+ * Performs the actual table validation and stores the promise.
2930
+ * Handles resetting the stored promise on failure to allow retries.
2931
+ */
2932
+ _performInitializationAndStore() {
2933
+ return this.validateTableExists().then((exists) => {
2934
+ if (!exists) {
2935
+ throw new Error(
2936
+ `Table ${this.tableName} does not exist or is not accessible. Ensure it's created via CDK/CloudFormation before using this store.`
2937
+ );
2938
+ }
2939
+ return true;
2940
+ }).catch((err) => {
2941
+ this.hasInitialized = null;
2942
+ throw err;
2943
+ });
2944
+ }
2945
+ async createTable({ tableName, schema }) {
2946
+ return this.stores.operations.createTable({ tableName, schema });
2947
+ }
2948
+ async alterTable(_args) {
2949
+ return this.stores.operations.alterTable(_args);
2950
+ }
2951
+ async clearTable({ tableName }) {
2952
+ return this.stores.operations.clearTable({ tableName });
2953
+ }
2954
+ async dropTable({ tableName }) {
2955
+ return this.stores.operations.dropTable({ tableName });
2956
+ }
2957
+ async insert({ tableName, record }) {
2958
+ return this.stores.operations.insert({ tableName, record });
2959
+ }
2960
+ async batchInsert({ tableName, records }) {
2961
+ return this.stores.operations.batchInsert({ tableName, records });
2962
+ }
2963
+ async load({ tableName, keys }) {
2964
+ return this.stores.operations.load({ tableName, keys });
2965
+ }
2966
+ // Thread operations
2967
+ async getThreadById({ threadId }) {
2968
+ return this.stores.memory.getThreadById({ threadId });
2969
+ }
2970
+ async getThreadsByResourceId(args) {
2971
+ return this.stores.memory.getThreadsByResourceId(args);
2972
+ }
2973
+ async saveThread({ thread }) {
2974
+ return this.stores.memory.saveThread({ thread });
2975
+ }
2976
+ async updateThread({
2977
+ id,
2978
+ title,
2979
+ metadata
2980
+ }) {
2981
+ return this.stores.memory.updateThread({ id, title, metadata });
2982
+ }
2983
+ async deleteThread({ threadId }) {
2984
+ return this.stores.memory.deleteThread({ threadId });
2985
+ }
2986
+ async getMessages({
2987
+ threadId,
2988
+ resourceId,
2989
+ selectBy,
2990
+ format
2991
+ }) {
2992
+ return this.stores.memory.getMessages({ threadId, resourceId, selectBy, format });
2993
+ }
2994
+ async getMessagesById({
2995
+ messageIds,
2996
+ format
2997
+ }) {
2998
+ return this.stores.memory.getMessagesById({ messageIds, format });
2999
+ }
3000
+ async saveMessages(args) {
3001
+ return this.stores.memory.saveMessages(args);
3002
+ }
3003
+ async getThreadsByResourceIdPaginated(args) {
3004
+ return this.stores.memory.getThreadsByResourceIdPaginated(args);
3005
+ }
3006
+ async getMessagesPaginated(args) {
3007
+ return this.stores.memory.getMessagesPaginated(args);
3008
+ }
3009
+ async updateMessages(_args) {
3010
+ return this.stores.memory.updateMessages(_args);
3011
+ }
3012
+ // Trace operations
3013
+ async getTraces(args) {
3014
+ return this.stores.traces.getTraces(args);
3015
+ }
3016
+ async batchTraceInsert({ records }) {
3017
+ return this.stores.traces.batchTraceInsert({ records });
3018
+ }
3019
+ async getTracesPaginated(_args) {
3020
+ return this.stores.traces.getTracesPaginated(_args);
3021
+ }
3022
+ // Workflow operations
3023
+ async updateWorkflowResults({
3024
+ workflowName,
3025
+ runId,
3026
+ stepId,
3027
+ result,
3028
+ runtimeContext
3029
+ }) {
3030
+ return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, runtimeContext });
3031
+ }
3032
+ async updateWorkflowState({
3033
+ workflowName,
3034
+ runId,
3035
+ opts
3036
+ }) {
3037
+ return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
3038
+ }
3039
+ async persistWorkflowSnapshot({
3040
+ workflowName,
3041
+ runId,
3042
+ snapshot
3043
+ }) {
3044
+ return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
3045
+ }
3046
+ async loadWorkflowSnapshot({
3047
+ workflowName,
3048
+ runId
3049
+ }) {
3050
+ return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
3051
+ }
3052
+ async getWorkflowRuns(args) {
3053
+ return this.stores.workflows.getWorkflowRuns(args);
3054
+ }
3055
+ async getWorkflowRunById(args) {
3056
+ return this.stores.workflows.getWorkflowRunById(args);
3057
+ }
3058
+ async getResourceById({ resourceId }) {
3059
+ return this.stores.memory.getResourceById({ resourceId });
3060
+ }
3061
+ async saveResource({ resource }) {
3062
+ return this.stores.memory.saveResource({ resource });
3063
+ }
3064
+ async updateResource({
3065
+ resourceId,
3066
+ workingMemory,
3067
+ metadata
3068
+ }) {
3069
+ return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
3070
+ }
3071
+ // Eval operations
3072
+ async getEvalsByAgentName(agentName, type) {
3073
+ return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
3074
+ }
3075
+ async getEvals(options) {
3076
+ return this.stores.legacyEvals.getEvals(options);
3077
+ }
1272
3078
  /**
1273
3079
  * Closes the DynamoDB client connection and cleans up resources.
1274
3080
  * Should be called when the store is no longer needed, e.g., at the end of tests or application shutdown.
@@ -1279,10 +3085,53 @@ var DynamoDBStore = class extends MastraStorage {
1279
3085
  this.client.destroy();
1280
3086
  this.logger.debug("DynamoDB client closed successfully for store:", { name: this.name });
1281
3087
  } catch (error) {
1282
- this.logger.error("Error closing DynamoDB client for store:", { name: this.name, error });
1283
- throw error;
3088
+ throw new MastraError(
3089
+ {
3090
+ id: "STORAGE_DYNAMODB_STORE_CLOSE_FAILED",
3091
+ domain: ErrorDomain.STORAGE,
3092
+ category: ErrorCategory.THIRD_PARTY
3093
+ },
3094
+ error
3095
+ );
1284
3096
  }
1285
3097
  }
3098
+ /**
3099
+ * SCORERS - Not implemented
3100
+ */
3101
+ async getScoreById({ id: _id }) {
3102
+ return this.stores.scores.getScoreById({ id: _id });
3103
+ }
3104
+ async saveScore(_score) {
3105
+ return this.stores.scores.saveScore(_score);
3106
+ }
3107
+ async getScoresByRunId({
3108
+ runId: _runId,
3109
+ pagination: _pagination
3110
+ }) {
3111
+ return this.stores.scores.getScoresByRunId({ runId: _runId, pagination: _pagination });
3112
+ }
3113
+ async getScoresByEntityId({
3114
+ entityId: _entityId,
3115
+ entityType: _entityType,
3116
+ pagination: _pagination
3117
+ }) {
3118
+ return this.stores.scores.getScoresByEntityId({
3119
+ entityId: _entityId,
3120
+ entityType: _entityType,
3121
+ pagination: _pagination
3122
+ });
3123
+ }
3124
+ async getScoresByScorerId({
3125
+ scorerId,
3126
+ source,
3127
+ entityId,
3128
+ entityType,
3129
+ pagination
3130
+ }) {
3131
+ return this.stores.scores.getScoresByScorerId({ scorerId, source, entityId, entityType, pagination });
3132
+ }
1286
3133
  };
1287
3134
 
1288
3135
  export { DynamoDBStore };
3136
+ //# sourceMappingURL=index.js.map
3137
+ //# sourceMappingURL=index.js.map