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