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