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