@mastra/dynamodb 0.0.0-taofeeqInngest-20250603090617 → 0.0.0-tool-call-parts-20250630193309
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_tsup-dts-rollup.d.cts +1160 -0
- package/dist/_tsup-dts-rollup.d.ts +1160 -0
- package/dist/index.cjs +376 -102
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +352 -78
- package/package.json +31 -17
- package/src/storage/index.test.ts +311 -1
- package/src/storage/index.ts +419 -94
package/src/storage/index.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { DynamoDBClient, DescribeTableCommand } from '@aws-sdk/client-dynamodb';
|
|
2
2
|
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
|
|
3
|
-
import type {
|
|
3
|
+
import type { MastraMessageContentV2 } from '@mastra/core/agent';
|
|
4
4
|
import { MessageList } from '@mastra/core/agent';
|
|
5
|
+
import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
|
|
6
|
+
import type { StorageThreadType, MastraMessageV2, MastraMessageV1 } from '@mastra/core/memory';
|
|
7
|
+
|
|
5
8
|
import {
|
|
6
9
|
MastraStorage,
|
|
7
10
|
TABLE_THREADS,
|
|
@@ -10,7 +13,19 @@ import {
|
|
|
10
13
|
TABLE_EVALS,
|
|
11
14
|
TABLE_TRACES,
|
|
12
15
|
} from '@mastra/core/storage';
|
|
13
|
-
import type {
|
|
16
|
+
import type {
|
|
17
|
+
EvalRow,
|
|
18
|
+
StorageGetMessagesArg,
|
|
19
|
+
WorkflowRun,
|
|
20
|
+
WorkflowRuns,
|
|
21
|
+
TABLE_NAMES,
|
|
22
|
+
StorageGetTracesArg,
|
|
23
|
+
PaginationInfo,
|
|
24
|
+
StorageColumn,
|
|
25
|
+
TABLE_RESOURCES,
|
|
26
|
+
} from '@mastra/core/storage';
|
|
27
|
+
import type { Trace } from '@mastra/core/telemetry';
|
|
28
|
+
import type { WorkflowRunState } from '@mastra/core/workflows';
|
|
14
29
|
import type { Service } from 'electrodb';
|
|
15
30
|
import { getElectroDbService } from '../entities';
|
|
16
31
|
|
|
@@ -24,6 +39,8 @@ export interface DynamoDBStoreConfig {
|
|
|
24
39
|
};
|
|
25
40
|
}
|
|
26
41
|
|
|
42
|
+
type SUPPORTED_TABLE_NAMES = Exclude<TABLE_NAMES, typeof TABLE_RESOURCES>;
|
|
43
|
+
|
|
27
44
|
// Define a type for our service that allows string indexing
|
|
28
45
|
type MastraService = Service<Record<string, any>> & {
|
|
29
46
|
[key: string]: any;
|
|
@@ -50,25 +67,36 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
50
67
|
super({ name });
|
|
51
68
|
|
|
52
69
|
// Validate required config
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
70
|
+
try {
|
|
71
|
+
if (!config.tableName || typeof config.tableName !== 'string' || config.tableName.trim() === '') {
|
|
72
|
+
throw new Error('DynamoDBStore: config.tableName must be provided and cannot be empty.');
|
|
73
|
+
}
|
|
74
|
+
// Validate tableName characters (basic check)
|
|
75
|
+
if (!/^[a-zA-Z0-9_.-]{3,255}$/.test(config.tableName)) {
|
|
76
|
+
throw new Error(
|
|
77
|
+
`DynamoDBStore: config.tableName "${config.tableName}" contains invalid characters or is not between 3 and 255 characters long.`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
62
80
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
81
|
+
const dynamoClient = new DynamoDBClient({
|
|
82
|
+
region: config.region || 'us-east-1',
|
|
83
|
+
endpoint: config.endpoint,
|
|
84
|
+
credentials: config.credentials,
|
|
85
|
+
});
|
|
68
86
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
87
|
+
this.tableName = config.tableName;
|
|
88
|
+
this.client = DynamoDBDocumentClient.from(dynamoClient);
|
|
89
|
+
this.service = getElectroDbService(this.client, this.tableName) as MastraService;
|
|
90
|
+
} catch (error) {
|
|
91
|
+
throw new MastraError(
|
|
92
|
+
{
|
|
93
|
+
id: 'STORAGE_DYNAMODB_STORE_CONSTRUCTOR_FAILED',
|
|
94
|
+
domain: ErrorDomain.STORAGE,
|
|
95
|
+
category: ErrorCategory.USER,
|
|
96
|
+
},
|
|
97
|
+
error,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
72
100
|
|
|
73
101
|
// We're using a single table design with ElectroDB,
|
|
74
102
|
// so we don't need to create multiple tables
|
|
@@ -100,7 +128,15 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
100
128
|
this.logger.debug(`Table ${this.tableName} exists and is accessible`);
|
|
101
129
|
} catch (error) {
|
|
102
130
|
this.logger.error('Error validating table access', { tableName: this.tableName, error });
|
|
103
|
-
throw
|
|
131
|
+
throw new MastraError(
|
|
132
|
+
{
|
|
133
|
+
id: 'STORAGE_DYNAMODB_STORE_VALIDATE_TABLE_ACCESS_FAILED',
|
|
134
|
+
domain: ErrorDomain.STORAGE,
|
|
135
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
136
|
+
details: { tableName: this.tableName },
|
|
137
|
+
},
|
|
138
|
+
error,
|
|
139
|
+
);
|
|
104
140
|
}
|
|
105
141
|
}
|
|
106
142
|
|
|
@@ -126,7 +162,15 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
126
162
|
}
|
|
127
163
|
|
|
128
164
|
// For other errors (like permissions issues), we should throw
|
|
129
|
-
throw
|
|
165
|
+
throw new MastraError(
|
|
166
|
+
{
|
|
167
|
+
id: 'STORAGE_DYNAMODB_STORE_VALIDATE_TABLE_EXISTS_FAILED',
|
|
168
|
+
domain: ErrorDomain.STORAGE,
|
|
169
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
170
|
+
details: { tableName: this.tableName },
|
|
171
|
+
},
|
|
172
|
+
error,
|
|
173
|
+
);
|
|
130
174
|
}
|
|
131
175
|
}
|
|
132
176
|
|
|
@@ -153,7 +197,15 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
153
197
|
// The error has already been handled by _performInitializationAndStore
|
|
154
198
|
// (i.e., this.hasInitialized was reset). Re-throwing here ensures
|
|
155
199
|
// the caller of init() is aware of the failure.
|
|
156
|
-
throw
|
|
200
|
+
throw new MastraError(
|
|
201
|
+
{
|
|
202
|
+
id: 'STORAGE_DYNAMODB_STORE_INIT_FAILED',
|
|
203
|
+
domain: ErrorDomain.STORAGE,
|
|
204
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
205
|
+
details: { tableName: this.tableName },
|
|
206
|
+
},
|
|
207
|
+
error,
|
|
208
|
+
);
|
|
157
209
|
}
|
|
158
210
|
}
|
|
159
211
|
|
|
@@ -180,15 +232,52 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
180
232
|
});
|
|
181
233
|
}
|
|
182
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Pre-processes a record to ensure Date objects are converted to ISO strings
|
|
237
|
+
* This is necessary because ElectroDB validation happens before setters are applied
|
|
238
|
+
*/
|
|
239
|
+
private preprocessRecord(record: Record<string, any>): Record<string, any> {
|
|
240
|
+
const processed = { ...record };
|
|
241
|
+
|
|
242
|
+
// Convert Date objects to ISO strings for date fields
|
|
243
|
+
// This prevents ElectroDB validation errors that occur when Date objects are passed
|
|
244
|
+
// to string-typed attributes, even when the attribute has a setter that converts dates
|
|
245
|
+
if (processed.createdAt instanceof Date) {
|
|
246
|
+
processed.createdAt = processed.createdAt.toISOString();
|
|
247
|
+
}
|
|
248
|
+
if (processed.updatedAt instanceof Date) {
|
|
249
|
+
processed.updatedAt = processed.updatedAt.toISOString();
|
|
250
|
+
}
|
|
251
|
+
if (processed.created_at instanceof Date) {
|
|
252
|
+
processed.created_at = processed.created_at.toISOString();
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return processed;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async alterTable(_args: {
|
|
259
|
+
tableName: TABLE_NAMES;
|
|
260
|
+
schema: Record<string, StorageColumn>;
|
|
261
|
+
ifNotExists: string[];
|
|
262
|
+
}): Promise<void> {
|
|
263
|
+
// Nothing to do here, DynamoDB has a flexible schema and handles new attributes automatically upon insertion/update.
|
|
264
|
+
}
|
|
265
|
+
|
|
183
266
|
/**
|
|
184
267
|
* Clear all items from a logical "table" (entity type)
|
|
185
268
|
*/
|
|
186
|
-
async clearTable({ tableName }: { tableName:
|
|
269
|
+
async clearTable({ tableName }: { tableName: SUPPORTED_TABLE_NAMES }): Promise<void> {
|
|
187
270
|
this.logger.debug('DynamoDB clearTable called', { tableName });
|
|
188
271
|
|
|
189
272
|
const entityName = this.getEntityNameForTable(tableName);
|
|
190
273
|
if (!entityName || !this.service.entities[entityName]) {
|
|
191
|
-
throw new
|
|
274
|
+
throw new MastraError({
|
|
275
|
+
id: 'STORAGE_DYNAMODB_STORE_CLEAR_TABLE_INVALID_ARGS',
|
|
276
|
+
domain: ErrorDomain.STORAGE,
|
|
277
|
+
category: ErrorCategory.USER,
|
|
278
|
+
text: 'No entity defined for tableName',
|
|
279
|
+
details: { tableName },
|
|
280
|
+
});
|
|
192
281
|
}
|
|
193
282
|
|
|
194
283
|
try {
|
|
@@ -258,45 +347,83 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
258
347
|
|
|
259
348
|
this.logger.debug(`Successfully cleared all records for ${tableName}`);
|
|
260
349
|
} catch (error) {
|
|
261
|
-
|
|
262
|
-
|
|
350
|
+
throw new MastraError(
|
|
351
|
+
{
|
|
352
|
+
id: 'STORAGE_DYNAMODB_STORE_CLEAR_TABLE_FAILED',
|
|
353
|
+
domain: ErrorDomain.STORAGE,
|
|
354
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
355
|
+
details: { tableName },
|
|
356
|
+
},
|
|
357
|
+
error,
|
|
358
|
+
);
|
|
263
359
|
}
|
|
264
360
|
}
|
|
265
361
|
|
|
266
362
|
/**
|
|
267
363
|
* Insert a record into the specified "table" (entity)
|
|
268
364
|
*/
|
|
269
|
-
async insert({
|
|
365
|
+
async insert({
|
|
366
|
+
tableName,
|
|
367
|
+
record,
|
|
368
|
+
}: {
|
|
369
|
+
tableName: SUPPORTED_TABLE_NAMES;
|
|
370
|
+
record: Record<string, any>;
|
|
371
|
+
}): Promise<void> {
|
|
270
372
|
this.logger.debug('DynamoDB insert called', { tableName });
|
|
271
373
|
|
|
272
374
|
const entityName = this.getEntityNameForTable(tableName);
|
|
273
375
|
if (!entityName || !this.service.entities[entityName]) {
|
|
274
|
-
throw new
|
|
376
|
+
throw new MastraError({
|
|
377
|
+
id: 'STORAGE_DYNAMODB_STORE_INSERT_INVALID_ARGS',
|
|
378
|
+
domain: ErrorDomain.STORAGE,
|
|
379
|
+
category: ErrorCategory.USER,
|
|
380
|
+
text: 'No entity defined for tableName',
|
|
381
|
+
details: { tableName },
|
|
382
|
+
});
|
|
275
383
|
}
|
|
276
384
|
|
|
277
385
|
try {
|
|
278
|
-
// Add the entity type to the record before creating
|
|
279
|
-
const dataToSave = { entity: entityName, ...record };
|
|
386
|
+
// Add the entity type to the record and preprocess before creating
|
|
387
|
+
const dataToSave = { entity: entityName, ...this.preprocessRecord(record) };
|
|
280
388
|
await this.service.entities[entityName].create(dataToSave).go();
|
|
281
389
|
} catch (error) {
|
|
282
|
-
|
|
283
|
-
|
|
390
|
+
throw new MastraError(
|
|
391
|
+
{
|
|
392
|
+
id: 'STORAGE_DYNAMODB_STORE_INSERT_FAILED',
|
|
393
|
+
domain: ErrorDomain.STORAGE,
|
|
394
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
395
|
+
details: { tableName },
|
|
396
|
+
},
|
|
397
|
+
error,
|
|
398
|
+
);
|
|
284
399
|
}
|
|
285
400
|
}
|
|
286
401
|
|
|
287
402
|
/**
|
|
288
403
|
* Insert multiple records as a batch
|
|
289
404
|
*/
|
|
290
|
-
async batchInsert({
|
|
405
|
+
async batchInsert({
|
|
406
|
+
tableName,
|
|
407
|
+
records,
|
|
408
|
+
}: {
|
|
409
|
+
tableName: SUPPORTED_TABLE_NAMES;
|
|
410
|
+
records: Record<string, any>[];
|
|
411
|
+
}): Promise<void> {
|
|
291
412
|
this.logger.debug('DynamoDB batchInsert called', { tableName, count: records.length });
|
|
292
413
|
|
|
293
414
|
const entityName = this.getEntityNameForTable(tableName);
|
|
294
415
|
if (!entityName || !this.service.entities[entityName]) {
|
|
295
|
-
throw new
|
|
416
|
+
throw new MastraError({
|
|
417
|
+
id: 'STORAGE_DYNAMODB_STORE_BATCH_INSERT_INVALID_ARGS',
|
|
418
|
+
domain: ErrorDomain.STORAGE,
|
|
419
|
+
category: ErrorCategory.USER,
|
|
420
|
+
text: 'No entity defined for tableName',
|
|
421
|
+
details: { tableName },
|
|
422
|
+
});
|
|
296
423
|
}
|
|
297
424
|
|
|
298
|
-
// Add entity type
|
|
299
|
-
const recordsToSave = records.map(rec => ({ entity: entityName, ...rec }));
|
|
425
|
+
// Add entity type and preprocess each record
|
|
426
|
+
const recordsToSave = records.map(rec => ({ entity: entityName, ...this.preprocessRecord(rec) }));
|
|
300
427
|
|
|
301
428
|
// ElectroDB has batch limits of 25 items, so we need to chunk
|
|
302
429
|
const batchSize = 25;
|
|
@@ -322,20 +449,39 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
322
449
|
// Original batch call: await this.service.entities[entityName].create(batch).go();
|
|
323
450
|
}
|
|
324
451
|
} catch (error) {
|
|
325
|
-
|
|
326
|
-
|
|
452
|
+
throw new MastraError(
|
|
453
|
+
{
|
|
454
|
+
id: 'STORAGE_DYNAMODB_STORE_BATCH_INSERT_FAILED',
|
|
455
|
+
domain: ErrorDomain.STORAGE,
|
|
456
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
457
|
+
details: { tableName },
|
|
458
|
+
},
|
|
459
|
+
error,
|
|
460
|
+
);
|
|
327
461
|
}
|
|
328
462
|
}
|
|
329
463
|
|
|
330
464
|
/**
|
|
331
465
|
* Load a record by its keys
|
|
332
466
|
*/
|
|
333
|
-
async load<R>({
|
|
467
|
+
async load<R>({
|
|
468
|
+
tableName,
|
|
469
|
+
keys,
|
|
470
|
+
}: {
|
|
471
|
+
tableName: SUPPORTED_TABLE_NAMES;
|
|
472
|
+
keys: Record<string, string>;
|
|
473
|
+
}): Promise<R | null> {
|
|
334
474
|
this.logger.debug('DynamoDB load called', { tableName, keys });
|
|
335
475
|
|
|
336
476
|
const entityName = this.getEntityNameForTable(tableName);
|
|
337
477
|
if (!entityName || !this.service.entities[entityName]) {
|
|
338
|
-
throw new
|
|
478
|
+
throw new MastraError({
|
|
479
|
+
id: 'STORAGE_DYNAMODB_STORE_LOAD_INVALID_ARGS',
|
|
480
|
+
domain: ErrorDomain.STORAGE,
|
|
481
|
+
category: ErrorCategory.USER,
|
|
482
|
+
text: 'No entity defined for tableName',
|
|
483
|
+
details: { tableName },
|
|
484
|
+
});
|
|
339
485
|
}
|
|
340
486
|
|
|
341
487
|
try {
|
|
@@ -360,8 +506,15 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
360
506
|
|
|
361
507
|
return data as R;
|
|
362
508
|
} catch (error) {
|
|
363
|
-
|
|
364
|
-
|
|
509
|
+
throw new MastraError(
|
|
510
|
+
{
|
|
511
|
+
id: 'STORAGE_DYNAMODB_STORE_LOAD_FAILED',
|
|
512
|
+
domain: ErrorDomain.STORAGE,
|
|
513
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
514
|
+
details: { tableName },
|
|
515
|
+
},
|
|
516
|
+
error,
|
|
517
|
+
);
|
|
365
518
|
}
|
|
366
519
|
}
|
|
367
520
|
|
|
@@ -379,12 +532,22 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
379
532
|
const data = result.data;
|
|
380
533
|
return {
|
|
381
534
|
...data,
|
|
535
|
+
// Convert date strings back to Date objects for consistency
|
|
536
|
+
createdAt: typeof data.createdAt === 'string' ? new Date(data.createdAt) : data.createdAt,
|
|
537
|
+
updatedAt: typeof data.updatedAt === 'string' ? new Date(data.updatedAt) : data.updatedAt,
|
|
382
538
|
// metadata: data.metadata ? JSON.parse(data.metadata) : undefined, // REMOVED by AI
|
|
383
539
|
// metadata is already transformed by the entity's getter
|
|
384
540
|
} as StorageThreadType;
|
|
385
541
|
} catch (error) {
|
|
386
|
-
|
|
387
|
-
|
|
542
|
+
throw new MastraError(
|
|
543
|
+
{
|
|
544
|
+
id: 'STORAGE_DYNAMODB_STORE_GET_THREAD_BY_ID_FAILED',
|
|
545
|
+
domain: ErrorDomain.STORAGE,
|
|
546
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
547
|
+
details: { threadId },
|
|
548
|
+
},
|
|
549
|
+
error,
|
|
550
|
+
);
|
|
388
551
|
}
|
|
389
552
|
}
|
|
390
553
|
|
|
@@ -400,12 +563,22 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
400
563
|
// ElectroDB handles the transformation with attribute getters
|
|
401
564
|
return result.data.map((data: any) => ({
|
|
402
565
|
...data,
|
|
566
|
+
// Convert date strings back to Date objects for consistency
|
|
567
|
+
createdAt: typeof data.createdAt === 'string' ? new Date(data.createdAt) : data.createdAt,
|
|
568
|
+
updatedAt: typeof data.updatedAt === 'string' ? new Date(data.updatedAt) : data.updatedAt,
|
|
403
569
|
// metadata: data.metadata ? JSON.parse(data.metadata) : undefined, // REMOVED by AI
|
|
404
570
|
// metadata is already transformed by the entity's getter
|
|
405
571
|
})) as StorageThreadType[];
|
|
406
572
|
} catch (error) {
|
|
407
|
-
|
|
408
|
-
|
|
573
|
+
throw new MastraError(
|
|
574
|
+
{
|
|
575
|
+
id: 'STORAGE_DYNAMODB_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED',
|
|
576
|
+
domain: ErrorDomain.STORAGE,
|
|
577
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
578
|
+
details: { resourceId },
|
|
579
|
+
},
|
|
580
|
+
error,
|
|
581
|
+
);
|
|
409
582
|
}
|
|
410
583
|
}
|
|
411
584
|
|
|
@@ -436,8 +609,15 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
436
609
|
metadata: thread.metadata,
|
|
437
610
|
};
|
|
438
611
|
} catch (error) {
|
|
439
|
-
|
|
440
|
-
|
|
612
|
+
throw new MastraError(
|
|
613
|
+
{
|
|
614
|
+
id: 'STORAGE_DYNAMODB_STORE_SAVE_THREAD_FAILED',
|
|
615
|
+
domain: ErrorDomain.STORAGE,
|
|
616
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
617
|
+
details: { threadId: thread.id },
|
|
618
|
+
},
|
|
619
|
+
error,
|
|
620
|
+
);
|
|
441
621
|
}
|
|
442
622
|
}
|
|
443
623
|
|
|
@@ -492,8 +672,15 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
492
672
|
updatedAt: now,
|
|
493
673
|
};
|
|
494
674
|
} catch (error) {
|
|
495
|
-
|
|
496
|
-
|
|
675
|
+
throw new MastraError(
|
|
676
|
+
{
|
|
677
|
+
id: 'STORAGE_DYNAMODB_STORE_UPDATE_THREAD_FAILED',
|
|
678
|
+
domain: ErrorDomain.STORAGE,
|
|
679
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
680
|
+
details: { threadId: id },
|
|
681
|
+
},
|
|
682
|
+
error,
|
|
683
|
+
);
|
|
497
684
|
}
|
|
498
685
|
}
|
|
499
686
|
|
|
@@ -509,8 +696,15 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
509
696
|
// 2. Delete any vector embeddings related to this thread
|
|
510
697
|
// These would be additional operations
|
|
511
698
|
} catch (error) {
|
|
512
|
-
|
|
513
|
-
|
|
699
|
+
throw new MastraError(
|
|
700
|
+
{
|
|
701
|
+
id: 'STORAGE_DYNAMODB_STORE_DELETE_THREAD_FAILED',
|
|
702
|
+
domain: ErrorDomain.STORAGE,
|
|
703
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
704
|
+
details: { threadId },
|
|
705
|
+
},
|
|
706
|
+
error,
|
|
707
|
+
);
|
|
514
708
|
}
|
|
515
709
|
}
|
|
516
710
|
|
|
@@ -530,12 +724,13 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
530
724
|
// Provide *all* composite key components for the 'byThread' index ('entity', 'threadId')
|
|
531
725
|
const query = this.service.entities.message.query.byThread({ entity: 'message', threadId });
|
|
532
726
|
|
|
727
|
+
const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: Number.MAX_SAFE_INTEGER });
|
|
533
728
|
// Apply the 'last' limit if provided
|
|
534
|
-
if (
|
|
535
|
-
// Use ElectroDB's limit parameter
|
|
536
|
-
//
|
|
537
|
-
//
|
|
538
|
-
const results = await query.go({ limit
|
|
729
|
+
if (limit !== Number.MAX_SAFE_INTEGER) {
|
|
730
|
+
// Use ElectroDB's limit parameter
|
|
731
|
+
// DDB GSIs are sorted in ascending order
|
|
732
|
+
// Use ElectroDB's order parameter to sort in descending order to retrieve 'latest' messages
|
|
733
|
+
const results = await query.go({ limit, order: 'desc' });
|
|
539
734
|
// Use arrow function in map to preserve 'this' context for parseMessageData
|
|
540
735
|
const list = new MessageList({ threadId, resourceId }).add(
|
|
541
736
|
results.data.map((data: any) => this.parseMessageData(data)),
|
|
@@ -555,8 +750,15 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
555
750
|
if (format === `v2`) return list.get.all.v2();
|
|
556
751
|
return list.get.all.v1();
|
|
557
752
|
} catch (error) {
|
|
558
|
-
|
|
559
|
-
|
|
753
|
+
throw new MastraError(
|
|
754
|
+
{
|
|
755
|
+
id: 'STORAGE_DYNAMODB_STORE_GET_MESSAGES_FAILED',
|
|
756
|
+
domain: ErrorDomain.STORAGE,
|
|
757
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
758
|
+
details: { threadId },
|
|
759
|
+
},
|
|
760
|
+
error,
|
|
761
|
+
);
|
|
560
762
|
}
|
|
561
763
|
}
|
|
562
764
|
async saveMessages(args: { messages: MastraMessageV1[]; format?: undefined | 'v1' }): Promise<MastraMessageV1[]>;
|
|
@@ -571,6 +773,11 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
571
773
|
return [];
|
|
572
774
|
}
|
|
573
775
|
|
|
776
|
+
const threadId = messages[0]?.threadId;
|
|
777
|
+
if (!threadId) {
|
|
778
|
+
throw new Error('Thread ID is required');
|
|
779
|
+
}
|
|
780
|
+
|
|
574
781
|
// Ensure 'entity' is added and complex fields are handled
|
|
575
782
|
const messagesToSave = messages.map(msg => {
|
|
576
783
|
const now = new Date().toISOString();
|
|
@@ -601,26 +808,41 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
601
808
|
batches.push(batch);
|
|
602
809
|
}
|
|
603
810
|
|
|
604
|
-
// Process each batch
|
|
605
|
-
|
|
606
|
-
//
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
811
|
+
// Process each batch and update thread's updatedAt in parallel for better performance
|
|
812
|
+
await Promise.all([
|
|
813
|
+
// Process message batches
|
|
814
|
+
...batches.map(async batch => {
|
|
815
|
+
for (const messageData of batch) {
|
|
816
|
+
// Ensure each item has the entity property before sending
|
|
817
|
+
if (!messageData.entity) {
|
|
818
|
+
this.logger.error('Missing entity property in message data for create', { messageData });
|
|
819
|
+
throw new Error('Internal error: Missing entity property during saveMessages');
|
|
820
|
+
}
|
|
821
|
+
await this.service.entities.message.put(messageData).go();
|
|
612
822
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
823
|
+
}),
|
|
824
|
+
// Update thread's updatedAt timestamp
|
|
825
|
+
this.service.entities.thread
|
|
826
|
+
.update({ entity: 'thread', id: threadId })
|
|
827
|
+
.set({
|
|
828
|
+
updatedAt: new Date().toISOString(),
|
|
829
|
+
})
|
|
830
|
+
.go(),
|
|
831
|
+
]);
|
|
617
832
|
|
|
618
833
|
const list = new MessageList().add(messages, 'memory');
|
|
619
834
|
if (format === `v1`) return list.get.all.v1();
|
|
620
835
|
return list.get.all.v2();
|
|
621
836
|
} catch (error) {
|
|
622
|
-
|
|
623
|
-
|
|
837
|
+
throw new MastraError(
|
|
838
|
+
{
|
|
839
|
+
id: 'STORAGE_DYNAMODB_STORE_SAVE_MESSAGES_FAILED',
|
|
840
|
+
domain: ErrorDomain.STORAGE,
|
|
841
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
842
|
+
details: { count: messages.length },
|
|
843
|
+
},
|
|
844
|
+
error,
|
|
845
|
+
);
|
|
624
846
|
}
|
|
625
847
|
}
|
|
626
848
|
|
|
@@ -684,8 +906,14 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
684
906
|
|
|
685
907
|
return items;
|
|
686
908
|
} catch (error) {
|
|
687
|
-
|
|
688
|
-
|
|
909
|
+
throw new MastraError(
|
|
910
|
+
{
|
|
911
|
+
id: 'STORAGE_DYNAMODB_STORE_GET_TRACES_FAILED',
|
|
912
|
+
domain: ErrorDomain.STORAGE,
|
|
913
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
914
|
+
},
|
|
915
|
+
error,
|
|
916
|
+
);
|
|
689
917
|
}
|
|
690
918
|
}
|
|
691
919
|
|
|
@@ -704,8 +932,15 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
704
932
|
records: recordsToSave, // Pass records with 'entity' included
|
|
705
933
|
});
|
|
706
934
|
} catch (error) {
|
|
707
|
-
|
|
708
|
-
|
|
935
|
+
throw new MastraError(
|
|
936
|
+
{
|
|
937
|
+
id: 'STORAGE_DYNAMODB_STORE_BATCH_TRACE_INSERT_FAILED',
|
|
938
|
+
domain: ErrorDomain.STORAGE,
|
|
939
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
940
|
+
details: { count: records.length },
|
|
941
|
+
},
|
|
942
|
+
error,
|
|
943
|
+
);
|
|
709
944
|
}
|
|
710
945
|
}
|
|
711
946
|
|
|
@@ -734,11 +969,18 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
734
969
|
updatedAt: now,
|
|
735
970
|
resourceId,
|
|
736
971
|
};
|
|
737
|
-
//
|
|
738
|
-
await this.service.entities.workflowSnapshot.
|
|
972
|
+
// Use upsert instead of create to handle both create and update cases
|
|
973
|
+
await this.service.entities.workflowSnapshot.upsert(data).go();
|
|
739
974
|
} catch (error) {
|
|
740
|
-
|
|
741
|
-
|
|
975
|
+
throw new MastraError(
|
|
976
|
+
{
|
|
977
|
+
id: 'STORAGE_DYNAMODB_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED',
|
|
978
|
+
domain: ErrorDomain.STORAGE,
|
|
979
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
980
|
+
details: { workflowName, runId },
|
|
981
|
+
},
|
|
982
|
+
error,
|
|
983
|
+
);
|
|
742
984
|
}
|
|
743
985
|
}
|
|
744
986
|
|
|
@@ -769,8 +1011,15 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
769
1011
|
// Parse the snapshot string
|
|
770
1012
|
return result.data.snapshot as WorkflowRunState;
|
|
771
1013
|
} catch (error) {
|
|
772
|
-
|
|
773
|
-
|
|
1014
|
+
throw new MastraError(
|
|
1015
|
+
{
|
|
1016
|
+
id: 'STORAGE_DYNAMODB_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED',
|
|
1017
|
+
domain: ErrorDomain.STORAGE,
|
|
1018
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1019
|
+
details: { workflowName, runId },
|
|
1020
|
+
},
|
|
1021
|
+
error,
|
|
1022
|
+
);
|
|
774
1023
|
}
|
|
775
1024
|
}
|
|
776
1025
|
|
|
@@ -860,8 +1109,15 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
860
1109
|
total,
|
|
861
1110
|
};
|
|
862
1111
|
} catch (error) {
|
|
863
|
-
|
|
864
|
-
|
|
1112
|
+
throw new MastraError(
|
|
1113
|
+
{
|
|
1114
|
+
id: 'STORAGE_DYNAMODB_STORE_GET_WORKFLOW_RUNS_FAILED',
|
|
1115
|
+
domain: ErrorDomain.STORAGE,
|
|
1116
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1117
|
+
details: { workflowName: args?.workflowName || '', resourceId: args?.resourceId || '' },
|
|
1118
|
+
},
|
|
1119
|
+
error,
|
|
1120
|
+
);
|
|
865
1121
|
}
|
|
866
1122
|
}
|
|
867
1123
|
|
|
@@ -932,8 +1188,15 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
932
1188
|
resourceId: matchingRunDbItem.resourceId,
|
|
933
1189
|
};
|
|
934
1190
|
} catch (error) {
|
|
935
|
-
|
|
936
|
-
|
|
1191
|
+
throw new MastraError(
|
|
1192
|
+
{
|
|
1193
|
+
id: 'STORAGE_DYNAMODB_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED',
|
|
1194
|
+
domain: ErrorDomain.STORAGE,
|
|
1195
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1196
|
+
details: { runId, workflowName: args?.workflowName || '' },
|
|
1197
|
+
},
|
|
1198
|
+
error,
|
|
1199
|
+
);
|
|
937
1200
|
}
|
|
938
1201
|
}
|
|
939
1202
|
|
|
@@ -950,8 +1213,8 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
950
1213
|
}
|
|
951
1214
|
|
|
952
1215
|
// Helper methods for entity/table mapping
|
|
953
|
-
private getEntityNameForTable(tableName:
|
|
954
|
-
const mapping: Record<
|
|
1216
|
+
private getEntityNameForTable(tableName: SUPPORTED_TABLE_NAMES): string | null {
|
|
1217
|
+
const mapping: Record<SUPPORTED_TABLE_NAMES, string> = {
|
|
955
1218
|
[TABLE_THREADS]: 'thread',
|
|
956
1219
|
[TABLE_MESSAGES]: 'message',
|
|
957
1220
|
[TABLE_WORKFLOW_SNAPSHOT]: 'workflowSnapshot',
|
|
@@ -1035,11 +1298,57 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
1035
1298
|
}
|
|
1036
1299
|
});
|
|
1037
1300
|
} catch (error) {
|
|
1038
|
-
|
|
1039
|
-
|
|
1301
|
+
throw new MastraError(
|
|
1302
|
+
{
|
|
1303
|
+
id: 'STORAGE_DYNAMODB_STORE_GET_EVALS_BY_AGENT_NAME_FAILED',
|
|
1304
|
+
domain: ErrorDomain.STORAGE,
|
|
1305
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1306
|
+
details: { agentName },
|
|
1307
|
+
},
|
|
1308
|
+
error,
|
|
1309
|
+
);
|
|
1040
1310
|
}
|
|
1041
1311
|
}
|
|
1042
1312
|
|
|
1313
|
+
async getTracesPaginated(_args: StorageGetTracesArg): Promise<PaginationInfo & { traces: Trace[] }> {
|
|
1314
|
+
throw new MastraError(
|
|
1315
|
+
{
|
|
1316
|
+
id: 'STORAGE_DYNAMODB_STORE_GET_TRACES_PAGINATED_FAILED',
|
|
1317
|
+
domain: ErrorDomain.STORAGE,
|
|
1318
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1319
|
+
},
|
|
1320
|
+
new Error('Method not implemented.'),
|
|
1321
|
+
);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
async getThreadsByResourceIdPaginated(_args: {
|
|
1325
|
+
resourceId: string;
|
|
1326
|
+
page?: number;
|
|
1327
|
+
perPage?: number;
|
|
1328
|
+
}): Promise<PaginationInfo & { threads: StorageThreadType[] }> {
|
|
1329
|
+
throw new MastraError(
|
|
1330
|
+
{
|
|
1331
|
+
id: 'STORAGE_DYNAMODB_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED',
|
|
1332
|
+
domain: ErrorDomain.STORAGE,
|
|
1333
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1334
|
+
},
|
|
1335
|
+
new Error('Method not implemented.'),
|
|
1336
|
+
);
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
async getMessagesPaginated(
|
|
1340
|
+
_args: StorageGetMessagesArg,
|
|
1341
|
+
): Promise<PaginationInfo & { messages: MastraMessageV1[] | MastraMessageV2[] }> {
|
|
1342
|
+
throw new MastraError(
|
|
1343
|
+
{
|
|
1344
|
+
id: 'STORAGE_DYNAMODB_STORE_GET_MESSAGES_PAGINATED_FAILED',
|
|
1345
|
+
domain: ErrorDomain.STORAGE,
|
|
1346
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1347
|
+
},
|
|
1348
|
+
new Error('Method not implemented.'),
|
|
1349
|
+
);
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1043
1352
|
/**
|
|
1044
1353
|
* Closes the DynamoDB client connection and cleans up resources.
|
|
1045
1354
|
* Should be called when the store is no longer needed, e.g., at the end of tests or application shutdown.
|
|
@@ -1050,9 +1359,25 @@ export class DynamoDBStore extends MastraStorage {
|
|
|
1050
1359
|
this.client.destroy();
|
|
1051
1360
|
this.logger.debug('DynamoDB client closed successfully for store:', { name: this.name });
|
|
1052
1361
|
} catch (error) {
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1362
|
+
throw new MastraError(
|
|
1363
|
+
{
|
|
1364
|
+
id: 'STORAGE_DYNAMODB_STORE_CLOSE_FAILED',
|
|
1365
|
+
domain: ErrorDomain.STORAGE,
|
|
1366
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1367
|
+
},
|
|
1368
|
+
error,
|
|
1369
|
+
);
|
|
1056
1370
|
}
|
|
1057
1371
|
}
|
|
1372
|
+
|
|
1373
|
+
async updateMessages(_args: {
|
|
1374
|
+
messages: Partial<Omit<MastraMessageV2, 'createdAt'>> &
|
|
1375
|
+
{
|
|
1376
|
+
id: string;
|
|
1377
|
+
content?: { metadata?: MastraMessageContentV2['metadata']; content?: MastraMessageContentV2['content'] };
|
|
1378
|
+
}[];
|
|
1379
|
+
}): Promise<MastraMessageV2[]> {
|
|
1380
|
+
this.logger.error('updateMessages is not yet implemented in DynamoDBStore');
|
|
1381
|
+
throw new Error('Method not implemented');
|
|
1382
|
+
}
|
|
1058
1383
|
}
|