@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/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
1
2
|
import { parseSqlIdentifier, parseFieldKey } from '@mastra/core/utils';
|
|
2
3
|
import { MastraVector } from '@mastra/core/vector';
|
|
3
4
|
import { Mutex } from 'async-mutex';
|
|
@@ -368,43 +369,57 @@ var PgVector = class extends MastraVector {
|
|
|
368
369
|
schemaName,
|
|
369
370
|
pgPoolOptions
|
|
370
371
|
}) {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
super();
|
|
377
|
-
this.schema = schemaName;
|
|
378
|
-
const basePool = new pg.Pool({
|
|
379
|
-
connectionString,
|
|
380
|
-
max: 20,
|
|
381
|
-
// Maximum number of clients in the pool
|
|
382
|
-
idleTimeoutMillis: 3e4,
|
|
383
|
-
// Close idle connections after 30 seconds
|
|
384
|
-
connectionTimeoutMillis: 2e3,
|
|
385
|
-
// Fail fast if can't connect
|
|
386
|
-
...pgPoolOptions
|
|
387
|
-
});
|
|
388
|
-
const telemetry = this.__getTelemetry();
|
|
389
|
-
this.pool = telemetry?.traceClass(basePool, {
|
|
390
|
-
spanNamePrefix: "pg-vector",
|
|
391
|
-
attributes: {
|
|
392
|
-
"vector.type": "postgres"
|
|
372
|
+
try {
|
|
373
|
+
if (!connectionString || connectionString.trim() === "") {
|
|
374
|
+
throw new Error(
|
|
375
|
+
"PgVector: connectionString must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults."
|
|
376
|
+
);
|
|
393
377
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
this.createdIndexes.set(indexName, key);
|
|
378
|
+
super();
|
|
379
|
+
this.schema = schemaName;
|
|
380
|
+
const basePool = new pg.Pool({
|
|
381
|
+
connectionString,
|
|
382
|
+
max: 20,
|
|
383
|
+
// Maximum number of clients in the pool
|
|
384
|
+
idleTimeoutMillis: 3e4,
|
|
385
|
+
// Close idle connections after 30 seconds
|
|
386
|
+
connectionTimeoutMillis: 2e3,
|
|
387
|
+
// Fail fast if can't connect
|
|
388
|
+
...pgPoolOptions
|
|
406
389
|
});
|
|
407
|
-
|
|
390
|
+
const telemetry = this.__getTelemetry();
|
|
391
|
+
this.pool = telemetry?.traceClass(basePool, {
|
|
392
|
+
spanNamePrefix: "pg-vector",
|
|
393
|
+
attributes: {
|
|
394
|
+
"vector.type": "postgres"
|
|
395
|
+
}
|
|
396
|
+
}) ?? basePool;
|
|
397
|
+
void (async () => {
|
|
398
|
+
const existingIndexes = await this.listIndexes();
|
|
399
|
+
void existingIndexes.map(async (indexName) => {
|
|
400
|
+
const info = await this.getIndexInfo({ indexName });
|
|
401
|
+
const key = await this.getIndexCacheKey({
|
|
402
|
+
indexName,
|
|
403
|
+
metric: info.metric,
|
|
404
|
+
dimension: info.dimension,
|
|
405
|
+
type: info.type
|
|
406
|
+
});
|
|
407
|
+
this.createdIndexes.set(indexName, key);
|
|
408
|
+
});
|
|
409
|
+
})();
|
|
410
|
+
} catch (error) {
|
|
411
|
+
throw new MastraError(
|
|
412
|
+
{
|
|
413
|
+
id: "MASTRA_STORAGE_PG_VECTOR_INITIALIZATION_FAILED",
|
|
414
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
415
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
416
|
+
details: {
|
|
417
|
+
schemaName: schemaName ?? ""
|
|
418
|
+
}
|
|
419
|
+
},
|
|
420
|
+
error
|
|
421
|
+
);
|
|
422
|
+
}
|
|
408
423
|
}
|
|
409
424
|
getMutexByName(indexName) {
|
|
410
425
|
if (!this.mutexesByName.has(indexName)) this.mutexesByName.set(indexName, new Mutex());
|
|
@@ -443,11 +458,27 @@ var PgVector = class extends MastraVector {
|
|
|
443
458
|
ef,
|
|
444
459
|
probes
|
|
445
460
|
}) {
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
461
|
+
try {
|
|
462
|
+
if (!Number.isInteger(topK) || topK <= 0) {
|
|
463
|
+
throw new Error("topK must be a positive integer");
|
|
464
|
+
}
|
|
465
|
+
if (!Array.isArray(queryVector) || !queryVector.every((x) => typeof x === "number" && Number.isFinite(x))) {
|
|
466
|
+
throw new Error("queryVector must be an array of finite numbers");
|
|
467
|
+
}
|
|
468
|
+
} catch (error) {
|
|
469
|
+
const mastraError = new MastraError(
|
|
470
|
+
{
|
|
471
|
+
id: "MASTRA_STORAGE_PG_VECTOR_QUERY_INVALID_INPUT",
|
|
472
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
473
|
+
category: ErrorCategory.USER,
|
|
474
|
+
details: {
|
|
475
|
+
indexName
|
|
476
|
+
}
|
|
477
|
+
},
|
|
478
|
+
error
|
|
479
|
+
);
|
|
480
|
+
this.logger?.trackException(mastraError);
|
|
481
|
+
throw mastraError;
|
|
451
482
|
}
|
|
452
483
|
const client = await this.pool.connect();
|
|
453
484
|
try {
|
|
@@ -486,6 +517,20 @@ var PgVector = class extends MastraVector {
|
|
|
486
517
|
metadata,
|
|
487
518
|
...includeVector && embedding && { vector: JSON.parse(embedding) }
|
|
488
519
|
}));
|
|
520
|
+
} catch (error) {
|
|
521
|
+
const mastraError = new MastraError(
|
|
522
|
+
{
|
|
523
|
+
id: "MASTRA_STORAGE_PG_VECTOR_QUERY_FAILED",
|
|
524
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
525
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
526
|
+
details: {
|
|
527
|
+
indexName
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
error
|
|
531
|
+
);
|
|
532
|
+
this.logger?.trackException(mastraError);
|
|
533
|
+
throw mastraError;
|
|
489
534
|
} finally {
|
|
490
535
|
client.release();
|
|
491
536
|
}
|
|
@@ -516,12 +561,37 @@ var PgVector = class extends MastraVector {
|
|
|
516
561
|
const match = error.message.match(/expected (\d+) dimensions, not (\d+)/);
|
|
517
562
|
if (match) {
|
|
518
563
|
const [, expected, actual] = match;
|
|
519
|
-
|
|
520
|
-
|
|
564
|
+
const mastraError2 = new MastraError(
|
|
565
|
+
{
|
|
566
|
+
id: "MASTRA_STORAGE_PG_VECTOR_UPSERT_INVALID_INPUT",
|
|
567
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
568
|
+
category: ErrorCategory.USER,
|
|
569
|
+
text: `Vector dimension mismatch: Index "${indexName}" expects ${expected} dimensions but got ${actual} dimensions. Either use a matching embedding model or delete and recreate the index with the new dimension.`,
|
|
570
|
+
details: {
|
|
571
|
+
indexName,
|
|
572
|
+
expected: expected ?? "",
|
|
573
|
+
actual: actual ?? ""
|
|
574
|
+
}
|
|
575
|
+
},
|
|
576
|
+
error
|
|
521
577
|
);
|
|
578
|
+
this.logger?.trackException(mastraError2);
|
|
579
|
+
throw mastraError2;
|
|
522
580
|
}
|
|
523
581
|
}
|
|
524
|
-
|
|
582
|
+
const mastraError = new MastraError(
|
|
583
|
+
{
|
|
584
|
+
id: "MASTRA_STORAGE_PG_VECTOR_UPSERT_FAILED",
|
|
585
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
586
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
587
|
+
details: {
|
|
588
|
+
indexName
|
|
589
|
+
}
|
|
590
|
+
},
|
|
591
|
+
error
|
|
592
|
+
);
|
|
593
|
+
this.logger?.trackException(mastraError);
|
|
594
|
+
throw mastraError;
|
|
525
595
|
} finally {
|
|
526
596
|
client.release();
|
|
527
597
|
}
|
|
@@ -589,11 +659,27 @@ var PgVector = class extends MastraVector {
|
|
|
589
659
|
buildIndex = true
|
|
590
660
|
}) {
|
|
591
661
|
const { tableName } = this.getTableName(indexName);
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
662
|
+
try {
|
|
663
|
+
if (!indexName.match(/^[a-zA-Z_][a-zA-Z0-9_]*$/)) {
|
|
664
|
+
throw new Error("Invalid index name format");
|
|
665
|
+
}
|
|
666
|
+
if (!Number.isInteger(dimension) || dimension <= 0) {
|
|
667
|
+
throw new Error("Dimension must be a positive integer");
|
|
668
|
+
}
|
|
669
|
+
} catch (error) {
|
|
670
|
+
const mastraError = new MastraError(
|
|
671
|
+
{
|
|
672
|
+
id: "MASTRA_STORAGE_PG_VECTOR_CREATE_INDEX_INVALID_INPUT",
|
|
673
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
674
|
+
category: ErrorCategory.USER,
|
|
675
|
+
details: {
|
|
676
|
+
indexName
|
|
677
|
+
}
|
|
678
|
+
},
|
|
679
|
+
error
|
|
680
|
+
);
|
|
681
|
+
this.logger?.trackException(mastraError);
|
|
682
|
+
throw mastraError;
|
|
597
683
|
}
|
|
598
684
|
const indexCacheKey = await this.getIndexCacheKey({ indexName, dimension, type: indexConfig.type, metric });
|
|
599
685
|
if (this.cachedIndexExists(indexName, indexCacheKey)) {
|
|
@@ -626,12 +712,40 @@ var PgVector = class extends MastraVector {
|
|
|
626
712
|
} finally {
|
|
627
713
|
client.release();
|
|
628
714
|
}
|
|
715
|
+
}).catch((error) => {
|
|
716
|
+
const mastraError = new MastraError(
|
|
717
|
+
{
|
|
718
|
+
id: "MASTRA_STORAGE_PG_VECTOR_CREATE_INDEX_FAILED",
|
|
719
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
720
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
721
|
+
details: {
|
|
722
|
+
indexName
|
|
723
|
+
}
|
|
724
|
+
},
|
|
725
|
+
error
|
|
726
|
+
);
|
|
727
|
+
this.logger?.trackException(mastraError);
|
|
728
|
+
throw mastraError;
|
|
629
729
|
});
|
|
630
730
|
}
|
|
631
731
|
async buildIndex({ indexName, metric = "cosine", indexConfig }) {
|
|
632
732
|
const client = await this.pool.connect();
|
|
633
733
|
try {
|
|
634
734
|
await this.setupIndex({ indexName, metric, indexConfig }, client);
|
|
735
|
+
} catch (error) {
|
|
736
|
+
const mastraError = new MastraError(
|
|
737
|
+
{
|
|
738
|
+
id: "MASTRA_STORAGE_PG_VECTOR_BUILD_INDEX_FAILED",
|
|
739
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
740
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
741
|
+
details: {
|
|
742
|
+
indexName
|
|
743
|
+
}
|
|
744
|
+
},
|
|
745
|
+
error
|
|
746
|
+
);
|
|
747
|
+
this.logger?.trackException(mastraError);
|
|
748
|
+
throw mastraError;
|
|
635
749
|
} finally {
|
|
636
750
|
client.release();
|
|
637
751
|
}
|
|
@@ -728,6 +842,17 @@ var PgVector = class extends MastraVector {
|
|
|
728
842
|
`;
|
|
729
843
|
const vectorTables = await client.query(vectorTablesQuery, [this.schema || "public"]);
|
|
730
844
|
return vectorTables.rows.map((row) => row.table_name);
|
|
845
|
+
} catch (e) {
|
|
846
|
+
const mastraError = new MastraError(
|
|
847
|
+
{
|
|
848
|
+
id: "MASTRA_STORAGE_PG_VECTOR_LIST_INDEXES_FAILED",
|
|
849
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
850
|
+
category: ErrorCategory.THIRD_PARTY
|
|
851
|
+
},
|
|
852
|
+
e
|
|
853
|
+
);
|
|
854
|
+
this.logger?.trackException(mastraError);
|
|
855
|
+
throw mastraError;
|
|
731
856
|
} finally {
|
|
732
857
|
client.release();
|
|
733
858
|
}
|
|
@@ -807,7 +932,19 @@ var PgVector = class extends MastraVector {
|
|
|
807
932
|
};
|
|
808
933
|
} catch (e) {
|
|
809
934
|
await client.query("ROLLBACK");
|
|
810
|
-
|
|
935
|
+
const mastraError = new MastraError(
|
|
936
|
+
{
|
|
937
|
+
id: "MASTRA_STORAGE_PG_VECTOR_DESCRIBE_INDEX_FAILED",
|
|
938
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
939
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
940
|
+
details: {
|
|
941
|
+
indexName
|
|
942
|
+
}
|
|
943
|
+
},
|
|
944
|
+
e
|
|
945
|
+
);
|
|
946
|
+
this.logger?.trackException(mastraError);
|
|
947
|
+
throw mastraError;
|
|
811
948
|
} finally {
|
|
812
949
|
client.release();
|
|
813
950
|
}
|
|
@@ -820,7 +957,19 @@ var PgVector = class extends MastraVector {
|
|
|
820
957
|
this.createdIndexes.delete(indexName);
|
|
821
958
|
} catch (error) {
|
|
822
959
|
await client.query("ROLLBACK");
|
|
823
|
-
|
|
960
|
+
const mastraError = new MastraError(
|
|
961
|
+
{
|
|
962
|
+
id: "MASTRA_STORAGE_PG_VECTOR_DELETE_INDEX_FAILED",
|
|
963
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
964
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
965
|
+
details: {
|
|
966
|
+
indexName
|
|
967
|
+
}
|
|
968
|
+
},
|
|
969
|
+
error
|
|
970
|
+
);
|
|
971
|
+
this.logger?.trackException(mastraError);
|
|
972
|
+
throw mastraError;
|
|
824
973
|
} finally {
|
|
825
974
|
client.release();
|
|
826
975
|
}
|
|
@@ -832,7 +981,19 @@ var PgVector = class extends MastraVector {
|
|
|
832
981
|
await client.query(`TRUNCATE ${tableName}`);
|
|
833
982
|
} catch (e) {
|
|
834
983
|
await client.query("ROLLBACK");
|
|
835
|
-
|
|
984
|
+
const mastraError = new MastraError(
|
|
985
|
+
{
|
|
986
|
+
id: "MASTRA_STORAGE_PG_VECTOR_TRUNCATE_INDEX_FAILED",
|
|
987
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
988
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
989
|
+
details: {
|
|
990
|
+
indexName
|
|
991
|
+
}
|
|
992
|
+
},
|
|
993
|
+
e
|
|
994
|
+
);
|
|
995
|
+
this.logger?.trackException(mastraError);
|
|
996
|
+
throw mastraError;
|
|
836
997
|
} finally {
|
|
837
998
|
client.release();
|
|
838
999
|
}
|
|
@@ -851,11 +1012,12 @@ var PgVector = class extends MastraVector {
|
|
|
851
1012
|
* @throws Will throw an error if no updates are provided or if the update operation fails.
|
|
852
1013
|
*/
|
|
853
1014
|
async updateVector({ indexName, id, update }) {
|
|
854
|
-
|
|
855
|
-
throw new Error("No updates provided");
|
|
856
|
-
}
|
|
857
|
-
const client = await this.pool.connect();
|
|
1015
|
+
let client;
|
|
858
1016
|
try {
|
|
1017
|
+
if (!update.vector && !update.metadata) {
|
|
1018
|
+
throw new Error("No updates provided");
|
|
1019
|
+
}
|
|
1020
|
+
client = await this.pool.connect();
|
|
859
1021
|
let updateParts = [];
|
|
860
1022
|
let values = [id];
|
|
861
1023
|
let valueIndex = 2;
|
|
@@ -879,9 +1041,22 @@ var PgVector = class extends MastraVector {
|
|
|
879
1041
|
`;
|
|
880
1042
|
await client.query(query, values);
|
|
881
1043
|
} catch (error) {
|
|
882
|
-
|
|
1044
|
+
const mastraError = new MastraError(
|
|
1045
|
+
{
|
|
1046
|
+
id: "MASTRA_STORAGE_PG_VECTOR_UPDATE_VECTOR_FAILED",
|
|
1047
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
1048
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1049
|
+
details: {
|
|
1050
|
+
indexName,
|
|
1051
|
+
id
|
|
1052
|
+
}
|
|
1053
|
+
},
|
|
1054
|
+
error
|
|
1055
|
+
);
|
|
1056
|
+
this.logger?.trackException(mastraError);
|
|
1057
|
+
throw mastraError;
|
|
883
1058
|
} finally {
|
|
884
|
-
client
|
|
1059
|
+
client?.release();
|
|
885
1060
|
}
|
|
886
1061
|
}
|
|
887
1062
|
/**
|
|
@@ -892,8 +1067,9 @@ var PgVector = class extends MastraVector {
|
|
|
892
1067
|
* @throws Will throw an error if the deletion operation fails.
|
|
893
1068
|
*/
|
|
894
1069
|
async deleteVector({ indexName, id }) {
|
|
895
|
-
|
|
1070
|
+
let client;
|
|
896
1071
|
try {
|
|
1072
|
+
client = await this.pool.connect();
|
|
897
1073
|
const { tableName } = this.getTableName(indexName);
|
|
898
1074
|
const query = `
|
|
899
1075
|
DELETE FROM ${tableName}
|
|
@@ -901,9 +1077,22 @@ var PgVector = class extends MastraVector {
|
|
|
901
1077
|
`;
|
|
902
1078
|
await client.query(query, [id]);
|
|
903
1079
|
} catch (error) {
|
|
904
|
-
|
|
1080
|
+
const mastraError = new MastraError(
|
|
1081
|
+
{
|
|
1082
|
+
id: "MASTRA_STORAGE_PG_VECTOR_DELETE_VECTOR_FAILED",
|
|
1083
|
+
domain: ErrorDomain.MASTRA_VECTOR,
|
|
1084
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1085
|
+
details: {
|
|
1086
|
+
indexName,
|
|
1087
|
+
id
|
|
1088
|
+
}
|
|
1089
|
+
},
|
|
1090
|
+
error
|
|
1091
|
+
);
|
|
1092
|
+
this.logger?.trackException(mastraError);
|
|
1093
|
+
throw mastraError;
|
|
905
1094
|
} finally {
|
|
906
|
-
client
|
|
1095
|
+
client?.release();
|
|
907
1096
|
}
|
|
908
1097
|
}
|
|
909
1098
|
};
|
|
@@ -914,35 +1103,46 @@ var PostgresStore = class extends MastraStorage {
|
|
|
914
1103
|
setupSchemaPromise = null;
|
|
915
1104
|
schemaSetupComplete = void 0;
|
|
916
1105
|
constructor(config) {
|
|
917
|
-
|
|
918
|
-
if (
|
|
919
|
-
|
|
920
|
-
"PostgresStore: connectionString must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults."
|
|
921
|
-
);
|
|
922
|
-
}
|
|
923
|
-
} else {
|
|
924
|
-
const required = ["host", "database", "user", "password"];
|
|
925
|
-
for (const key of required) {
|
|
926
|
-
if (!(key in config) || typeof config[key] !== "string" || config[key].trim() === "") {
|
|
1106
|
+
try {
|
|
1107
|
+
if ("connectionString" in config) {
|
|
1108
|
+
if (!config.connectionString || typeof config.connectionString !== "string" || config.connectionString.trim() === "") {
|
|
927
1109
|
throw new Error(
|
|
928
|
-
|
|
1110
|
+
"PostgresStore: connectionString must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults."
|
|
929
1111
|
);
|
|
930
1112
|
}
|
|
1113
|
+
} else {
|
|
1114
|
+
const required = ["host", "database", "user", "password"];
|
|
1115
|
+
for (const key of required) {
|
|
1116
|
+
if (!(key in config) || typeof config[key] !== "string" || config[key].trim() === "") {
|
|
1117
|
+
throw new Error(
|
|
1118
|
+
`PostgresStore: ${key} must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults.`
|
|
1119
|
+
);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
931
1122
|
}
|
|
1123
|
+
super({ name: "PostgresStore" });
|
|
1124
|
+
this.pgp = pgPromise();
|
|
1125
|
+
this.schema = config.schemaName;
|
|
1126
|
+
this.db = this.pgp(
|
|
1127
|
+
`connectionString` in config ? { connectionString: config.connectionString } : {
|
|
1128
|
+
host: config.host,
|
|
1129
|
+
port: config.port,
|
|
1130
|
+
database: config.database,
|
|
1131
|
+
user: config.user,
|
|
1132
|
+
password: config.password,
|
|
1133
|
+
ssl: config.ssl
|
|
1134
|
+
}
|
|
1135
|
+
);
|
|
1136
|
+
} catch (e) {
|
|
1137
|
+
throw new MastraError(
|
|
1138
|
+
{
|
|
1139
|
+
id: "MASTRA_STORAGE_PG_STORE_INITIALIZATION_FAILED",
|
|
1140
|
+
domain: ErrorDomain.STORAGE,
|
|
1141
|
+
category: ErrorCategory.USER
|
|
1142
|
+
},
|
|
1143
|
+
e
|
|
1144
|
+
);
|
|
932
1145
|
}
|
|
933
|
-
super({ name: "PostgresStore" });
|
|
934
|
-
this.pgp = pgPromise();
|
|
935
|
-
this.schema = config.schemaName;
|
|
936
|
-
this.db = this.pgp(
|
|
937
|
-
`connectionString` in config ? { connectionString: config.connectionString } : {
|
|
938
|
-
host: config.host,
|
|
939
|
-
port: config.port,
|
|
940
|
-
database: config.database,
|
|
941
|
-
user: config.user,
|
|
942
|
-
password: config.password,
|
|
943
|
-
ssl: config.ssl
|
|
944
|
-
}
|
|
945
|
-
);
|
|
946
1146
|
}
|
|
947
1147
|
get supports() {
|
|
948
1148
|
return {
|
|
@@ -1004,9 +1204,19 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1004
1204
|
}
|
|
1005
1205
|
await this.db.query("COMMIT");
|
|
1006
1206
|
} catch (error) {
|
|
1007
|
-
console.error(`Error inserting into ${tableName}:`, error);
|
|
1008
1207
|
await this.db.query("ROLLBACK");
|
|
1009
|
-
throw
|
|
1208
|
+
throw new MastraError(
|
|
1209
|
+
{
|
|
1210
|
+
id: "MASTRA_STORAGE_PG_STORE_BATCH_INSERT_FAILED",
|
|
1211
|
+
domain: ErrorDomain.STORAGE,
|
|
1212
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1213
|
+
details: {
|
|
1214
|
+
tableName,
|
|
1215
|
+
numberOfRecords: records.length
|
|
1216
|
+
}
|
|
1217
|
+
},
|
|
1218
|
+
error
|
|
1219
|
+
);
|
|
1010
1220
|
}
|
|
1011
1221
|
}
|
|
1012
1222
|
/**
|
|
@@ -1063,8 +1273,24 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1063
1273
|
}
|
|
1064
1274
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1065
1275
|
const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(TABLE_TRACES)} ${whereClause}`;
|
|
1066
|
-
|
|
1067
|
-
|
|
1276
|
+
let total = 0;
|
|
1277
|
+
try {
|
|
1278
|
+
const countResult = await this.db.one(countQuery, queryParams);
|
|
1279
|
+
total = parseInt(countResult.count, 10);
|
|
1280
|
+
} catch (error) {
|
|
1281
|
+
throw new MastraError(
|
|
1282
|
+
{
|
|
1283
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_TRACES_PAGINATED_FAILED_TO_RETRIEVE_TOTAL_COUNT",
|
|
1284
|
+
domain: ErrorDomain.STORAGE,
|
|
1285
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1286
|
+
details: {
|
|
1287
|
+
name: args.name ?? "",
|
|
1288
|
+
scope: args.scope ?? ""
|
|
1289
|
+
}
|
|
1290
|
+
},
|
|
1291
|
+
error
|
|
1292
|
+
);
|
|
1293
|
+
}
|
|
1068
1294
|
if (total === 0) {
|
|
1069
1295
|
return {
|
|
1070
1296
|
traces: [],
|
|
@@ -1078,30 +1304,45 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1078
1304
|
TABLE_TRACES
|
|
1079
1305
|
)} ${whereClause} ORDER BY "createdAt" DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
1080
1306
|
const finalQueryParams = [...queryParams, perPage, currentOffset];
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1307
|
+
try {
|
|
1308
|
+
const rows = await this.db.manyOrNone(dataQuery, finalQueryParams);
|
|
1309
|
+
const traces = rows.map((row) => ({
|
|
1310
|
+
id: row.id,
|
|
1311
|
+
parentSpanId: row.parentSpanId,
|
|
1312
|
+
traceId: row.traceId,
|
|
1313
|
+
name: row.name,
|
|
1314
|
+
scope: row.scope,
|
|
1315
|
+
kind: row.kind,
|
|
1316
|
+
status: row.status,
|
|
1317
|
+
events: row.events,
|
|
1318
|
+
links: row.links,
|
|
1319
|
+
attributes: row.attributes,
|
|
1320
|
+
startTime: row.startTime,
|
|
1321
|
+
endTime: row.endTime,
|
|
1322
|
+
other: row.other,
|
|
1323
|
+
createdAt: row.createdAt
|
|
1324
|
+
}));
|
|
1325
|
+
return {
|
|
1326
|
+
traces,
|
|
1327
|
+
total,
|
|
1328
|
+
page,
|
|
1329
|
+
perPage,
|
|
1330
|
+
hasMore: currentOffset + traces.length < total
|
|
1331
|
+
};
|
|
1332
|
+
} catch (error) {
|
|
1333
|
+
throw new MastraError(
|
|
1334
|
+
{
|
|
1335
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_TRACES_PAGINATED_FAILED_TO_RETRIEVE_TRACES",
|
|
1336
|
+
domain: ErrorDomain.STORAGE,
|
|
1337
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1338
|
+
details: {
|
|
1339
|
+
name: args.name ?? "",
|
|
1340
|
+
scope: args.scope ?? ""
|
|
1341
|
+
}
|
|
1342
|
+
},
|
|
1343
|
+
error
|
|
1344
|
+
);
|
|
1345
|
+
}
|
|
1105
1346
|
}
|
|
1106
1347
|
async setupSchema() {
|
|
1107
1348
|
if (!this.schema || this.schemaSetupComplete) {
|
|
@@ -1176,8 +1417,17 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1176
1417
|
`;
|
|
1177
1418
|
await this.db.none(sql);
|
|
1178
1419
|
} catch (error) {
|
|
1179
|
-
|
|
1180
|
-
|
|
1420
|
+
throw new MastraError(
|
|
1421
|
+
{
|
|
1422
|
+
id: "MASTRA_STORAGE_PG_STORE_CREATE_TABLE_FAILED",
|
|
1423
|
+
domain: ErrorDomain.STORAGE,
|
|
1424
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1425
|
+
details: {
|
|
1426
|
+
tableName
|
|
1427
|
+
}
|
|
1428
|
+
},
|
|
1429
|
+
error
|
|
1430
|
+
);
|
|
1181
1431
|
}
|
|
1182
1432
|
}
|
|
1183
1433
|
getDefaultValue(type) {
|
|
@@ -1216,18 +1466,34 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1216
1466
|
}
|
|
1217
1467
|
}
|
|
1218
1468
|
} catch (error) {
|
|
1219
|
-
|
|
1220
|
-
|
|
1469
|
+
throw new MastraError(
|
|
1470
|
+
{
|
|
1471
|
+
id: "MASTRA_STORAGE_PG_STORE_ALTER_TABLE_FAILED",
|
|
1472
|
+
domain: ErrorDomain.STORAGE,
|
|
1473
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1474
|
+
details: {
|
|
1475
|
+
tableName
|
|
1476
|
+
}
|
|
1477
|
+
},
|
|
1478
|
+
error
|
|
1221
1479
|
);
|
|
1222
|
-
throw new Error(`Failed to alter table ${tableName}: ${error}`);
|
|
1223
1480
|
}
|
|
1224
1481
|
}
|
|
1225
1482
|
async clearTable({ tableName }) {
|
|
1226
1483
|
try {
|
|
1227
1484
|
await this.db.none(`TRUNCATE TABLE ${this.getTableName(tableName)} CASCADE`);
|
|
1228
1485
|
} catch (error) {
|
|
1229
|
-
|
|
1230
|
-
|
|
1486
|
+
throw new MastraError(
|
|
1487
|
+
{
|
|
1488
|
+
id: "MASTRA_STORAGE_PG_STORE_CLEAR_TABLE_FAILED",
|
|
1489
|
+
domain: ErrorDomain.STORAGE,
|
|
1490
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1491
|
+
details: {
|
|
1492
|
+
tableName
|
|
1493
|
+
}
|
|
1494
|
+
},
|
|
1495
|
+
error
|
|
1496
|
+
);
|
|
1231
1497
|
}
|
|
1232
1498
|
}
|
|
1233
1499
|
async insert({ tableName, record }) {
|
|
@@ -1240,8 +1506,17 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1240
1506
|
values
|
|
1241
1507
|
);
|
|
1242
1508
|
} catch (error) {
|
|
1243
|
-
|
|
1244
|
-
|
|
1509
|
+
throw new MastraError(
|
|
1510
|
+
{
|
|
1511
|
+
id: "MASTRA_STORAGE_PG_STORE_INSERT_FAILED",
|
|
1512
|
+
domain: ErrorDomain.STORAGE,
|
|
1513
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1514
|
+
details: {
|
|
1515
|
+
tableName
|
|
1516
|
+
}
|
|
1517
|
+
},
|
|
1518
|
+
error
|
|
1519
|
+
);
|
|
1245
1520
|
}
|
|
1246
1521
|
}
|
|
1247
1522
|
async load({ tableName, keys }) {
|
|
@@ -1265,8 +1540,17 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1265
1540
|
}
|
|
1266
1541
|
return result;
|
|
1267
1542
|
} catch (error) {
|
|
1268
|
-
|
|
1269
|
-
|
|
1543
|
+
throw new MastraError(
|
|
1544
|
+
{
|
|
1545
|
+
id: "MASTRA_STORAGE_PG_STORE_LOAD_FAILED",
|
|
1546
|
+
domain: ErrorDomain.STORAGE,
|
|
1547
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1548
|
+
details: {
|
|
1549
|
+
tableName
|
|
1550
|
+
}
|
|
1551
|
+
},
|
|
1552
|
+
error
|
|
1553
|
+
);
|
|
1270
1554
|
}
|
|
1271
1555
|
}
|
|
1272
1556
|
async getThreadById({ threadId }) {
|
|
@@ -1293,8 +1577,17 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1293
1577
|
updatedAt: thread.updatedAt
|
|
1294
1578
|
};
|
|
1295
1579
|
} catch (error) {
|
|
1296
|
-
|
|
1297
|
-
|
|
1580
|
+
throw new MastraError(
|
|
1581
|
+
{
|
|
1582
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_THREAD_BY_ID_FAILED",
|
|
1583
|
+
domain: ErrorDomain.STORAGE,
|
|
1584
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1585
|
+
details: {
|
|
1586
|
+
threadId
|
|
1587
|
+
}
|
|
1588
|
+
},
|
|
1589
|
+
error
|
|
1590
|
+
);
|
|
1298
1591
|
}
|
|
1299
1592
|
}
|
|
1300
1593
|
/**
|
|
@@ -1354,7 +1647,20 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1354
1647
|
hasMore: currentOffset + threads.length < total
|
|
1355
1648
|
};
|
|
1356
1649
|
} catch (error) {
|
|
1357
|
-
|
|
1650
|
+
const mastraError = new MastraError(
|
|
1651
|
+
{
|
|
1652
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
|
|
1653
|
+
domain: ErrorDomain.STORAGE,
|
|
1654
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1655
|
+
details: {
|
|
1656
|
+
resourceId,
|
|
1657
|
+
page
|
|
1658
|
+
}
|
|
1659
|
+
},
|
|
1660
|
+
error
|
|
1661
|
+
);
|
|
1662
|
+
this.logger?.error?.(mastraError.toString());
|
|
1663
|
+
this.logger?.trackException(mastraError);
|
|
1358
1664
|
return { threads: [], total: 0, page, perPage: perPageInput || 100, hasMore: false };
|
|
1359
1665
|
}
|
|
1360
1666
|
}
|
|
@@ -1386,8 +1692,17 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1386
1692
|
);
|
|
1387
1693
|
return thread;
|
|
1388
1694
|
} catch (error) {
|
|
1389
|
-
|
|
1390
|
-
|
|
1695
|
+
throw new MastraError(
|
|
1696
|
+
{
|
|
1697
|
+
id: "MASTRA_STORAGE_PG_STORE_SAVE_THREAD_FAILED",
|
|
1698
|
+
domain: ErrorDomain.STORAGE,
|
|
1699
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1700
|
+
details: {
|
|
1701
|
+
threadId: thread.id
|
|
1702
|
+
}
|
|
1703
|
+
},
|
|
1704
|
+
error
|
|
1705
|
+
);
|
|
1391
1706
|
}
|
|
1392
1707
|
}
|
|
1393
1708
|
async updateThread({
|
|
@@ -1395,20 +1710,29 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1395
1710
|
title,
|
|
1396
1711
|
metadata
|
|
1397
1712
|
}) {
|
|
1713
|
+
const existingThread = await this.getThreadById({ threadId: id });
|
|
1714
|
+
if (!existingThread) {
|
|
1715
|
+
throw new MastraError({
|
|
1716
|
+
id: "MASTRA_STORAGE_PG_STORE_UPDATE_THREAD_FAILED",
|
|
1717
|
+
domain: ErrorDomain.STORAGE,
|
|
1718
|
+
category: ErrorCategory.USER,
|
|
1719
|
+
text: `Thread ${id} not found`,
|
|
1720
|
+
details: {
|
|
1721
|
+
threadId: id,
|
|
1722
|
+
title
|
|
1723
|
+
}
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1726
|
+
const mergedMetadata = {
|
|
1727
|
+
...existingThread.metadata,
|
|
1728
|
+
...metadata
|
|
1729
|
+
};
|
|
1398
1730
|
try {
|
|
1399
|
-
const existingThread = await this.getThreadById({ threadId: id });
|
|
1400
|
-
if (!existingThread) {
|
|
1401
|
-
throw new Error(`Thread ${id} not found`);
|
|
1402
|
-
}
|
|
1403
|
-
const mergedMetadata = {
|
|
1404
|
-
...existingThread.metadata,
|
|
1405
|
-
...metadata
|
|
1406
|
-
};
|
|
1407
1731
|
const thread = await this.db.one(
|
|
1408
1732
|
`UPDATE ${this.getTableName(TABLE_THREADS)}
|
|
1409
1733
|
SET title = $1,
|
|
1410
|
-
|
|
1411
|
-
|
|
1734
|
+
metadata = $2,
|
|
1735
|
+
"updatedAt" = $3
|
|
1412
1736
|
WHERE id = $4
|
|
1413
1737
|
RETURNING *`,
|
|
1414
1738
|
[title, mergedMetadata, (/* @__PURE__ */ new Date()).toISOString(), id]
|
|
@@ -1420,8 +1744,18 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1420
1744
|
updatedAt: thread.updatedAt
|
|
1421
1745
|
};
|
|
1422
1746
|
} catch (error) {
|
|
1423
|
-
|
|
1424
|
-
|
|
1747
|
+
throw new MastraError(
|
|
1748
|
+
{
|
|
1749
|
+
id: "MASTRA_STORAGE_PG_STORE_UPDATE_THREAD_FAILED",
|
|
1750
|
+
domain: ErrorDomain.STORAGE,
|
|
1751
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1752
|
+
details: {
|
|
1753
|
+
threadId: id,
|
|
1754
|
+
title
|
|
1755
|
+
}
|
|
1756
|
+
},
|
|
1757
|
+
error
|
|
1758
|
+
);
|
|
1425
1759
|
}
|
|
1426
1760
|
}
|
|
1427
1761
|
async deleteThread({ threadId }) {
|
|
@@ -1431,26 +1765,34 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1431
1765
|
await t.none(`DELETE FROM ${this.getTableName(TABLE_THREADS)} WHERE id = $1`, [threadId]);
|
|
1432
1766
|
});
|
|
1433
1767
|
} catch (error) {
|
|
1434
|
-
|
|
1435
|
-
|
|
1768
|
+
throw new MastraError(
|
|
1769
|
+
{
|
|
1770
|
+
id: "MASTRA_STORAGE_PG_STORE_DELETE_THREAD_FAILED",
|
|
1771
|
+
domain: ErrorDomain.STORAGE,
|
|
1772
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1773
|
+
details: {
|
|
1774
|
+
threadId
|
|
1775
|
+
}
|
|
1776
|
+
},
|
|
1777
|
+
error
|
|
1778
|
+
);
|
|
1436
1779
|
}
|
|
1437
1780
|
}
|
|
1438
|
-
async
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
`
|
|
1781
|
+
async _getIncludedMessages({
|
|
1782
|
+
threadId,
|
|
1783
|
+
selectBy,
|
|
1784
|
+
orderByStatement
|
|
1785
|
+
}) {
|
|
1786
|
+
const include = selectBy?.include;
|
|
1787
|
+
if (!include) return null;
|
|
1788
|
+
const unionQueries = [];
|
|
1789
|
+
const params = [];
|
|
1790
|
+
let paramIdx = 1;
|
|
1791
|
+
for (const inc of include) {
|
|
1792
|
+
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
1793
|
+
const searchId = inc.threadId || threadId;
|
|
1794
|
+
unionQueries.push(
|
|
1795
|
+
`
|
|
1454
1796
|
SELECT * FROM (
|
|
1455
1797
|
WITH ordered_messages AS (
|
|
1456
1798
|
SELECT
|
|
@@ -1482,34 +1824,45 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1482
1824
|
)
|
|
1483
1825
|
) AS query_${paramIdx}
|
|
1484
1826
|
`
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1827
|
+
// Keep ASC for final sorting after fetching context
|
|
1828
|
+
);
|
|
1829
|
+
params.push(searchId, id, withPreviousMessages, withNextMessages);
|
|
1830
|
+
paramIdx += 4;
|
|
1831
|
+
}
|
|
1832
|
+
const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
|
|
1833
|
+
const includedRows = await this.db.manyOrNone(finalQuery, params);
|
|
1834
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1835
|
+
const dedupedRows = includedRows.filter((row) => {
|
|
1836
|
+
if (seen.has(row.id)) return false;
|
|
1837
|
+
seen.add(row.id);
|
|
1838
|
+
return true;
|
|
1839
|
+
});
|
|
1840
|
+
return dedupedRows;
|
|
1841
|
+
}
|
|
1842
|
+
async getMessages(args) {
|
|
1843
|
+
const { threadId, format, selectBy } = args;
|
|
1844
|
+
const selectStatement = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId"`;
|
|
1845
|
+
const orderByStatement = `ORDER BY "createdAt" DESC`;
|
|
1846
|
+
const limit = this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
1847
|
+
try {
|
|
1848
|
+
let rows = [];
|
|
1849
|
+
const include = selectBy?.include || [];
|
|
1850
|
+
if (include?.length) {
|
|
1851
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
|
|
1852
|
+
if (includeMessages) {
|
|
1853
|
+
rows.push(...includeMessages);
|
|
1511
1854
|
}
|
|
1512
1855
|
}
|
|
1856
|
+
const excludeIds = rows.map((m) => m.id);
|
|
1857
|
+
const excludeIdsParam = excludeIds.map((_, idx) => `$${idx + 2}`).join(", ");
|
|
1858
|
+
let query = `${selectStatement} FROM ${this.getTableName(TABLE_MESSAGES)} WHERE thread_id = $1
|
|
1859
|
+
${excludeIds.length ? `AND id NOT IN (${excludeIdsParam})` : ""}
|
|
1860
|
+
${orderByStatement}
|
|
1861
|
+
LIMIT $${excludeIds.length + 2}
|
|
1862
|
+
`;
|
|
1863
|
+
const queryParams = [threadId, ...excludeIds, limit];
|
|
1864
|
+
const remainingRows = await this.db.manyOrNone(query, queryParams);
|
|
1865
|
+
rows.push(...remainingRows);
|
|
1513
1866
|
const fetchedMessages = (rows || []).map((message) => {
|
|
1514
1867
|
if (typeof message.content === "string") {
|
|
1515
1868
|
try {
|
|
@@ -1527,7 +1880,19 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1527
1880
|
(m) => ({ ...m, content: m.content || { format: 2, parts: [{ type: "text", text: "" }] } })
|
|
1528
1881
|
) : sortedMessages;
|
|
1529
1882
|
} catch (error) {
|
|
1530
|
-
|
|
1883
|
+
const mastraError = new MastraError(
|
|
1884
|
+
{
|
|
1885
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_MESSAGES_FAILED",
|
|
1886
|
+
domain: ErrorDomain.STORAGE,
|
|
1887
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1888
|
+
details: {
|
|
1889
|
+
threadId
|
|
1890
|
+
}
|
|
1891
|
+
},
|
|
1892
|
+
error
|
|
1893
|
+
);
|
|
1894
|
+
this.logger?.error?.(mastraError.toString());
|
|
1895
|
+
this.logger?.trackException(mastraError);
|
|
1531
1896
|
return [];
|
|
1532
1897
|
}
|
|
1533
1898
|
}
|
|
@@ -1538,6 +1903,13 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1538
1903
|
const toDate = dateRange?.end;
|
|
1539
1904
|
const selectStatement = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId"`;
|
|
1540
1905
|
const orderByStatement = `ORDER BY "createdAt" DESC`;
|
|
1906
|
+
const messages = [];
|
|
1907
|
+
if (selectBy?.include?.length) {
|
|
1908
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
|
|
1909
|
+
if (includeMessages) {
|
|
1910
|
+
messages.push(...includeMessages);
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1541
1913
|
try {
|
|
1542
1914
|
const perPage = perPageInput !== void 0 ? perPageInput : 40;
|
|
1543
1915
|
const currentOffset = page * perPage;
|
|
@@ -1569,7 +1941,8 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1569
1941
|
TABLE_MESSAGES
|
|
1570
1942
|
)} ${whereClause} ${orderByStatement} LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
1571
1943
|
const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
|
|
1572
|
-
|
|
1944
|
+
messages.push(...rows || []);
|
|
1945
|
+
const list = new MessageList().add(messages, "memory");
|
|
1573
1946
|
const messagesToReturn = format === `v2` ? list.get.all.v2() : list.get.all.v1();
|
|
1574
1947
|
return {
|
|
1575
1948
|
messages: messagesToReturn,
|
|
@@ -1579,7 +1952,20 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1579
1952
|
hasMore: currentOffset + rows.length < total
|
|
1580
1953
|
};
|
|
1581
1954
|
} catch (error) {
|
|
1582
|
-
|
|
1955
|
+
const mastraError = new MastraError(
|
|
1956
|
+
{
|
|
1957
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_MESSAGES_PAGINATED_FAILED",
|
|
1958
|
+
domain: ErrorDomain.STORAGE,
|
|
1959
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1960
|
+
details: {
|
|
1961
|
+
threadId,
|
|
1962
|
+
page
|
|
1963
|
+
}
|
|
1964
|
+
},
|
|
1965
|
+
error
|
|
1966
|
+
);
|
|
1967
|
+
this.logger?.error?.(mastraError.toString());
|
|
1968
|
+
this.logger?.trackException(mastraError);
|
|
1583
1969
|
return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
|
|
1584
1970
|
}
|
|
1585
1971
|
}
|
|
@@ -1588,15 +1974,28 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1588
1974
|
format
|
|
1589
1975
|
}) {
|
|
1590
1976
|
if (messages.length === 0) return messages;
|
|
1977
|
+
const threadId = messages[0]?.threadId;
|
|
1978
|
+
if (!threadId) {
|
|
1979
|
+
throw new MastraError({
|
|
1980
|
+
id: "MASTRA_STORAGE_PG_STORE_SAVE_MESSAGES_FAILED",
|
|
1981
|
+
domain: ErrorDomain.STORAGE,
|
|
1982
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1983
|
+
text: `Thread ID is required`
|
|
1984
|
+
});
|
|
1985
|
+
}
|
|
1986
|
+
const thread = await this.getThreadById({ threadId });
|
|
1987
|
+
if (!thread) {
|
|
1988
|
+
throw new MastraError({
|
|
1989
|
+
id: "MASTRA_STORAGE_PG_STORE_SAVE_MESSAGES_FAILED",
|
|
1990
|
+
domain: ErrorDomain.STORAGE,
|
|
1991
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1992
|
+
text: `Thread ${threadId} not found`,
|
|
1993
|
+
details: {
|
|
1994
|
+
threadId
|
|
1995
|
+
}
|
|
1996
|
+
});
|
|
1997
|
+
}
|
|
1591
1998
|
try {
|
|
1592
|
-
const threadId = messages[0]?.threadId;
|
|
1593
|
-
if (!threadId) {
|
|
1594
|
-
throw new Error("Thread ID is required");
|
|
1595
|
-
}
|
|
1596
|
-
const thread = await this.getThreadById({ threadId });
|
|
1597
|
-
if (!thread) {
|
|
1598
|
-
throw new Error(`Thread ${threadId} not found`);
|
|
1599
|
-
}
|
|
1600
1999
|
await this.db.tx(async (t) => {
|
|
1601
2000
|
const messageInserts = messages.map((message) => {
|
|
1602
2001
|
if (!message.threadId) {
|
|
@@ -1635,8 +2034,17 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1635
2034
|
if (format === `v2`) return list.get.all.v2();
|
|
1636
2035
|
return list.get.all.v1();
|
|
1637
2036
|
} catch (error) {
|
|
1638
|
-
|
|
1639
|
-
|
|
2037
|
+
throw new MastraError(
|
|
2038
|
+
{
|
|
2039
|
+
id: "MASTRA_STORAGE_PG_STORE_SAVE_MESSAGES_FAILED",
|
|
2040
|
+
domain: ErrorDomain.STORAGE,
|
|
2041
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2042
|
+
details: {
|
|
2043
|
+
threadId
|
|
2044
|
+
}
|
|
2045
|
+
},
|
|
2046
|
+
error
|
|
2047
|
+
);
|
|
1640
2048
|
}
|
|
1641
2049
|
}
|
|
1642
2050
|
async persistWorkflowSnapshot({
|
|
@@ -1660,8 +2068,18 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1660
2068
|
[workflowName, runId, JSON.stringify(snapshot), now, now]
|
|
1661
2069
|
);
|
|
1662
2070
|
} catch (error) {
|
|
1663
|
-
|
|
1664
|
-
|
|
2071
|
+
throw new MastraError(
|
|
2072
|
+
{
|
|
2073
|
+
id: "MASTRA_STORAGE_PG_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
|
|
2074
|
+
domain: ErrorDomain.STORAGE,
|
|
2075
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2076
|
+
details: {
|
|
2077
|
+
workflowName,
|
|
2078
|
+
runId
|
|
2079
|
+
}
|
|
2080
|
+
},
|
|
2081
|
+
error
|
|
2082
|
+
);
|
|
1665
2083
|
}
|
|
1666
2084
|
}
|
|
1667
2085
|
async loadWorkflowSnapshot({
|
|
@@ -1681,8 +2099,18 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1681
2099
|
}
|
|
1682
2100
|
return result.snapshot;
|
|
1683
2101
|
} catch (error) {
|
|
1684
|
-
|
|
1685
|
-
|
|
2102
|
+
throw new MastraError(
|
|
2103
|
+
{
|
|
2104
|
+
id: "MASTRA_STORAGE_PG_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
|
|
2105
|
+
domain: ErrorDomain.STORAGE,
|
|
2106
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2107
|
+
details: {
|
|
2108
|
+
workflowName,
|
|
2109
|
+
runId
|
|
2110
|
+
}
|
|
2111
|
+
},
|
|
2112
|
+
error
|
|
2113
|
+
);
|
|
1686
2114
|
}
|
|
1687
2115
|
}
|
|
1688
2116
|
async hasColumn(table, column) {
|
|
@@ -1770,8 +2198,17 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1770
2198
|
});
|
|
1771
2199
|
return { runs, total: total || runs.length };
|
|
1772
2200
|
} catch (error) {
|
|
1773
|
-
|
|
1774
|
-
|
|
2201
|
+
throw new MastraError(
|
|
2202
|
+
{
|
|
2203
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_WORKFLOW_RUNS_FAILED",
|
|
2204
|
+
domain: ErrorDomain.STORAGE,
|
|
2205
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2206
|
+
details: {
|
|
2207
|
+
workflowName: workflowName || "all"
|
|
2208
|
+
}
|
|
2209
|
+
},
|
|
2210
|
+
error
|
|
2211
|
+
);
|
|
1775
2212
|
}
|
|
1776
2213
|
}
|
|
1777
2214
|
async getWorkflowRunById({
|
|
@@ -1804,8 +2241,18 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1804
2241
|
}
|
|
1805
2242
|
return this.parseWorkflowRun(result);
|
|
1806
2243
|
} catch (error) {
|
|
1807
|
-
|
|
1808
|
-
|
|
2244
|
+
throw new MastraError(
|
|
2245
|
+
{
|
|
2246
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
|
|
2247
|
+
domain: ErrorDomain.STORAGE,
|
|
2248
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2249
|
+
details: {
|
|
2250
|
+
runId,
|
|
2251
|
+
workflowName: workflowName || ""
|
|
2252
|
+
}
|
|
2253
|
+
},
|
|
2254
|
+
error
|
|
2255
|
+
);
|
|
1809
2256
|
}
|
|
1810
2257
|
}
|
|
1811
2258
|
async close() {
|
|
@@ -1837,29 +2284,144 @@ var PostgresStore = class extends MastraStorage {
|
|
|
1837
2284
|
}
|
|
1838
2285
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1839
2286
|
const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(TABLE_EVALS)} ${whereClause}`;
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
2287
|
+
try {
|
|
2288
|
+
const countResult = await this.db.one(countQuery, queryParams);
|
|
2289
|
+
const total = parseInt(countResult.count, 10);
|
|
2290
|
+
const currentOffset = page * perPage;
|
|
2291
|
+
if (total === 0) {
|
|
2292
|
+
return {
|
|
2293
|
+
evals: [],
|
|
2294
|
+
total: 0,
|
|
2295
|
+
page,
|
|
2296
|
+
perPage,
|
|
2297
|
+
hasMore: false
|
|
2298
|
+
};
|
|
2299
|
+
}
|
|
2300
|
+
const dataQuery = `SELECT * FROM ${this.getTableName(
|
|
2301
|
+
TABLE_EVALS
|
|
2302
|
+
)} ${whereClause} ORDER BY created_at DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
2303
|
+
const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
|
|
1844
2304
|
return {
|
|
1845
|
-
evals: [],
|
|
1846
|
-
total
|
|
2305
|
+
evals: rows?.map((row) => this.transformEvalRow(row)) ?? [],
|
|
2306
|
+
total,
|
|
1847
2307
|
page,
|
|
1848
2308
|
perPage,
|
|
1849
|
-
hasMore:
|
|
2309
|
+
hasMore: currentOffset + (rows?.length ?? 0) < total
|
|
1850
2310
|
};
|
|
2311
|
+
} catch (error) {
|
|
2312
|
+
const mastraError = new MastraError(
|
|
2313
|
+
{
|
|
2314
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_EVALS_FAILED",
|
|
2315
|
+
domain: ErrorDomain.STORAGE,
|
|
2316
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2317
|
+
details: {
|
|
2318
|
+
agentName: agentName || "all",
|
|
2319
|
+
type: type || "all",
|
|
2320
|
+
page,
|
|
2321
|
+
perPage
|
|
2322
|
+
}
|
|
2323
|
+
},
|
|
2324
|
+
error
|
|
2325
|
+
);
|
|
2326
|
+
this.logger?.error?.(mastraError.toString());
|
|
2327
|
+
this.logger?.trackException(mastraError);
|
|
2328
|
+
throw mastraError;
|
|
1851
2329
|
}
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
}
|
|
2330
|
+
}
|
|
2331
|
+
async updateMessages({
|
|
2332
|
+
messages
|
|
2333
|
+
}) {
|
|
2334
|
+
if (messages.length === 0) {
|
|
2335
|
+
return [];
|
|
2336
|
+
}
|
|
2337
|
+
const messageIds = messages.map((m) => m.id);
|
|
2338
|
+
const selectQuery = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId", "resourceId" FROM ${this.getTableName(
|
|
2339
|
+
TABLE_MESSAGES
|
|
2340
|
+
)} WHERE id IN ($1:list)`;
|
|
2341
|
+
const existingMessagesDb = await this.db.manyOrNone(selectQuery, [messageIds]);
|
|
2342
|
+
if (existingMessagesDb.length === 0) {
|
|
2343
|
+
return [];
|
|
2344
|
+
}
|
|
2345
|
+
const existingMessages = existingMessagesDb.map((msg) => {
|
|
2346
|
+
if (typeof msg.content === "string") {
|
|
2347
|
+
try {
|
|
2348
|
+
msg.content = JSON.parse(msg.content);
|
|
2349
|
+
} catch {
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
return msg;
|
|
2353
|
+
});
|
|
2354
|
+
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
2355
|
+
await this.db.tx(async (t) => {
|
|
2356
|
+
const queries = [];
|
|
2357
|
+
const columnMapping = {
|
|
2358
|
+
threadId: "thread_id"
|
|
2359
|
+
};
|
|
2360
|
+
for (const existingMessage of existingMessages) {
|
|
2361
|
+
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
2362
|
+
if (!updatePayload) continue;
|
|
2363
|
+
const { id, ...fieldsToUpdate } = updatePayload;
|
|
2364
|
+
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
2365
|
+
threadIdsToUpdate.add(existingMessage.threadId);
|
|
2366
|
+
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
2367
|
+
threadIdsToUpdate.add(updatePayload.threadId);
|
|
2368
|
+
}
|
|
2369
|
+
const setClauses = [];
|
|
2370
|
+
const values = [];
|
|
2371
|
+
let paramIndex = 1;
|
|
2372
|
+
const updatableFields = { ...fieldsToUpdate };
|
|
2373
|
+
if (updatableFields.content) {
|
|
2374
|
+
const newContent = {
|
|
2375
|
+
...existingMessage.content,
|
|
2376
|
+
...updatableFields.content,
|
|
2377
|
+
// Deep merge metadata if it exists on both
|
|
2378
|
+
...existingMessage.content?.metadata && updatableFields.content.metadata ? {
|
|
2379
|
+
metadata: {
|
|
2380
|
+
...existingMessage.content.metadata,
|
|
2381
|
+
...updatableFields.content.metadata
|
|
2382
|
+
}
|
|
2383
|
+
} : {}
|
|
2384
|
+
};
|
|
2385
|
+
setClauses.push(`content = $${paramIndex++}`);
|
|
2386
|
+
values.push(newContent);
|
|
2387
|
+
delete updatableFields.content;
|
|
2388
|
+
}
|
|
2389
|
+
for (const key in updatableFields) {
|
|
2390
|
+
if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
|
|
2391
|
+
const dbColumn = columnMapping[key] || key;
|
|
2392
|
+
setClauses.push(`"${dbColumn}" = $${paramIndex++}`);
|
|
2393
|
+
values.push(updatableFields[key]);
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
if (setClauses.length > 0) {
|
|
2397
|
+
values.push(id);
|
|
2398
|
+
const sql = `UPDATE ${this.getTableName(
|
|
2399
|
+
TABLE_MESSAGES
|
|
2400
|
+
)} SET ${setClauses.join(", ")} WHERE id = $${paramIndex}`;
|
|
2401
|
+
queries.push(t.none(sql, values));
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
if (threadIdsToUpdate.size > 0) {
|
|
2405
|
+
queries.push(
|
|
2406
|
+
t.none(`UPDATE ${this.getTableName(TABLE_THREADS)} SET "updatedAt" = NOW() WHERE id IN ($1:list)`, [
|
|
2407
|
+
Array.from(threadIdsToUpdate)
|
|
2408
|
+
])
|
|
2409
|
+
);
|
|
2410
|
+
}
|
|
2411
|
+
if (queries.length > 0) {
|
|
2412
|
+
await t.batch(queries);
|
|
2413
|
+
}
|
|
2414
|
+
});
|
|
2415
|
+
const updatedMessages = await this.db.manyOrNone(selectQuery, [messageIds]);
|
|
2416
|
+
return (updatedMessages || []).map((message) => {
|
|
2417
|
+
if (typeof message.content === "string") {
|
|
2418
|
+
try {
|
|
2419
|
+
message.content = JSON.parse(message.content);
|
|
2420
|
+
} catch {
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
2423
|
+
return message;
|
|
2424
|
+
});
|
|
1863
2425
|
}
|
|
1864
2426
|
};
|
|
1865
2427
|
|