@mastra/dynamodb 0.0.0-share-agent-metadata-with-cloud-20250718123411 → 0.0.0-span-scorring-test-20251124132129
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 +1484 -0
- 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 +1754 -566
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1755 -567
- package/dist/index.js.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +61 -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/workflows/index.d.ts +44 -0
- package/dist/storage/domains/workflows/index.d.ts.map +1 -0
- package/dist/storage/index.d.ts +204 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/package.json +31 -18
- package/dist/_tsup-dts-rollup.d.cts +0 -1160
- package/dist/_tsup-dts-rollup.d.ts +0 -1160
- package/dist/index.d.cts +0 -2
- 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 -1483
- package/src/storage/index.ts +0 -1383
package/dist/index.cjs
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
var clientDynamodb = require('@aws-sdk/client-dynamodb');
|
|
4
4
|
var libDynamodb = require('@aws-sdk/lib-dynamodb');
|
|
5
|
-
var agent = require('@mastra/core/agent');
|
|
6
5
|
var error = require('@mastra/core/error');
|
|
7
6
|
var storage = require('@mastra/core/storage');
|
|
8
7
|
var electrodb = require('electrodb');
|
|
8
|
+
var agent = require('@mastra/core/agent');
|
|
9
|
+
var evals = require('@mastra/core/evals');
|
|
9
10
|
|
|
10
11
|
// src/storage/index.ts
|
|
11
12
|
|
|
@@ -296,9 +297,9 @@ var messageEntity = new electrodb.Entity({
|
|
|
296
297
|
}
|
|
297
298
|
}
|
|
298
299
|
});
|
|
299
|
-
var
|
|
300
|
+
var resourceEntity = new electrodb.Entity({
|
|
300
301
|
model: {
|
|
301
|
-
entity: "
|
|
302
|
+
entity: "resource",
|
|
302
303
|
version: "1",
|
|
303
304
|
service: "mastra"
|
|
304
305
|
},
|
|
@@ -312,25 +313,21 @@ var threadEntity = new electrodb.Entity({
|
|
|
312
313
|
type: "string",
|
|
313
314
|
required: true
|
|
314
315
|
},
|
|
315
|
-
|
|
316
|
-
type: "string",
|
|
317
|
-
required: true
|
|
318
|
-
},
|
|
319
|
-
title: {
|
|
316
|
+
workingMemory: {
|
|
320
317
|
type: "string",
|
|
321
|
-
required:
|
|
318
|
+
required: false
|
|
322
319
|
},
|
|
323
320
|
metadata: {
|
|
324
321
|
type: "string",
|
|
325
322
|
required: false,
|
|
326
|
-
// Stringify
|
|
323
|
+
// Stringify content object on set if it's not already a string
|
|
327
324
|
set: (value) => {
|
|
328
325
|
if (value && typeof value !== "string") {
|
|
329
326
|
return JSON.stringify(value);
|
|
330
327
|
}
|
|
331
328
|
return value;
|
|
332
329
|
},
|
|
333
|
-
// Parse JSON string to object on get
|
|
330
|
+
// Parse JSON string to object on get ONLY if it looks like JSON
|
|
334
331
|
get: (value) => {
|
|
335
332
|
if (value && typeof value === "string") {
|
|
336
333
|
try {
|
|
@@ -348,18 +345,13 @@ var threadEntity = new electrodb.Entity({
|
|
|
348
345
|
indexes: {
|
|
349
346
|
primary: {
|
|
350
347
|
pk: { field: "pk", composite: ["entity", "id"] },
|
|
351
|
-
sk: { field: "sk", composite: ["
|
|
352
|
-
},
|
|
353
|
-
byResource: {
|
|
354
|
-
index: "gsi1",
|
|
355
|
-
pk: { field: "gsi1pk", composite: ["entity", "resourceId"] },
|
|
356
|
-
sk: { field: "gsi1sk", composite: ["createdAt"] }
|
|
348
|
+
sk: { field: "sk", composite: ["entity"] }
|
|
357
349
|
}
|
|
358
350
|
}
|
|
359
351
|
});
|
|
360
|
-
var
|
|
352
|
+
var scoreEntity = new electrodb.Entity({
|
|
361
353
|
model: {
|
|
362
|
-
entity: "
|
|
354
|
+
entity: "score",
|
|
363
355
|
version: "1",
|
|
364
356
|
service: "mastra"
|
|
365
357
|
},
|
|
@@ -373,123 +365,315 @@ var traceEntity = new electrodb.Entity({
|
|
|
373
365
|
type: "string",
|
|
374
366
|
required: true
|
|
375
367
|
},
|
|
376
|
-
|
|
368
|
+
scorerId: {
|
|
369
|
+
type: "string",
|
|
370
|
+
required: true
|
|
371
|
+
},
|
|
372
|
+
traceId: {
|
|
377
373
|
type: "string",
|
|
378
374
|
required: false
|
|
379
375
|
},
|
|
380
|
-
|
|
376
|
+
spanId: {
|
|
381
377
|
type: "string",
|
|
382
|
-
required:
|
|
378
|
+
required: false
|
|
383
379
|
},
|
|
384
|
-
|
|
380
|
+
runId: {
|
|
385
381
|
type: "string",
|
|
386
382
|
required: true
|
|
387
383
|
},
|
|
388
|
-
|
|
384
|
+
scorer: {
|
|
389
385
|
type: "string",
|
|
390
|
-
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
|
+
}
|
|
391
405
|
},
|
|
392
|
-
|
|
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: {
|
|
393
473
|
type: "number",
|
|
394
474
|
required: true
|
|
395
475
|
},
|
|
396
|
-
|
|
476
|
+
reason: {
|
|
397
477
|
type: "string",
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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,
|
|
401
504
|
set: (value) => {
|
|
402
505
|
if (value && typeof value !== "string") {
|
|
403
506
|
return JSON.stringify(value);
|
|
404
507
|
}
|
|
405
508
|
return value;
|
|
406
509
|
},
|
|
407
|
-
// Parse JSON string to object on get
|
|
408
510
|
get: (value) => {
|
|
409
|
-
|
|
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;
|
|
410
521
|
}
|
|
411
522
|
},
|
|
412
|
-
|
|
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: {
|
|
413
546
|
type: "string",
|
|
414
|
-
// JSON stringified
|
|
415
547
|
required: false,
|
|
416
|
-
// Stringify object on set
|
|
417
548
|
set: (value) => {
|
|
418
549
|
if (value && typeof value !== "string") {
|
|
419
550
|
return JSON.stringify(value);
|
|
420
551
|
}
|
|
421
552
|
return value;
|
|
422
553
|
},
|
|
423
|
-
// Parse JSON string to object on get
|
|
424
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
|
+
}
|
|
425
564
|
return value;
|
|
426
565
|
}
|
|
427
566
|
},
|
|
428
|
-
|
|
567
|
+
requestContext: {
|
|
429
568
|
type: "string",
|
|
430
|
-
// JSON stringified
|
|
431
569
|
required: false,
|
|
432
|
-
// Stringify object on set
|
|
433
570
|
set: (value) => {
|
|
434
571
|
if (value && typeof value !== "string") {
|
|
435
572
|
return JSON.stringify(value);
|
|
436
573
|
}
|
|
437
574
|
return value;
|
|
438
575
|
},
|
|
439
|
-
// Parse JSON string to object on get
|
|
440
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
|
+
}
|
|
441
586
|
return value;
|
|
442
587
|
}
|
|
443
588
|
},
|
|
444
|
-
|
|
589
|
+
entityType: {
|
|
590
|
+
type: "string",
|
|
591
|
+
required: false
|
|
592
|
+
},
|
|
593
|
+
entityData: {
|
|
445
594
|
type: "string",
|
|
446
|
-
// JSON stringified
|
|
447
595
|
required: false,
|
|
448
|
-
// Stringify object on set
|
|
449
596
|
set: (value) => {
|
|
450
597
|
if (value && typeof value !== "string") {
|
|
451
598
|
return JSON.stringify(value);
|
|
452
599
|
}
|
|
453
600
|
return value;
|
|
454
601
|
},
|
|
455
|
-
// Parse JSON string to object on get
|
|
456
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
|
+
}
|
|
457
612
|
return value;
|
|
458
613
|
}
|
|
459
614
|
},
|
|
460
|
-
|
|
615
|
+
entityId: {
|
|
461
616
|
type: "string",
|
|
462
617
|
required: false
|
|
463
618
|
},
|
|
464
|
-
|
|
465
|
-
type: "
|
|
619
|
+
source: {
|
|
620
|
+
type: "string",
|
|
466
621
|
required: true
|
|
467
622
|
},
|
|
468
|
-
|
|
469
|
-
type: "
|
|
470
|
-
required:
|
|
623
|
+
resourceId: {
|
|
624
|
+
type: "string",
|
|
625
|
+
required: false
|
|
626
|
+
},
|
|
627
|
+
threadId: {
|
|
628
|
+
type: "string",
|
|
629
|
+
required: false
|
|
471
630
|
}
|
|
472
631
|
},
|
|
473
632
|
indexes: {
|
|
474
633
|
primary: {
|
|
475
634
|
pk: { field: "pk", composite: ["entity", "id"] },
|
|
476
|
-
sk: { field: "sk", composite: [] }
|
|
635
|
+
sk: { field: "sk", composite: ["entity"] }
|
|
477
636
|
},
|
|
478
|
-
|
|
637
|
+
byScorer: {
|
|
479
638
|
index: "gsi1",
|
|
480
|
-
pk: { field: "gsi1pk", composite: ["entity", "
|
|
481
|
-
sk: { field: "gsi1sk", composite: ["
|
|
639
|
+
pk: { field: "gsi1pk", composite: ["entity", "scorerId"] },
|
|
640
|
+
sk: { field: "gsi1sk", composite: ["createdAt"] }
|
|
482
641
|
},
|
|
483
|
-
|
|
642
|
+
byRun: {
|
|
484
643
|
index: "gsi2",
|
|
485
|
-
pk: { field: "gsi2pk", composite: ["entity", "
|
|
486
|
-
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"] }
|
|
487
671
|
}
|
|
488
672
|
}
|
|
489
673
|
});
|
|
490
|
-
var
|
|
674
|
+
var threadEntity = new electrodb.Entity({
|
|
491
675
|
model: {
|
|
492
|
-
entity: "
|
|
676
|
+
entity: "thread",
|
|
493
677
|
version: "1",
|
|
494
678
|
service: "mastra"
|
|
495
679
|
},
|
|
@@ -499,11 +683,202 @@ var workflowSnapshotEntity = new electrodb.Entity({
|
|
|
499
683
|
required: true
|
|
500
684
|
},
|
|
501
685
|
...baseAttributes,
|
|
502
|
-
|
|
686
|
+
id: {
|
|
503
687
|
type: "string",
|
|
504
688
|
required: true
|
|
505
689
|
},
|
|
506
|
-
|
|
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: {
|
|
507
882
|
type: "string",
|
|
508
883
|
required: true
|
|
509
884
|
},
|
|
@@ -550,7 +925,9 @@ function getElectroDbService(client, tableName) {
|
|
|
550
925
|
message: messageEntity,
|
|
551
926
|
eval: evalEntity,
|
|
552
927
|
trace: traceEntity,
|
|
553
|
-
|
|
928
|
+
workflow_snapshot: workflowSnapshotEntity,
|
|
929
|
+
resource: resourceEntity,
|
|
930
|
+
score: scoreEntity
|
|
554
931
|
},
|
|
555
932
|
{
|
|
556
933
|
client,
|
|
@@ -558,76 +935,771 @@ function getElectroDbService(client, tableName) {
|
|
|
558
935
|
}
|
|
559
936
|
);
|
|
560
937
|
}
|
|
561
|
-
|
|
562
|
-
// src/storage/index.ts
|
|
563
|
-
var DynamoDBStore = class extends storage.MastraStorage {
|
|
564
|
-
tableName;
|
|
565
|
-
client;
|
|
938
|
+
var MemoryStorageDynamoDB = class extends storage.MemoryStorage {
|
|
566
939
|
service;
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
940
|
+
constructor({ service }) {
|
|
941
|
+
super();
|
|
942
|
+
this.service = service;
|
|
943
|
+
}
|
|
944
|
+
// Helper function to parse message data (handle JSON fields)
|
|
945
|
+
parseMessageData(data) {
|
|
946
|
+
return {
|
|
947
|
+
...data,
|
|
948
|
+
// Ensure dates are Date objects if needed (ElectroDB might return strings)
|
|
949
|
+
createdAt: data.createdAt ? new Date(data.createdAt) : void 0,
|
|
950
|
+
updatedAt: data.updatedAt ? new Date(data.updatedAt) : void 0
|
|
951
|
+
// Other fields like content, toolCallArgs etc. are assumed to be correctly
|
|
952
|
+
// transformed by the ElectroDB entity getters.
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
// Helper function to transform and sort threads
|
|
956
|
+
transformAndSortThreads(rawThreads, field, direction) {
|
|
957
|
+
return rawThreads.map((data) => ({
|
|
958
|
+
...data,
|
|
959
|
+
// Convert date strings back to Date objects for consistency
|
|
960
|
+
createdAt: typeof data.createdAt === "string" ? new Date(data.createdAt) : data.createdAt,
|
|
961
|
+
updatedAt: typeof data.updatedAt === "string" ? new Date(data.updatedAt) : data.updatedAt
|
|
962
|
+
})).sort((a, b) => {
|
|
963
|
+
const fieldA = field === "createdAt" ? a.createdAt : a.updatedAt;
|
|
964
|
+
const fieldB = field === "createdAt" ? b.createdAt : b.updatedAt;
|
|
965
|
+
const comparison = fieldA.getTime() - fieldB.getTime();
|
|
966
|
+
return direction === "DESC" ? -comparison : comparison;
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
async getThreadById({ threadId }) {
|
|
970
|
+
this.logger.debug("Getting thread by ID", { threadId });
|
|
570
971
|
try {
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
if (!/^[a-zA-Z0-9_.-]{3,255}$/.test(config.tableName)) {
|
|
575
|
-
throw new Error(
|
|
576
|
-
`DynamoDBStore: config.tableName "${config.tableName}" contains invalid characters or is not between 3 and 255 characters long.`
|
|
577
|
-
);
|
|
972
|
+
const result = await this.service.entities.thread.get({ entity: "thread", id: threadId }).go();
|
|
973
|
+
if (!result.data) {
|
|
974
|
+
return null;
|
|
578
975
|
}
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
976
|
+
const data = result.data;
|
|
977
|
+
return {
|
|
978
|
+
...data,
|
|
979
|
+
// Convert date strings back to Date objects for consistency
|
|
980
|
+
createdAt: typeof data.createdAt === "string" ? new Date(data.createdAt) : data.createdAt,
|
|
981
|
+
updatedAt: typeof data.updatedAt === "string" ? new Date(data.updatedAt) : data.updatedAt
|
|
982
|
+
// metadata: data.metadata ? JSON.parse(data.metadata) : undefined, // REMOVED by AI
|
|
983
|
+
// metadata is already transformed by the entity's getter
|
|
984
|
+
};
|
|
587
985
|
} catch (error$1) {
|
|
588
986
|
throw new error.MastraError(
|
|
589
987
|
{
|
|
590
|
-
id: "
|
|
988
|
+
id: "STORAGE_DYNAMODB_STORE_GET_THREAD_BY_ID_FAILED",
|
|
591
989
|
domain: error.ErrorDomain.STORAGE,
|
|
592
|
-
category: error.ErrorCategory.
|
|
990
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
991
|
+
details: { threadId }
|
|
593
992
|
},
|
|
594
993
|
error$1
|
|
595
994
|
);
|
|
596
995
|
}
|
|
597
996
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
997
|
+
async saveThread({ thread }) {
|
|
998
|
+
this.logger.debug("Saving thread", { threadId: thread.id });
|
|
999
|
+
const now = /* @__PURE__ */ new Date();
|
|
1000
|
+
const threadData = {
|
|
1001
|
+
entity: "thread",
|
|
1002
|
+
id: thread.id,
|
|
1003
|
+
resourceId: thread.resourceId,
|
|
1004
|
+
title: thread.title || `Thread ${thread.id}`,
|
|
1005
|
+
createdAt: thread.createdAt?.toISOString() || now.toISOString(),
|
|
1006
|
+
updatedAt: thread.updatedAt?.toISOString() || now.toISOString(),
|
|
1007
|
+
metadata: thread.metadata ? JSON.stringify(thread.metadata) : void 0
|
|
1008
|
+
};
|
|
607
1009
|
try {
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
1010
|
+
await this.service.entities.thread.upsert(threadData).go();
|
|
1011
|
+
return {
|
|
1012
|
+
id: thread.id,
|
|
1013
|
+
resourceId: thread.resourceId,
|
|
1014
|
+
title: threadData.title,
|
|
1015
|
+
createdAt: thread.createdAt || now,
|
|
1016
|
+
updatedAt: thread.updatedAt || now,
|
|
1017
|
+
metadata: thread.metadata
|
|
1018
|
+
};
|
|
1019
|
+
} catch (error$1) {
|
|
1020
|
+
throw new error.MastraError(
|
|
1021
|
+
{
|
|
1022
|
+
id: "STORAGE_DYNAMODB_STORE_SAVE_THREAD_FAILED",
|
|
1023
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1024
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1025
|
+
details: { threadId: thread.id }
|
|
1026
|
+
},
|
|
1027
|
+
error$1
|
|
1028
|
+
);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
async updateThread({
|
|
1032
|
+
id,
|
|
1033
|
+
title,
|
|
1034
|
+
metadata
|
|
1035
|
+
}) {
|
|
1036
|
+
this.logger.debug("Updating thread", { threadId: id });
|
|
1037
|
+
try {
|
|
1038
|
+
const existingThread = await this.getThreadById({ threadId: id });
|
|
1039
|
+
if (!existingThread) {
|
|
1040
|
+
throw new Error(`Thread not found: ${id}`);
|
|
1041
|
+
}
|
|
1042
|
+
const now = /* @__PURE__ */ new Date();
|
|
1043
|
+
const updateData = {
|
|
1044
|
+
updatedAt: now.toISOString()
|
|
1045
|
+
};
|
|
1046
|
+
if (title) {
|
|
1047
|
+
updateData.title = title;
|
|
1048
|
+
}
|
|
1049
|
+
if (metadata) {
|
|
1050
|
+
const existingMetadata = existingThread.metadata ? typeof existingThread.metadata === "string" ? JSON.parse(existingThread.metadata) : existingThread.metadata : {};
|
|
1051
|
+
const mergedMetadata = { ...existingMetadata, ...metadata };
|
|
1052
|
+
updateData.metadata = JSON.stringify(mergedMetadata);
|
|
1053
|
+
}
|
|
1054
|
+
await this.service.entities.thread.update({ entity: "thread", id }).set(updateData).go();
|
|
1055
|
+
return {
|
|
1056
|
+
...existingThread,
|
|
1057
|
+
title: title || existingThread.title,
|
|
1058
|
+
metadata: metadata ? { ...existingThread.metadata, ...metadata } : existingThread.metadata,
|
|
1059
|
+
updatedAt: now
|
|
1060
|
+
};
|
|
1061
|
+
} catch (error$1) {
|
|
1062
|
+
throw new error.MastraError(
|
|
1063
|
+
{
|
|
1064
|
+
id: "STORAGE_DYNAMODB_STORE_UPDATE_THREAD_FAILED",
|
|
1065
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1066
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1067
|
+
details: { threadId: id }
|
|
1068
|
+
},
|
|
1069
|
+
error$1
|
|
1070
|
+
);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
async deleteThread({ threadId }) {
|
|
1074
|
+
this.logger.debug("Deleting thread", { threadId });
|
|
1075
|
+
try {
|
|
1076
|
+
const { messages } = await this.listMessages({ threadId, perPage: false });
|
|
1077
|
+
if (messages.length > 0) {
|
|
1078
|
+
const batchSize = 25;
|
|
1079
|
+
for (let i = 0; i < messages.length; i += batchSize) {
|
|
1080
|
+
const batch = messages.slice(i, i + batchSize);
|
|
1081
|
+
await Promise.all(
|
|
1082
|
+
batch.map(
|
|
1083
|
+
(message) => this.service.entities.message.delete({
|
|
1084
|
+
entity: "message",
|
|
1085
|
+
id: message.id,
|
|
1086
|
+
threadId: message.threadId
|
|
1087
|
+
}).go()
|
|
1088
|
+
)
|
|
1089
|
+
);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
await this.service.entities.thread.delete({ entity: "thread", id: threadId }).go();
|
|
1093
|
+
} catch (error$1) {
|
|
1094
|
+
throw new error.MastraError(
|
|
1095
|
+
{
|
|
1096
|
+
id: "STORAGE_DYNAMODB_STORE_DELETE_THREAD_FAILED",
|
|
1097
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1098
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1099
|
+
details: { threadId }
|
|
1100
|
+
},
|
|
1101
|
+
error$1
|
|
1102
|
+
);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
async listMessagesById({ messageIds }) {
|
|
1106
|
+
this.logger.debug("Getting messages by ID", { messageIds });
|
|
1107
|
+
if (messageIds.length === 0) return { messages: [] };
|
|
1108
|
+
try {
|
|
1109
|
+
const results = await Promise.all(
|
|
1110
|
+
messageIds.map((id) => this.service.entities.message.query.primary({ entity: "message", id }).go())
|
|
1111
|
+
);
|
|
1112
|
+
const data = results.map((result) => result.data).flat(1);
|
|
1113
|
+
let parsedMessages = data.map((data2) => this.parseMessageData(data2)).filter((msg) => "content" in msg);
|
|
1114
|
+
const uniqueMessages = parsedMessages.filter(
|
|
1115
|
+
(message, index, self) => index === self.findIndex((m) => m.id === message.id)
|
|
1116
|
+
);
|
|
1117
|
+
const list = new agent.MessageList().add(uniqueMessages, "memory");
|
|
1118
|
+
return { messages: list.get.all.db() };
|
|
1119
|
+
} catch (error$1) {
|
|
1120
|
+
throw new error.MastraError(
|
|
1121
|
+
{
|
|
1122
|
+
id: "STORAGE_DYNAMODB_STORE_LIST_MESSAGES_BY_ID_FAILED",
|
|
1123
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1124
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1125
|
+
details: { messageIds: JSON.stringify(messageIds) }
|
|
1126
|
+
},
|
|
1127
|
+
error$1
|
|
1128
|
+
);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
async listMessages(args) {
|
|
1132
|
+
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
1133
|
+
if (!threadId.trim()) {
|
|
1134
|
+
throw new error.MastraError(
|
|
1135
|
+
{
|
|
1136
|
+
id: "STORAGE_DYNAMODB_LIST_MESSAGES_INVALID_THREAD_ID",
|
|
1137
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1138
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1139
|
+
details: { threadId }
|
|
1140
|
+
},
|
|
1141
|
+
new Error("threadId must be a non-empty string")
|
|
1142
|
+
);
|
|
1143
|
+
}
|
|
1144
|
+
const perPage = storage.normalizePerPage(perPageInput, 40);
|
|
1145
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1146
|
+
try {
|
|
1147
|
+
if (page < 0) {
|
|
1148
|
+
throw new error.MastraError(
|
|
1149
|
+
{
|
|
1150
|
+
id: "STORAGE_DYNAMODB_LIST_MESSAGES_INVALID_PAGE",
|
|
1151
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1152
|
+
category: error.ErrorCategory.USER,
|
|
1153
|
+
details: { page }
|
|
1154
|
+
},
|
|
1155
|
+
new Error("page must be >= 0")
|
|
615
1156
|
);
|
|
616
1157
|
}
|
|
617
|
-
|
|
1158
|
+
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
1159
|
+
this.logger.debug("Getting messages with listMessages", {
|
|
1160
|
+
threadId,
|
|
1161
|
+
resourceId,
|
|
1162
|
+
perPageInput,
|
|
1163
|
+
offset,
|
|
1164
|
+
perPage,
|
|
1165
|
+
page,
|
|
1166
|
+
field,
|
|
1167
|
+
direction
|
|
1168
|
+
});
|
|
1169
|
+
const query = this.service.entities.message.query.byThread({ entity: "message", threadId });
|
|
1170
|
+
const results = await query.go();
|
|
1171
|
+
let allThreadMessages = results.data.map((data) => this.parseMessageData(data)).filter((msg) => "content" in msg && typeof msg.content === "object");
|
|
1172
|
+
if (resourceId) {
|
|
1173
|
+
allThreadMessages = allThreadMessages.filter((msg) => msg.resourceId === resourceId);
|
|
1174
|
+
}
|
|
1175
|
+
if (filter?.dateRange) {
|
|
1176
|
+
const dateRange = filter.dateRange;
|
|
1177
|
+
allThreadMessages = allThreadMessages.filter((msg) => {
|
|
1178
|
+
const createdAt = new Date(msg.createdAt).getTime();
|
|
1179
|
+
if (dateRange.start) {
|
|
1180
|
+
const startTime = dateRange.start instanceof Date ? dateRange.start.getTime() : new Date(dateRange.start).getTime();
|
|
1181
|
+
if (createdAt < startTime) return false;
|
|
1182
|
+
}
|
|
1183
|
+
if (dateRange.end) {
|
|
1184
|
+
const endTime = dateRange.end instanceof Date ? dateRange.end.getTime() : new Date(dateRange.end).getTime();
|
|
1185
|
+
if (createdAt > endTime) return false;
|
|
1186
|
+
}
|
|
1187
|
+
return true;
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1190
|
+
allThreadMessages.sort((a, b) => {
|
|
1191
|
+
const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
|
|
1192
|
+
const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
|
|
1193
|
+
if (aValue === bValue) {
|
|
1194
|
+
return a.id.localeCompare(b.id);
|
|
1195
|
+
}
|
|
1196
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
1197
|
+
});
|
|
1198
|
+
const total = allThreadMessages.length;
|
|
1199
|
+
const paginatedMessages = allThreadMessages.slice(offset, offset + perPage);
|
|
1200
|
+
const paginatedCount = paginatedMessages.length;
|
|
1201
|
+
if (total === 0 && paginatedCount === 0 && (!include || include.length === 0)) {
|
|
1202
|
+
return {
|
|
1203
|
+
messages: [],
|
|
1204
|
+
total: 0,
|
|
1205
|
+
page,
|
|
1206
|
+
perPage: perPageForResponse,
|
|
1207
|
+
hasMore: false
|
|
1208
|
+
};
|
|
1209
|
+
}
|
|
1210
|
+
const messageIds = new Set(paginatedMessages.map((m) => m.id));
|
|
1211
|
+
let includeMessages = [];
|
|
1212
|
+
if (include && include.length > 0) {
|
|
1213
|
+
const selectBy = { include };
|
|
1214
|
+
includeMessages = await this._getIncludedMessages(threadId, selectBy);
|
|
1215
|
+
for (const includeMsg of includeMessages) {
|
|
1216
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
1217
|
+
paginatedMessages.push(includeMsg);
|
|
1218
|
+
messageIds.add(includeMsg.id);
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
const list = new agent.MessageList().add(paginatedMessages, "memory");
|
|
1223
|
+
let finalMessages = list.get.all.db();
|
|
1224
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
1225
|
+
const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
|
|
1226
|
+
const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
|
|
1227
|
+
if (aValue === bValue) {
|
|
1228
|
+
return a.id.localeCompare(b.id);
|
|
1229
|
+
}
|
|
1230
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
1231
|
+
});
|
|
1232
|
+
const returnedThreadMessageIds = new Set(finalMessages.filter((m) => m.threadId === threadId).map((m) => m.id));
|
|
1233
|
+
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
1234
|
+
let hasMore = false;
|
|
1235
|
+
if (perPageInput !== false && !allThreadMessagesReturned) {
|
|
1236
|
+
hasMore = offset + paginatedCount < total;
|
|
1237
|
+
}
|
|
1238
|
+
return {
|
|
1239
|
+
messages: finalMessages,
|
|
1240
|
+
total,
|
|
1241
|
+
page,
|
|
1242
|
+
perPage: perPageForResponse,
|
|
1243
|
+
hasMore
|
|
1244
|
+
};
|
|
1245
|
+
} catch (error$1) {
|
|
1246
|
+
const mastraError = new error.MastraError(
|
|
1247
|
+
{
|
|
1248
|
+
id: "STORAGE_DYNAMODB_STORE_LIST_MESSAGES_FAILED",
|
|
1249
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1250
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1251
|
+
details: {
|
|
1252
|
+
threadId,
|
|
1253
|
+
resourceId: resourceId ?? ""
|
|
1254
|
+
}
|
|
1255
|
+
},
|
|
1256
|
+
error$1
|
|
1257
|
+
);
|
|
1258
|
+
this.logger?.error?.(mastraError.toString());
|
|
1259
|
+
this.logger?.trackException?.(mastraError);
|
|
1260
|
+
return {
|
|
1261
|
+
messages: [],
|
|
1262
|
+
total: 0,
|
|
1263
|
+
page,
|
|
1264
|
+
perPage: perPageForResponse,
|
|
1265
|
+
hasMore: false
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
async saveMessages(args) {
|
|
1270
|
+
const { messages } = args;
|
|
1271
|
+
this.logger.debug("Saving messages", { count: messages.length });
|
|
1272
|
+
if (!messages.length) {
|
|
1273
|
+
return { messages: [] };
|
|
1274
|
+
}
|
|
1275
|
+
const threadId = messages[0]?.threadId;
|
|
1276
|
+
if (!threadId) {
|
|
1277
|
+
throw new Error("Thread ID is required");
|
|
1278
|
+
}
|
|
1279
|
+
const messagesToSave = messages.map((msg) => {
|
|
1280
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1281
|
+
return {
|
|
1282
|
+
entity: "message",
|
|
1283
|
+
// Add entity type
|
|
1284
|
+
id: msg.id,
|
|
1285
|
+
threadId: msg.threadId,
|
|
1286
|
+
role: msg.role,
|
|
1287
|
+
type: msg.type,
|
|
1288
|
+
resourceId: msg.resourceId,
|
|
1289
|
+
// Ensure complex fields are stringified if not handled by attribute setters
|
|
1290
|
+
content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content),
|
|
1291
|
+
toolCallArgs: `toolCallArgs` in msg && msg.toolCallArgs ? JSON.stringify(msg.toolCallArgs) : void 0,
|
|
1292
|
+
toolCallIds: `toolCallIds` in msg && msg.toolCallIds ? JSON.stringify(msg.toolCallIds) : void 0,
|
|
1293
|
+
toolNames: `toolNames` in msg && msg.toolNames ? JSON.stringify(msg.toolNames) : void 0,
|
|
1294
|
+
createdAt: msg.createdAt instanceof Date ? msg.createdAt.toISOString() : msg.createdAt || now,
|
|
1295
|
+
updatedAt: now
|
|
1296
|
+
// Add updatedAt
|
|
1297
|
+
};
|
|
1298
|
+
});
|
|
1299
|
+
try {
|
|
1300
|
+
const savedMessageIds = [];
|
|
1301
|
+
for (const messageData of messagesToSave) {
|
|
1302
|
+
if (!messageData.entity) {
|
|
1303
|
+
this.logger.error("Missing entity property in message data for create", { messageData });
|
|
1304
|
+
throw new Error("Internal error: Missing entity property during saveMessages");
|
|
1305
|
+
}
|
|
1306
|
+
try {
|
|
1307
|
+
await this.service.entities.message.put(messageData).go();
|
|
1308
|
+
savedMessageIds.push(messageData.id);
|
|
1309
|
+
} catch (error) {
|
|
1310
|
+
for (const savedId of savedMessageIds) {
|
|
1311
|
+
try {
|
|
1312
|
+
await this.service.entities.message.delete({ entity: "message", id: savedId }).go();
|
|
1313
|
+
} catch (rollbackError) {
|
|
1314
|
+
this.logger.error("Failed to rollback message during save error", {
|
|
1315
|
+
messageId: savedId,
|
|
1316
|
+
error: rollbackError
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
throw error;
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
await this.service.entities.thread.update({ entity: "thread", id: threadId }).set({
|
|
1324
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1325
|
+
}).go();
|
|
1326
|
+
const list = new agent.MessageList().add(messages, "memory");
|
|
1327
|
+
return { messages: list.get.all.db() };
|
|
618
1328
|
} catch (error$1) {
|
|
619
|
-
this.logger.error("Error validating table access", { tableName: this.tableName, error: error$1 });
|
|
620
1329
|
throw new error.MastraError(
|
|
621
1330
|
{
|
|
622
|
-
id: "
|
|
1331
|
+
id: "STORAGE_DYNAMODB_STORE_SAVE_MESSAGES_FAILED",
|
|
623
1332
|
domain: error.ErrorDomain.STORAGE,
|
|
624
1333
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
625
|
-
details: {
|
|
1334
|
+
details: { count: messages.length }
|
|
1335
|
+
},
|
|
1336
|
+
error$1
|
|
1337
|
+
);
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
async listThreadsByResourceId(args) {
|
|
1341
|
+
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
1342
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
1343
|
+
if (page < 0) {
|
|
1344
|
+
throw new error.MastraError(
|
|
1345
|
+
{
|
|
1346
|
+
id: "STORAGE_DYNAMODB_LIST_THREADS_BY_RESOURCE_ID_INVALID_PAGE",
|
|
1347
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1348
|
+
category: error.ErrorCategory.USER,
|
|
1349
|
+
details: { page }
|
|
1350
|
+
},
|
|
1351
|
+
new Error("page must be >= 0")
|
|
1352
|
+
);
|
|
1353
|
+
}
|
|
1354
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1355
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
1356
|
+
this.logger.debug("Getting threads by resource ID with pagination", {
|
|
1357
|
+
resourceId,
|
|
1358
|
+
page,
|
|
1359
|
+
perPage,
|
|
1360
|
+
field,
|
|
1361
|
+
direction
|
|
1362
|
+
});
|
|
1363
|
+
try {
|
|
1364
|
+
const query = this.service.entities.thread.query.byResource({ entity: "thread", resourceId });
|
|
1365
|
+
const results = await query.go();
|
|
1366
|
+
const allThreads = this.transformAndSortThreads(results.data, field, direction);
|
|
1367
|
+
const endIndex = offset + perPage;
|
|
1368
|
+
const paginatedThreads = allThreads.slice(offset, endIndex);
|
|
1369
|
+
const total = allThreads.length;
|
|
1370
|
+
const hasMore = offset + perPage < total;
|
|
1371
|
+
return {
|
|
1372
|
+
threads: paginatedThreads,
|
|
1373
|
+
total,
|
|
1374
|
+
page,
|
|
1375
|
+
perPage: perPageForResponse,
|
|
1376
|
+
hasMore
|
|
1377
|
+
};
|
|
1378
|
+
} catch (error$1) {
|
|
1379
|
+
throw new error.MastraError(
|
|
1380
|
+
{
|
|
1381
|
+
id: "DYNAMODB_STORAGE_LIST_THREADS_BY_RESOURCE_ID_FAILED",
|
|
1382
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1383
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1384
|
+
details: { resourceId, page, perPage }
|
|
1385
|
+
},
|
|
1386
|
+
error$1
|
|
1387
|
+
);
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
// Helper method to get included messages with context
|
|
1391
|
+
async _getIncludedMessages(threadId, selectBy) {
|
|
1392
|
+
if (!threadId.trim()) throw new Error("threadId must be a non-empty string");
|
|
1393
|
+
if (!selectBy?.include?.length) {
|
|
1394
|
+
return [];
|
|
1395
|
+
}
|
|
1396
|
+
const includeMessages = [];
|
|
1397
|
+
for (const includeItem of selectBy.include) {
|
|
1398
|
+
try {
|
|
1399
|
+
const { id, threadId: targetThreadId, withPreviousMessages = 0, withNextMessages = 0 } = includeItem;
|
|
1400
|
+
const searchThreadId = targetThreadId || threadId;
|
|
1401
|
+
this.logger.debug("Getting included messages for", {
|
|
1402
|
+
id,
|
|
1403
|
+
targetThreadId,
|
|
1404
|
+
searchThreadId,
|
|
1405
|
+
withPreviousMessages,
|
|
1406
|
+
withNextMessages
|
|
1407
|
+
});
|
|
1408
|
+
const query = this.service.entities.message.query.byThread({ entity: "message", threadId: searchThreadId });
|
|
1409
|
+
const results = await query.go();
|
|
1410
|
+
const allMessages = results.data.map((data) => this.parseMessageData(data)).filter((msg) => "content" in msg && typeof msg.content === "object");
|
|
1411
|
+
this.logger.debug("Found messages in thread", {
|
|
1412
|
+
threadId: searchThreadId,
|
|
1413
|
+
messageCount: allMessages.length,
|
|
1414
|
+
messageIds: allMessages.map((m) => m.id)
|
|
1415
|
+
});
|
|
1416
|
+
allMessages.sort((a, b) => {
|
|
1417
|
+
const timeA = a.createdAt.getTime();
|
|
1418
|
+
const timeB = b.createdAt.getTime();
|
|
1419
|
+
if (timeA === timeB) {
|
|
1420
|
+
return a.id.localeCompare(b.id);
|
|
1421
|
+
}
|
|
1422
|
+
return timeA - timeB;
|
|
1423
|
+
});
|
|
1424
|
+
const targetIndex = allMessages.findIndex((msg) => msg.id === id);
|
|
1425
|
+
if (targetIndex === -1) {
|
|
1426
|
+
this.logger.warn("Target message not found", { id, threadId: searchThreadId });
|
|
1427
|
+
continue;
|
|
1428
|
+
}
|
|
1429
|
+
this.logger.debug("Found target message at index", { id, targetIndex, totalMessages: allMessages.length });
|
|
1430
|
+
const startIndex = Math.max(0, targetIndex - withPreviousMessages);
|
|
1431
|
+
const endIndex = Math.min(allMessages.length, targetIndex + withNextMessages + 1);
|
|
1432
|
+
const contextMessages = allMessages.slice(startIndex, endIndex);
|
|
1433
|
+
this.logger.debug("Context messages", {
|
|
1434
|
+
startIndex,
|
|
1435
|
+
endIndex,
|
|
1436
|
+
contextCount: contextMessages.length,
|
|
1437
|
+
contextIds: contextMessages.map((m) => m.id)
|
|
1438
|
+
});
|
|
1439
|
+
includeMessages.push(...contextMessages);
|
|
1440
|
+
} catch (error) {
|
|
1441
|
+
this.logger.warn("Failed to get included message", { messageId: includeItem.id, error });
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
this.logger.debug("Total included messages", {
|
|
1445
|
+
count: includeMessages.length,
|
|
1446
|
+
ids: includeMessages.map((m) => m.id)
|
|
1447
|
+
});
|
|
1448
|
+
return includeMessages;
|
|
1449
|
+
}
|
|
1450
|
+
async updateMessages(args) {
|
|
1451
|
+
const { messages } = args;
|
|
1452
|
+
this.logger.debug("Updating messages", { count: messages.length });
|
|
1453
|
+
if (!messages.length) {
|
|
1454
|
+
return [];
|
|
1455
|
+
}
|
|
1456
|
+
const updatedMessages = [];
|
|
1457
|
+
const affectedThreadIds = /* @__PURE__ */ new Set();
|
|
1458
|
+
try {
|
|
1459
|
+
for (const updateData of messages) {
|
|
1460
|
+
const { id, ...updates } = updateData;
|
|
1461
|
+
const existingMessage = await this.service.entities.message.get({ entity: "message", id }).go();
|
|
1462
|
+
if (!existingMessage.data) {
|
|
1463
|
+
this.logger.warn("Message not found for update", { id });
|
|
1464
|
+
continue;
|
|
1465
|
+
}
|
|
1466
|
+
const existingMsg = this.parseMessageData(existingMessage.data);
|
|
1467
|
+
const originalThreadId = existingMsg.threadId;
|
|
1468
|
+
affectedThreadIds.add(originalThreadId);
|
|
1469
|
+
const updatePayload = {
|
|
1470
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1471
|
+
};
|
|
1472
|
+
if ("role" in updates && updates.role !== void 0) updatePayload.role = updates.role;
|
|
1473
|
+
if ("type" in updates && updates.type !== void 0) updatePayload.type = updates.type;
|
|
1474
|
+
if ("resourceId" in updates && updates.resourceId !== void 0) updatePayload.resourceId = updates.resourceId;
|
|
1475
|
+
if ("threadId" in updates && updates.threadId !== void 0 && updates.threadId !== null) {
|
|
1476
|
+
updatePayload.threadId = updates.threadId;
|
|
1477
|
+
affectedThreadIds.add(updates.threadId);
|
|
1478
|
+
}
|
|
1479
|
+
if (updates.content) {
|
|
1480
|
+
const existingContent = existingMsg.content;
|
|
1481
|
+
let newContent = { ...existingContent };
|
|
1482
|
+
if (updates.content.metadata !== void 0) {
|
|
1483
|
+
newContent.metadata = {
|
|
1484
|
+
...existingContent.metadata || {},
|
|
1485
|
+
...updates.content.metadata || {}
|
|
1486
|
+
};
|
|
1487
|
+
}
|
|
1488
|
+
if (updates.content.content !== void 0) {
|
|
1489
|
+
newContent.content = updates.content.content;
|
|
1490
|
+
}
|
|
1491
|
+
if ("parts" in updates.content && updates.content.parts !== void 0) {
|
|
1492
|
+
newContent.parts = updates.content.parts;
|
|
1493
|
+
}
|
|
1494
|
+
updatePayload.content = JSON.stringify(newContent);
|
|
1495
|
+
}
|
|
1496
|
+
await this.service.entities.message.update({ entity: "message", id }).set(updatePayload).go();
|
|
1497
|
+
const updatedMessage = await this.service.entities.message.get({ entity: "message", id }).go();
|
|
1498
|
+
if (updatedMessage.data) {
|
|
1499
|
+
updatedMessages.push(this.parseMessageData(updatedMessage.data));
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
for (const threadId of affectedThreadIds) {
|
|
1503
|
+
await this.service.entities.thread.update({ entity: "thread", id: threadId }).set({
|
|
1504
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1505
|
+
}).go();
|
|
1506
|
+
}
|
|
1507
|
+
return updatedMessages;
|
|
1508
|
+
} catch (error$1) {
|
|
1509
|
+
throw new error.MastraError(
|
|
1510
|
+
{
|
|
1511
|
+
id: "STORAGE_DYNAMODB_STORE_UPDATE_MESSAGES_FAILED",
|
|
1512
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1513
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1514
|
+
details: { count: messages.length }
|
|
1515
|
+
},
|
|
1516
|
+
error$1
|
|
1517
|
+
);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
async getResourceById({ resourceId }) {
|
|
1521
|
+
this.logger.debug("Getting resource by ID", { resourceId });
|
|
1522
|
+
try {
|
|
1523
|
+
const result = await this.service.entities.resource.get({ entity: "resource", id: resourceId }).go();
|
|
1524
|
+
if (!result.data) {
|
|
1525
|
+
return null;
|
|
1526
|
+
}
|
|
1527
|
+
const data = result.data;
|
|
1528
|
+
return {
|
|
1529
|
+
...data,
|
|
1530
|
+
// Convert date strings back to Date objects for consistency
|
|
1531
|
+
createdAt: typeof data.createdAt === "string" ? new Date(data.createdAt) : data.createdAt,
|
|
1532
|
+
updatedAt: typeof data.updatedAt === "string" ? new Date(data.updatedAt) : data.updatedAt,
|
|
1533
|
+
// Ensure workingMemory is always returned as a string, regardless of automatic parsing
|
|
1534
|
+
workingMemory: typeof data.workingMemory === "object" ? JSON.stringify(data.workingMemory) : data.workingMemory
|
|
1535
|
+
// metadata is already transformed by the entity's getter
|
|
1536
|
+
};
|
|
1537
|
+
} catch (error$1) {
|
|
1538
|
+
throw new error.MastraError(
|
|
1539
|
+
{
|
|
1540
|
+
id: "STORAGE_DYNAMODB_STORE_GET_RESOURCE_BY_ID_FAILED",
|
|
1541
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1542
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1543
|
+
details: { resourceId }
|
|
1544
|
+
},
|
|
1545
|
+
error$1
|
|
1546
|
+
);
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
async saveResource({ resource }) {
|
|
1550
|
+
this.logger.debug("Saving resource", { resourceId: resource.id });
|
|
1551
|
+
const now = /* @__PURE__ */ new Date();
|
|
1552
|
+
const resourceData = {
|
|
1553
|
+
entity: "resource",
|
|
1554
|
+
id: resource.id,
|
|
1555
|
+
workingMemory: resource.workingMemory,
|
|
1556
|
+
metadata: resource.metadata ? JSON.stringify(resource.metadata) : void 0,
|
|
1557
|
+
createdAt: resource.createdAt?.toISOString() || now.toISOString(),
|
|
1558
|
+
updatedAt: now.toISOString()
|
|
1559
|
+
};
|
|
1560
|
+
try {
|
|
1561
|
+
await this.service.entities.resource.upsert(resourceData).go();
|
|
1562
|
+
return {
|
|
1563
|
+
id: resource.id,
|
|
1564
|
+
workingMemory: resource.workingMemory,
|
|
1565
|
+
metadata: resource.metadata,
|
|
1566
|
+
createdAt: resource.createdAt || now,
|
|
1567
|
+
updatedAt: now
|
|
1568
|
+
};
|
|
1569
|
+
} catch (error$1) {
|
|
1570
|
+
throw new error.MastraError(
|
|
1571
|
+
{
|
|
1572
|
+
id: "STORAGE_DYNAMODB_STORE_SAVE_RESOURCE_FAILED",
|
|
1573
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1574
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1575
|
+
details: { resourceId: resource.id }
|
|
626
1576
|
},
|
|
627
1577
|
error$1
|
|
628
1578
|
);
|
|
629
1579
|
}
|
|
630
1580
|
}
|
|
1581
|
+
async updateResource({
|
|
1582
|
+
resourceId,
|
|
1583
|
+
workingMemory,
|
|
1584
|
+
metadata
|
|
1585
|
+
}) {
|
|
1586
|
+
this.logger.debug("Updating resource", { resourceId });
|
|
1587
|
+
try {
|
|
1588
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
1589
|
+
if (!existingResource) {
|
|
1590
|
+
const newResource = {
|
|
1591
|
+
id: resourceId,
|
|
1592
|
+
workingMemory,
|
|
1593
|
+
metadata: metadata || {},
|
|
1594
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1595
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1596
|
+
};
|
|
1597
|
+
return this.saveResource({ resource: newResource });
|
|
1598
|
+
}
|
|
1599
|
+
const now = /* @__PURE__ */ new Date();
|
|
1600
|
+
const updateData = {
|
|
1601
|
+
updatedAt: now.toISOString()
|
|
1602
|
+
};
|
|
1603
|
+
if (workingMemory !== void 0) {
|
|
1604
|
+
updateData.workingMemory = workingMemory;
|
|
1605
|
+
}
|
|
1606
|
+
if (metadata) {
|
|
1607
|
+
const existingMetadata = existingResource.metadata || {};
|
|
1608
|
+
const mergedMetadata = { ...existingMetadata, ...metadata };
|
|
1609
|
+
updateData.metadata = JSON.stringify(mergedMetadata);
|
|
1610
|
+
}
|
|
1611
|
+
await this.service.entities.resource.update({ entity: "resource", id: resourceId }).set(updateData).go();
|
|
1612
|
+
return {
|
|
1613
|
+
...existingResource,
|
|
1614
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
1615
|
+
metadata: metadata ? { ...existingResource.metadata, ...metadata } : existingResource.metadata,
|
|
1616
|
+
updatedAt: now
|
|
1617
|
+
};
|
|
1618
|
+
} catch (error$1) {
|
|
1619
|
+
throw new error.MastraError(
|
|
1620
|
+
{
|
|
1621
|
+
id: "STORAGE_DYNAMODB_STORE_UPDATE_RESOURCE_FAILED",
|
|
1622
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1623
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1624
|
+
details: { resourceId }
|
|
1625
|
+
},
|
|
1626
|
+
error$1
|
|
1627
|
+
);
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
};
|
|
1631
|
+
var StoreOperationsDynamoDB = class extends storage.StoreOperations {
|
|
1632
|
+
client;
|
|
1633
|
+
tableName;
|
|
1634
|
+
service;
|
|
1635
|
+
constructor({
|
|
1636
|
+
service,
|
|
1637
|
+
tableName,
|
|
1638
|
+
client
|
|
1639
|
+
}) {
|
|
1640
|
+
super();
|
|
1641
|
+
this.service = service;
|
|
1642
|
+
this.client = client;
|
|
1643
|
+
this.tableName = tableName;
|
|
1644
|
+
}
|
|
1645
|
+
async hasColumn() {
|
|
1646
|
+
return true;
|
|
1647
|
+
}
|
|
1648
|
+
async dropTable() {
|
|
1649
|
+
}
|
|
1650
|
+
// Helper methods for entity/table mapping
|
|
1651
|
+
getEntityNameForTable(tableName) {
|
|
1652
|
+
const mapping = {
|
|
1653
|
+
[storage.TABLE_THREADS]: "thread",
|
|
1654
|
+
[storage.TABLE_MESSAGES]: "message",
|
|
1655
|
+
[storage.TABLE_WORKFLOW_SNAPSHOT]: "workflow_snapshot",
|
|
1656
|
+
[storage.TABLE_SCORERS]: "score",
|
|
1657
|
+
[storage.TABLE_TRACES]: "trace",
|
|
1658
|
+
[storage.TABLE_RESOURCES]: "resource",
|
|
1659
|
+
[storage.TABLE_SPANS]: "ai_span"
|
|
1660
|
+
};
|
|
1661
|
+
return mapping[tableName] || null;
|
|
1662
|
+
}
|
|
1663
|
+
/**
|
|
1664
|
+
* Pre-processes a record to ensure Date objects are converted to ISO strings
|
|
1665
|
+
* This is necessary because ElectroDB validation happens before setters are applied
|
|
1666
|
+
*/
|
|
1667
|
+
preprocessRecord(record) {
|
|
1668
|
+
const processed = { ...record };
|
|
1669
|
+
if (processed.createdAt instanceof Date) {
|
|
1670
|
+
processed.createdAt = processed.createdAt.toISOString();
|
|
1671
|
+
}
|
|
1672
|
+
if (processed.updatedAt instanceof Date) {
|
|
1673
|
+
processed.updatedAt = processed.updatedAt.toISOString();
|
|
1674
|
+
}
|
|
1675
|
+
if (processed.created_at instanceof Date) {
|
|
1676
|
+
processed.created_at = processed.created_at.toISOString();
|
|
1677
|
+
}
|
|
1678
|
+
if (processed.result && typeof processed.result === "object") {
|
|
1679
|
+
processed.result = JSON.stringify(processed.result);
|
|
1680
|
+
}
|
|
1681
|
+
if (processed.test_info && typeof processed.test_info === "object") {
|
|
1682
|
+
processed.test_info = JSON.stringify(processed.test_info);
|
|
1683
|
+
} else if (processed.test_info === void 0 || processed.test_info === null) {
|
|
1684
|
+
delete processed.test_info;
|
|
1685
|
+
}
|
|
1686
|
+
if (processed.snapshot && typeof processed.snapshot === "object") {
|
|
1687
|
+
processed.snapshot = JSON.stringify(processed.snapshot);
|
|
1688
|
+
}
|
|
1689
|
+
if (processed.attributes && typeof processed.attributes === "object") {
|
|
1690
|
+
processed.attributes = JSON.stringify(processed.attributes);
|
|
1691
|
+
}
|
|
1692
|
+
if (processed.status && typeof processed.status === "object") {
|
|
1693
|
+
processed.status = JSON.stringify(processed.status);
|
|
1694
|
+
}
|
|
1695
|
+
if (processed.events && typeof processed.events === "object") {
|
|
1696
|
+
processed.events = JSON.stringify(processed.events);
|
|
1697
|
+
}
|
|
1698
|
+
if (processed.links && typeof processed.links === "object") {
|
|
1699
|
+
processed.links = JSON.stringify(processed.links);
|
|
1700
|
+
}
|
|
1701
|
+
return processed;
|
|
1702
|
+
}
|
|
631
1703
|
/**
|
|
632
1704
|
* Validates that the required DynamoDB table exists and is accessible.
|
|
633
1705
|
* This does not check the table structure - it assumes the table
|
|
@@ -646,7 +1718,40 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
646
1718
|
}
|
|
647
1719
|
throw new error.MastraError(
|
|
648
1720
|
{
|
|
649
|
-
id: "STORAGE_DYNAMODB_STORE_VALIDATE_TABLE_EXISTS_FAILED",
|
|
1721
|
+
id: "STORAGE_DYNAMODB_STORE_VALIDATE_TABLE_EXISTS_FAILED",
|
|
1722
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1723
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1724
|
+
details: { tableName: this.tableName }
|
|
1725
|
+
},
|
|
1726
|
+
error$1
|
|
1727
|
+
);
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
/**
|
|
1731
|
+
* This method is modified for DynamoDB with ElectroDB single-table design.
|
|
1732
|
+
* It assumes the table is created and managed externally via CDK/CloudFormation.
|
|
1733
|
+
*
|
|
1734
|
+
* This implementation only validates that the required table exists and is accessible.
|
|
1735
|
+
* No table creation is attempted - we simply check if we can access the table.
|
|
1736
|
+
*/
|
|
1737
|
+
async createTable({ tableName }) {
|
|
1738
|
+
this.logger.debug("Validating access to externally managed table", { tableName, physicalTable: this.tableName });
|
|
1739
|
+
try {
|
|
1740
|
+
const tableExists = await this.validateTableExists();
|
|
1741
|
+
if (!tableExists) {
|
|
1742
|
+
this.logger.error(
|
|
1743
|
+
`Table ${this.tableName} does not exist or is not accessible. It should be created via CDK/CloudFormation.`
|
|
1744
|
+
);
|
|
1745
|
+
throw new Error(
|
|
1746
|
+
`Table ${this.tableName} does not exist or is not accessible. Ensure it's created via CDK/CloudFormation before using this store.`
|
|
1747
|
+
);
|
|
1748
|
+
}
|
|
1749
|
+
this.logger.debug(`Table ${this.tableName} exists and is accessible`);
|
|
1750
|
+
} catch (error$1) {
|
|
1751
|
+
this.logger.error("Error validating table access", { tableName: this.tableName, error: error$1 });
|
|
1752
|
+
throw new error.MastraError(
|
|
1753
|
+
{
|
|
1754
|
+
id: "STORAGE_DYNAMODB_STORE_VALIDATE_TABLE_ACCESS_FAILED",
|
|
650
1755
|
domain: error.ErrorDomain.STORAGE,
|
|
651
1756
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
652
1757
|
details: { tableName: this.tableName }
|
|
@@ -655,63 +1760,33 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
655
1760
|
);
|
|
656
1761
|
}
|
|
657
1762
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
1763
|
+
async insert({ tableName, record }) {
|
|
1764
|
+
this.logger.debug("DynamoDB insert called", { tableName });
|
|
1765
|
+
const entityName = this.getEntityNameForTable(tableName);
|
|
1766
|
+
if (!entityName || !this.service.entities[entityName]) {
|
|
1767
|
+
throw new error.MastraError({
|
|
1768
|
+
id: "STORAGE_DYNAMODB_STORE_INSERT_INVALID_ARGS",
|
|
1769
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1770
|
+
category: error.ErrorCategory.USER,
|
|
1771
|
+
text: "No entity defined for tableName",
|
|
1772
|
+
details: { tableName }
|
|
1773
|
+
});
|
|
666
1774
|
}
|
|
667
1775
|
try {
|
|
668
|
-
|
|
1776
|
+
const dataToSave = { entity: entityName, ...this.preprocessRecord(record) };
|
|
1777
|
+
await this.service.entities[entityName].create(dataToSave).go();
|
|
669
1778
|
} catch (error$1) {
|
|
670
1779
|
throw new error.MastraError(
|
|
671
1780
|
{
|
|
672
|
-
id: "
|
|
1781
|
+
id: "STORAGE_DYNAMODB_STORE_INSERT_FAILED",
|
|
673
1782
|
domain: error.ErrorDomain.STORAGE,
|
|
674
1783
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
675
|
-
details: { tableName
|
|
1784
|
+
details: { tableName }
|
|
676
1785
|
},
|
|
677
1786
|
error$1
|
|
678
1787
|
);
|
|
679
1788
|
}
|
|
680
1789
|
}
|
|
681
|
-
/**
|
|
682
|
-
* Performs the actual table validation and stores the promise.
|
|
683
|
-
* Handles resetting the stored promise on failure to allow retries.
|
|
684
|
-
*/
|
|
685
|
-
_performInitializationAndStore() {
|
|
686
|
-
return this.validateTableExists().then((exists) => {
|
|
687
|
-
if (!exists) {
|
|
688
|
-
throw new Error(
|
|
689
|
-
`Table ${this.tableName} does not exist or is not accessible. Ensure it's created via CDK/CloudFormation before using this store.`
|
|
690
|
-
);
|
|
691
|
-
}
|
|
692
|
-
return true;
|
|
693
|
-
}).catch((err) => {
|
|
694
|
-
this.hasInitialized = null;
|
|
695
|
-
throw err;
|
|
696
|
-
});
|
|
697
|
-
}
|
|
698
|
-
/**
|
|
699
|
-
* Pre-processes a record to ensure Date objects are converted to ISO strings
|
|
700
|
-
* This is necessary because ElectroDB validation happens before setters are applied
|
|
701
|
-
*/
|
|
702
|
-
preprocessRecord(record) {
|
|
703
|
-
const processed = { ...record };
|
|
704
|
-
if (processed.createdAt instanceof Date) {
|
|
705
|
-
processed.createdAt = processed.createdAt.toISOString();
|
|
706
|
-
}
|
|
707
|
-
if (processed.updatedAt instanceof Date) {
|
|
708
|
-
processed.updatedAt = processed.updatedAt.toISOString();
|
|
709
|
-
}
|
|
710
|
-
if (processed.created_at instanceof Date) {
|
|
711
|
-
processed.created_at = processed.created_at.toISOString();
|
|
712
|
-
}
|
|
713
|
-
return processed;
|
|
714
|
-
}
|
|
715
1790
|
async alterTable(_args) {
|
|
716
1791
|
}
|
|
717
1792
|
/**
|
|
@@ -747,10 +1822,10 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
747
1822
|
if (!item.id) throw new Error(`Missing required key 'id' for entity 'message'`);
|
|
748
1823
|
key.id = item.id;
|
|
749
1824
|
break;
|
|
750
|
-
case "
|
|
1825
|
+
case "workflow_snapshot":
|
|
751
1826
|
if (!item.workflow_name)
|
|
752
|
-
throw new Error(`Missing required key 'workflow_name' for entity '
|
|
753
|
-
if (!item.run_id) throw new Error(`Missing required key 'run_id' for entity '
|
|
1827
|
+
throw new Error(`Missing required key 'workflow_name' for entity 'workflow_snapshot'`);
|
|
1828
|
+
if (!item.run_id) throw new Error(`Missing required key 'run_id' for entity 'workflow_snapshot'`);
|
|
754
1829
|
key.workflow_name = item.workflow_name;
|
|
755
1830
|
key.run_id = item.run_id;
|
|
756
1831
|
break;
|
|
@@ -762,6 +1837,14 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
762
1837
|
if (!item.id) throw new Error(`Missing required key 'id' for entity 'trace'`);
|
|
763
1838
|
key.id = item.id;
|
|
764
1839
|
break;
|
|
1840
|
+
case "score":
|
|
1841
|
+
if (!item.id) throw new Error(`Missing required key 'id' for entity 'score'`);
|
|
1842
|
+
key.id = item.id;
|
|
1843
|
+
break;
|
|
1844
|
+
case "resource":
|
|
1845
|
+
if (!item.id) throw new Error(`Missing required key 'id' for entity 'resource'`);
|
|
1846
|
+
key.id = item.id;
|
|
1847
|
+
break;
|
|
765
1848
|
default:
|
|
766
1849
|
this.logger.warn(`Unknown entity type encountered during clearTable: ${entityName}`);
|
|
767
1850
|
throw new Error(`Cannot construct delete key for unknown entity type: ${entityName}`);
|
|
@@ -786,46 +1869,10 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
786
1869
|
);
|
|
787
1870
|
}
|
|
788
1871
|
}
|
|
789
|
-
/**
|
|
790
|
-
* Insert a record into the specified "table" (entity)
|
|
791
|
-
*/
|
|
792
|
-
async insert({
|
|
793
|
-
tableName,
|
|
794
|
-
record
|
|
795
|
-
}) {
|
|
796
|
-
this.logger.debug("DynamoDB insert called", { tableName });
|
|
797
|
-
const entityName = this.getEntityNameForTable(tableName);
|
|
798
|
-
if (!entityName || !this.service.entities[entityName]) {
|
|
799
|
-
throw new error.MastraError({
|
|
800
|
-
id: "STORAGE_DYNAMODB_STORE_INSERT_INVALID_ARGS",
|
|
801
|
-
domain: error.ErrorDomain.STORAGE,
|
|
802
|
-
category: error.ErrorCategory.USER,
|
|
803
|
-
text: "No entity defined for tableName",
|
|
804
|
-
details: { tableName }
|
|
805
|
-
});
|
|
806
|
-
}
|
|
807
|
-
try {
|
|
808
|
-
const dataToSave = { entity: entityName, ...this.preprocessRecord(record) };
|
|
809
|
-
await this.service.entities[entityName].create(dataToSave).go();
|
|
810
|
-
} catch (error$1) {
|
|
811
|
-
throw new error.MastraError(
|
|
812
|
-
{
|
|
813
|
-
id: "STORAGE_DYNAMODB_STORE_INSERT_FAILED",
|
|
814
|
-
domain: error.ErrorDomain.STORAGE,
|
|
815
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
816
|
-
details: { tableName }
|
|
817
|
-
},
|
|
818
|
-
error$1
|
|
819
|
-
);
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
1872
|
/**
|
|
823
1873
|
* Insert multiple records as a batch
|
|
824
1874
|
*/
|
|
825
|
-
async batchInsert({
|
|
826
|
-
tableName,
|
|
827
|
-
records
|
|
828
|
-
}) {
|
|
1875
|
+
async batchInsert({ tableName, records }) {
|
|
829
1876
|
this.logger.debug("DynamoDB batchInsert called", { tableName, count: records.length });
|
|
830
1877
|
const entityName = this.getEntityNameForTable(tableName);
|
|
831
1878
|
if (!entityName || !this.service.entities[entityName]) {
|
|
@@ -870,10 +1917,7 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
870
1917
|
/**
|
|
871
1918
|
* Load a record by its keys
|
|
872
1919
|
*/
|
|
873
|
-
async load({
|
|
874
|
-
tableName,
|
|
875
|
-
keys
|
|
876
|
-
}) {
|
|
1920
|
+
async load({ tableName, keys }) {
|
|
877
1921
|
this.logger.debug("DynamoDB load called", { tableName, keys });
|
|
878
1922
|
const entityName = this.getEntityNameForTable(tableName);
|
|
879
1923
|
if (!entityName || !this.service.entities[entityName]) {
|
|
@@ -905,344 +1949,320 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
905
1949
|
);
|
|
906
1950
|
}
|
|
907
1951
|
}
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
1952
|
+
};
|
|
1953
|
+
var ScoresStorageDynamoDB = class extends storage.ScoresStorage {
|
|
1954
|
+
service;
|
|
1955
|
+
constructor({ service }) {
|
|
1956
|
+
super();
|
|
1957
|
+
this.service = service;
|
|
1958
|
+
}
|
|
1959
|
+
// Helper function to parse score data (handle JSON fields)
|
|
1960
|
+
parseScoreData(data) {
|
|
1961
|
+
return {
|
|
1962
|
+
...data,
|
|
1963
|
+
// Convert date strings back to Date objects for consistency
|
|
1964
|
+
createdAt: data.createdAt ? new Date(data.createdAt) : /* @__PURE__ */ new Date(),
|
|
1965
|
+
updatedAt: data.updatedAt ? new Date(data.updatedAt) : /* @__PURE__ */ new Date()
|
|
1966
|
+
// JSON fields are already transformed by the entity's getters
|
|
1967
|
+
};
|
|
1968
|
+
}
|
|
1969
|
+
async getScoreById({ id }) {
|
|
1970
|
+
this.logger.debug("Getting score by ID", { id });
|
|
911
1971
|
try {
|
|
912
|
-
const result = await this.service.entities.
|
|
1972
|
+
const result = await this.service.entities.score.get({ entity: "score", id }).go();
|
|
913
1973
|
if (!result.data) {
|
|
914
1974
|
return null;
|
|
915
1975
|
}
|
|
916
|
-
|
|
917
|
-
return {
|
|
918
|
-
...data,
|
|
919
|
-
// Convert date strings back to Date objects for consistency
|
|
920
|
-
createdAt: typeof data.createdAt === "string" ? new Date(data.createdAt) : data.createdAt,
|
|
921
|
-
updatedAt: typeof data.updatedAt === "string" ? new Date(data.updatedAt) : data.updatedAt
|
|
922
|
-
// metadata: data.metadata ? JSON.parse(data.metadata) : undefined, // REMOVED by AI
|
|
923
|
-
// metadata is already transformed by the entity's getter
|
|
924
|
-
};
|
|
1976
|
+
return this.parseScoreData(result.data);
|
|
925
1977
|
} catch (error$1) {
|
|
926
1978
|
throw new error.MastraError(
|
|
927
1979
|
{
|
|
928
|
-
id: "
|
|
1980
|
+
id: "STORAGE_DYNAMODB_STORE_GET_SCORE_BY_ID_FAILED",
|
|
929
1981
|
domain: error.ErrorDomain.STORAGE,
|
|
930
1982
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
931
|
-
details: {
|
|
1983
|
+
details: { id }
|
|
932
1984
|
},
|
|
933
1985
|
error$1
|
|
934
1986
|
);
|
|
935
1987
|
}
|
|
936
1988
|
}
|
|
937
|
-
async
|
|
938
|
-
|
|
1989
|
+
async saveScore(score) {
|
|
1990
|
+
let validatedScore;
|
|
939
1991
|
try {
|
|
940
|
-
|
|
941
|
-
if (!result.data.length) {
|
|
942
|
-
return [];
|
|
943
|
-
}
|
|
944
|
-
return result.data.map((data) => ({
|
|
945
|
-
...data,
|
|
946
|
-
// Convert date strings back to Date objects for consistency
|
|
947
|
-
createdAt: typeof data.createdAt === "string" ? new Date(data.createdAt) : data.createdAt,
|
|
948
|
-
updatedAt: typeof data.updatedAt === "string" ? new Date(data.updatedAt) : data.updatedAt
|
|
949
|
-
// metadata: data.metadata ? JSON.parse(data.metadata) : undefined, // REMOVED by AI
|
|
950
|
-
// metadata is already transformed by the entity's getter
|
|
951
|
-
}));
|
|
1992
|
+
validatedScore = evals.saveScorePayloadSchema.parse(score);
|
|
952
1993
|
} catch (error$1) {
|
|
953
1994
|
throw new error.MastraError(
|
|
954
1995
|
{
|
|
955
|
-
id: "
|
|
1996
|
+
id: "STORAGE_DYNAMODB_STORE_SAVE_SCORE_FAILED",
|
|
956
1997
|
domain: error.ErrorDomain.STORAGE,
|
|
957
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
958
|
-
details: { resourceId }
|
|
1998
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
959
1999
|
},
|
|
960
2000
|
error$1
|
|
961
2001
|
);
|
|
962
2002
|
}
|
|
963
|
-
}
|
|
964
|
-
async saveThread({ thread }) {
|
|
965
|
-
this.logger.debug("Saving thread", { threadId: thread.id });
|
|
966
2003
|
const now = /* @__PURE__ */ new Date();
|
|
967
|
-
const
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
2004
|
+
const scoreId = `score-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
2005
|
+
const scoreData = {
|
|
2006
|
+
entity: "score",
|
|
2007
|
+
id: scoreId,
|
|
2008
|
+
scorerId: validatedScore.scorerId,
|
|
2009
|
+
traceId: validatedScore.traceId || "",
|
|
2010
|
+
spanId: validatedScore.spanId || "",
|
|
2011
|
+
runId: validatedScore.runId,
|
|
2012
|
+
scorer: typeof validatedScore.scorer === "string" ? validatedScore.scorer : JSON.stringify(validatedScore.scorer),
|
|
2013
|
+
preprocessStepResult: typeof validatedScore.preprocessStepResult === "string" ? validatedScore.preprocessStepResult : JSON.stringify(validatedScore.preprocessStepResult),
|
|
2014
|
+
analyzeStepResult: typeof validatedScore.analyzeStepResult === "string" ? validatedScore.analyzeStepResult : JSON.stringify(validatedScore.analyzeStepResult),
|
|
2015
|
+
score: validatedScore.score,
|
|
2016
|
+
reason: validatedScore.reason,
|
|
2017
|
+
preprocessPrompt: validatedScore.preprocessPrompt,
|
|
2018
|
+
generateScorePrompt: validatedScore.generateScorePrompt,
|
|
2019
|
+
generateReasonPrompt: validatedScore.generateReasonPrompt,
|
|
2020
|
+
analyzePrompt: validatedScore.analyzePrompt,
|
|
2021
|
+
input: typeof validatedScore.input === "string" ? validatedScore.input : JSON.stringify(validatedScore.input),
|
|
2022
|
+
output: typeof validatedScore.output === "string" ? validatedScore.output : JSON.stringify(validatedScore.output),
|
|
2023
|
+
additionalContext: typeof validatedScore.additionalContext === "string" ? validatedScore.additionalContext : JSON.stringify(validatedScore.additionalContext),
|
|
2024
|
+
requestContext: typeof validatedScore.requestContext === "string" ? validatedScore.requestContext : JSON.stringify(validatedScore.requestContext),
|
|
2025
|
+
entityType: validatedScore.entityType,
|
|
2026
|
+
entityData: typeof validatedScore.entity === "string" ? validatedScore.entity : JSON.stringify(validatedScore.entity),
|
|
2027
|
+
entityId: validatedScore.entityId,
|
|
2028
|
+
source: validatedScore.source,
|
|
2029
|
+
resourceId: validatedScore.resourceId || "",
|
|
2030
|
+
threadId: validatedScore.threadId || "",
|
|
2031
|
+
createdAt: now.toISOString(),
|
|
2032
|
+
updatedAt: now.toISOString()
|
|
975
2033
|
};
|
|
976
2034
|
try {
|
|
977
|
-
await this.service.entities.
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
createdAt: thread.createdAt || now,
|
|
983
|
-
updatedAt: now,
|
|
984
|
-
metadata: thread.metadata
|
|
985
|
-
};
|
|
986
|
-
} catch (error$1) {
|
|
987
|
-
throw new error.MastraError(
|
|
988
|
-
{
|
|
989
|
-
id: "STORAGE_DYNAMODB_STORE_SAVE_THREAD_FAILED",
|
|
990
|
-
domain: error.ErrorDomain.STORAGE,
|
|
991
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
992
|
-
details: { threadId: thread.id }
|
|
993
|
-
},
|
|
994
|
-
error$1
|
|
995
|
-
);
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
async updateThread({
|
|
999
|
-
id,
|
|
1000
|
-
title,
|
|
1001
|
-
metadata
|
|
1002
|
-
}) {
|
|
1003
|
-
this.logger.debug("Updating thread", { threadId: id });
|
|
1004
|
-
try {
|
|
1005
|
-
const existingThread = await this.getThreadById({ threadId: id });
|
|
1006
|
-
if (!existingThread) {
|
|
1007
|
-
throw new Error(`Thread not found: ${id}`);
|
|
1008
|
-
}
|
|
1009
|
-
const now = /* @__PURE__ */ new Date();
|
|
1010
|
-
const updateData = {
|
|
1011
|
-
updatedAt: now.toISOString()
|
|
1012
|
-
};
|
|
1013
|
-
if (title) {
|
|
1014
|
-
updateData.title = title;
|
|
1015
|
-
}
|
|
1016
|
-
if (metadata) {
|
|
1017
|
-
updateData.metadata = JSON.stringify(metadata);
|
|
1018
|
-
}
|
|
1019
|
-
await this.service.entities.thread.update({ entity: "thread", id }).set(updateData).go();
|
|
1020
|
-
return {
|
|
1021
|
-
...existingThread,
|
|
1022
|
-
title: title || existingThread.title,
|
|
1023
|
-
metadata: metadata || existingThread.metadata,
|
|
2035
|
+
await this.service.entities.score.upsert(scoreData).go();
|
|
2036
|
+
const savedScore = {
|
|
2037
|
+
...score,
|
|
2038
|
+
id: scoreId,
|
|
2039
|
+
createdAt: now,
|
|
1024
2040
|
updatedAt: now
|
|
1025
2041
|
};
|
|
2042
|
+
return { score: savedScore };
|
|
1026
2043
|
} catch (error$1) {
|
|
1027
2044
|
throw new error.MastraError(
|
|
1028
2045
|
{
|
|
1029
|
-
id: "
|
|
1030
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1031
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
1032
|
-
details: { threadId: id }
|
|
1033
|
-
},
|
|
1034
|
-
error$1
|
|
1035
|
-
);
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
async deleteThread({ threadId }) {
|
|
1039
|
-
this.logger.debug("Deleting thread", { threadId });
|
|
1040
|
-
try {
|
|
1041
|
-
await this.service.entities.thread.delete({ entity: "thread", id: threadId }).go();
|
|
1042
|
-
} catch (error$1) {
|
|
1043
|
-
throw new error.MastraError(
|
|
1044
|
-
{
|
|
1045
|
-
id: "STORAGE_DYNAMODB_STORE_DELETE_THREAD_FAILED",
|
|
2046
|
+
id: "STORAGE_DYNAMODB_STORE_SAVE_SCORE_FAILED",
|
|
1046
2047
|
domain: error.ErrorDomain.STORAGE,
|
|
1047
2048
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1048
|
-
details: {
|
|
2049
|
+
details: { scorerId: score.scorerId, runId: score.runId }
|
|
1049
2050
|
},
|
|
1050
2051
|
error$1
|
|
1051
2052
|
);
|
|
1052
2053
|
}
|
|
1053
2054
|
}
|
|
1054
|
-
async
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
2055
|
+
async listScoresByScorerId({
|
|
2056
|
+
scorerId,
|
|
2057
|
+
pagination,
|
|
2058
|
+
entityId,
|
|
2059
|
+
entityType,
|
|
2060
|
+
source
|
|
1059
2061
|
}) {
|
|
1060
|
-
this.logger.debug("Getting messages", { threadId, selectBy });
|
|
1061
2062
|
try {
|
|
1062
|
-
const query = this.service.entities.
|
|
1063
|
-
const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: Number.MAX_SAFE_INTEGER });
|
|
1064
|
-
if (limit !== Number.MAX_SAFE_INTEGER) {
|
|
1065
|
-
const results2 = await query.go({ limit, order: "desc" });
|
|
1066
|
-
const list2 = new agent.MessageList({ threadId, resourceId }).add(
|
|
1067
|
-
results2.data.map((data) => this.parseMessageData(data)),
|
|
1068
|
-
"memory"
|
|
1069
|
-
);
|
|
1070
|
-
if (format === `v2`) return list2.get.all.v2();
|
|
1071
|
-
return list2.get.all.v1();
|
|
1072
|
-
}
|
|
2063
|
+
const query = this.service.entities.score.query.byScorer({ entity: "score", scorerId });
|
|
1073
2064
|
const results = await query.go();
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
if (
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
if (!threadId) {
|
|
1100
|
-
throw new Error("Thread ID is required");
|
|
1101
|
-
}
|
|
1102
|
-
const messagesToSave = messages.map((msg) => {
|
|
1103
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1104
|
-
return {
|
|
1105
|
-
entity: "message",
|
|
1106
|
-
// Add entity type
|
|
1107
|
-
id: msg.id,
|
|
1108
|
-
threadId: msg.threadId,
|
|
1109
|
-
role: msg.role,
|
|
1110
|
-
type: msg.type,
|
|
1111
|
-
resourceId: msg.resourceId,
|
|
1112
|
-
// Ensure complex fields are stringified if not handled by attribute setters
|
|
1113
|
-
content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content),
|
|
1114
|
-
toolCallArgs: `toolCallArgs` in msg && msg.toolCallArgs ? JSON.stringify(msg.toolCallArgs) : void 0,
|
|
1115
|
-
toolCallIds: `toolCallIds` in msg && msg.toolCallIds ? JSON.stringify(msg.toolCallIds) : void 0,
|
|
1116
|
-
toolNames: `toolNames` in msg && msg.toolNames ? JSON.stringify(msg.toolNames) : void 0,
|
|
1117
|
-
createdAt: msg.createdAt instanceof Date ? msg.createdAt.toISOString() : msg.createdAt || now,
|
|
1118
|
-
updatedAt: now
|
|
1119
|
-
// Add updatedAt
|
|
2065
|
+
let allScores = results.data.map((data) => this.parseScoreData(data));
|
|
2066
|
+
if (entityId) {
|
|
2067
|
+
allScores = allScores.filter((score) => score.entityId === entityId);
|
|
2068
|
+
}
|
|
2069
|
+
if (entityType) {
|
|
2070
|
+
allScores = allScores.filter((score) => score.entityType === entityType);
|
|
2071
|
+
}
|
|
2072
|
+
if (source) {
|
|
2073
|
+
allScores = allScores.filter((score) => score.source === source);
|
|
2074
|
+
}
|
|
2075
|
+
allScores.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
2076
|
+
const { page, perPage: perPageInput } = pagination;
|
|
2077
|
+
const perPage = storage.normalizePerPage(perPageInput, Number.MAX_SAFE_INTEGER);
|
|
2078
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
2079
|
+
const total = allScores.length;
|
|
2080
|
+
const end = perPageInput === false ? allScores.length : start + perPage;
|
|
2081
|
+
const paginatedScores = allScores.slice(start, end);
|
|
2082
|
+
return {
|
|
2083
|
+
scores: paginatedScores,
|
|
2084
|
+
pagination: {
|
|
2085
|
+
total,
|
|
2086
|
+
page,
|
|
2087
|
+
perPage: perPageForResponse,
|
|
2088
|
+
hasMore: end < total
|
|
2089
|
+
}
|
|
1120
2090
|
};
|
|
1121
|
-
});
|
|
1122
|
-
try {
|
|
1123
|
-
const batchSize = 25;
|
|
1124
|
-
const batches = [];
|
|
1125
|
-
for (let i = 0; i < messagesToSave.length; i += batchSize) {
|
|
1126
|
-
const batch = messagesToSave.slice(i, i + batchSize);
|
|
1127
|
-
batches.push(batch);
|
|
1128
|
-
}
|
|
1129
|
-
await Promise.all([
|
|
1130
|
-
// Process message batches
|
|
1131
|
-
...batches.map(async (batch) => {
|
|
1132
|
-
for (const messageData of batch) {
|
|
1133
|
-
if (!messageData.entity) {
|
|
1134
|
-
this.logger.error("Missing entity property in message data for create", { messageData });
|
|
1135
|
-
throw new Error("Internal error: Missing entity property during saveMessages");
|
|
1136
|
-
}
|
|
1137
|
-
await this.service.entities.message.put(messageData).go();
|
|
1138
|
-
}
|
|
1139
|
-
}),
|
|
1140
|
-
// Update thread's updatedAt timestamp
|
|
1141
|
-
this.service.entities.thread.update({ entity: "thread", id: threadId }).set({
|
|
1142
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1143
|
-
}).go()
|
|
1144
|
-
]);
|
|
1145
|
-
const list = new agent.MessageList().add(messages, "memory");
|
|
1146
|
-
if (format === `v1`) return list.get.all.v1();
|
|
1147
|
-
return list.get.all.v2();
|
|
1148
2091
|
} catch (error$1) {
|
|
1149
2092
|
throw new error.MastraError(
|
|
1150
2093
|
{
|
|
1151
|
-
id: "
|
|
2094
|
+
id: "STORAGE_DYNAMODB_STORE_GET_SCORES_BY_SCORER_ID_FAILED",
|
|
1152
2095
|
domain: error.ErrorDomain.STORAGE,
|
|
1153
2096
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1154
|
-
details: {
|
|
2097
|
+
details: {
|
|
2098
|
+
scorerId: scorerId || "",
|
|
2099
|
+
entityId: entityId || "",
|
|
2100
|
+
entityType: entityType || "",
|
|
2101
|
+
source: source || "",
|
|
2102
|
+
page: pagination.page,
|
|
2103
|
+
perPage: pagination.perPage
|
|
2104
|
+
}
|
|
1155
2105
|
},
|
|
1156
2106
|
error$1
|
|
1157
2107
|
);
|
|
1158
2108
|
}
|
|
1159
2109
|
}
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
createdAt: data.createdAt ? new Date(data.createdAt) : void 0,
|
|
1166
|
-
updatedAt: data.updatedAt ? new Date(data.updatedAt) : void 0
|
|
1167
|
-
// Other fields like content, toolCallArgs etc. are assumed to be correctly
|
|
1168
|
-
// transformed by the ElectroDB entity getters.
|
|
1169
|
-
};
|
|
1170
|
-
}
|
|
1171
|
-
// Trace operations
|
|
1172
|
-
async getTraces(args) {
|
|
1173
|
-
const { name, scope, page, perPage } = args;
|
|
1174
|
-
this.logger.debug("Getting traces", { name, scope, page, perPage });
|
|
2110
|
+
async listScoresByRunId({
|
|
2111
|
+
runId,
|
|
2112
|
+
pagination
|
|
2113
|
+
}) {
|
|
2114
|
+
this.logger.debug("Getting scores by run ID", { runId, pagination });
|
|
1175
2115
|
try {
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
items = results.data;
|
|
1194
|
-
break;
|
|
1195
|
-
}
|
|
1196
|
-
cursor = results.cursor;
|
|
1197
|
-
if (!cursor && results.data.length > 0 && pagesFetched < startPage) {
|
|
1198
|
-
break;
|
|
2116
|
+
const query = this.service.entities.score.query.byRun({ entity: "score", runId });
|
|
2117
|
+
const results = await query.go();
|
|
2118
|
+
const allScores = results.data.map((data) => this.parseScoreData(data));
|
|
2119
|
+
allScores.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
2120
|
+
const { page, perPage: perPageInput } = pagination;
|
|
2121
|
+
const perPage = storage.normalizePerPage(perPageInput, Number.MAX_SAFE_INTEGER);
|
|
2122
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
2123
|
+
const total = allScores.length;
|
|
2124
|
+
const end = perPageInput === false ? allScores.length : start + perPage;
|
|
2125
|
+
const paginatedScores = allScores.slice(start, end);
|
|
2126
|
+
return {
|
|
2127
|
+
scores: paginatedScores,
|
|
2128
|
+
pagination: {
|
|
2129
|
+
total,
|
|
2130
|
+
page,
|
|
2131
|
+
perPage: perPageForResponse,
|
|
2132
|
+
hasMore: end < total
|
|
1199
2133
|
}
|
|
1200
|
-
}
|
|
1201
|
-
return items;
|
|
2134
|
+
};
|
|
1202
2135
|
} catch (error$1) {
|
|
1203
2136
|
throw new error.MastraError(
|
|
1204
2137
|
{
|
|
1205
|
-
id: "
|
|
2138
|
+
id: "STORAGE_DYNAMODB_STORE_GET_SCORES_BY_RUN_ID_FAILED",
|
|
1206
2139
|
domain: error.ErrorDomain.STORAGE,
|
|
1207
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
2140
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2141
|
+
details: { runId, page: pagination.page, perPage: pagination.perPage }
|
|
1208
2142
|
},
|
|
1209
2143
|
error$1
|
|
1210
2144
|
);
|
|
1211
2145
|
}
|
|
1212
2146
|
}
|
|
1213
|
-
async
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
2147
|
+
async listScoresByEntityId({
|
|
2148
|
+
entityId,
|
|
2149
|
+
entityType,
|
|
2150
|
+
pagination
|
|
2151
|
+
}) {
|
|
2152
|
+
this.logger.debug("Getting scores by entity ID", { entityId, entityType, pagination });
|
|
2153
|
+
try {
|
|
2154
|
+
const query = this.service.entities.score.query.byEntityData({ entity: "score", entityId });
|
|
2155
|
+
const results = await query.go();
|
|
2156
|
+
let allScores = results.data.map((data) => this.parseScoreData(data));
|
|
2157
|
+
allScores = allScores.filter((score) => score.entityType === entityType);
|
|
2158
|
+
allScores.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
2159
|
+
const { page, perPage: perPageInput } = pagination;
|
|
2160
|
+
const perPage = storage.normalizePerPage(perPageInput, Number.MAX_SAFE_INTEGER);
|
|
2161
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
2162
|
+
const total = allScores.length;
|
|
2163
|
+
const end = perPageInput === false ? allScores.length : start + perPage;
|
|
2164
|
+
const paginatedScores = allScores.slice(start, end);
|
|
2165
|
+
return {
|
|
2166
|
+
scores: paginatedScores,
|
|
2167
|
+
pagination: {
|
|
2168
|
+
total,
|
|
2169
|
+
page,
|
|
2170
|
+
perPage: perPageForResponse,
|
|
2171
|
+
hasMore: end < total
|
|
2172
|
+
}
|
|
2173
|
+
};
|
|
2174
|
+
} catch (error$1) {
|
|
2175
|
+
throw new error.MastraError(
|
|
2176
|
+
{
|
|
2177
|
+
id: "STORAGE_DYNAMODB_STORE_GET_SCORES_BY_ENTITY_ID_FAILED",
|
|
2178
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2179
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2180
|
+
details: { entityId, entityType, page: pagination.page, perPage: pagination.perPage }
|
|
2181
|
+
},
|
|
2182
|
+
error$1
|
|
2183
|
+
);
|
|
1217
2184
|
}
|
|
2185
|
+
}
|
|
2186
|
+
async listScoresBySpan({
|
|
2187
|
+
traceId,
|
|
2188
|
+
spanId,
|
|
2189
|
+
pagination
|
|
2190
|
+
}) {
|
|
2191
|
+
this.logger.debug("Getting scores by span", { traceId, spanId, pagination });
|
|
1218
2192
|
try {
|
|
1219
|
-
const
|
|
1220
|
-
await
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
2193
|
+
const query = this.service.entities.score.query.bySpan({ entity: "score", traceId, spanId });
|
|
2194
|
+
const results = await query.go();
|
|
2195
|
+
const allScores = results.data.map((data) => this.parseScoreData(data));
|
|
2196
|
+
allScores.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
2197
|
+
const { page, perPage: perPageInput } = pagination;
|
|
2198
|
+
const perPage = storage.normalizePerPage(perPageInput, Number.MAX_SAFE_INTEGER);
|
|
2199
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
2200
|
+
const total = allScores.length;
|
|
2201
|
+
const end = perPageInput === false ? allScores.length : start + perPage;
|
|
2202
|
+
const paginatedScores = allScores.slice(start, end);
|
|
2203
|
+
return {
|
|
2204
|
+
scores: paginatedScores,
|
|
2205
|
+
pagination: {
|
|
2206
|
+
total,
|
|
2207
|
+
page,
|
|
2208
|
+
perPage: perPageForResponse,
|
|
2209
|
+
hasMore: end < total
|
|
2210
|
+
}
|
|
2211
|
+
};
|
|
1225
2212
|
} catch (error$1) {
|
|
1226
2213
|
throw new error.MastraError(
|
|
1227
2214
|
{
|
|
1228
|
-
id: "
|
|
2215
|
+
id: "STORAGE_DYNAMODB_STORE_GET_SCORES_BY_SPAN_FAILED",
|
|
1229
2216
|
domain: error.ErrorDomain.STORAGE,
|
|
1230
2217
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1231
|
-
details: {
|
|
2218
|
+
details: { traceId, spanId, page: pagination.page, perPage: pagination.perPage }
|
|
1232
2219
|
},
|
|
1233
2220
|
error$1
|
|
1234
2221
|
);
|
|
1235
2222
|
}
|
|
1236
2223
|
}
|
|
2224
|
+
};
|
|
2225
|
+
function formatWorkflowRun(snapshotData) {
|
|
2226
|
+
return {
|
|
2227
|
+
workflowName: snapshotData.workflow_name,
|
|
2228
|
+
runId: snapshotData.run_id,
|
|
2229
|
+
snapshot: snapshotData.snapshot,
|
|
2230
|
+
createdAt: new Date(snapshotData.createdAt),
|
|
2231
|
+
updatedAt: new Date(snapshotData.updatedAt),
|
|
2232
|
+
resourceId: snapshotData.resourceId
|
|
2233
|
+
};
|
|
2234
|
+
}
|
|
2235
|
+
var WorkflowStorageDynamoDB = class extends storage.WorkflowsStorage {
|
|
2236
|
+
service;
|
|
2237
|
+
constructor({ service }) {
|
|
2238
|
+
super();
|
|
2239
|
+
this.service = service;
|
|
2240
|
+
}
|
|
2241
|
+
updateWorkflowResults({
|
|
2242
|
+
// workflowName,
|
|
2243
|
+
// runId,
|
|
2244
|
+
// stepId,
|
|
2245
|
+
// result,
|
|
2246
|
+
// requestContext,
|
|
2247
|
+
}) {
|
|
2248
|
+
throw new Error("Method not implemented.");
|
|
2249
|
+
}
|
|
2250
|
+
updateWorkflowState({
|
|
2251
|
+
// workflowName,
|
|
2252
|
+
// runId,
|
|
2253
|
+
// opts,
|
|
2254
|
+
}) {
|
|
2255
|
+
throw new Error("Method not implemented.");
|
|
2256
|
+
}
|
|
1237
2257
|
// Workflow operations
|
|
1238
2258
|
async persistWorkflowSnapshot({
|
|
1239
2259
|
workflowName,
|
|
1240
2260
|
runId,
|
|
2261
|
+
resourceId,
|
|
1241
2262
|
snapshot
|
|
1242
2263
|
}) {
|
|
1243
2264
|
this.logger.debug("Persisting workflow snapshot", { workflowName, runId });
|
|
1244
2265
|
try {
|
|
1245
|
-
const resourceId = "resourceId" in snapshot ? snapshot.resourceId : void 0;
|
|
1246
2266
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1247
2267
|
const data = {
|
|
1248
2268
|
entity: "workflow_snapshot",
|
|
@@ -1250,12 +2270,11 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
1250
2270
|
workflow_name: workflowName,
|
|
1251
2271
|
run_id: runId,
|
|
1252
2272
|
snapshot: JSON.stringify(snapshot),
|
|
1253
|
-
// Stringify the snapshot object
|
|
1254
2273
|
createdAt: now,
|
|
1255
2274
|
updatedAt: now,
|
|
1256
2275
|
resourceId
|
|
1257
2276
|
};
|
|
1258
|
-
await this.service.entities.
|
|
2277
|
+
await this.service.entities.workflow_snapshot.upsert(data).go();
|
|
1259
2278
|
} catch (error$1) {
|
|
1260
2279
|
throw new error.MastraError(
|
|
1261
2280
|
{
|
|
@@ -1274,7 +2293,7 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
1274
2293
|
}) {
|
|
1275
2294
|
this.logger.debug("Loading workflow snapshot", { workflowName, runId });
|
|
1276
2295
|
try {
|
|
1277
|
-
const result = await this.service.entities.
|
|
2296
|
+
const result = await this.service.entities.workflow_snapshot.get({
|
|
1278
2297
|
entity: "workflow_snapshot",
|
|
1279
2298
|
// Add entity type
|
|
1280
2299
|
workflow_name: workflowName,
|
|
@@ -1296,21 +2315,34 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
1296
2315
|
);
|
|
1297
2316
|
}
|
|
1298
2317
|
}
|
|
1299
|
-
async
|
|
2318
|
+
async listWorkflowRuns(args) {
|
|
1300
2319
|
this.logger.debug("Getting workflow runs", { args });
|
|
1301
2320
|
try {
|
|
1302
|
-
const
|
|
1303
|
-
const
|
|
2321
|
+
const perPage = args?.perPage !== void 0 ? args.perPage : 10;
|
|
2322
|
+
const page = args?.page !== void 0 ? args.page : 0;
|
|
2323
|
+
if (page < 0) {
|
|
2324
|
+
throw new error.MastraError(
|
|
2325
|
+
{
|
|
2326
|
+
id: "DYNAMODB_STORE_INVALID_PAGE",
|
|
2327
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2328
|
+
category: error.ErrorCategory.USER,
|
|
2329
|
+
details: { page }
|
|
2330
|
+
},
|
|
2331
|
+
new Error("page must be >= 0")
|
|
2332
|
+
);
|
|
2333
|
+
}
|
|
2334
|
+
const normalizedPerPage = storage.normalizePerPage(perPage, 10);
|
|
2335
|
+
const offset = page * normalizedPerPage;
|
|
1304
2336
|
let query;
|
|
1305
2337
|
if (args?.workflowName) {
|
|
1306
|
-
query = this.service.entities.
|
|
2338
|
+
query = this.service.entities.workflow_snapshot.query.primary({
|
|
1307
2339
|
entity: "workflow_snapshot",
|
|
1308
2340
|
// Add entity type
|
|
1309
2341
|
workflow_name: args.workflowName
|
|
1310
2342
|
});
|
|
1311
2343
|
} else {
|
|
1312
2344
|
this.logger.warn("Performing a scan operation on workflow snapshots - consider using a more specific query");
|
|
1313
|
-
query = this.service.entities.
|
|
2345
|
+
query = this.service.entities.workflow_snapshot.scan;
|
|
1314
2346
|
}
|
|
1315
2347
|
const allMatchingSnapshots = [];
|
|
1316
2348
|
let cursor = null;
|
|
@@ -1322,6 +2354,11 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
1322
2354
|
});
|
|
1323
2355
|
if (pageResults.data && pageResults.data.length > 0) {
|
|
1324
2356
|
let pageFilteredData = pageResults.data;
|
|
2357
|
+
if (args?.status) {
|
|
2358
|
+
pageFilteredData = pageFilteredData.filter((snapshot) => {
|
|
2359
|
+
return snapshot.snapshot.status === args.status;
|
|
2360
|
+
});
|
|
2361
|
+
}
|
|
1325
2362
|
if (args?.fromDate || args?.toDate) {
|
|
1326
2363
|
pageFilteredData = pageFilteredData.filter((snapshot) => {
|
|
1327
2364
|
const createdAt = new Date(snapshot.createdAt);
|
|
@@ -1347,8 +2384,8 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
1347
2384
|
return { runs: [], total: 0 };
|
|
1348
2385
|
}
|
|
1349
2386
|
const total = allMatchingSnapshots.length;
|
|
1350
|
-
const paginatedData = allMatchingSnapshots.slice(offset, offset +
|
|
1351
|
-
const runs = paginatedData.map((snapshot) =>
|
|
2387
|
+
const paginatedData = allMatchingSnapshots.slice(offset, offset + normalizedPerPage);
|
|
2388
|
+
const runs = paginatedData.map((snapshot) => formatWorkflowRun(snapshot));
|
|
1352
2389
|
return {
|
|
1353
2390
|
runs,
|
|
1354
2391
|
total
|
|
@@ -1356,7 +2393,7 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
1356
2393
|
} catch (error$1) {
|
|
1357
2394
|
throw new error.MastraError(
|
|
1358
2395
|
{
|
|
1359
|
-
id: "
|
|
2396
|
+
id: "STORAGE_DYNAMODB_STORE_LIST_WORKFLOW_RUNS_FAILED",
|
|
1360
2397
|
domain: error.ErrorDomain.STORAGE,
|
|
1361
2398
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1362
2399
|
details: { workflowName: args?.workflowName || "", resourceId: args?.resourceId || "" }
|
|
@@ -1371,7 +2408,7 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
1371
2408
|
try {
|
|
1372
2409
|
if (workflowName) {
|
|
1373
2410
|
this.logger.debug("WorkflowName provided, using direct GET operation.");
|
|
1374
|
-
const result2 = await this.service.entities.
|
|
2411
|
+
const result2 = await this.service.entities.workflow_snapshot.get({
|
|
1375
2412
|
entity: "workflow_snapshot",
|
|
1376
2413
|
// Entity type for PK
|
|
1377
2414
|
workflow_name: workflowName,
|
|
@@ -1393,7 +2430,7 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
1393
2430
|
this.logger.debug(
|
|
1394
2431
|
'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.'
|
|
1395
2432
|
);
|
|
1396
|
-
const result = await this.service.entities.
|
|
2433
|
+
const result = await this.service.entities.workflow_snapshot.query.gsi2({ entity: "workflow_snapshot", run_id: runId }).go();
|
|
1397
2434
|
const matchingRunDbItem = result.data && result.data.length > 0 ? result.data[0] : null;
|
|
1398
2435
|
if (!matchingRunDbItem) {
|
|
1399
2436
|
return null;
|
|
@@ -1419,121 +2456,232 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
1419
2456
|
);
|
|
1420
2457
|
}
|
|
1421
2458
|
}
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
2459
|
+
};
|
|
2460
|
+
|
|
2461
|
+
// src/storage/index.ts
|
|
2462
|
+
var DynamoDBStore = class extends storage.MastraStorage {
|
|
2463
|
+
tableName;
|
|
2464
|
+
client;
|
|
2465
|
+
service;
|
|
2466
|
+
hasInitialized = null;
|
|
2467
|
+
stores;
|
|
2468
|
+
constructor({ name, config }) {
|
|
2469
|
+
super({ id: config.id, name });
|
|
2470
|
+
try {
|
|
2471
|
+
if (!config.tableName || typeof config.tableName !== "string" || config.tableName.trim() === "") {
|
|
2472
|
+
throw new Error("DynamoDBStore: config.tableName must be provided and cannot be empty.");
|
|
2473
|
+
}
|
|
2474
|
+
if (!/^[a-zA-Z0-9_.-]{3,255}$/.test(config.tableName)) {
|
|
2475
|
+
throw new Error(
|
|
2476
|
+
`DynamoDBStore: config.tableName "${config.tableName}" contains invalid characters or is not between 3 and 255 characters long.`
|
|
2477
|
+
);
|
|
2478
|
+
}
|
|
2479
|
+
const dynamoClient = new clientDynamodb.DynamoDBClient({
|
|
2480
|
+
region: config.region || "us-east-1",
|
|
2481
|
+
endpoint: config.endpoint,
|
|
2482
|
+
credentials: config.credentials
|
|
2483
|
+
});
|
|
2484
|
+
this.tableName = config.tableName;
|
|
2485
|
+
this.client = libDynamodb.DynamoDBDocumentClient.from(dynamoClient);
|
|
2486
|
+
this.service = getElectroDbService(this.client, this.tableName);
|
|
2487
|
+
const operations = new StoreOperationsDynamoDB({
|
|
2488
|
+
service: this.service,
|
|
2489
|
+
tableName: this.tableName,
|
|
2490
|
+
client: this.client
|
|
2491
|
+
});
|
|
2492
|
+
const workflows = new WorkflowStorageDynamoDB({ service: this.service });
|
|
2493
|
+
const memory = new MemoryStorageDynamoDB({ service: this.service });
|
|
2494
|
+
const scores = new ScoresStorageDynamoDB({ service: this.service });
|
|
2495
|
+
this.stores = {
|
|
2496
|
+
operations,
|
|
2497
|
+
workflows,
|
|
2498
|
+
memory,
|
|
2499
|
+
scores
|
|
2500
|
+
};
|
|
2501
|
+
} catch (error$1) {
|
|
2502
|
+
throw new error.MastraError(
|
|
2503
|
+
{
|
|
2504
|
+
id: "STORAGE_DYNAMODB_STORE_CONSTRUCTOR_FAILED",
|
|
2505
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2506
|
+
category: error.ErrorCategory.USER
|
|
2507
|
+
},
|
|
2508
|
+
error$1
|
|
2509
|
+
);
|
|
2510
|
+
}
|
|
1432
2511
|
}
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
2512
|
+
get supports() {
|
|
2513
|
+
return {
|
|
2514
|
+
selectByIncludeResourceScope: true,
|
|
2515
|
+
resourceWorkingMemory: true,
|
|
2516
|
+
hasColumn: false,
|
|
2517
|
+
createTable: false,
|
|
2518
|
+
deleteMessages: false,
|
|
2519
|
+
listScoresBySpan: true
|
|
1441
2520
|
};
|
|
1442
|
-
return mapping[tableName] || null;
|
|
1443
2521
|
}
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
2522
|
+
/**
|
|
2523
|
+
* Validates that the required DynamoDB table exists and is accessible.
|
|
2524
|
+
* This does not check the table structure - it assumes the table
|
|
2525
|
+
* was created with the correct structure via CDK/CloudFormation.
|
|
2526
|
+
*/
|
|
2527
|
+
async validateTableExists() {
|
|
1447
2528
|
try {
|
|
1448
|
-
const
|
|
1449
|
-
|
|
1450
|
-
if (!results.data.length) {
|
|
1451
|
-
return [];
|
|
1452
|
-
}
|
|
1453
|
-
let filteredData = results.data;
|
|
1454
|
-
if (type) {
|
|
1455
|
-
filteredData = filteredData.filter((evalRecord) => {
|
|
1456
|
-
try {
|
|
1457
|
-
const testInfo = evalRecord.test_info && typeof evalRecord.test_info === "string" ? JSON.parse(evalRecord.test_info) : void 0;
|
|
1458
|
-
if (type === "test" && !testInfo) {
|
|
1459
|
-
return false;
|
|
1460
|
-
}
|
|
1461
|
-
if (type === "live" && testInfo) {
|
|
1462
|
-
return false;
|
|
1463
|
-
}
|
|
1464
|
-
} catch (e) {
|
|
1465
|
-
this.logger.warn("Failed to parse test_info during filtering", { record: evalRecord, error: e });
|
|
1466
|
-
}
|
|
1467
|
-
return true;
|
|
1468
|
-
});
|
|
1469
|
-
}
|
|
1470
|
-
return filteredData.map((evalRecord) => {
|
|
1471
|
-
try {
|
|
1472
|
-
return {
|
|
1473
|
-
input: evalRecord.input,
|
|
1474
|
-
output: evalRecord.output,
|
|
1475
|
-
// Safely parse result and test_info
|
|
1476
|
-
result: evalRecord.result && typeof evalRecord.result === "string" ? JSON.parse(evalRecord.result) : void 0,
|
|
1477
|
-
agentName: evalRecord.agent_name,
|
|
1478
|
-
createdAt: evalRecord.created_at,
|
|
1479
|
-
// Keep as string from DDB?
|
|
1480
|
-
metricName: evalRecord.metric_name,
|
|
1481
|
-
instructions: evalRecord.instructions,
|
|
1482
|
-
runId: evalRecord.run_id,
|
|
1483
|
-
globalRunId: evalRecord.global_run_id,
|
|
1484
|
-
testInfo: evalRecord.test_info && typeof evalRecord.test_info === "string" ? JSON.parse(evalRecord.test_info) : void 0
|
|
1485
|
-
};
|
|
1486
|
-
} catch (parseError) {
|
|
1487
|
-
this.logger.error("Failed to parse eval record", { record: evalRecord, error: parseError });
|
|
1488
|
-
return {
|
|
1489
|
-
agentName: evalRecord.agent_name,
|
|
1490
|
-
createdAt: evalRecord.created_at,
|
|
1491
|
-
runId: evalRecord.run_id,
|
|
1492
|
-
globalRunId: evalRecord.global_run_id
|
|
1493
|
-
};
|
|
1494
|
-
}
|
|
2529
|
+
const command = new clientDynamodb.DescribeTableCommand({
|
|
2530
|
+
TableName: this.tableName
|
|
1495
2531
|
});
|
|
2532
|
+
await this.client.send(command);
|
|
2533
|
+
return true;
|
|
1496
2534
|
} catch (error$1) {
|
|
2535
|
+
if (error$1.name === "ResourceNotFoundException") {
|
|
2536
|
+
return false;
|
|
2537
|
+
}
|
|
1497
2538
|
throw new error.MastraError(
|
|
1498
2539
|
{
|
|
1499
|
-
id: "
|
|
2540
|
+
id: "STORAGE_DYNAMODB_STORE_VALIDATE_TABLE_EXISTS_FAILED",
|
|
1500
2541
|
domain: error.ErrorDomain.STORAGE,
|
|
1501
2542
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1502
|
-
details: {
|
|
2543
|
+
details: { tableName: this.tableName }
|
|
1503
2544
|
},
|
|
1504
2545
|
error$1
|
|
1505
2546
|
);
|
|
1506
2547
|
}
|
|
1507
2548
|
}
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
2549
|
+
/**
|
|
2550
|
+
* Initialize storage, validating the externally managed table is accessible.
|
|
2551
|
+
* For the single-table design, we only validate once that we can access
|
|
2552
|
+
* the table that was created via CDK/CloudFormation.
|
|
2553
|
+
*/
|
|
2554
|
+
async init() {
|
|
2555
|
+
if (this.hasInitialized === null) {
|
|
2556
|
+
this.hasInitialized = this._performInitializationAndStore();
|
|
2557
|
+
}
|
|
2558
|
+
try {
|
|
2559
|
+
await this.hasInitialized;
|
|
2560
|
+
} catch (error$1) {
|
|
2561
|
+
throw new error.MastraError(
|
|
2562
|
+
{
|
|
2563
|
+
id: "STORAGE_DYNAMODB_STORE_INIT_FAILED",
|
|
2564
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2565
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2566
|
+
details: { tableName: this.tableName }
|
|
2567
|
+
},
|
|
2568
|
+
error$1
|
|
2569
|
+
);
|
|
2570
|
+
}
|
|
1517
2571
|
}
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
2572
|
+
/**
|
|
2573
|
+
* Performs the actual table validation and stores the promise.
|
|
2574
|
+
* Handles resetting the stored promise on failure to allow retries.
|
|
2575
|
+
*/
|
|
2576
|
+
_performInitializationAndStore() {
|
|
2577
|
+
return this.validateTableExists().then((exists) => {
|
|
2578
|
+
if (!exists) {
|
|
2579
|
+
throw new Error(
|
|
2580
|
+
`Table ${this.tableName} does not exist or is not accessible. Ensure it's created via CDK/CloudFormation before using this store.`
|
|
2581
|
+
);
|
|
2582
|
+
}
|
|
2583
|
+
return true;
|
|
2584
|
+
}).catch((err) => {
|
|
2585
|
+
this.hasInitialized = null;
|
|
2586
|
+
throw err;
|
|
2587
|
+
});
|
|
1527
2588
|
}
|
|
1528
|
-
async
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
2589
|
+
async createTable({ tableName, schema }) {
|
|
2590
|
+
return this.stores.operations.createTable({ tableName, schema });
|
|
2591
|
+
}
|
|
2592
|
+
async alterTable(_args) {
|
|
2593
|
+
return this.stores.operations.alterTable(_args);
|
|
2594
|
+
}
|
|
2595
|
+
async clearTable({ tableName }) {
|
|
2596
|
+
return this.stores.operations.clearTable({ tableName });
|
|
2597
|
+
}
|
|
2598
|
+
async dropTable({ tableName }) {
|
|
2599
|
+
return this.stores.operations.dropTable({ tableName });
|
|
2600
|
+
}
|
|
2601
|
+
async insert({ tableName, record }) {
|
|
2602
|
+
return this.stores.operations.insert({ tableName, record });
|
|
2603
|
+
}
|
|
2604
|
+
async batchInsert({ tableName, records }) {
|
|
2605
|
+
return this.stores.operations.batchInsert({ tableName, records });
|
|
2606
|
+
}
|
|
2607
|
+
async load({ tableName, keys }) {
|
|
2608
|
+
return this.stores.operations.load({ tableName, keys });
|
|
2609
|
+
}
|
|
2610
|
+
// Thread operations
|
|
2611
|
+
async getThreadById({ threadId }) {
|
|
2612
|
+
return this.stores.memory.getThreadById({ threadId });
|
|
2613
|
+
}
|
|
2614
|
+
async saveThread({ thread }) {
|
|
2615
|
+
return this.stores.memory.saveThread({ thread });
|
|
2616
|
+
}
|
|
2617
|
+
async updateThread({
|
|
2618
|
+
id,
|
|
2619
|
+
title,
|
|
2620
|
+
metadata
|
|
2621
|
+
}) {
|
|
2622
|
+
return this.stores.memory.updateThread({ id, title, metadata });
|
|
2623
|
+
}
|
|
2624
|
+
async deleteThread({ threadId }) {
|
|
2625
|
+
return this.stores.memory.deleteThread({ threadId });
|
|
2626
|
+
}
|
|
2627
|
+
async listMessagesById(args) {
|
|
2628
|
+
return this.stores.memory.listMessagesById(args);
|
|
2629
|
+
}
|
|
2630
|
+
async saveMessages(args) {
|
|
2631
|
+
return this.stores.memory.saveMessages(args);
|
|
2632
|
+
}
|
|
2633
|
+
async updateMessages(_args) {
|
|
2634
|
+
return this.stores.memory.updateMessages(_args);
|
|
2635
|
+
}
|
|
2636
|
+
// Workflow operations
|
|
2637
|
+
async updateWorkflowResults({
|
|
2638
|
+
workflowName,
|
|
2639
|
+
runId,
|
|
2640
|
+
stepId,
|
|
2641
|
+
result,
|
|
2642
|
+
requestContext
|
|
2643
|
+
}) {
|
|
2644
|
+
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
2645
|
+
}
|
|
2646
|
+
async updateWorkflowState({
|
|
2647
|
+
workflowName,
|
|
2648
|
+
runId,
|
|
2649
|
+
opts
|
|
2650
|
+
}) {
|
|
2651
|
+
return this.stores.workflows.updateWorkflowState({ workflowName, runId, opts });
|
|
2652
|
+
}
|
|
2653
|
+
async persistWorkflowSnapshot({
|
|
2654
|
+
workflowName,
|
|
2655
|
+
runId,
|
|
2656
|
+
resourceId,
|
|
2657
|
+
snapshot
|
|
2658
|
+
}) {
|
|
2659
|
+
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot });
|
|
2660
|
+
}
|
|
2661
|
+
async loadWorkflowSnapshot({
|
|
2662
|
+
workflowName,
|
|
2663
|
+
runId
|
|
2664
|
+
}) {
|
|
2665
|
+
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2666
|
+
}
|
|
2667
|
+
async listWorkflowRuns(args) {
|
|
2668
|
+
return this.stores.workflows.listWorkflowRuns(args);
|
|
2669
|
+
}
|
|
2670
|
+
async getWorkflowRunById(args) {
|
|
2671
|
+
return this.stores.workflows.getWorkflowRunById(args);
|
|
2672
|
+
}
|
|
2673
|
+
async getResourceById({ resourceId }) {
|
|
2674
|
+
return this.stores.memory.getResourceById({ resourceId });
|
|
2675
|
+
}
|
|
2676
|
+
async saveResource({ resource }) {
|
|
2677
|
+
return this.stores.memory.saveResource({ resource });
|
|
2678
|
+
}
|
|
2679
|
+
async updateResource({
|
|
2680
|
+
resourceId,
|
|
2681
|
+
workingMemory,
|
|
2682
|
+
metadata
|
|
2683
|
+
}) {
|
|
2684
|
+
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
1537
2685
|
}
|
|
1538
2686
|
/**
|
|
1539
2687
|
* Closes the DynamoDB client connection and cleans up resources.
|
|
@@ -1555,10 +2703,50 @@ var DynamoDBStore = class extends storage.MastraStorage {
|
|
|
1555
2703
|
);
|
|
1556
2704
|
}
|
|
1557
2705
|
}
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
2706
|
+
/**
|
|
2707
|
+
* SCORERS - Not implemented
|
|
2708
|
+
*/
|
|
2709
|
+
async getScoreById({ id: _id }) {
|
|
2710
|
+
return this.stores.scores.getScoreById({ id: _id });
|
|
2711
|
+
}
|
|
2712
|
+
async saveScore(_score) {
|
|
2713
|
+
return this.stores.scores.saveScore(_score);
|
|
2714
|
+
}
|
|
2715
|
+
async listScoresByRunId({
|
|
2716
|
+
runId: _runId,
|
|
2717
|
+
pagination: _pagination
|
|
2718
|
+
}) {
|
|
2719
|
+
return this.stores.scores.listScoresByRunId({ runId: _runId, pagination: _pagination });
|
|
2720
|
+
}
|
|
2721
|
+
async listScoresByEntityId({
|
|
2722
|
+
entityId: _entityId,
|
|
2723
|
+
entityType: _entityType,
|
|
2724
|
+
pagination: _pagination
|
|
2725
|
+
}) {
|
|
2726
|
+
return this.stores.scores.listScoresByEntityId({
|
|
2727
|
+
entityId: _entityId,
|
|
2728
|
+
entityType: _entityType,
|
|
2729
|
+
pagination: _pagination
|
|
2730
|
+
});
|
|
2731
|
+
}
|
|
2732
|
+
async listScoresByScorerId({
|
|
2733
|
+
scorerId,
|
|
2734
|
+
source,
|
|
2735
|
+
entityId,
|
|
2736
|
+
entityType,
|
|
2737
|
+
pagination
|
|
2738
|
+
}) {
|
|
2739
|
+
return this.stores.scores.listScoresByScorerId({ scorerId, source, entityId, entityType, pagination });
|
|
2740
|
+
}
|
|
2741
|
+
async listScoresBySpan({
|
|
2742
|
+
traceId,
|
|
2743
|
+
spanId,
|
|
2744
|
+
pagination
|
|
2745
|
+
}) {
|
|
2746
|
+
return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
|
|
1561
2747
|
}
|
|
1562
2748
|
};
|
|
1563
2749
|
|
|
1564
2750
|
exports.DynamoDBStore = DynamoDBStore;
|
|
2751
|
+
//# sourceMappingURL=index.cjs.map
|
|
2752
|
+
//# sourceMappingURL=index.cjs.map
|