@mastra/pg 0.11.0 → 0.11.1-alpha.1
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/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +24 -0
- package/dist/_tsup-dts-rollup.d.cts +11 -0
- package/dist/_tsup-dts-rollup.d.ts +11 -0
- package/dist/index.cjs +809 -247
- package/dist/index.js +785 -223
- package/package.json +3 -3
- package/src/storage/index.test.ts +242 -12
- package/src/storage/index.ts +606 -191
- package/src/vector/index.ts +279 -86
package/src/storage/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { MessageList } from '@mastra/core/agent';
|
|
2
|
-
import type { MastraMessageV2 } from '@mastra/core/agent';
|
|
2
|
+
import type { MastraMessageContentV2, MastraMessageV2 } from '@mastra/core/agent';
|
|
3
|
+
import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
|
|
3
4
|
import type { MetricResult } from '@mastra/core/eval';
|
|
4
5
|
import type { MastraMessageV1, StorageThreadType } from '@mastra/core/memory';
|
|
5
6
|
import {
|
|
@@ -50,41 +51,52 @@ export class PostgresStore extends MastraStorage {
|
|
|
50
51
|
|
|
51
52
|
constructor(config: PostgresConfig) {
|
|
52
53
|
// Validation: connectionString or host/database/user/password must not be empty
|
|
53
|
-
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
'PostgresStore: connectionString must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults.',
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
} else {
|
|
64
|
-
const required = ['host', 'database', 'user', 'password'];
|
|
65
|
-
for (const key of required) {
|
|
66
|
-
if (!(key in config) || typeof (config as any)[key] !== 'string' || (config as any)[key].trim() === '') {
|
|
54
|
+
try {
|
|
55
|
+
if ('connectionString' in config) {
|
|
56
|
+
if (
|
|
57
|
+
!config.connectionString ||
|
|
58
|
+
typeof config.connectionString !== 'string' ||
|
|
59
|
+
config.connectionString.trim() === ''
|
|
60
|
+
) {
|
|
67
61
|
throw new Error(
|
|
68
|
-
|
|
62
|
+
'PostgresStore: connectionString must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults.',
|
|
69
63
|
);
|
|
70
64
|
}
|
|
65
|
+
} else {
|
|
66
|
+
const required = ['host', 'database', 'user', 'password'];
|
|
67
|
+
for (const key of required) {
|
|
68
|
+
if (!(key in config) || typeof (config as any)[key] !== 'string' || (config as any)[key].trim() === '') {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`PostgresStore: ${key} must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults.`,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
71
74
|
}
|
|
75
|
+
super({ name: 'PostgresStore' });
|
|
76
|
+
this.pgp = pgPromise();
|
|
77
|
+
this.schema = config.schemaName;
|
|
78
|
+
this.db = this.pgp(
|
|
79
|
+
`connectionString` in config
|
|
80
|
+
? { connectionString: config.connectionString }
|
|
81
|
+
: {
|
|
82
|
+
host: config.host,
|
|
83
|
+
port: config.port,
|
|
84
|
+
database: config.database,
|
|
85
|
+
user: config.user,
|
|
86
|
+
password: config.password,
|
|
87
|
+
ssl: config.ssl,
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
} catch (e) {
|
|
91
|
+
throw new MastraError(
|
|
92
|
+
{
|
|
93
|
+
id: 'MASTRA_STORAGE_PG_STORE_INITIALIZATION_FAILED',
|
|
94
|
+
domain: ErrorDomain.STORAGE,
|
|
95
|
+
category: ErrorCategory.USER,
|
|
96
|
+
},
|
|
97
|
+
e,
|
|
98
|
+
);
|
|
72
99
|
}
|
|
73
|
-
super({ name: 'PostgresStore' });
|
|
74
|
-
this.pgp = pgPromise();
|
|
75
|
-
this.schema = config.schemaName;
|
|
76
|
-
this.db = this.pgp(
|
|
77
|
-
`connectionString` in config
|
|
78
|
-
? { connectionString: config.connectionString }
|
|
79
|
-
: {
|
|
80
|
-
host: config.host,
|
|
81
|
-
port: config.port,
|
|
82
|
-
database: config.database,
|
|
83
|
-
user: config.user,
|
|
84
|
-
password: config.password,
|
|
85
|
-
ssl: config.ssl,
|
|
86
|
-
},
|
|
87
|
-
);
|
|
88
100
|
}
|
|
89
101
|
|
|
90
102
|
public get supports(): {
|
|
@@ -163,9 +175,19 @@ export class PostgresStore extends MastraStorage {
|
|
|
163
175
|
}
|
|
164
176
|
await this.db.query('COMMIT');
|
|
165
177
|
} catch (error) {
|
|
166
|
-
console.error(`Error inserting into ${tableName}:`, error);
|
|
167
178
|
await this.db.query('ROLLBACK');
|
|
168
|
-
throw
|
|
179
|
+
throw new MastraError(
|
|
180
|
+
{
|
|
181
|
+
id: 'MASTRA_STORAGE_PG_STORE_BATCH_INSERT_FAILED',
|
|
182
|
+
domain: ErrorDomain.STORAGE,
|
|
183
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
184
|
+
details: {
|
|
185
|
+
tableName,
|
|
186
|
+
numberOfRecords: records.length,
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
error,
|
|
190
|
+
);
|
|
169
191
|
}
|
|
170
192
|
}
|
|
171
193
|
|
|
@@ -250,8 +272,24 @@ export class PostgresStore extends MastraStorage {
|
|
|
250
272
|
|
|
251
273
|
// Get total count
|
|
252
274
|
const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(TABLE_TRACES)} ${whereClause}`;
|
|
253
|
-
|
|
254
|
-
|
|
275
|
+
let total = 0;
|
|
276
|
+
try {
|
|
277
|
+
const countResult = await this.db.one(countQuery, queryParams);
|
|
278
|
+
total = parseInt(countResult.count, 10);
|
|
279
|
+
} catch (error) {
|
|
280
|
+
throw new MastraError(
|
|
281
|
+
{
|
|
282
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_TRACES_PAGINATED_FAILED_TO_RETRIEVE_TOTAL_COUNT',
|
|
283
|
+
domain: ErrorDomain.STORAGE,
|
|
284
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
285
|
+
details: {
|
|
286
|
+
name: args.name ?? '',
|
|
287
|
+
scope: args.scope ?? '',
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
error,
|
|
291
|
+
);
|
|
292
|
+
}
|
|
255
293
|
|
|
256
294
|
if (total === 0) {
|
|
257
295
|
return {
|
|
@@ -268,31 +306,46 @@ export class PostgresStore extends MastraStorage {
|
|
|
268
306
|
)} ${whereClause} ORDER BY "createdAt" DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
269
307
|
const finalQueryParams = [...queryParams, perPage, currentOffset];
|
|
270
308
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
309
|
+
try {
|
|
310
|
+
const rows = await this.db.manyOrNone<any>(dataQuery, finalQueryParams);
|
|
311
|
+
const traces = rows.map(row => ({
|
|
312
|
+
id: row.id,
|
|
313
|
+
parentSpanId: row.parentSpanId,
|
|
314
|
+
traceId: row.traceId,
|
|
315
|
+
name: row.name,
|
|
316
|
+
scope: row.scope,
|
|
317
|
+
kind: row.kind,
|
|
318
|
+
status: row.status,
|
|
319
|
+
events: row.events,
|
|
320
|
+
links: row.links,
|
|
321
|
+
attributes: row.attributes,
|
|
322
|
+
startTime: row.startTime,
|
|
323
|
+
endTime: row.endTime,
|
|
324
|
+
other: row.other,
|
|
325
|
+
createdAt: row.createdAt,
|
|
326
|
+
}));
|
|
288
327
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
328
|
+
return {
|
|
329
|
+
traces,
|
|
330
|
+
total,
|
|
331
|
+
page,
|
|
332
|
+
perPage,
|
|
333
|
+
hasMore: currentOffset + traces.length < total,
|
|
334
|
+
};
|
|
335
|
+
} catch (error) {
|
|
336
|
+
throw new MastraError(
|
|
337
|
+
{
|
|
338
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_TRACES_PAGINATED_FAILED_TO_RETRIEVE_TRACES',
|
|
339
|
+
domain: ErrorDomain.STORAGE,
|
|
340
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
341
|
+
details: {
|
|
342
|
+
name: args.name ?? '',
|
|
343
|
+
scope: args.scope ?? '',
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
error,
|
|
347
|
+
);
|
|
348
|
+
}
|
|
296
349
|
}
|
|
297
350
|
|
|
298
351
|
private async setupSchema() {
|
|
@@ -390,8 +443,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
390
443
|
|
|
391
444
|
await this.db.none(sql);
|
|
392
445
|
} catch (error) {
|
|
393
|
-
|
|
394
|
-
|
|
446
|
+
throw new MastraError(
|
|
447
|
+
{
|
|
448
|
+
id: 'MASTRA_STORAGE_PG_STORE_CREATE_TABLE_FAILED',
|
|
449
|
+
domain: ErrorDomain.STORAGE,
|
|
450
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
451
|
+
details: {
|
|
452
|
+
tableName,
|
|
453
|
+
},
|
|
454
|
+
},
|
|
455
|
+
error,
|
|
456
|
+
);
|
|
395
457
|
}
|
|
396
458
|
}
|
|
397
459
|
|
|
@@ -439,10 +501,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
439
501
|
}
|
|
440
502
|
}
|
|
441
503
|
} catch (error) {
|
|
442
|
-
|
|
443
|
-
|
|
504
|
+
throw new MastraError(
|
|
505
|
+
{
|
|
506
|
+
id: 'MASTRA_STORAGE_PG_STORE_ALTER_TABLE_FAILED',
|
|
507
|
+
domain: ErrorDomain.STORAGE,
|
|
508
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
509
|
+
details: {
|
|
510
|
+
tableName,
|
|
511
|
+
},
|
|
512
|
+
},
|
|
513
|
+
error,
|
|
444
514
|
);
|
|
445
|
-
throw new Error(`Failed to alter table ${tableName}: ${error}`);
|
|
446
515
|
}
|
|
447
516
|
}
|
|
448
517
|
|
|
@@ -450,8 +519,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
450
519
|
try {
|
|
451
520
|
await this.db.none(`TRUNCATE TABLE ${this.getTableName(tableName)} CASCADE`);
|
|
452
521
|
} catch (error) {
|
|
453
|
-
|
|
454
|
-
|
|
522
|
+
throw new MastraError(
|
|
523
|
+
{
|
|
524
|
+
id: 'MASTRA_STORAGE_PG_STORE_CLEAR_TABLE_FAILED',
|
|
525
|
+
domain: ErrorDomain.STORAGE,
|
|
526
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
527
|
+
details: {
|
|
528
|
+
tableName,
|
|
529
|
+
},
|
|
530
|
+
},
|
|
531
|
+
error,
|
|
532
|
+
);
|
|
455
533
|
}
|
|
456
534
|
}
|
|
457
535
|
|
|
@@ -466,8 +544,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
466
544
|
values,
|
|
467
545
|
);
|
|
468
546
|
} catch (error) {
|
|
469
|
-
|
|
470
|
-
|
|
547
|
+
throw new MastraError(
|
|
548
|
+
{
|
|
549
|
+
id: 'MASTRA_STORAGE_PG_STORE_INSERT_FAILED',
|
|
550
|
+
domain: ErrorDomain.STORAGE,
|
|
551
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
552
|
+
details: {
|
|
553
|
+
tableName,
|
|
554
|
+
},
|
|
555
|
+
},
|
|
556
|
+
error,
|
|
557
|
+
);
|
|
471
558
|
}
|
|
472
559
|
}
|
|
473
560
|
|
|
@@ -497,8 +584,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
497
584
|
|
|
498
585
|
return result;
|
|
499
586
|
} catch (error) {
|
|
500
|
-
|
|
501
|
-
|
|
587
|
+
throw new MastraError(
|
|
588
|
+
{
|
|
589
|
+
id: 'MASTRA_STORAGE_PG_STORE_LOAD_FAILED',
|
|
590
|
+
domain: ErrorDomain.STORAGE,
|
|
591
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
592
|
+
details: {
|
|
593
|
+
tableName,
|
|
594
|
+
},
|
|
595
|
+
},
|
|
596
|
+
error,
|
|
597
|
+
);
|
|
502
598
|
}
|
|
503
599
|
}
|
|
504
600
|
|
|
@@ -528,8 +624,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
528
624
|
updatedAt: thread.updatedAt,
|
|
529
625
|
};
|
|
530
626
|
} catch (error) {
|
|
531
|
-
|
|
532
|
-
|
|
627
|
+
throw new MastraError(
|
|
628
|
+
{
|
|
629
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_THREAD_BY_ID_FAILED',
|
|
630
|
+
domain: ErrorDomain.STORAGE,
|
|
631
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
632
|
+
details: {
|
|
633
|
+
threadId,
|
|
634
|
+
},
|
|
635
|
+
},
|
|
636
|
+
error,
|
|
637
|
+
);
|
|
533
638
|
}
|
|
534
639
|
}
|
|
535
640
|
|
|
@@ -601,7 +706,20 @@ export class PostgresStore extends MastraStorage {
|
|
|
601
706
|
hasMore: currentOffset + threads.length < total,
|
|
602
707
|
};
|
|
603
708
|
} catch (error) {
|
|
604
|
-
|
|
709
|
+
const mastraError = new MastraError(
|
|
710
|
+
{
|
|
711
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED',
|
|
712
|
+
domain: ErrorDomain.STORAGE,
|
|
713
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
714
|
+
details: {
|
|
715
|
+
resourceId,
|
|
716
|
+
page,
|
|
717
|
+
},
|
|
718
|
+
},
|
|
719
|
+
error,
|
|
720
|
+
);
|
|
721
|
+
this.logger?.error?.(mastraError.toString());
|
|
722
|
+
this.logger?.trackException(mastraError);
|
|
605
723
|
return { threads: [], total: 0, page, perPage: perPageInput || 100, hasMore: false };
|
|
606
724
|
}
|
|
607
725
|
}
|
|
@@ -635,8 +753,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
635
753
|
|
|
636
754
|
return thread;
|
|
637
755
|
} catch (error) {
|
|
638
|
-
|
|
639
|
-
|
|
756
|
+
throw new MastraError(
|
|
757
|
+
{
|
|
758
|
+
id: 'MASTRA_STORAGE_PG_STORE_SAVE_THREAD_FAILED',
|
|
759
|
+
domain: ErrorDomain.STORAGE,
|
|
760
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
761
|
+
details: {
|
|
762
|
+
threadId: thread.id,
|
|
763
|
+
},
|
|
764
|
+
},
|
|
765
|
+
error,
|
|
766
|
+
);
|
|
640
767
|
}
|
|
641
768
|
}
|
|
642
769
|
|
|
@@ -649,24 +776,33 @@ export class PostgresStore extends MastraStorage {
|
|
|
649
776
|
title: string;
|
|
650
777
|
metadata: Record<string, unknown>;
|
|
651
778
|
}): Promise<StorageThreadType> {
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
779
|
+
// First get the existing thread to merge metadata
|
|
780
|
+
const existingThread = await this.getThreadById({ threadId: id });
|
|
781
|
+
if (!existingThread) {
|
|
782
|
+
throw new MastraError({
|
|
783
|
+
id: 'MASTRA_STORAGE_PG_STORE_UPDATE_THREAD_FAILED',
|
|
784
|
+
domain: ErrorDomain.STORAGE,
|
|
785
|
+
category: ErrorCategory.USER,
|
|
786
|
+
text: `Thread ${id} not found`,
|
|
787
|
+
details: {
|
|
788
|
+
threadId: id,
|
|
789
|
+
title,
|
|
790
|
+
},
|
|
791
|
+
});
|
|
792
|
+
}
|
|
658
793
|
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
794
|
+
// Merge the existing metadata with the new metadata
|
|
795
|
+
const mergedMetadata = {
|
|
796
|
+
...existingThread.metadata,
|
|
797
|
+
...metadata,
|
|
798
|
+
};
|
|
664
799
|
|
|
800
|
+
try {
|
|
665
801
|
const thread = await this.db.one<StorageThreadType>(
|
|
666
802
|
`UPDATE ${this.getTableName(TABLE_THREADS)}
|
|
667
803
|
SET title = $1,
|
|
668
|
-
|
|
669
|
-
|
|
804
|
+
metadata = $2,
|
|
805
|
+
"updatedAt" = $3
|
|
670
806
|
WHERE id = $4
|
|
671
807
|
RETURNING *`,
|
|
672
808
|
[title, mergedMetadata, new Date().toISOString(), id],
|
|
@@ -679,8 +815,18 @@ export class PostgresStore extends MastraStorage {
|
|
|
679
815
|
updatedAt: thread.updatedAt,
|
|
680
816
|
};
|
|
681
817
|
} catch (error) {
|
|
682
|
-
|
|
683
|
-
|
|
818
|
+
throw new MastraError(
|
|
819
|
+
{
|
|
820
|
+
id: 'MASTRA_STORAGE_PG_STORE_UPDATE_THREAD_FAILED',
|
|
821
|
+
domain: ErrorDomain.STORAGE,
|
|
822
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
823
|
+
details: {
|
|
824
|
+
threadId: id,
|
|
825
|
+
title,
|
|
826
|
+
},
|
|
827
|
+
},
|
|
828
|
+
error,
|
|
829
|
+
);
|
|
684
830
|
}
|
|
685
831
|
}
|
|
686
832
|
|
|
@@ -694,41 +840,42 @@ export class PostgresStore extends MastraStorage {
|
|
|
694
840
|
await t.none(`DELETE FROM ${this.getTableName(TABLE_THREADS)} WHERE id = $1`, [threadId]);
|
|
695
841
|
});
|
|
696
842
|
} catch (error) {
|
|
697
|
-
|
|
698
|
-
|
|
843
|
+
throw new MastraError(
|
|
844
|
+
{
|
|
845
|
+
id: 'MASTRA_STORAGE_PG_STORE_DELETE_THREAD_FAILED',
|
|
846
|
+
domain: ErrorDomain.STORAGE,
|
|
847
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
848
|
+
details: {
|
|
849
|
+
threadId,
|
|
850
|
+
},
|
|
851
|
+
},
|
|
852
|
+
error,
|
|
853
|
+
);
|
|
699
854
|
}
|
|
700
855
|
}
|
|
701
856
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
const
|
|
715
|
-
const
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
let paramIdx = 1;
|
|
725
|
-
|
|
726
|
-
for (const inc of include) {
|
|
727
|
-
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
728
|
-
// if threadId is provided, use it, otherwise use threadId from args
|
|
729
|
-
const searchId = inc.threadId || threadId;
|
|
730
|
-
unionQueries.push(
|
|
731
|
-
`
|
|
857
|
+
private async _getIncludedMessages({
|
|
858
|
+
threadId,
|
|
859
|
+
selectBy,
|
|
860
|
+
orderByStatement,
|
|
861
|
+
}: {
|
|
862
|
+
threadId: string;
|
|
863
|
+
selectBy: StorageGetMessagesArg['selectBy'];
|
|
864
|
+
orderByStatement: string;
|
|
865
|
+
}) {
|
|
866
|
+
const include = selectBy?.include;
|
|
867
|
+
if (!include) return null;
|
|
868
|
+
|
|
869
|
+
const unionQueries: string[] = [];
|
|
870
|
+
const params: any[] = [];
|
|
871
|
+
let paramIdx = 1;
|
|
872
|
+
|
|
873
|
+
for (const inc of include) {
|
|
874
|
+
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
875
|
+
// if threadId is provided, use it, otherwise use threadId from args
|
|
876
|
+
const searchId = inc.threadId || threadId;
|
|
877
|
+
unionQueries.push(
|
|
878
|
+
`
|
|
732
879
|
SELECT * FROM (
|
|
733
880
|
WITH ordered_messages AS (
|
|
734
881
|
SELECT
|
|
@@ -760,37 +907,59 @@ export class PostgresStore extends MastraStorage {
|
|
|
760
907
|
)
|
|
761
908
|
) AS query_${paramIdx}
|
|
762
909
|
`, // Keep ASC for final sorting after fetching context
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
910
|
+
);
|
|
911
|
+
params.push(searchId, id, withPreviousMessages, withNextMessages);
|
|
912
|
+
paramIdx += 4;
|
|
913
|
+
}
|
|
914
|
+
const finalQuery = unionQueries.join(' UNION ALL ') + ' ORDER BY "createdAt" ASC';
|
|
915
|
+
const includedRows = await this.db.manyOrNone(finalQuery, params);
|
|
916
|
+
const seen = new Set<string>();
|
|
917
|
+
const dedupedRows = includedRows.filter(row => {
|
|
918
|
+
if (seen.has(row.id)) return false;
|
|
919
|
+
seen.add(row.id);
|
|
920
|
+
return true;
|
|
921
|
+
});
|
|
922
|
+
return dedupedRows;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
/**
|
|
926
|
+
* @deprecated use getMessagesPaginated instead
|
|
927
|
+
*/
|
|
928
|
+
public async getMessages(args: StorageGetMessagesArg & { format?: 'v1' }): Promise<MastraMessageV1[]>;
|
|
929
|
+
public async getMessages(args: StorageGetMessagesArg & { format: 'v2' }): Promise<MastraMessageV2[]>;
|
|
930
|
+
public async getMessages(
|
|
931
|
+
args: StorageGetMessagesArg & {
|
|
932
|
+
format?: 'v1' | 'v2';
|
|
933
|
+
},
|
|
934
|
+
): Promise<MastraMessageV1[] | MastraMessageV2[]> {
|
|
935
|
+
const { threadId, format, selectBy } = args;
|
|
936
|
+
|
|
937
|
+
const selectStatement = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId"`;
|
|
938
|
+
const orderByStatement = `ORDER BY "createdAt" DESC`;
|
|
939
|
+
const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
940
|
+
|
|
941
|
+
try {
|
|
942
|
+
let rows: any[] = [];
|
|
943
|
+
const include = selectBy?.include || [];
|
|
944
|
+
|
|
945
|
+
if (include?.length) {
|
|
946
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
|
|
947
|
+
if (includeMessages) {
|
|
948
|
+
rows.push(...includeMessages);
|
|
791
949
|
}
|
|
792
950
|
}
|
|
793
951
|
|
|
952
|
+
const excludeIds = rows.map(m => m.id);
|
|
953
|
+
const excludeIdsParam = excludeIds.map((_, idx) => `$${idx + 2}`).join(', ');
|
|
954
|
+
let query = `${selectStatement} FROM ${this.getTableName(TABLE_MESSAGES)} WHERE thread_id = $1
|
|
955
|
+
${excludeIds.length ? `AND id NOT IN (${excludeIdsParam})` : ''}
|
|
956
|
+
${orderByStatement}
|
|
957
|
+
LIMIT $${excludeIds.length + 2}
|
|
958
|
+
`;
|
|
959
|
+
const queryParams: any[] = [threadId, ...excludeIds, limit];
|
|
960
|
+
const remainingRows = await this.db.manyOrNone(query, queryParams);
|
|
961
|
+
rows.push(...remainingRows);
|
|
962
|
+
|
|
794
963
|
const fetchedMessages = (rows || []).map(message => {
|
|
795
964
|
if (typeof message.content === 'string') {
|
|
796
965
|
try {
|
|
@@ -815,7 +984,19 @@ export class PostgresStore extends MastraStorage {
|
|
|
815
984
|
)
|
|
816
985
|
: sortedMessages;
|
|
817
986
|
} catch (error) {
|
|
818
|
-
|
|
987
|
+
const mastraError = new MastraError(
|
|
988
|
+
{
|
|
989
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_MESSAGES_FAILED',
|
|
990
|
+
domain: ErrorDomain.STORAGE,
|
|
991
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
992
|
+
details: {
|
|
993
|
+
threadId,
|
|
994
|
+
},
|
|
995
|
+
},
|
|
996
|
+
error,
|
|
997
|
+
);
|
|
998
|
+
this.logger?.error?.(mastraError.toString());
|
|
999
|
+
this.logger?.trackException(mastraError);
|
|
819
1000
|
return [];
|
|
820
1001
|
}
|
|
821
1002
|
}
|
|
@@ -833,6 +1014,15 @@ export class PostgresStore extends MastraStorage {
|
|
|
833
1014
|
const selectStatement = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId"`;
|
|
834
1015
|
const orderByStatement = `ORDER BY "createdAt" DESC`;
|
|
835
1016
|
|
|
1017
|
+
const messages: MastraMessageV2[] = [];
|
|
1018
|
+
|
|
1019
|
+
if (selectBy?.include?.length) {
|
|
1020
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
|
|
1021
|
+
if (includeMessages) {
|
|
1022
|
+
messages.push(...includeMessages);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
|
|
836
1026
|
try {
|
|
837
1027
|
const perPage = perPageInput !== undefined ? perPageInput : 40;
|
|
838
1028
|
const currentOffset = page * perPage;
|
|
@@ -869,8 +1059,9 @@ export class PostgresStore extends MastraStorage {
|
|
|
869
1059
|
TABLE_MESSAGES,
|
|
870
1060
|
)} ${whereClause} ${orderByStatement} LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
871
1061
|
const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
|
|
1062
|
+
messages.push(...(rows || []));
|
|
872
1063
|
|
|
873
|
-
const list = new MessageList().add(
|
|
1064
|
+
const list = new MessageList().add(messages, 'memory');
|
|
874
1065
|
const messagesToReturn = format === `v2` ? list.get.all.v2() : list.get.all.v1();
|
|
875
1066
|
|
|
876
1067
|
return {
|
|
@@ -881,7 +1072,20 @@ export class PostgresStore extends MastraStorage {
|
|
|
881
1072
|
hasMore: currentOffset + rows.length < total,
|
|
882
1073
|
};
|
|
883
1074
|
} catch (error) {
|
|
884
|
-
|
|
1075
|
+
const mastraError = new MastraError(
|
|
1076
|
+
{
|
|
1077
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_MESSAGES_PAGINATED_FAILED',
|
|
1078
|
+
domain: ErrorDomain.STORAGE,
|
|
1079
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1080
|
+
details: {
|
|
1081
|
+
threadId,
|
|
1082
|
+
page,
|
|
1083
|
+
},
|
|
1084
|
+
},
|
|
1085
|
+
error,
|
|
1086
|
+
);
|
|
1087
|
+
this.logger?.error?.(mastraError.toString());
|
|
1088
|
+
this.logger?.trackException(mastraError);
|
|
885
1089
|
return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
|
|
886
1090
|
}
|
|
887
1091
|
}
|
|
@@ -896,18 +1100,31 @@ export class PostgresStore extends MastraStorage {
|
|
|
896
1100
|
| { messages: MastraMessageV2[]; format: 'v2' }): Promise<MastraMessageV2[] | MastraMessageV1[]> {
|
|
897
1101
|
if (messages.length === 0) return messages;
|
|
898
1102
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
1103
|
+
const threadId = messages[0]?.threadId;
|
|
1104
|
+
if (!threadId) {
|
|
1105
|
+
throw new MastraError({
|
|
1106
|
+
id: 'MASTRA_STORAGE_PG_STORE_SAVE_MESSAGES_FAILED',
|
|
1107
|
+
domain: ErrorDomain.STORAGE,
|
|
1108
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1109
|
+
text: `Thread ID is required`,
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
904
1112
|
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1113
|
+
// Check if thread exists
|
|
1114
|
+
const thread = await this.getThreadById({ threadId });
|
|
1115
|
+
if (!thread) {
|
|
1116
|
+
throw new MastraError({
|
|
1117
|
+
id: 'MASTRA_STORAGE_PG_STORE_SAVE_MESSAGES_FAILED',
|
|
1118
|
+
domain: ErrorDomain.STORAGE,
|
|
1119
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1120
|
+
text: `Thread ${threadId} not found`,
|
|
1121
|
+
details: {
|
|
1122
|
+
threadId,
|
|
1123
|
+
},
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
910
1126
|
|
|
1127
|
+
try {
|
|
911
1128
|
await this.db.tx(async t => {
|
|
912
1129
|
// Execute message inserts and thread update in parallel for better performance
|
|
913
1130
|
const messageInserts = messages.map(message => {
|
|
@@ -950,8 +1167,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
950
1167
|
if (format === `v2`) return list.get.all.v2();
|
|
951
1168
|
return list.get.all.v1();
|
|
952
1169
|
} catch (error) {
|
|
953
|
-
|
|
954
|
-
|
|
1170
|
+
throw new MastraError(
|
|
1171
|
+
{
|
|
1172
|
+
id: 'MASTRA_STORAGE_PG_STORE_SAVE_MESSAGES_FAILED',
|
|
1173
|
+
domain: ErrorDomain.STORAGE,
|
|
1174
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1175
|
+
details: {
|
|
1176
|
+
threadId,
|
|
1177
|
+
},
|
|
1178
|
+
},
|
|
1179
|
+
error,
|
|
1180
|
+
);
|
|
955
1181
|
}
|
|
956
1182
|
}
|
|
957
1183
|
|
|
@@ -980,8 +1206,18 @@ export class PostgresStore extends MastraStorage {
|
|
|
980
1206
|
[workflowName, runId, JSON.stringify(snapshot), now, now],
|
|
981
1207
|
);
|
|
982
1208
|
} catch (error) {
|
|
983
|
-
|
|
984
|
-
|
|
1209
|
+
throw new MastraError(
|
|
1210
|
+
{
|
|
1211
|
+
id: 'MASTRA_STORAGE_PG_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED',
|
|
1212
|
+
domain: ErrorDomain.STORAGE,
|
|
1213
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1214
|
+
details: {
|
|
1215
|
+
workflowName,
|
|
1216
|
+
runId,
|
|
1217
|
+
},
|
|
1218
|
+
},
|
|
1219
|
+
error,
|
|
1220
|
+
);
|
|
985
1221
|
}
|
|
986
1222
|
}
|
|
987
1223
|
|
|
@@ -1007,8 +1243,18 @@ export class PostgresStore extends MastraStorage {
|
|
|
1007
1243
|
|
|
1008
1244
|
return (result as any).snapshot;
|
|
1009
1245
|
} catch (error) {
|
|
1010
|
-
|
|
1011
|
-
|
|
1246
|
+
throw new MastraError(
|
|
1247
|
+
{
|
|
1248
|
+
id: 'MASTRA_STORAGE_PG_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED',
|
|
1249
|
+
domain: ErrorDomain.STORAGE,
|
|
1250
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1251
|
+
details: {
|
|
1252
|
+
workflowName,
|
|
1253
|
+
runId,
|
|
1254
|
+
},
|
|
1255
|
+
},
|
|
1256
|
+
error,
|
|
1257
|
+
);
|
|
1012
1258
|
}
|
|
1013
1259
|
}
|
|
1014
1260
|
|
|
@@ -1122,8 +1368,17 @@ export class PostgresStore extends MastraStorage {
|
|
|
1122
1368
|
// Use runs.length as total when not paginating
|
|
1123
1369
|
return { runs, total: total || runs.length };
|
|
1124
1370
|
} catch (error) {
|
|
1125
|
-
|
|
1126
|
-
|
|
1371
|
+
throw new MastraError(
|
|
1372
|
+
{
|
|
1373
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_WORKFLOW_RUNS_FAILED',
|
|
1374
|
+
domain: ErrorDomain.STORAGE,
|
|
1375
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1376
|
+
details: {
|
|
1377
|
+
workflowName: workflowName || 'all',
|
|
1378
|
+
},
|
|
1379
|
+
},
|
|
1380
|
+
error,
|
|
1381
|
+
);
|
|
1127
1382
|
}
|
|
1128
1383
|
}
|
|
1129
1384
|
|
|
@@ -1169,8 +1424,18 @@ export class PostgresStore extends MastraStorage {
|
|
|
1169
1424
|
|
|
1170
1425
|
return this.parseWorkflowRun(result);
|
|
1171
1426
|
} catch (error) {
|
|
1172
|
-
|
|
1173
|
-
|
|
1427
|
+
throw new MastraError(
|
|
1428
|
+
{
|
|
1429
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED',
|
|
1430
|
+
domain: ErrorDomain.STORAGE,
|
|
1431
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1432
|
+
details: {
|
|
1433
|
+
runId,
|
|
1434
|
+
workflowName: workflowName || '',
|
|
1435
|
+
},
|
|
1436
|
+
},
|
|
1437
|
+
error,
|
|
1438
|
+
);
|
|
1174
1439
|
}
|
|
1175
1440
|
}
|
|
1176
1441
|
|
|
@@ -1216,31 +1481,181 @@ export class PostgresStore extends MastraStorage {
|
|
|
1216
1481
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
1217
1482
|
|
|
1218
1483
|
const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(TABLE_EVALS)} ${whereClause}`;
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1484
|
+
try {
|
|
1485
|
+
const countResult = await this.db.one(countQuery, queryParams);
|
|
1486
|
+
const total = parseInt(countResult.count, 10);
|
|
1487
|
+
const currentOffset = page * perPage;
|
|
1488
|
+
|
|
1489
|
+
if (total === 0) {
|
|
1490
|
+
return {
|
|
1491
|
+
evals: [],
|
|
1492
|
+
total: 0,
|
|
1493
|
+
page,
|
|
1494
|
+
perPage,
|
|
1495
|
+
hasMore: false,
|
|
1496
|
+
};
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
const dataQuery = `SELECT * FROM ${this.getTableName(
|
|
1500
|
+
TABLE_EVALS,
|
|
1501
|
+
)} ${whereClause} ORDER BY created_at DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
1502
|
+
const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
|
|
1222
1503
|
|
|
1223
|
-
if (total === 0) {
|
|
1224
1504
|
return {
|
|
1225
|
-
evals: [],
|
|
1226
|
-
total
|
|
1505
|
+
evals: rows?.map(row => this.transformEvalRow(row)) ?? [],
|
|
1506
|
+
total,
|
|
1227
1507
|
page,
|
|
1228
1508
|
perPage,
|
|
1229
|
-
hasMore:
|
|
1509
|
+
hasMore: currentOffset + (rows?.length ?? 0) < total,
|
|
1230
1510
|
};
|
|
1511
|
+
} catch (error) {
|
|
1512
|
+
const mastraError = new MastraError(
|
|
1513
|
+
{
|
|
1514
|
+
id: 'MASTRA_STORAGE_PG_STORE_GET_EVALS_FAILED',
|
|
1515
|
+
domain: ErrorDomain.STORAGE,
|
|
1516
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1517
|
+
details: {
|
|
1518
|
+
agentName: agentName || 'all',
|
|
1519
|
+
type: type || 'all',
|
|
1520
|
+
page,
|
|
1521
|
+
perPage,
|
|
1522
|
+
},
|
|
1523
|
+
},
|
|
1524
|
+
error,
|
|
1525
|
+
);
|
|
1526
|
+
this.logger?.error?.(mastraError.toString());
|
|
1527
|
+
this.logger?.trackException(mastraError);
|
|
1528
|
+
throw mastraError;
|
|
1231
1529
|
}
|
|
1530
|
+
}
|
|
1232
1531
|
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1532
|
+
async updateMessages({
|
|
1533
|
+
messages,
|
|
1534
|
+
}: {
|
|
1535
|
+
messages: (Partial<Omit<MastraMessageV2, 'createdAt'>> & {
|
|
1536
|
+
id: string;
|
|
1537
|
+
content?: {
|
|
1538
|
+
metadata?: MastraMessageContentV2['metadata'];
|
|
1539
|
+
content?: MastraMessageContentV2['content'];
|
|
1540
|
+
};
|
|
1541
|
+
})[];
|
|
1542
|
+
}): Promise<MastraMessageV2[]> {
|
|
1543
|
+
if (messages.length === 0) {
|
|
1544
|
+
return [];
|
|
1545
|
+
}
|
|
1237
1546
|
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1547
|
+
const messageIds = messages.map(m => m.id);
|
|
1548
|
+
|
|
1549
|
+
const selectQuery = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId", "resourceId" FROM ${this.getTableName(
|
|
1550
|
+
TABLE_MESSAGES,
|
|
1551
|
+
)} WHERE id IN ($1:list)`;
|
|
1552
|
+
|
|
1553
|
+
const existingMessagesDb = await this.db.manyOrNone(selectQuery, [messageIds]);
|
|
1554
|
+
|
|
1555
|
+
if (existingMessagesDb.length === 0) {
|
|
1556
|
+
return [];
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
// Parse content from string to object for merging
|
|
1560
|
+
const existingMessages: MastraMessageV2[] = existingMessagesDb.map(msg => {
|
|
1561
|
+
if (typeof msg.content === 'string') {
|
|
1562
|
+
try {
|
|
1563
|
+
msg.content = JSON.parse(msg.content);
|
|
1564
|
+
} catch {
|
|
1565
|
+
// ignore if not valid json
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
return msg as MastraMessageV2;
|
|
1569
|
+
});
|
|
1570
|
+
|
|
1571
|
+
const threadIdsToUpdate = new Set<string>();
|
|
1572
|
+
|
|
1573
|
+
await this.db.tx(async t => {
|
|
1574
|
+
const queries = [];
|
|
1575
|
+
const columnMapping: Record<string, string> = {
|
|
1576
|
+
threadId: 'thread_id',
|
|
1577
|
+
};
|
|
1578
|
+
|
|
1579
|
+
for (const existingMessage of existingMessages) {
|
|
1580
|
+
const updatePayload = messages.find(m => m.id === existingMessage.id);
|
|
1581
|
+
if (!updatePayload) continue;
|
|
1582
|
+
|
|
1583
|
+
const { id, ...fieldsToUpdate } = updatePayload;
|
|
1584
|
+
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
1585
|
+
|
|
1586
|
+
threadIdsToUpdate.add(existingMessage.threadId!);
|
|
1587
|
+
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
1588
|
+
threadIdsToUpdate.add(updatePayload.threadId);
|
|
1589
|
+
}
|
|
1590
|
+
|
|
1591
|
+
const setClauses: string[] = [];
|
|
1592
|
+
const values: any[] = [];
|
|
1593
|
+
let paramIndex = 1;
|
|
1594
|
+
|
|
1595
|
+
const updatableFields = { ...fieldsToUpdate };
|
|
1596
|
+
|
|
1597
|
+
// Special handling for content: merge in code, then update the whole field
|
|
1598
|
+
if (updatableFields.content) {
|
|
1599
|
+
const newContent = {
|
|
1600
|
+
...existingMessage.content,
|
|
1601
|
+
...updatableFields.content,
|
|
1602
|
+
// Deep merge metadata if it exists on both
|
|
1603
|
+
...(existingMessage.content?.metadata && updatableFields.content.metadata
|
|
1604
|
+
? {
|
|
1605
|
+
metadata: {
|
|
1606
|
+
...existingMessage.content.metadata,
|
|
1607
|
+
...updatableFields.content.metadata,
|
|
1608
|
+
},
|
|
1609
|
+
}
|
|
1610
|
+
: {}),
|
|
1611
|
+
};
|
|
1612
|
+
setClauses.push(`content = $${paramIndex++}`);
|
|
1613
|
+
values.push(newContent);
|
|
1614
|
+
delete updatableFields.content;
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
for (const key in updatableFields) {
|
|
1618
|
+
if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
|
|
1619
|
+
const dbColumn = columnMapping[key] || key;
|
|
1620
|
+
setClauses.push(`"${dbColumn}" = $${paramIndex++}`);
|
|
1621
|
+
values.push(updatableFields[key as keyof typeof updatableFields]);
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
if (setClauses.length > 0) {
|
|
1626
|
+
values.push(id);
|
|
1627
|
+
const sql = `UPDATE ${this.getTableName(
|
|
1628
|
+
TABLE_MESSAGES,
|
|
1629
|
+
)} SET ${setClauses.join(', ')} WHERE id = $${paramIndex}`;
|
|
1630
|
+
queries.push(t.none(sql, values));
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
if (threadIdsToUpdate.size > 0) {
|
|
1635
|
+
queries.push(
|
|
1636
|
+
t.none(`UPDATE ${this.getTableName(TABLE_THREADS)} SET "updatedAt" = NOW() WHERE id IN ($1:list)`, [
|
|
1637
|
+
Array.from(threadIdsToUpdate),
|
|
1638
|
+
]),
|
|
1639
|
+
);
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
if (queries.length > 0) {
|
|
1643
|
+
await t.batch(queries);
|
|
1644
|
+
}
|
|
1645
|
+
});
|
|
1646
|
+
|
|
1647
|
+
// Re-fetch to return the fully updated messages
|
|
1648
|
+
const updatedMessages = await this.db.manyOrNone<MastraMessageV2>(selectQuery, [messageIds]);
|
|
1649
|
+
|
|
1650
|
+
return (updatedMessages || []).map(message => {
|
|
1651
|
+
if (typeof message.content === 'string') {
|
|
1652
|
+
try {
|
|
1653
|
+
message.content = JSON.parse(message.content);
|
|
1654
|
+
} catch {
|
|
1655
|
+
/* ignore */
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
return message;
|
|
1659
|
+
});
|
|
1245
1660
|
}
|
|
1246
1661
|
}
|