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