@mastra/dynamodb 0.0.0-pass-headers-for-create-mastra-client-20250530010057 → 0.0.0-rag-chunk-extract-llm-option-20250926183645

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