@mastra/pg 0.12.3 → 0.12.4-alpha.0
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 +26 -0
- package/dist/_tsup-dts-rollup.d.cts +346 -63
- package/dist/_tsup-dts-rollup.d.ts +346 -63
- package/dist/index.cjs +1610 -1117
- package/dist/index.js +1611 -1118
- package/package.json +3 -3
- package/src/storage/domains/legacy-evals/index.ts +151 -0
- package/src/storage/domains/memory/index.ts +900 -0
- package/src/storage/domains/operations/index.ts +368 -0
- package/src/storage/domains/scores/index.ts +231 -0
- package/src/storage/domains/traces/index.ts +160 -0
- package/src/storage/domains/utils.ts +12 -0
- package/src/storage/domains/workflows/index.ts +253 -0
- package/src/storage/index.test.ts +5 -2389
- package/src/storage/index.ts +157 -1545
- package/src/storage/test-utils.ts +368 -0
- package/src/vector/index.test.ts +89 -0
- package/src/vector/index.ts +3 -0
package/dist/index.cjs
CHANGED
|
@@ -7,9 +7,9 @@ var asyncMutex = require('async-mutex');
|
|
|
7
7
|
var pg = require('pg');
|
|
8
8
|
var xxhash = require('xxhash-wasm');
|
|
9
9
|
var filter = require('@mastra/core/vector/filter');
|
|
10
|
-
var agent = require('@mastra/core/agent');
|
|
11
10
|
var storage = require('@mastra/core/storage');
|
|
12
11
|
var pgPromise = require('pg-promise');
|
|
12
|
+
var agent = require('@mastra/core/agent');
|
|
13
13
|
|
|
14
14
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
15
|
|
|
@@ -490,6 +490,7 @@ var PgVector = class extends vector.MastraVector {
|
|
|
490
490
|
}
|
|
491
491
|
const client = await this.pool.connect();
|
|
492
492
|
try {
|
|
493
|
+
await client.query("BEGIN");
|
|
493
494
|
const vectorStr = `[${queryVector.join(",")}]`;
|
|
494
495
|
const translatedFilter = this.transformFilter(filter);
|
|
495
496
|
const { sql: filterQuery, values: filterValues } = buildFilterQuery(translatedFilter, minScore, topK);
|
|
@@ -519,6 +520,7 @@ var PgVector = class extends vector.MastraVector {
|
|
|
519
520
|
ORDER BY score DESC
|
|
520
521
|
LIMIT $2`;
|
|
521
522
|
const result = await client.query(query, filterValues);
|
|
523
|
+
await client.query("COMMIT");
|
|
522
524
|
return result.rows.map(({ id, score, metadata, embedding }) => ({
|
|
523
525
|
id,
|
|
524
526
|
score,
|
|
@@ -526,6 +528,7 @@ var PgVector = class extends vector.MastraVector {
|
|
|
526
528
|
...includeVector && embedding && { vector: JSON.parse(embedding) }
|
|
527
529
|
}));
|
|
528
530
|
} catch (error$1) {
|
|
531
|
+
await client.query("ROLLBACK");
|
|
529
532
|
const mastraError = new error.MastraError(
|
|
530
533
|
{
|
|
531
534
|
id: "MASTRA_STORAGE_PG_VECTOR_QUERY_FAILED",
|
|
@@ -1104,77 +1107,55 @@ var PgVector = class extends vector.MastraVector {
|
|
|
1104
1107
|
}
|
|
1105
1108
|
}
|
|
1106
1109
|
};
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1110
|
+
function getSchemaName(schema) {
|
|
1111
|
+
return schema ? `"${utils.parseSqlIdentifier(schema, "schema name")}"` : void 0;
|
|
1112
|
+
}
|
|
1113
|
+
function getTableName({ indexName, schemaName }) {
|
|
1114
|
+
const parsedIndexName = utils.parseSqlIdentifier(indexName, "index name");
|
|
1115
|
+
const quotedIndexName = `"${parsedIndexName}"`;
|
|
1116
|
+
const quotedSchemaName = schemaName;
|
|
1117
|
+
return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
// src/storage/domains/legacy-evals/index.ts
|
|
1121
|
+
function transformEvalRow(row) {
|
|
1122
|
+
let testInfoValue = null;
|
|
1123
|
+
if (row.test_info) {
|
|
1114
1124
|
try {
|
|
1115
|
-
|
|
1116
|
-
if (!config.connectionString || typeof config.connectionString !== "string" || config.connectionString.trim() === "") {
|
|
1117
|
-
throw new Error(
|
|
1118
|
-
"PostgresStore: connectionString must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults."
|
|
1119
|
-
);
|
|
1120
|
-
}
|
|
1121
|
-
} else {
|
|
1122
|
-
const required = ["host", "database", "user", "password"];
|
|
1123
|
-
for (const key of required) {
|
|
1124
|
-
if (!(key in config) || typeof config[key] !== "string" || config[key].trim() === "") {
|
|
1125
|
-
throw new Error(
|
|
1126
|
-
`PostgresStore: ${key} must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults.`
|
|
1127
|
-
);
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
super({ name: "PostgresStore" });
|
|
1132
|
-
this.pgp = pgPromise__default.default();
|
|
1133
|
-
this.schema = config.schemaName;
|
|
1134
|
-
this.db = this.pgp(
|
|
1135
|
-
`connectionString` in config ? { connectionString: config.connectionString } : {
|
|
1136
|
-
host: config.host,
|
|
1137
|
-
port: config.port,
|
|
1138
|
-
database: config.database,
|
|
1139
|
-
user: config.user,
|
|
1140
|
-
password: config.password,
|
|
1141
|
-
ssl: config.ssl
|
|
1142
|
-
}
|
|
1143
|
-
);
|
|
1125
|
+
testInfoValue = typeof row.test_info === "string" ? JSON.parse(row.test_info) : row.test_info;
|
|
1144
1126
|
} catch (e) {
|
|
1145
|
-
|
|
1146
|
-
{
|
|
1147
|
-
id: "MASTRA_STORAGE_PG_STORE_INITIALIZATION_FAILED",
|
|
1148
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1149
|
-
category: error.ErrorCategory.USER
|
|
1150
|
-
},
|
|
1151
|
-
e
|
|
1152
|
-
);
|
|
1127
|
+
console.warn("Failed to parse test_info:", e);
|
|
1153
1128
|
}
|
|
1154
1129
|
}
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
|
|
1130
|
+
return {
|
|
1131
|
+
agentName: row.agent_name,
|
|
1132
|
+
input: row.input,
|
|
1133
|
+
output: row.output,
|
|
1134
|
+
result: row.result,
|
|
1135
|
+
metricName: row.metric_name,
|
|
1136
|
+
instructions: row.instructions,
|
|
1137
|
+
testInfo: testInfoValue,
|
|
1138
|
+
globalRunId: row.global_run_id,
|
|
1139
|
+
runId: row.run_id,
|
|
1140
|
+
createdAt: row.created_atZ || row.created_at
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
var LegacyEvalsPG = class extends storage.LegacyEvalsStorage {
|
|
1144
|
+
client;
|
|
1145
|
+
schema;
|
|
1146
|
+
constructor({ client, schema }) {
|
|
1147
|
+
super();
|
|
1148
|
+
this.client = client;
|
|
1149
|
+
this.schema = schema;
|
|
1169
1150
|
}
|
|
1170
1151
|
/** @deprecated use getEvals instead */
|
|
1171
1152
|
async getEvalsByAgentName(agentName, type) {
|
|
1172
1153
|
try {
|
|
1173
|
-
const baseQuery = `SELECT * FROM ${
|
|
1154
|
+
const baseQuery = `SELECT * FROM ${getTableName({ indexName: storage.TABLE_EVALS, schemaName: getSchemaName(this.schema) })} WHERE agent_name = $1`;
|
|
1174
1155
|
const typeCondition = type === "test" ? " AND test_info IS NOT NULL AND test_info->>'testPath' IS NOT NULL" : type === "live" ? " AND (test_info IS NULL OR test_info->>'testPath' IS NULL)" : "";
|
|
1175
1156
|
const query = `${baseQuery}${typeCondition} ORDER BY created_at DESC`;
|
|
1176
|
-
const rows = await this.
|
|
1177
|
-
return rows?.map((row) =>
|
|
1157
|
+
const rows = await this.client.manyOrNone(query, [agentName]);
|
|
1158
|
+
return rows?.map((row) => transformEvalRow(row)) ?? [];
|
|
1178
1159
|
} catch (error) {
|
|
1179
1160
|
if (error instanceof Error && error.message.includes("relation") && error.message.includes("does not exist")) {
|
|
1180
1161
|
return [];
|
|
@@ -1183,486 +1164,522 @@ var PostgresStore = class extends storage.MastraStorage {
|
|
|
1183
1164
|
throw error;
|
|
1184
1165
|
}
|
|
1185
1166
|
}
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1167
|
+
async getEvals(options = {}) {
|
|
1168
|
+
const tableName = getTableName({ indexName: storage.TABLE_EVALS, schemaName: getSchemaName(this.schema) });
|
|
1169
|
+
const { agentName, type, page = 0, perPage = 100, dateRange } = options;
|
|
1170
|
+
const fromDate = dateRange?.start;
|
|
1171
|
+
const toDate = dateRange?.end;
|
|
1172
|
+
const conditions = [];
|
|
1173
|
+
const queryParams = [];
|
|
1174
|
+
let paramIndex = 1;
|
|
1175
|
+
if (agentName) {
|
|
1176
|
+
conditions.push(`agent_name = $${paramIndex++}`);
|
|
1177
|
+
queryParams.push(agentName);
|
|
1194
1178
|
}
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1179
|
+
if (type === "test") {
|
|
1180
|
+
conditions.push(`(test_info IS NOT NULL AND test_info->>'testPath' IS NOT NULL)`);
|
|
1181
|
+
} else if (type === "live") {
|
|
1182
|
+
conditions.push(`(test_info IS NULL OR test_info->>'testPath' IS NULL)`);
|
|
1183
|
+
}
|
|
1184
|
+
if (fromDate) {
|
|
1185
|
+
conditions.push(`created_at >= $${paramIndex++}`);
|
|
1186
|
+
queryParams.push(fromDate);
|
|
1187
|
+
}
|
|
1188
|
+
if (toDate) {
|
|
1189
|
+
conditions.push(`created_at <= $${paramIndex++}`);
|
|
1190
|
+
queryParams.push(toDate);
|
|
1191
|
+
}
|
|
1192
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1193
|
+
const countQuery = `SELECT COUNT(*) FROM ${tableName} ${whereClause}`;
|
|
1209
1194
|
try {
|
|
1210
|
-
await this.
|
|
1211
|
-
|
|
1212
|
-
|
|
1195
|
+
const countResult = await this.client.one(countQuery, queryParams);
|
|
1196
|
+
const total = parseInt(countResult.count, 10);
|
|
1197
|
+
const currentOffset = page * perPage;
|
|
1198
|
+
if (total === 0) {
|
|
1199
|
+
return {
|
|
1200
|
+
evals: [],
|
|
1201
|
+
total: 0,
|
|
1202
|
+
page,
|
|
1203
|
+
perPage,
|
|
1204
|
+
hasMore: false
|
|
1205
|
+
};
|
|
1213
1206
|
}
|
|
1214
|
-
|
|
1207
|
+
const dataQuery = `SELECT * FROM ${tableName} ${whereClause} ORDER BY created_at DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
1208
|
+
const rows = await this.client.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
|
|
1209
|
+
return {
|
|
1210
|
+
evals: rows?.map((row) => transformEvalRow(row)) ?? [],
|
|
1211
|
+
total,
|
|
1212
|
+
page,
|
|
1213
|
+
perPage,
|
|
1214
|
+
hasMore: currentOffset + (rows?.length ?? 0) < total
|
|
1215
|
+
};
|
|
1215
1216
|
} catch (error$1) {
|
|
1216
|
-
|
|
1217
|
-
throw new error.MastraError(
|
|
1217
|
+
const mastraError = new error.MastraError(
|
|
1218
1218
|
{
|
|
1219
|
-
id: "
|
|
1219
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_EVALS_FAILED",
|
|
1220
1220
|
domain: error.ErrorDomain.STORAGE,
|
|
1221
1221
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1222
1222
|
details: {
|
|
1223
|
-
|
|
1224
|
-
|
|
1223
|
+
agentName: agentName || "all",
|
|
1224
|
+
type: type || "all",
|
|
1225
|
+
page,
|
|
1226
|
+
perPage
|
|
1225
1227
|
}
|
|
1226
1228
|
},
|
|
1227
1229
|
error$1
|
|
1228
1230
|
);
|
|
1231
|
+
this.logger?.error?.(mastraError.toString());
|
|
1232
|
+
this.logger?.trackException(mastraError);
|
|
1233
|
+
throw mastraError;
|
|
1229
1234
|
}
|
|
1230
1235
|
}
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1236
|
+
};
|
|
1237
|
+
var MemoryPG = class extends storage.MemoryStorage {
|
|
1238
|
+
client;
|
|
1239
|
+
schema;
|
|
1240
|
+
operations;
|
|
1241
|
+
constructor({
|
|
1242
|
+
client,
|
|
1243
|
+
schema,
|
|
1244
|
+
operations
|
|
1245
|
+
}) {
|
|
1246
|
+
super();
|
|
1247
|
+
this.client = client;
|
|
1248
|
+
this.schema = schema;
|
|
1249
|
+
this.operations = operations;
|
|
1243
1250
|
}
|
|
1244
|
-
async
|
|
1245
|
-
const { name, scope, page = 0, perPage: perPageInput, attributes, filters, dateRange } = args;
|
|
1246
|
-
const fromDate = dateRange?.start;
|
|
1247
|
-
const toDate = dateRange?.end;
|
|
1248
|
-
const perPage = perPageInput !== void 0 ? perPageInput : 100;
|
|
1249
|
-
const currentOffset = page * perPage;
|
|
1250
|
-
const queryParams = [];
|
|
1251
|
-
const conditions = [];
|
|
1252
|
-
let paramIndex = 1;
|
|
1253
|
-
if (name) {
|
|
1254
|
-
conditions.push(`name LIKE $${paramIndex++}`);
|
|
1255
|
-
queryParams.push(`${name}%`);
|
|
1256
|
-
}
|
|
1257
|
-
if (scope) {
|
|
1258
|
-
conditions.push(`scope = $${paramIndex++}`);
|
|
1259
|
-
queryParams.push(scope);
|
|
1260
|
-
}
|
|
1261
|
-
if (attributes) {
|
|
1262
|
-
Object.entries(attributes).forEach(([key, value]) => {
|
|
1263
|
-
const parsedKey = utils.parseFieldKey(key);
|
|
1264
|
-
conditions.push(`attributes->>'${parsedKey}' = $${paramIndex++}`);
|
|
1265
|
-
queryParams.push(value);
|
|
1266
|
-
});
|
|
1267
|
-
}
|
|
1268
|
-
if (filters) {
|
|
1269
|
-
Object.entries(filters).forEach(([key, value]) => {
|
|
1270
|
-
const parsedKey = utils.parseFieldKey(key);
|
|
1271
|
-
conditions.push(`"${parsedKey}" = $${paramIndex++}`);
|
|
1272
|
-
queryParams.push(value);
|
|
1273
|
-
});
|
|
1274
|
-
}
|
|
1275
|
-
if (fromDate) {
|
|
1276
|
-
conditions.push(`"createdAt" >= $${paramIndex++}`);
|
|
1277
|
-
queryParams.push(fromDate);
|
|
1278
|
-
}
|
|
1279
|
-
if (toDate) {
|
|
1280
|
-
conditions.push(`"createdAt" <= $${paramIndex++}`);
|
|
1281
|
-
queryParams.push(toDate);
|
|
1282
|
-
}
|
|
1283
|
-
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1284
|
-
const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(storage.TABLE_TRACES)} ${whereClause}`;
|
|
1285
|
-
let total = 0;
|
|
1251
|
+
async getThreadById({ threadId }) {
|
|
1286
1252
|
try {
|
|
1287
|
-
const
|
|
1288
|
-
|
|
1253
|
+
const tableName = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
|
|
1254
|
+
const thread = await this.client.oneOrNone(
|
|
1255
|
+
`SELECT * FROM ${tableName} WHERE id = $1`,
|
|
1256
|
+
[threadId]
|
|
1257
|
+
);
|
|
1258
|
+
if (!thread) {
|
|
1259
|
+
return null;
|
|
1260
|
+
}
|
|
1261
|
+
return {
|
|
1262
|
+
id: thread.id,
|
|
1263
|
+
resourceId: thread.resourceId,
|
|
1264
|
+
title: thread.title,
|
|
1265
|
+
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
1266
|
+
createdAt: thread.createdAtZ || thread.createdAt,
|
|
1267
|
+
updatedAt: thread.updatedAtZ || thread.updatedAt
|
|
1268
|
+
};
|
|
1289
1269
|
} catch (error$1) {
|
|
1290
1270
|
throw new error.MastraError(
|
|
1291
1271
|
{
|
|
1292
|
-
id: "
|
|
1272
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_THREAD_BY_ID_FAILED",
|
|
1293
1273
|
domain: error.ErrorDomain.STORAGE,
|
|
1294
1274
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1295
1275
|
details: {
|
|
1296
|
-
|
|
1297
|
-
scope: args.scope ?? ""
|
|
1276
|
+
threadId
|
|
1298
1277
|
}
|
|
1299
1278
|
},
|
|
1300
1279
|
error$1
|
|
1301
1280
|
);
|
|
1302
1281
|
}
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
};
|
|
1282
|
+
}
|
|
1283
|
+
/**
|
|
1284
|
+
* @deprecated use getThreadsByResourceIdPaginated instead
|
|
1285
|
+
*/
|
|
1286
|
+
async getThreadsByResourceId(args) {
|
|
1287
|
+
const { resourceId } = args;
|
|
1288
|
+
try {
|
|
1289
|
+
const tableName = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
|
|
1290
|
+
const baseQuery = `FROM ${tableName} WHERE "resourceId" = $1`;
|
|
1291
|
+
const queryParams = [resourceId];
|
|
1292
|
+
const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "createdAt" DESC`;
|
|
1293
|
+
const rows = await this.client.manyOrNone(dataQuery, queryParams);
|
|
1294
|
+
return (rows || []).map((thread) => ({
|
|
1295
|
+
...thread,
|
|
1296
|
+
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
1297
|
+
createdAt: thread.createdAt,
|
|
1298
|
+
updatedAt: thread.updatedAt
|
|
1299
|
+
}));
|
|
1300
|
+
} catch (error) {
|
|
1301
|
+
this.logger.error(`Error getting threads for resource ${resourceId}:`, error);
|
|
1302
|
+
return [];
|
|
1311
1303
|
}
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
const finalQueryParams = [...queryParams, perPage, currentOffset];
|
|
1304
|
+
}
|
|
1305
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
1306
|
+
const { resourceId, page = 0, perPage: perPageInput } = args;
|
|
1316
1307
|
try {
|
|
1317
|
-
const
|
|
1318
|
-
const
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1308
|
+
const tableName = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
|
|
1309
|
+
const baseQuery = `FROM ${tableName} WHERE "resourceId" = $1`;
|
|
1310
|
+
const queryParams = [resourceId];
|
|
1311
|
+
const perPage = perPageInput !== void 0 ? perPageInput : 100;
|
|
1312
|
+
const currentOffset = page * perPage;
|
|
1313
|
+
const countQuery = `SELECT COUNT(*) ${baseQuery}`;
|
|
1314
|
+
const countResult = await this.client.one(countQuery, queryParams);
|
|
1315
|
+
const total = parseInt(countResult.count, 10);
|
|
1316
|
+
if (total === 0) {
|
|
1317
|
+
return {
|
|
1318
|
+
threads: [],
|
|
1319
|
+
total: 0,
|
|
1320
|
+
page,
|
|
1321
|
+
perPage,
|
|
1322
|
+
hasMore: false
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "createdAt" DESC LIMIT $2 OFFSET $3`;
|
|
1326
|
+
const rows = await this.client.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
|
|
1327
|
+
const threads = (rows || []).map((thread) => ({
|
|
1328
|
+
...thread,
|
|
1329
|
+
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
1330
|
+
createdAt: thread.createdAt,
|
|
1331
|
+
// Assuming already Date objects or ISO strings
|
|
1332
|
+
updatedAt: thread.updatedAt
|
|
1333
1333
|
}));
|
|
1334
1334
|
return {
|
|
1335
|
-
|
|
1335
|
+
threads,
|
|
1336
1336
|
total,
|
|
1337
1337
|
page,
|
|
1338
1338
|
perPage,
|
|
1339
|
-
hasMore: currentOffset +
|
|
1339
|
+
hasMore: currentOffset + threads.length < total
|
|
1340
1340
|
};
|
|
1341
1341
|
} catch (error$1) {
|
|
1342
|
-
|
|
1342
|
+
const mastraError = new error.MastraError(
|
|
1343
1343
|
{
|
|
1344
|
-
id: "
|
|
1344
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_THREADS_BY_RESOURCE_ID_PAGINATED_FAILED",
|
|
1345
1345
|
domain: error.ErrorDomain.STORAGE,
|
|
1346
1346
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1347
1347
|
details: {
|
|
1348
|
-
|
|
1349
|
-
|
|
1348
|
+
resourceId,
|
|
1349
|
+
page
|
|
1350
1350
|
}
|
|
1351
1351
|
},
|
|
1352
1352
|
error$1
|
|
1353
1353
|
);
|
|
1354
|
+
this.logger?.error?.(mastraError.toString());
|
|
1355
|
+
this.logger?.trackException(mastraError);
|
|
1356
|
+
return { threads: [], total: 0, page, perPage: perPageInput || 100, hasMore: false };
|
|
1354
1357
|
}
|
|
1355
1358
|
}
|
|
1356
|
-
async
|
|
1357
|
-
if (!this.schema || this.schemaSetupComplete) {
|
|
1358
|
-
return;
|
|
1359
|
-
}
|
|
1360
|
-
if (!this.setupSchemaPromise) {
|
|
1361
|
-
this.setupSchemaPromise = (async () => {
|
|
1362
|
-
try {
|
|
1363
|
-
const schemaExists = await this.db.oneOrNone(
|
|
1364
|
-
`
|
|
1365
|
-
SELECT EXISTS (
|
|
1366
|
-
SELECT 1 FROM information_schema.schemata
|
|
1367
|
-
WHERE schema_name = $1
|
|
1368
|
-
)
|
|
1369
|
-
`,
|
|
1370
|
-
[this.schema]
|
|
1371
|
-
);
|
|
1372
|
-
if (!schemaExists?.exists) {
|
|
1373
|
-
try {
|
|
1374
|
-
await this.db.none(`CREATE SCHEMA IF NOT EXISTS ${this.getSchemaName()}`);
|
|
1375
|
-
this.logger.info(`Schema "${this.schema}" created successfully`);
|
|
1376
|
-
} catch (error) {
|
|
1377
|
-
this.logger.error(`Failed to create schema "${this.schema}"`, { error });
|
|
1378
|
-
throw new Error(
|
|
1379
|
-
`Unable to create schema "${this.schema}". This requires CREATE privilege on the database. Either create the schema manually or grant CREATE privilege to the user.`
|
|
1380
|
-
);
|
|
1381
|
-
}
|
|
1382
|
-
}
|
|
1383
|
-
this.schemaSetupComplete = true;
|
|
1384
|
-
this.logger.debug(`Schema "${this.schema}" is ready for use`);
|
|
1385
|
-
} catch (error) {
|
|
1386
|
-
this.schemaSetupComplete = void 0;
|
|
1387
|
-
this.setupSchemaPromise = null;
|
|
1388
|
-
throw error;
|
|
1389
|
-
} finally {
|
|
1390
|
-
this.setupSchemaPromise = null;
|
|
1391
|
-
}
|
|
1392
|
-
})();
|
|
1393
|
-
}
|
|
1394
|
-
await this.setupSchemaPromise;
|
|
1395
|
-
}
|
|
1396
|
-
async createTable({
|
|
1397
|
-
tableName,
|
|
1398
|
-
schema
|
|
1399
|
-
}) {
|
|
1359
|
+
async saveThread({ thread }) {
|
|
1400
1360
|
try {
|
|
1401
|
-
const
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1361
|
+
const tableName = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
|
|
1362
|
+
await this.client.none(
|
|
1363
|
+
`INSERT INTO ${tableName} (
|
|
1364
|
+
id,
|
|
1365
|
+
"resourceId",
|
|
1366
|
+
title,
|
|
1367
|
+
metadata,
|
|
1368
|
+
"createdAt",
|
|
1369
|
+
"createdAtZ",
|
|
1370
|
+
"updatedAt",
|
|
1371
|
+
"updatedAtZ"
|
|
1372
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
1373
|
+
ON CONFLICT (id) DO UPDATE SET
|
|
1374
|
+
"resourceId" = EXCLUDED."resourceId",
|
|
1375
|
+
title = EXCLUDED.title,
|
|
1376
|
+
metadata = EXCLUDED.metadata,
|
|
1377
|
+
"createdAt" = EXCLUDED."createdAt",
|
|
1378
|
+
"createdAtZ" = EXCLUDED."createdAtZ",
|
|
1379
|
+
"updatedAt" = EXCLUDED."updatedAt",
|
|
1380
|
+
"updatedAtZ" = EXCLUDED."updatedAtZ"`,
|
|
1381
|
+
[
|
|
1382
|
+
thread.id,
|
|
1383
|
+
thread.resourceId,
|
|
1384
|
+
thread.title,
|
|
1385
|
+
thread.metadata ? JSON.stringify(thread.metadata) : null,
|
|
1386
|
+
thread.createdAt,
|
|
1387
|
+
thread.createdAt,
|
|
1388
|
+
thread.updatedAt,
|
|
1389
|
+
thread.updatedAt
|
|
1390
|
+
]
|
|
1391
|
+
);
|
|
1392
|
+
return thread;
|
|
1428
1393
|
} catch (error$1) {
|
|
1429
1394
|
throw new error.MastraError(
|
|
1430
1395
|
{
|
|
1431
|
-
id: "
|
|
1396
|
+
id: "MASTRA_STORAGE_PG_STORE_SAVE_THREAD_FAILED",
|
|
1432
1397
|
domain: error.ErrorDomain.STORAGE,
|
|
1433
1398
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1434
1399
|
details: {
|
|
1435
|
-
|
|
1400
|
+
threadId: thread.id
|
|
1436
1401
|
}
|
|
1437
1402
|
},
|
|
1438
1403
|
error$1
|
|
1439
1404
|
);
|
|
1440
1405
|
}
|
|
1441
1406
|
}
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
case "jsonb":
|
|
1447
|
-
return "DEFAULT '{}'::jsonb";
|
|
1448
|
-
default:
|
|
1449
|
-
return super.getDefaultValue(type);
|
|
1450
|
-
}
|
|
1451
|
-
}
|
|
1452
|
-
/**
|
|
1453
|
-
* Alters table schema to add columns if they don't exist
|
|
1454
|
-
* @param tableName Name of the table
|
|
1455
|
-
* @param schema Schema of the table
|
|
1456
|
-
* @param ifNotExists Array of column names to add if they don't exist
|
|
1457
|
-
*/
|
|
1458
|
-
async alterTable({
|
|
1459
|
-
tableName,
|
|
1460
|
-
schema,
|
|
1461
|
-
ifNotExists
|
|
1407
|
+
async updateThread({
|
|
1408
|
+
id,
|
|
1409
|
+
title,
|
|
1410
|
+
metadata
|
|
1462
1411
|
}) {
|
|
1463
|
-
const
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
this.logger?.debug?.(`Ensured column ${parsedColumnName} exists in table ${fullTableName}`);
|
|
1412
|
+
const threadTableName = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
|
|
1413
|
+
const existingThread = await this.getThreadById({ threadId: id });
|
|
1414
|
+
if (!existingThread) {
|
|
1415
|
+
throw new error.MastraError({
|
|
1416
|
+
id: "MASTRA_STORAGE_PG_STORE_UPDATE_THREAD_FAILED",
|
|
1417
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1418
|
+
category: error.ErrorCategory.USER,
|
|
1419
|
+
text: `Thread ${id} not found`,
|
|
1420
|
+
details: {
|
|
1421
|
+
threadId: id,
|
|
1422
|
+
title
|
|
1475
1423
|
}
|
|
1476
|
-
}
|
|
1424
|
+
});
|
|
1425
|
+
}
|
|
1426
|
+
const mergedMetadata = {
|
|
1427
|
+
...existingThread.metadata,
|
|
1428
|
+
...metadata
|
|
1429
|
+
};
|
|
1430
|
+
try {
|
|
1431
|
+
const thread = await this.client.one(
|
|
1432
|
+
`UPDATE ${threadTableName}
|
|
1433
|
+
SET
|
|
1434
|
+
title = $1,
|
|
1435
|
+
metadata = $2,
|
|
1436
|
+
"updatedAt" = $3,
|
|
1437
|
+
"updatedAtZ" = $3
|
|
1438
|
+
WHERE id = $4
|
|
1439
|
+
RETURNING *
|
|
1440
|
+
`,
|
|
1441
|
+
[title, mergedMetadata, (/* @__PURE__ */ new Date()).toISOString(), id]
|
|
1442
|
+
);
|
|
1443
|
+
return {
|
|
1444
|
+
id: thread.id,
|
|
1445
|
+
resourceId: thread.resourceId,
|
|
1446
|
+
title: thread.title,
|
|
1447
|
+
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
1448
|
+
createdAt: thread.createdAtZ || thread.createdAt,
|
|
1449
|
+
updatedAt: thread.updatedAtZ || thread.updatedAt
|
|
1450
|
+
};
|
|
1477
1451
|
} catch (error$1) {
|
|
1478
1452
|
throw new error.MastraError(
|
|
1479
1453
|
{
|
|
1480
|
-
id: "
|
|
1454
|
+
id: "MASTRA_STORAGE_PG_STORE_UPDATE_THREAD_FAILED",
|
|
1481
1455
|
domain: error.ErrorDomain.STORAGE,
|
|
1482
1456
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1483
1457
|
details: {
|
|
1484
|
-
|
|
1458
|
+
threadId: id,
|
|
1459
|
+
title
|
|
1485
1460
|
}
|
|
1486
1461
|
},
|
|
1487
1462
|
error$1
|
|
1488
1463
|
);
|
|
1489
1464
|
}
|
|
1490
1465
|
}
|
|
1491
|
-
async
|
|
1466
|
+
async deleteThread({ threadId }) {
|
|
1492
1467
|
try {
|
|
1493
|
-
|
|
1468
|
+
const tableName = getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
|
|
1469
|
+
const threadTableName = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
|
|
1470
|
+
await this.client.tx(async (t) => {
|
|
1471
|
+
await t.none(`DELETE FROM ${tableName} WHERE thread_id = $1`, [threadId]);
|
|
1472
|
+
await t.none(`DELETE FROM ${threadTableName} WHERE id = $1`, [threadId]);
|
|
1473
|
+
});
|
|
1494
1474
|
} catch (error$1) {
|
|
1495
1475
|
throw new error.MastraError(
|
|
1496
1476
|
{
|
|
1497
|
-
id: "
|
|
1477
|
+
id: "MASTRA_STORAGE_PG_STORE_DELETE_THREAD_FAILED",
|
|
1498
1478
|
domain: error.ErrorDomain.STORAGE,
|
|
1499
1479
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1500
1480
|
details: {
|
|
1501
|
-
|
|
1481
|
+
threadId
|
|
1502
1482
|
}
|
|
1503
1483
|
},
|
|
1504
1484
|
error$1
|
|
1505
1485
|
);
|
|
1506
1486
|
}
|
|
1507
1487
|
}
|
|
1508
|
-
async
|
|
1488
|
+
async _getIncludedMessages({
|
|
1489
|
+
threadId,
|
|
1490
|
+
selectBy,
|
|
1491
|
+
orderByStatement
|
|
1492
|
+
}) {
|
|
1493
|
+
const include = selectBy?.include;
|
|
1494
|
+
if (!include) return null;
|
|
1495
|
+
const unionQueries = [];
|
|
1496
|
+
const params = [];
|
|
1497
|
+
let paramIdx = 1;
|
|
1498
|
+
const tableName = getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
|
|
1499
|
+
for (const inc of include) {
|
|
1500
|
+
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
1501
|
+
const searchId = inc.threadId || threadId;
|
|
1502
|
+
unionQueries.push(
|
|
1503
|
+
`
|
|
1504
|
+
SELECT * FROM (
|
|
1505
|
+
WITH ordered_messages AS (
|
|
1506
|
+
SELECT
|
|
1507
|
+
*,
|
|
1508
|
+
ROW_NUMBER() OVER (${orderByStatement}) as row_num
|
|
1509
|
+
FROM ${tableName}
|
|
1510
|
+
WHERE thread_id = $${paramIdx}
|
|
1511
|
+
)
|
|
1512
|
+
SELECT
|
|
1513
|
+
m.id,
|
|
1514
|
+
m.content,
|
|
1515
|
+
m.role,
|
|
1516
|
+
m.type,
|
|
1517
|
+
m."createdAt",
|
|
1518
|
+
m.thread_id AS "threadId",
|
|
1519
|
+
m."resourceId"
|
|
1520
|
+
FROM ordered_messages m
|
|
1521
|
+
WHERE m.id = $${paramIdx + 1}
|
|
1522
|
+
OR EXISTS (
|
|
1523
|
+
SELECT 1 FROM ordered_messages target
|
|
1524
|
+
WHERE target.id = $${paramIdx + 1}
|
|
1525
|
+
AND (
|
|
1526
|
+
-- Get previous messages based on the max withPreviousMessages
|
|
1527
|
+
(m.row_num <= target.row_num + $${paramIdx + 2} AND m.row_num > target.row_num)
|
|
1528
|
+
OR
|
|
1529
|
+
-- Get next messages based on the max withNextMessages
|
|
1530
|
+
(m.row_num >= target.row_num - $${paramIdx + 3} AND m.row_num < target.row_num)
|
|
1531
|
+
)
|
|
1532
|
+
)
|
|
1533
|
+
) AS query_${paramIdx}
|
|
1534
|
+
`
|
|
1535
|
+
// Keep ASC for final sorting after fetching context
|
|
1536
|
+
);
|
|
1537
|
+
params.push(searchId, id, withPreviousMessages, withNextMessages);
|
|
1538
|
+
paramIdx += 4;
|
|
1539
|
+
}
|
|
1540
|
+
const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
|
|
1541
|
+
const includedRows = await this.client.manyOrNone(finalQuery, params);
|
|
1542
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1543
|
+
const dedupedRows = includedRows.filter((row) => {
|
|
1544
|
+
if (seen.has(row.id)) return false;
|
|
1545
|
+
seen.add(row.id);
|
|
1546
|
+
return true;
|
|
1547
|
+
});
|
|
1548
|
+
return dedupedRows;
|
|
1549
|
+
}
|
|
1550
|
+
async getMessages(args) {
|
|
1551
|
+
const { threadId, format, selectBy } = args;
|
|
1552
|
+
const selectStatement = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId", "resourceId"`;
|
|
1553
|
+
const orderByStatement = `ORDER BY "createdAt" DESC`;
|
|
1554
|
+
const limit = storage.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
1509
1555
|
try {
|
|
1510
|
-
|
|
1511
|
-
const
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1556
|
+
let rows = [];
|
|
1557
|
+
const include = selectBy?.include || [];
|
|
1558
|
+
if (include?.length) {
|
|
1559
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
|
|
1560
|
+
if (includeMessages) {
|
|
1561
|
+
rows.push(...includeMessages);
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
const excludeIds = rows.map((m) => m.id);
|
|
1565
|
+
const tableName = getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
|
|
1566
|
+
const excludeIdsParam = excludeIds.map((_, idx) => `$${idx + 2}`).join(", ");
|
|
1567
|
+
let query = `${selectStatement} FROM ${tableName} WHERE thread_id = $1
|
|
1568
|
+
${excludeIds.length ? `AND id NOT IN (${excludeIdsParam})` : ""}
|
|
1569
|
+
${orderByStatement}
|
|
1570
|
+
LIMIT $${excludeIds.length + 2}
|
|
1571
|
+
`;
|
|
1572
|
+
const queryParams = [threadId, ...excludeIds, limit];
|
|
1573
|
+
const remainingRows = await this.client.manyOrNone(query, queryParams);
|
|
1574
|
+
rows.push(...remainingRows);
|
|
1575
|
+
const fetchedMessages = (rows || []).map((message) => {
|
|
1576
|
+
if (typeof message.content === "string") {
|
|
1577
|
+
try {
|
|
1578
|
+
message.content = JSON.parse(message.content);
|
|
1579
|
+
} catch {
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
if (message.type === "v2") delete message.type;
|
|
1583
|
+
return message;
|
|
1584
|
+
});
|
|
1585
|
+
const sortedMessages = fetchedMessages.sort(
|
|
1586
|
+
(a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
|
|
1516
1587
|
);
|
|
1588
|
+
return format === "v2" ? sortedMessages.map(
|
|
1589
|
+
(m) => ({ ...m, content: m.content || { format: 2, parts: [{ type: "text", text: "" }] } })
|
|
1590
|
+
) : sortedMessages;
|
|
1517
1591
|
} catch (error$1) {
|
|
1518
|
-
|
|
1592
|
+
const mastraError = new error.MastraError(
|
|
1519
1593
|
{
|
|
1520
|
-
id: "
|
|
1594
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_MESSAGES_FAILED",
|
|
1521
1595
|
domain: error.ErrorDomain.STORAGE,
|
|
1522
1596
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1523
1597
|
details: {
|
|
1524
|
-
|
|
1525
|
-
}
|
|
1526
|
-
},
|
|
1527
|
-
error$1
|
|
1528
|
-
);
|
|
1529
|
-
}
|
|
1530
|
-
}
|
|
1531
|
-
async load({ tableName, keys }) {
|
|
1532
|
-
try {
|
|
1533
|
-
const keyEntries = Object.entries(keys).map(([key, value]) => [utils.parseSqlIdentifier(key, "column name"), value]);
|
|
1534
|
-
const conditions = keyEntries.map(([key], index) => `"${key}" = $${index + 1}`).join(" AND ");
|
|
1535
|
-
const values = keyEntries.map(([_, value]) => value);
|
|
1536
|
-
const result = await this.db.oneOrNone(
|
|
1537
|
-
`SELECT * FROM ${this.getTableName(tableName)} WHERE ${conditions}`,
|
|
1538
|
-
values
|
|
1539
|
-
);
|
|
1540
|
-
if (!result) {
|
|
1541
|
-
return null;
|
|
1542
|
-
}
|
|
1543
|
-
if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
|
|
1544
|
-
const snapshot = result;
|
|
1545
|
-
if (typeof snapshot.snapshot === "string") {
|
|
1546
|
-
snapshot.snapshot = JSON.parse(snapshot.snapshot);
|
|
1547
|
-
}
|
|
1548
|
-
return snapshot;
|
|
1549
|
-
}
|
|
1550
|
-
return result;
|
|
1551
|
-
} catch (error$1) {
|
|
1552
|
-
throw new error.MastraError(
|
|
1553
|
-
{
|
|
1554
|
-
id: "MASTRA_STORAGE_PG_STORE_LOAD_FAILED",
|
|
1555
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1556
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
1557
|
-
details: {
|
|
1558
|
-
tableName
|
|
1598
|
+
threadId
|
|
1559
1599
|
}
|
|
1560
1600
|
},
|
|
1561
1601
|
error$1
|
|
1562
1602
|
);
|
|
1603
|
+
this.logger?.error?.(mastraError.toString());
|
|
1604
|
+
this.logger?.trackException(mastraError);
|
|
1605
|
+
return [];
|
|
1563
1606
|
}
|
|
1564
1607
|
}
|
|
1565
|
-
async
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
[threadId]
|
|
1578
|
-
);
|
|
1579
|
-
if (!thread) {
|
|
1580
|
-
return null;
|
|
1608
|
+
async getMessagesPaginated(args) {
|
|
1609
|
+
const { threadId, format, selectBy } = args;
|
|
1610
|
+
const { page = 0, perPage: perPageInput, dateRange } = selectBy?.pagination || {};
|
|
1611
|
+
const fromDate = dateRange?.start;
|
|
1612
|
+
const toDate = dateRange?.end;
|
|
1613
|
+
const selectStatement = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId", "resourceId"`;
|
|
1614
|
+
const orderByStatement = `ORDER BY "createdAt" DESC`;
|
|
1615
|
+
const messages = [];
|
|
1616
|
+
if (selectBy?.include?.length) {
|
|
1617
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
|
|
1618
|
+
if (includeMessages) {
|
|
1619
|
+
messages.push(...includeMessages);
|
|
1581
1620
|
}
|
|
1582
|
-
return {
|
|
1583
|
-
...thread,
|
|
1584
|
-
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
1585
|
-
createdAt: thread.createdAt,
|
|
1586
|
-
updatedAt: thread.updatedAt
|
|
1587
|
-
};
|
|
1588
|
-
} catch (error$1) {
|
|
1589
|
-
throw new error.MastraError(
|
|
1590
|
-
{
|
|
1591
|
-
id: "MASTRA_STORAGE_PG_STORE_GET_THREAD_BY_ID_FAILED",
|
|
1592
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1593
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
1594
|
-
details: {
|
|
1595
|
-
threadId
|
|
1596
|
-
}
|
|
1597
|
-
},
|
|
1598
|
-
error$1
|
|
1599
|
-
);
|
|
1600
|
-
}
|
|
1601
|
-
}
|
|
1602
|
-
/**
|
|
1603
|
-
* @deprecated use getThreadsByResourceIdPaginated instead
|
|
1604
|
-
*/
|
|
1605
|
-
async getThreadsByResourceId(args) {
|
|
1606
|
-
const { resourceId } = args;
|
|
1607
|
-
try {
|
|
1608
|
-
const baseQuery = `FROM ${this.getTableName(storage.TABLE_THREADS)} WHERE "resourceId" = $1`;
|
|
1609
|
-
const queryParams = [resourceId];
|
|
1610
|
-
const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "createdAt" DESC`;
|
|
1611
|
-
const rows = await this.db.manyOrNone(dataQuery, queryParams);
|
|
1612
|
-
return (rows || []).map((thread) => ({
|
|
1613
|
-
...thread,
|
|
1614
|
-
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
1615
|
-
createdAt: thread.createdAt,
|
|
1616
|
-
updatedAt: thread.updatedAt
|
|
1617
|
-
}));
|
|
1618
|
-
} catch (error) {
|
|
1619
|
-
this.logger.error(`Error getting threads for resource ${resourceId}:`, error);
|
|
1620
|
-
return [];
|
|
1621
1621
|
}
|
|
1622
|
-
}
|
|
1623
|
-
async getThreadsByResourceIdPaginated(args) {
|
|
1624
|
-
const { resourceId, page = 0, perPage: perPageInput } = args;
|
|
1625
1622
|
try {
|
|
1626
|
-
const
|
|
1627
|
-
const queryParams = [resourceId];
|
|
1628
|
-
const perPage = perPageInput !== void 0 ? perPageInput : 100;
|
|
1623
|
+
const perPage = perPageInput !== void 0 ? perPageInput : storage.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
1629
1624
|
const currentOffset = page * perPage;
|
|
1630
|
-
const
|
|
1631
|
-
const
|
|
1625
|
+
const conditions = [`thread_id = $1`];
|
|
1626
|
+
const queryParams = [threadId];
|
|
1627
|
+
let paramIndex = 2;
|
|
1628
|
+
if (fromDate) {
|
|
1629
|
+
conditions.push(`"createdAt" >= $${paramIndex++}`);
|
|
1630
|
+
queryParams.push(fromDate);
|
|
1631
|
+
}
|
|
1632
|
+
if (toDate) {
|
|
1633
|
+
conditions.push(`"createdAt" <= $${paramIndex++}`);
|
|
1634
|
+
queryParams.push(toDate);
|
|
1635
|
+
}
|
|
1636
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1637
|
+
const tableName = getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
|
|
1638
|
+
const countQuery = `SELECT COUNT(*) FROM ${tableName} ${whereClause}`;
|
|
1639
|
+
const countResult = await this.client.one(countQuery, queryParams);
|
|
1632
1640
|
const total = parseInt(countResult.count, 10);
|
|
1633
|
-
if (total === 0) {
|
|
1641
|
+
if (total === 0 && messages.length === 0) {
|
|
1634
1642
|
return {
|
|
1635
|
-
|
|
1643
|
+
messages: [],
|
|
1636
1644
|
total: 0,
|
|
1637
1645
|
page,
|
|
1638
1646
|
perPage,
|
|
1639
1647
|
hasMore: false
|
|
1640
1648
|
};
|
|
1641
1649
|
}
|
|
1642
|
-
const
|
|
1643
|
-
const
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1650
|
+
const excludeIds = messages.map((m) => m.id);
|
|
1651
|
+
const excludeIdsParam = excludeIds.map((_, idx) => `$${idx + paramIndex}`).join(", ");
|
|
1652
|
+
paramIndex += excludeIds.length;
|
|
1653
|
+
const dataQuery = `${selectStatement} FROM ${tableName} ${whereClause} ${excludeIds.length ? `AND id NOT IN (${excludeIdsParam})` : ""}${orderByStatement} LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
1654
|
+
const rows = await this.client.manyOrNone(dataQuery, [...queryParams, ...excludeIds, perPage, currentOffset]);
|
|
1655
|
+
messages.push(...rows || []);
|
|
1656
|
+
const messagesWithParsedContent = messages.map((message) => {
|
|
1657
|
+
if (typeof message.content === "string") {
|
|
1658
|
+
try {
|
|
1659
|
+
return { ...message, content: JSON.parse(message.content) };
|
|
1660
|
+
} catch {
|
|
1661
|
+
return message;
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
return message;
|
|
1665
|
+
});
|
|
1666
|
+
const list = new agent.MessageList().add(messagesWithParsedContent, "memory");
|
|
1667
|
+
const messagesToReturn = format === `v2` ? list.get.all.v2() : list.get.all.v1();
|
|
1651
1668
|
return {
|
|
1652
|
-
|
|
1669
|
+
messages: messagesToReturn,
|
|
1653
1670
|
total,
|
|
1654
1671
|
page,
|
|
1655
1672
|
perPage,
|
|
1656
|
-
hasMore: currentOffset +
|
|
1673
|
+
hasMore: currentOffset + rows.length < total
|
|
1657
1674
|
};
|
|
1658
1675
|
} catch (error$1) {
|
|
1659
1676
|
const mastraError = new error.MastraError(
|
|
1660
1677
|
{
|
|
1661
|
-
id: "
|
|
1678
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_MESSAGES_PAGINATED_FAILED",
|
|
1662
1679
|
domain: error.ErrorDomain.STORAGE,
|
|
1663
1680
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1664
1681
|
details: {
|
|
1665
|
-
|
|
1682
|
+
threadId,
|
|
1666
1683
|
page
|
|
1667
1684
|
}
|
|
1668
1685
|
},
|
|
@@ -1670,872 +1687,1348 @@ var PostgresStore = class extends storage.MastraStorage {
|
|
|
1670
1687
|
);
|
|
1671
1688
|
this.logger?.error?.(mastraError.toString());
|
|
1672
1689
|
this.logger?.trackException(mastraError);
|
|
1673
|
-
return {
|
|
1690
|
+
return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
|
|
1674
1691
|
}
|
|
1675
1692
|
}
|
|
1676
|
-
async
|
|
1693
|
+
async saveMessages({
|
|
1694
|
+
messages,
|
|
1695
|
+
format
|
|
1696
|
+
}) {
|
|
1697
|
+
if (messages.length === 0) return messages;
|
|
1698
|
+
const threadId = messages[0]?.threadId;
|
|
1699
|
+
if (!threadId) {
|
|
1700
|
+
throw new error.MastraError({
|
|
1701
|
+
id: "MASTRA_STORAGE_PG_STORE_SAVE_MESSAGES_FAILED",
|
|
1702
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1703
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1704
|
+
text: `Thread ID is required`
|
|
1705
|
+
});
|
|
1706
|
+
}
|
|
1707
|
+
const thread = await this.getThreadById({ threadId });
|
|
1708
|
+
if (!thread) {
|
|
1709
|
+
throw new error.MastraError({
|
|
1710
|
+
id: "MASTRA_STORAGE_PG_STORE_SAVE_MESSAGES_FAILED",
|
|
1711
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1712
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1713
|
+
text: `Thread ${threadId} not found`,
|
|
1714
|
+
details: {
|
|
1715
|
+
threadId
|
|
1716
|
+
}
|
|
1717
|
+
});
|
|
1718
|
+
}
|
|
1677
1719
|
try {
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1720
|
+
const tableName = getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) });
|
|
1721
|
+
await this.client.tx(async (t) => {
|
|
1722
|
+
const messageInserts = messages.map((message) => {
|
|
1723
|
+
if (!message.threadId) {
|
|
1724
|
+
throw new Error(
|
|
1725
|
+
`Expected to find a threadId for message, but couldn't find one. An unexpected error has occurred.`
|
|
1726
|
+
);
|
|
1727
|
+
}
|
|
1728
|
+
if (!message.resourceId) {
|
|
1729
|
+
throw new Error(
|
|
1730
|
+
`Expected to find a resourceId for message, but couldn't find one. An unexpected error has occurred.`
|
|
1731
|
+
);
|
|
1732
|
+
}
|
|
1733
|
+
return t.none(
|
|
1734
|
+
`INSERT INTO ${tableName} (id, thread_id, content, "createdAt", "createdAtZ", role, type, "resourceId")
|
|
1735
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
1736
|
+
ON CONFLICT (id) DO UPDATE SET
|
|
1737
|
+
thread_id = EXCLUDED.thread_id,
|
|
1738
|
+
content = EXCLUDED.content,
|
|
1739
|
+
role = EXCLUDED.role,
|
|
1740
|
+
type = EXCLUDED.type,
|
|
1741
|
+
"resourceId" = EXCLUDED."resourceId"`,
|
|
1742
|
+
[
|
|
1743
|
+
message.id,
|
|
1744
|
+
message.threadId,
|
|
1745
|
+
typeof message.content === "string" ? message.content : JSON.stringify(message.content),
|
|
1746
|
+
message.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
|
|
1747
|
+
message.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
|
|
1748
|
+
message.role,
|
|
1749
|
+
message.type || "v2",
|
|
1750
|
+
message.resourceId
|
|
1751
|
+
]
|
|
1752
|
+
);
|
|
1753
|
+
});
|
|
1754
|
+
const threadTableName = getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) });
|
|
1755
|
+
const threadUpdate = t.none(
|
|
1756
|
+
`UPDATE ${threadTableName}
|
|
1757
|
+
SET
|
|
1758
|
+
"updatedAt" = $1,
|
|
1759
|
+
"updatedAtZ" = $1
|
|
1760
|
+
WHERE id = $2
|
|
1761
|
+
`,
|
|
1762
|
+
[(/* @__PURE__ */ new Date()).toISOString(), threadId]
|
|
1763
|
+
);
|
|
1764
|
+
await Promise.all([...messageInserts, threadUpdate]);
|
|
1765
|
+
});
|
|
1766
|
+
const messagesWithParsedContent = messages.map((message) => {
|
|
1767
|
+
if (typeof message.content === "string") {
|
|
1768
|
+
try {
|
|
1769
|
+
return { ...message, content: JSON.parse(message.content) };
|
|
1770
|
+
} catch {
|
|
1771
|
+
return message;
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
return message;
|
|
1775
|
+
});
|
|
1776
|
+
const list = new agent.MessageList().add(messagesWithParsedContent, "memory");
|
|
1777
|
+
if (format === `v2`) return list.get.all.v2();
|
|
1778
|
+
return list.get.all.v1();
|
|
1703
1779
|
} catch (error$1) {
|
|
1704
1780
|
throw new error.MastraError(
|
|
1705
1781
|
{
|
|
1706
|
-
id: "
|
|
1782
|
+
id: "MASTRA_STORAGE_PG_STORE_SAVE_MESSAGES_FAILED",
|
|
1707
1783
|
domain: error.ErrorDomain.STORAGE,
|
|
1708
1784
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1709
1785
|
details: {
|
|
1710
|
-
threadId
|
|
1786
|
+
threadId
|
|
1711
1787
|
}
|
|
1712
1788
|
},
|
|
1713
1789
|
error$1
|
|
1714
1790
|
);
|
|
1715
1791
|
}
|
|
1716
1792
|
}
|
|
1717
|
-
async
|
|
1718
|
-
|
|
1719
|
-
title,
|
|
1720
|
-
metadata
|
|
1793
|
+
async updateMessages({
|
|
1794
|
+
messages
|
|
1721
1795
|
}) {
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1796
|
+
if (messages.length === 0) {
|
|
1797
|
+
return [];
|
|
1798
|
+
}
|
|
1799
|
+
const messageIds = messages.map((m) => m.id);
|
|
1800
|
+
const selectQuery = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId", "resourceId" FROM ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} WHERE id IN ($1:list)`;
|
|
1801
|
+
const existingMessagesDb = await this.client.manyOrNone(selectQuery, [messageIds]);
|
|
1802
|
+
if (existingMessagesDb.length === 0) {
|
|
1803
|
+
return [];
|
|
1804
|
+
}
|
|
1805
|
+
const existingMessages = existingMessagesDb.map((msg) => {
|
|
1806
|
+
if (typeof msg.content === "string") {
|
|
1807
|
+
try {
|
|
1808
|
+
msg.content = JSON.parse(msg.content);
|
|
1809
|
+
} catch {
|
|
1732
1810
|
}
|
|
1733
|
-
}
|
|
1811
|
+
}
|
|
1812
|
+
return msg;
|
|
1813
|
+
});
|
|
1814
|
+
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
1815
|
+
await this.client.tx(async (t) => {
|
|
1816
|
+
const queries = [];
|
|
1817
|
+
const columnMapping = {
|
|
1818
|
+
threadId: "thread_id"
|
|
1819
|
+
};
|
|
1820
|
+
for (const existingMessage of existingMessages) {
|
|
1821
|
+
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
1822
|
+
if (!updatePayload) continue;
|
|
1823
|
+
const { id, ...fieldsToUpdate } = updatePayload;
|
|
1824
|
+
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
1825
|
+
threadIdsToUpdate.add(existingMessage.threadId);
|
|
1826
|
+
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
1827
|
+
threadIdsToUpdate.add(updatePayload.threadId);
|
|
1828
|
+
}
|
|
1829
|
+
const setClauses = [];
|
|
1830
|
+
const values = [];
|
|
1831
|
+
let paramIndex = 1;
|
|
1832
|
+
const updatableFields = { ...fieldsToUpdate };
|
|
1833
|
+
if (updatableFields.content) {
|
|
1834
|
+
const newContent = {
|
|
1835
|
+
...existingMessage.content,
|
|
1836
|
+
...updatableFields.content,
|
|
1837
|
+
// Deep merge metadata if it exists on both
|
|
1838
|
+
...existingMessage.content?.metadata && updatableFields.content.metadata ? {
|
|
1839
|
+
metadata: {
|
|
1840
|
+
...existingMessage.content.metadata,
|
|
1841
|
+
...updatableFields.content.metadata
|
|
1842
|
+
}
|
|
1843
|
+
} : {}
|
|
1844
|
+
};
|
|
1845
|
+
setClauses.push(`content = $${paramIndex++}`);
|
|
1846
|
+
values.push(newContent);
|
|
1847
|
+
delete updatableFields.content;
|
|
1848
|
+
}
|
|
1849
|
+
for (const key in updatableFields) {
|
|
1850
|
+
if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
|
|
1851
|
+
const dbColumn = columnMapping[key] || key;
|
|
1852
|
+
setClauses.push(`"${dbColumn}" = $${paramIndex++}`);
|
|
1853
|
+
values.push(updatableFields[key]);
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
if (setClauses.length > 0) {
|
|
1857
|
+
values.push(id);
|
|
1858
|
+
const sql = `UPDATE ${getTableName({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName(this.schema) })} SET ${setClauses.join(", ")} WHERE id = $${paramIndex}`;
|
|
1859
|
+
queries.push(t.none(sql, values));
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
if (threadIdsToUpdate.size > 0) {
|
|
1863
|
+
queries.push(
|
|
1864
|
+
t.none(
|
|
1865
|
+
`UPDATE ${getTableName({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName(this.schema) })} SET "updatedAt" = NOW(), "updatedAtZ" = NOW() WHERE id IN ($1:list)`,
|
|
1866
|
+
[Array.from(threadIdsToUpdate)]
|
|
1867
|
+
)
|
|
1868
|
+
);
|
|
1869
|
+
}
|
|
1870
|
+
if (queries.length > 0) {
|
|
1871
|
+
await t.batch(queries);
|
|
1872
|
+
}
|
|
1873
|
+
});
|
|
1874
|
+
const updatedMessages = await this.client.manyOrNone(selectQuery, [messageIds]);
|
|
1875
|
+
return (updatedMessages || []).map((message) => {
|
|
1876
|
+
if (typeof message.content === "string") {
|
|
1877
|
+
try {
|
|
1878
|
+
message.content = JSON.parse(message.content);
|
|
1879
|
+
} catch {
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
return message;
|
|
1883
|
+
});
|
|
1884
|
+
}
|
|
1885
|
+
async getResourceById({ resourceId }) {
|
|
1886
|
+
const tableName = getTableName({ indexName: storage.TABLE_RESOURCES, schemaName: getSchemaName(this.schema) });
|
|
1887
|
+
const result = await this.client.oneOrNone(
|
|
1888
|
+
`SELECT * FROM ${tableName} WHERE id = $1`,
|
|
1889
|
+
[resourceId]
|
|
1890
|
+
);
|
|
1891
|
+
if (!result) {
|
|
1892
|
+
return null;
|
|
1734
1893
|
}
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1894
|
+
return {
|
|
1895
|
+
id: result.id,
|
|
1896
|
+
createdAt: result.createdAtZ || result.createdAt,
|
|
1897
|
+
updatedAt: result.updatedAtZ || result.updatedAt,
|
|
1898
|
+
workingMemory: result.workingMemory,
|
|
1899
|
+
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
|
|
1900
|
+
};
|
|
1901
|
+
}
|
|
1902
|
+
async saveResource({ resource }) {
|
|
1903
|
+
await this.operations.insert({
|
|
1904
|
+
tableName: storage.TABLE_RESOURCES,
|
|
1905
|
+
record: {
|
|
1906
|
+
...resource,
|
|
1907
|
+
metadata: JSON.stringify(resource.metadata)
|
|
1908
|
+
}
|
|
1909
|
+
});
|
|
1910
|
+
return resource;
|
|
1911
|
+
}
|
|
1912
|
+
async updateResource({
|
|
1913
|
+
resourceId,
|
|
1914
|
+
workingMemory,
|
|
1915
|
+
metadata
|
|
1916
|
+
}) {
|
|
1917
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
1918
|
+
if (!existingResource) {
|
|
1919
|
+
const newResource = {
|
|
1920
|
+
id: resourceId,
|
|
1921
|
+
workingMemory,
|
|
1922
|
+
metadata: metadata || {},
|
|
1923
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1924
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1925
|
+
};
|
|
1926
|
+
return this.saveResource({ resource: newResource });
|
|
1927
|
+
}
|
|
1928
|
+
const updatedResource = {
|
|
1929
|
+
...existingResource,
|
|
1930
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
1931
|
+
metadata: {
|
|
1932
|
+
...existingResource.metadata,
|
|
1933
|
+
...metadata
|
|
1934
|
+
},
|
|
1935
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1738
1936
|
};
|
|
1937
|
+
const tableName = getTableName({ indexName: storage.TABLE_RESOURCES, schemaName: getSchemaName(this.schema) });
|
|
1938
|
+
const updates = [];
|
|
1939
|
+
const values = [];
|
|
1940
|
+
let paramIndex = 1;
|
|
1941
|
+
if (workingMemory !== void 0) {
|
|
1942
|
+
updates.push(`"workingMemory" = $${paramIndex}`);
|
|
1943
|
+
values.push(workingMemory);
|
|
1944
|
+
paramIndex++;
|
|
1945
|
+
}
|
|
1946
|
+
if (metadata) {
|
|
1947
|
+
updates.push(`metadata = $${paramIndex}`);
|
|
1948
|
+
values.push(JSON.stringify(updatedResource.metadata));
|
|
1949
|
+
paramIndex++;
|
|
1950
|
+
}
|
|
1951
|
+
updates.push(`"updatedAt" = $${paramIndex}`);
|
|
1952
|
+
values.push(updatedResource.updatedAt.toISOString());
|
|
1953
|
+
updates.push(`"updatedAtZ" = $${paramIndex++}`);
|
|
1954
|
+
values.push(updatedResource.updatedAt.toISOString());
|
|
1955
|
+
paramIndex++;
|
|
1956
|
+
values.push(resourceId);
|
|
1957
|
+
await this.client.none(`UPDATE ${tableName} SET ${updates.join(", ")} WHERE id = $${paramIndex}`, values);
|
|
1958
|
+
return updatedResource;
|
|
1959
|
+
}
|
|
1960
|
+
};
|
|
1961
|
+
var StoreOperationsPG = class extends storage.StoreOperations {
|
|
1962
|
+
client;
|
|
1963
|
+
schemaName;
|
|
1964
|
+
setupSchemaPromise = null;
|
|
1965
|
+
schemaSetupComplete = void 0;
|
|
1966
|
+
constructor({ client, schemaName }) {
|
|
1967
|
+
super();
|
|
1968
|
+
this.client = client;
|
|
1969
|
+
this.schemaName = schemaName;
|
|
1970
|
+
}
|
|
1971
|
+
async hasColumn(table, column) {
|
|
1972
|
+
const schema = this.schemaName || "public";
|
|
1973
|
+
const result = await this.client.oneOrNone(
|
|
1974
|
+
`SELECT 1 FROM information_schema.columns WHERE table_schema = $1 AND table_name = $2 AND (column_name = $3 OR column_name = $4)`,
|
|
1975
|
+
[schema, table, column, column.toLowerCase()]
|
|
1976
|
+
);
|
|
1977
|
+
return !!result;
|
|
1978
|
+
}
|
|
1979
|
+
async setupSchema() {
|
|
1980
|
+
if (!this.schemaName || this.schemaSetupComplete) {
|
|
1981
|
+
return;
|
|
1982
|
+
}
|
|
1983
|
+
const schemaName = getSchemaName(this.schemaName);
|
|
1984
|
+
if (!this.setupSchemaPromise) {
|
|
1985
|
+
this.setupSchemaPromise = (async () => {
|
|
1986
|
+
try {
|
|
1987
|
+
const schemaExists = await this.client.oneOrNone(
|
|
1988
|
+
`
|
|
1989
|
+
SELECT EXISTS (
|
|
1990
|
+
SELECT 1 FROM information_schema.schemata
|
|
1991
|
+
WHERE schema_name = $1
|
|
1992
|
+
)
|
|
1993
|
+
`,
|
|
1994
|
+
[this.schemaName]
|
|
1995
|
+
);
|
|
1996
|
+
if (!schemaExists?.exists) {
|
|
1997
|
+
try {
|
|
1998
|
+
await this.client.none(`CREATE SCHEMA IF NOT EXISTS ${schemaName}`);
|
|
1999
|
+
this.logger.info(`Schema "${this.schemaName}" created successfully`);
|
|
2000
|
+
} catch (error) {
|
|
2001
|
+
this.logger.error(`Failed to create schema "${this.schemaName}"`, { error });
|
|
2002
|
+
throw new Error(
|
|
2003
|
+
`Unable to create schema "${this.schemaName}". This requires CREATE privilege on the database. Either create the schema manually or grant CREATE privilege to the user.`
|
|
2004
|
+
);
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
this.schemaSetupComplete = true;
|
|
2008
|
+
this.logger.debug(`Schema "${schemaName}" is ready for use`);
|
|
2009
|
+
} catch (error) {
|
|
2010
|
+
this.schemaSetupComplete = void 0;
|
|
2011
|
+
this.setupSchemaPromise = null;
|
|
2012
|
+
throw error;
|
|
2013
|
+
} finally {
|
|
2014
|
+
this.setupSchemaPromise = null;
|
|
2015
|
+
}
|
|
2016
|
+
})();
|
|
2017
|
+
}
|
|
2018
|
+
await this.setupSchemaPromise;
|
|
2019
|
+
}
|
|
2020
|
+
async insert({ tableName, record }) {
|
|
1739
2021
|
try {
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
2022
|
+
if (record.createdAt) {
|
|
2023
|
+
record.createdAtZ = record.createdAt;
|
|
2024
|
+
}
|
|
2025
|
+
if (record.created_at) {
|
|
2026
|
+
record.created_atZ = record.created_at;
|
|
2027
|
+
}
|
|
2028
|
+
if (record.updatedAt) {
|
|
2029
|
+
record.updatedAtZ = record.updatedAt;
|
|
2030
|
+
}
|
|
2031
|
+
const schemaName = getSchemaName(this.schemaName);
|
|
2032
|
+
const columns = Object.keys(record).map((col) => utils.parseSqlIdentifier(col, "column name"));
|
|
2033
|
+
const values = Object.values(record);
|
|
2034
|
+
const placeholders = values.map((_, i) => `$${i + 1}`).join(", ");
|
|
2035
|
+
await this.client.none(
|
|
2036
|
+
`INSERT INTO ${getTableName({ indexName: tableName, schemaName })} (${columns.map((c) => `"${c}"`).join(", ")}) VALUES (${placeholders})`,
|
|
2037
|
+
values
|
|
1748
2038
|
);
|
|
1749
|
-
return {
|
|
1750
|
-
...thread,
|
|
1751
|
-
metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
|
|
1752
|
-
createdAt: thread.createdAt,
|
|
1753
|
-
updatedAt: thread.updatedAt
|
|
1754
|
-
};
|
|
1755
2039
|
} catch (error$1) {
|
|
1756
2040
|
throw new error.MastraError(
|
|
1757
2041
|
{
|
|
1758
|
-
id: "
|
|
2042
|
+
id: "MASTRA_STORAGE_PG_STORE_INSERT_FAILED",
|
|
1759
2043
|
domain: error.ErrorDomain.STORAGE,
|
|
1760
2044
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1761
2045
|
details: {
|
|
1762
|
-
|
|
1763
|
-
title
|
|
2046
|
+
tableName
|
|
1764
2047
|
}
|
|
1765
2048
|
},
|
|
1766
2049
|
error$1
|
|
1767
2050
|
);
|
|
1768
2051
|
}
|
|
1769
2052
|
}
|
|
1770
|
-
async
|
|
2053
|
+
async clearTable({ tableName }) {
|
|
1771
2054
|
try {
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
});
|
|
2055
|
+
const schemaName = getSchemaName(this.schemaName);
|
|
2056
|
+
const tableNameWithSchema = getTableName({ indexName: tableName, schemaName });
|
|
2057
|
+
await this.client.none(`TRUNCATE TABLE ${tableNameWithSchema} CASCADE`);
|
|
1776
2058
|
} catch (error$1) {
|
|
1777
2059
|
throw new error.MastraError(
|
|
1778
2060
|
{
|
|
1779
|
-
id: "
|
|
2061
|
+
id: "MASTRA_STORAGE_PG_STORE_CLEAR_TABLE_FAILED",
|
|
1780
2062
|
domain: error.ErrorDomain.STORAGE,
|
|
1781
2063
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1782
2064
|
details: {
|
|
1783
|
-
|
|
2065
|
+
tableName
|
|
1784
2066
|
}
|
|
1785
2067
|
},
|
|
1786
2068
|
error$1
|
|
1787
2069
|
);
|
|
1788
2070
|
}
|
|
1789
2071
|
}
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
2072
|
+
getDefaultValue(type) {
|
|
2073
|
+
switch (type) {
|
|
2074
|
+
case "timestamp":
|
|
2075
|
+
return "DEFAULT NOW()";
|
|
2076
|
+
case "jsonb":
|
|
2077
|
+
return "DEFAULT '{}'::jsonb";
|
|
2078
|
+
default:
|
|
2079
|
+
return super.getDefaultValue(type);
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
async createTable({
|
|
2083
|
+
tableName,
|
|
2084
|
+
schema
|
|
1794
2085
|
}) {
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
const
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
2086
|
+
try {
|
|
2087
|
+
const timeZColumnNames = Object.entries(schema).filter(([_, def]) => def.type === "timestamp").map(([name]) => name);
|
|
2088
|
+
const timeZColumns = Object.entries(schema).filter(([_, def]) => def.type === "timestamp").map(([name]) => {
|
|
2089
|
+
const parsedName = utils.parseSqlIdentifier(name, "column name");
|
|
2090
|
+
return `"${parsedName}Z" TIMESTAMPTZ DEFAULT NOW()`;
|
|
2091
|
+
});
|
|
2092
|
+
const columns = Object.entries(schema).map(([name, def]) => {
|
|
2093
|
+
const parsedName = utils.parseSqlIdentifier(name, "column name");
|
|
2094
|
+
const constraints = [];
|
|
2095
|
+
if (def.primaryKey) constraints.push("PRIMARY KEY");
|
|
2096
|
+
if (!def.nullable) constraints.push("NOT NULL");
|
|
2097
|
+
return `"${parsedName}" ${def.type.toUpperCase()} ${constraints.join(" ")}`;
|
|
2098
|
+
});
|
|
2099
|
+
if (this.schemaName) {
|
|
2100
|
+
await this.setupSchema();
|
|
2101
|
+
}
|
|
2102
|
+
const finalColumns = [...columns, ...timeZColumns].join(",\n");
|
|
2103
|
+
const sql = `
|
|
2104
|
+
CREATE TABLE IF NOT EXISTS ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} (
|
|
2105
|
+
${finalColumns}
|
|
2106
|
+
);
|
|
2107
|
+
${tableName === storage.TABLE_WORKFLOW_SNAPSHOT ? `
|
|
2108
|
+
DO $$ BEGIN
|
|
2109
|
+
IF NOT EXISTS (
|
|
2110
|
+
SELECT 1 FROM pg_constraint WHERE conname = 'mastra_workflow_snapshot_workflow_name_run_id_key'
|
|
2111
|
+
) THEN
|
|
2112
|
+
ALTER TABLE ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })}
|
|
2113
|
+
ADD CONSTRAINT mastra_workflow_snapshot_workflow_name_run_id_key
|
|
2114
|
+
UNIQUE (workflow_name, run_id);
|
|
2115
|
+
END IF;
|
|
2116
|
+
END $$;
|
|
2117
|
+
` : ""}
|
|
2118
|
+
`;
|
|
2119
|
+
await this.client.none(sql);
|
|
2120
|
+
console.log("Alter Table SQL", tableName);
|
|
2121
|
+
console.log("timeZColumnNames", timeZColumnNames);
|
|
2122
|
+
await this.alterTable({
|
|
2123
|
+
tableName,
|
|
2124
|
+
schema,
|
|
2125
|
+
ifNotExists: timeZColumnNames
|
|
2126
|
+
});
|
|
2127
|
+
} catch (error$1) {
|
|
2128
|
+
throw new error.MastraError(
|
|
2129
|
+
{
|
|
2130
|
+
id: "MASTRA_STORAGE_PG_STORE_CREATE_TABLE_FAILED",
|
|
2131
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2132
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2133
|
+
details: {
|
|
2134
|
+
tableName
|
|
2135
|
+
}
|
|
2136
|
+
},
|
|
2137
|
+
error$1
|
|
1837
2138
|
);
|
|
1838
|
-
params.push(searchId, id, withPreviousMessages, withNextMessages);
|
|
1839
|
-
paramIdx += 4;
|
|
1840
2139
|
}
|
|
1841
|
-
const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
|
|
1842
|
-
const includedRows = await this.db.manyOrNone(finalQuery, params);
|
|
1843
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1844
|
-
const dedupedRows = includedRows.filter((row) => {
|
|
1845
|
-
if (seen.has(row.id)) return false;
|
|
1846
|
-
seen.add(row.id);
|
|
1847
|
-
return true;
|
|
1848
|
-
});
|
|
1849
|
-
return dedupedRows;
|
|
1850
2140
|
}
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
2141
|
+
/**
|
|
2142
|
+
* Alters table schema to add columns if they don't exist
|
|
2143
|
+
* @param tableName Name of the table
|
|
2144
|
+
* @param schema Schema of the table
|
|
2145
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
2146
|
+
*/
|
|
2147
|
+
async alterTable({
|
|
2148
|
+
tableName,
|
|
2149
|
+
schema,
|
|
2150
|
+
ifNotExists
|
|
2151
|
+
}) {
|
|
2152
|
+
const fullTableName = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
|
|
1856
2153
|
try {
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
${orderByStatement}
|
|
1870
|
-
LIMIT $${excludeIds.length + 2}
|
|
1871
|
-
`;
|
|
1872
|
-
const queryParams = [threadId, ...excludeIds, limit];
|
|
1873
|
-
const remainingRows = await this.db.manyOrNone(query, queryParams);
|
|
1874
|
-
rows.push(...remainingRows);
|
|
1875
|
-
const fetchedMessages = (rows || []).map((message) => {
|
|
1876
|
-
if (typeof message.content === "string") {
|
|
1877
|
-
try {
|
|
1878
|
-
message.content = JSON.parse(message.content);
|
|
1879
|
-
} catch {
|
|
2154
|
+
for (const columnName of ifNotExists) {
|
|
2155
|
+
if (schema[columnName]) {
|
|
2156
|
+
const columnDef = schema[columnName];
|
|
2157
|
+
const sqlType = this.getSqlType(columnDef.type);
|
|
2158
|
+
const nullable = columnDef.nullable === false ? "NOT NULL" : "";
|
|
2159
|
+
const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
|
|
2160
|
+
const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
|
|
2161
|
+
const alterSql = `ALTER TABLE ${fullTableName} ADD COLUMN IF NOT EXISTS "${parsedColumnName}" ${sqlType} ${nullable} ${defaultValue}`.trim();
|
|
2162
|
+
await this.client.none(alterSql);
|
|
2163
|
+
if (sqlType === "TIMESTAMP") {
|
|
2164
|
+
const alterSql2 = `ALTER TABLE ${fullTableName} ADD COLUMN IF NOT EXISTS "${parsedColumnName}Z" TIMESTAMPTZ DEFAULT NOW()`.trim();
|
|
2165
|
+
await this.client.none(alterSql2);
|
|
1880
2166
|
}
|
|
2167
|
+
this.logger?.debug?.(`Ensured column ${parsedColumnName} exists in table ${fullTableName}`);
|
|
1881
2168
|
}
|
|
1882
|
-
|
|
1883
|
-
return message;
|
|
1884
|
-
});
|
|
1885
|
-
const sortedMessages = fetchedMessages.sort(
|
|
1886
|
-
(a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
|
|
1887
|
-
);
|
|
1888
|
-
return format === "v2" ? sortedMessages.map(
|
|
1889
|
-
(m) => ({ ...m, content: m.content || { format: 2, parts: [{ type: "text", text: "" }] } })
|
|
1890
|
-
) : sortedMessages;
|
|
2169
|
+
}
|
|
1891
2170
|
} catch (error$1) {
|
|
1892
|
-
|
|
2171
|
+
throw new error.MastraError(
|
|
1893
2172
|
{
|
|
1894
|
-
id: "
|
|
2173
|
+
id: "MASTRA_STORAGE_PG_STORE_ALTER_TABLE_FAILED",
|
|
1895
2174
|
domain: error.ErrorDomain.STORAGE,
|
|
1896
2175
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1897
2176
|
details: {
|
|
1898
|
-
|
|
2177
|
+
tableName
|
|
1899
2178
|
}
|
|
1900
2179
|
},
|
|
1901
2180
|
error$1
|
|
1902
2181
|
);
|
|
1903
|
-
this.logger?.error?.(mastraError.toString());
|
|
1904
|
-
this.logger?.trackException(mastraError);
|
|
1905
|
-
return [];
|
|
1906
2182
|
}
|
|
1907
2183
|
}
|
|
1908
|
-
async
|
|
1909
|
-
const { threadId, format, selectBy } = args;
|
|
1910
|
-
const { page = 0, perPage: perPageInput, dateRange } = selectBy?.pagination || {};
|
|
1911
|
-
const fromDate = dateRange?.start;
|
|
1912
|
-
const toDate = dateRange?.end;
|
|
1913
|
-
const selectStatement = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId", "resourceId"`;
|
|
1914
|
-
const orderByStatement = `ORDER BY "createdAt" DESC`;
|
|
1915
|
-
const messages = [];
|
|
1916
|
-
if (selectBy?.include?.length) {
|
|
1917
|
-
const includeMessages = await this._getIncludedMessages({ threadId, selectBy, orderByStatement });
|
|
1918
|
-
if (includeMessages) {
|
|
1919
|
-
messages.push(...includeMessages);
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
2184
|
+
async load({ tableName, keys }) {
|
|
1922
2185
|
try {
|
|
1923
|
-
const
|
|
1924
|
-
const
|
|
1925
|
-
const
|
|
1926
|
-
const
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
if (toDate) {
|
|
1933
|
-
conditions.push(`"createdAt" <= $${paramIndex++}`);
|
|
1934
|
-
queryParams.push(toDate);
|
|
1935
|
-
}
|
|
1936
|
-
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1937
|
-
const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(storage.TABLE_MESSAGES)} ${whereClause}`;
|
|
1938
|
-
const countResult = await this.db.one(countQuery, queryParams);
|
|
1939
|
-
const total = parseInt(countResult.count, 10);
|
|
1940
|
-
if (total === 0 && messages.length === 0) {
|
|
1941
|
-
return {
|
|
1942
|
-
messages: [],
|
|
1943
|
-
total: 0,
|
|
1944
|
-
page,
|
|
1945
|
-
perPage,
|
|
1946
|
-
hasMore: false
|
|
1947
|
-
};
|
|
2186
|
+
const keyEntries = Object.entries(keys).map(([key, value]) => [utils.parseSqlIdentifier(key, "column name"), value]);
|
|
2187
|
+
const conditions = keyEntries.map(([key], index) => `"${key}" = $${index + 1}`).join(" AND ");
|
|
2188
|
+
const values = keyEntries.map(([_, value]) => value);
|
|
2189
|
+
const result = await this.client.oneOrNone(
|
|
2190
|
+
`SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions}`,
|
|
2191
|
+
values
|
|
2192
|
+
);
|
|
2193
|
+
if (!result) {
|
|
2194
|
+
return null;
|
|
1948
2195
|
}
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
storage.TABLE_MESSAGES
|
|
1954
|
-
)} ${whereClause} ${excludeIds.length ? `AND id NOT IN (${excludeIdsParam})` : ""}${orderByStatement} LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
|
|
1955
|
-
const rows = await this.db.manyOrNone(dataQuery, [...queryParams, ...excludeIds, perPage, currentOffset]);
|
|
1956
|
-
messages.push(...rows || []);
|
|
1957
|
-
const messagesWithParsedContent = messages.map((message) => {
|
|
1958
|
-
if (typeof message.content === "string") {
|
|
1959
|
-
try {
|
|
1960
|
-
return { ...message, content: JSON.parse(message.content) };
|
|
1961
|
-
} catch {
|
|
1962
|
-
return message;
|
|
1963
|
-
}
|
|
2196
|
+
if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
|
|
2197
|
+
const snapshot = result;
|
|
2198
|
+
if (typeof snapshot.snapshot === "string") {
|
|
2199
|
+
snapshot.snapshot = JSON.parse(snapshot.snapshot);
|
|
1964
2200
|
}
|
|
1965
|
-
return
|
|
1966
|
-
}
|
|
1967
|
-
|
|
1968
|
-
const messagesToReturn = format === `v2` ? list.get.all.v2() : list.get.all.v1();
|
|
1969
|
-
return {
|
|
1970
|
-
messages: messagesToReturn,
|
|
1971
|
-
total,
|
|
1972
|
-
page,
|
|
1973
|
-
perPage,
|
|
1974
|
-
hasMore: currentOffset + rows.length < total
|
|
1975
|
-
};
|
|
2201
|
+
return snapshot;
|
|
2202
|
+
}
|
|
2203
|
+
return result;
|
|
1976
2204
|
} catch (error$1) {
|
|
1977
|
-
|
|
2205
|
+
throw new error.MastraError(
|
|
1978
2206
|
{
|
|
1979
|
-
id: "
|
|
2207
|
+
id: "MASTRA_STORAGE_PG_STORE_LOAD_FAILED",
|
|
1980
2208
|
domain: error.ErrorDomain.STORAGE,
|
|
1981
2209
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1982
2210
|
details: {
|
|
1983
|
-
|
|
1984
|
-
page
|
|
2211
|
+
tableName
|
|
1985
2212
|
}
|
|
1986
2213
|
},
|
|
1987
2214
|
error$1
|
|
1988
2215
|
);
|
|
1989
|
-
this.logger?.error?.(mastraError.toString());
|
|
1990
|
-
this.logger?.trackException(mastraError);
|
|
1991
|
-
return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
|
|
1992
2216
|
}
|
|
1993
2217
|
}
|
|
1994
|
-
async
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
details: {
|
|
2016
|
-
threadId
|
|
2017
|
-
}
|
|
2018
|
-
});
|
|
2218
|
+
async batchInsert({ tableName, records }) {
|
|
2219
|
+
try {
|
|
2220
|
+
await this.client.query("BEGIN");
|
|
2221
|
+
for (const record of records) {
|
|
2222
|
+
await this.insert({ tableName, record });
|
|
2223
|
+
}
|
|
2224
|
+
await this.client.query("COMMIT");
|
|
2225
|
+
} catch (error$1) {
|
|
2226
|
+
await this.client.query("ROLLBACK");
|
|
2227
|
+
throw new error.MastraError(
|
|
2228
|
+
{
|
|
2229
|
+
id: "MASTRA_STORAGE_PG_STORE_BATCH_INSERT_FAILED",
|
|
2230
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2231
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2232
|
+
details: {
|
|
2233
|
+
tableName,
|
|
2234
|
+
numberOfRecords: records.length
|
|
2235
|
+
}
|
|
2236
|
+
},
|
|
2237
|
+
error$1
|
|
2238
|
+
);
|
|
2019
2239
|
}
|
|
2240
|
+
}
|
|
2241
|
+
async dropTable({ tableName }) {
|
|
2020
2242
|
try {
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
}
|
|
2033
|
-
return t.none(
|
|
2034
|
-
`INSERT INTO ${this.getTableName(storage.TABLE_MESSAGES)} (id, thread_id, content, "createdAt", role, type, "resourceId")
|
|
2035
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
2036
|
-
ON CONFLICT (id) DO UPDATE SET
|
|
2037
|
-
thread_id = EXCLUDED.thread_id,
|
|
2038
|
-
content = EXCLUDED.content,
|
|
2039
|
-
role = EXCLUDED.role,
|
|
2040
|
-
type = EXCLUDED.type,
|
|
2041
|
-
"resourceId" = EXCLUDED."resourceId"`,
|
|
2042
|
-
[
|
|
2043
|
-
message.id,
|
|
2044
|
-
message.threadId,
|
|
2045
|
-
typeof message.content === "string" ? message.content : JSON.stringify(message.content),
|
|
2046
|
-
message.createdAt || (/* @__PURE__ */ new Date()).toISOString(),
|
|
2047
|
-
message.role,
|
|
2048
|
-
message.type || "v2",
|
|
2049
|
-
message.resourceId
|
|
2050
|
-
]
|
|
2051
|
-
);
|
|
2052
|
-
});
|
|
2053
|
-
const threadUpdate = t.none(
|
|
2054
|
-
`UPDATE ${this.getTableName(storage.TABLE_THREADS)}
|
|
2055
|
-
SET "updatedAt" = $1
|
|
2056
|
-
WHERE id = $2`,
|
|
2057
|
-
[(/* @__PURE__ */ new Date()).toISOString(), threadId]
|
|
2058
|
-
);
|
|
2059
|
-
await Promise.all([...messageInserts, threadUpdate]);
|
|
2060
|
-
});
|
|
2061
|
-
const messagesWithParsedContent = messages.map((message) => {
|
|
2062
|
-
if (typeof message.content === "string") {
|
|
2063
|
-
try {
|
|
2064
|
-
return { ...message, content: JSON.parse(message.content) };
|
|
2065
|
-
} catch {
|
|
2066
|
-
return message;
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
return message;
|
|
2070
|
-
});
|
|
2071
|
-
const list = new agent.MessageList().add(messagesWithParsedContent, "memory");
|
|
2072
|
-
if (format === `v2`) return list.get.all.v2();
|
|
2073
|
-
return list.get.all.v1();
|
|
2074
|
-
} catch (error$1) {
|
|
2075
|
-
throw new error.MastraError(
|
|
2076
|
-
{
|
|
2077
|
-
id: "MASTRA_STORAGE_PG_STORE_SAVE_MESSAGES_FAILED",
|
|
2078
|
-
domain: error.ErrorDomain.STORAGE,
|
|
2079
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
2080
|
-
details: {
|
|
2081
|
-
threadId
|
|
2243
|
+
const schemaName = getSchemaName(this.schemaName);
|
|
2244
|
+
const tableNameWithSchema = getTableName({ indexName: tableName, schemaName });
|
|
2245
|
+
await this.client.none(`DROP TABLE IF EXISTS ${tableNameWithSchema}`);
|
|
2246
|
+
} catch (error$1) {
|
|
2247
|
+
throw new error.MastraError(
|
|
2248
|
+
{
|
|
2249
|
+
id: "MASTRA_STORAGE_PG_STORE_DROP_TABLE_FAILED",
|
|
2250
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2251
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2252
|
+
details: {
|
|
2253
|
+
tableName
|
|
2082
2254
|
}
|
|
2083
2255
|
},
|
|
2084
2256
|
error$1
|
|
2085
2257
|
);
|
|
2086
2258
|
}
|
|
2087
2259
|
}
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
}) {
|
|
2260
|
+
};
|
|
2261
|
+
function transformScoreRow(row) {
|
|
2262
|
+
let input = void 0;
|
|
2263
|
+
if (row.input) {
|
|
2093
2264
|
try {
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2265
|
+
input = JSON.parse(row.input);
|
|
2266
|
+
} catch {
|
|
2267
|
+
input = row.input;
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
return {
|
|
2271
|
+
...row,
|
|
2272
|
+
input,
|
|
2273
|
+
createdAt: row.createdAtZ || row.createdAt,
|
|
2274
|
+
updatedAt: row.updatedAtZ || row.updatedAt
|
|
2275
|
+
};
|
|
2276
|
+
}
|
|
2277
|
+
var ScoresPG = class extends storage.ScoresStorage {
|
|
2278
|
+
client;
|
|
2279
|
+
operations;
|
|
2280
|
+
constructor({ client, operations }) {
|
|
2281
|
+
super();
|
|
2282
|
+
this.client = client;
|
|
2283
|
+
this.operations = operations;
|
|
2284
|
+
}
|
|
2285
|
+
async getScoreById({ id }) {
|
|
2286
|
+
try {
|
|
2287
|
+
const result = await this.client.oneOrNone(`SELECT * FROM ${storage.TABLE_SCORERS} WHERE id = $1`, [id]);
|
|
2288
|
+
return transformScoreRow(result);
|
|
2108
2289
|
} catch (error$1) {
|
|
2109
2290
|
throw new error.MastraError(
|
|
2110
2291
|
{
|
|
2111
|
-
id: "
|
|
2292
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_SCORE_BY_ID_FAILED",
|
|
2112
2293
|
domain: error.ErrorDomain.STORAGE,
|
|
2113
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
2114
|
-
details: {
|
|
2115
|
-
workflowName,
|
|
2116
|
-
runId
|
|
2117
|
-
}
|
|
2294
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2118
2295
|
},
|
|
2119
2296
|
error$1
|
|
2120
2297
|
);
|
|
2121
2298
|
}
|
|
2122
2299
|
}
|
|
2123
|
-
async
|
|
2124
|
-
|
|
2125
|
-
|
|
2300
|
+
async getScoresByScorerId({
|
|
2301
|
+
scorerId,
|
|
2302
|
+
pagination
|
|
2126
2303
|
}) {
|
|
2127
2304
|
try {
|
|
2128
|
-
const
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2305
|
+
const total = await this.client.oneOrNone(
|
|
2306
|
+
`SELECT COUNT(*) FROM ${storage.TABLE_SCORERS} WHERE "scorerId" = $1`,
|
|
2307
|
+
[scorerId]
|
|
2308
|
+
);
|
|
2309
|
+
if (total?.count === "0" || !total?.count) {
|
|
2310
|
+
return {
|
|
2311
|
+
pagination: {
|
|
2312
|
+
total: 0,
|
|
2313
|
+
page: pagination.page,
|
|
2314
|
+
perPage: pagination.perPage,
|
|
2315
|
+
hasMore: false
|
|
2316
|
+
},
|
|
2317
|
+
scores: []
|
|
2318
|
+
};
|
|
2137
2319
|
}
|
|
2138
|
-
|
|
2320
|
+
const result = await this.client.manyOrNone(
|
|
2321
|
+
`SELECT * FROM ${storage.TABLE_SCORERS} WHERE "scorerId" = $1 LIMIT $2 OFFSET $3`,
|
|
2322
|
+
[scorerId, pagination.perPage, pagination.page * pagination.perPage]
|
|
2323
|
+
);
|
|
2324
|
+
return {
|
|
2325
|
+
pagination: {
|
|
2326
|
+
total: Number(total?.count) || 0,
|
|
2327
|
+
page: pagination.page,
|
|
2328
|
+
perPage: pagination.perPage,
|
|
2329
|
+
hasMore: Number(total?.count) > (pagination.page + 1) * pagination.perPage
|
|
2330
|
+
},
|
|
2331
|
+
scores: result
|
|
2332
|
+
};
|
|
2139
2333
|
} catch (error$1) {
|
|
2140
2334
|
throw new error.MastraError(
|
|
2141
2335
|
{
|
|
2142
|
-
id: "
|
|
2336
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_SCORES_BY_SCORER_ID_FAILED",
|
|
2143
2337
|
domain: error.ErrorDomain.STORAGE,
|
|
2144
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
2145
|
-
details: {
|
|
2146
|
-
workflowName,
|
|
2147
|
-
runId
|
|
2148
|
-
}
|
|
2338
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2149
2339
|
},
|
|
2150
2340
|
error$1
|
|
2151
2341
|
);
|
|
2152
2342
|
}
|
|
2153
2343
|
}
|
|
2154
|
-
async
|
|
2155
|
-
const schema = this.schema || "public";
|
|
2156
|
-
const result = await this.db.oneOrNone(
|
|
2157
|
-
`SELECT 1 FROM information_schema.columns WHERE table_schema = $1 AND table_name = $2 AND (column_name = $3 OR column_name = $4)`,
|
|
2158
|
-
[schema, table, column, column.toLowerCase()]
|
|
2159
|
-
);
|
|
2160
|
-
return !!result;
|
|
2161
|
-
}
|
|
2162
|
-
parseWorkflowRun(row) {
|
|
2163
|
-
let parsedSnapshot = row.snapshot;
|
|
2164
|
-
if (typeof parsedSnapshot === "string") {
|
|
2165
|
-
try {
|
|
2166
|
-
parsedSnapshot = JSON.parse(row.snapshot);
|
|
2167
|
-
} catch (e) {
|
|
2168
|
-
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
2169
|
-
}
|
|
2170
|
-
}
|
|
2171
|
-
return {
|
|
2172
|
-
workflowName: row.workflow_name,
|
|
2173
|
-
runId: row.run_id,
|
|
2174
|
-
snapshot: parsedSnapshot,
|
|
2175
|
-
createdAt: row.createdAt,
|
|
2176
|
-
updatedAt: row.updatedAt,
|
|
2177
|
-
resourceId: row.resourceId
|
|
2178
|
-
};
|
|
2179
|
-
}
|
|
2180
|
-
async getWorkflowRuns({
|
|
2181
|
-
workflowName,
|
|
2182
|
-
fromDate,
|
|
2183
|
-
toDate,
|
|
2184
|
-
limit,
|
|
2185
|
-
offset,
|
|
2186
|
-
resourceId
|
|
2187
|
-
} = {}) {
|
|
2344
|
+
async saveScore(score) {
|
|
2188
2345
|
try {
|
|
2189
|
-
const
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
if (resourceId) {
|
|
2198
|
-
const hasResourceId = await this.hasColumn(storage.TABLE_WORKFLOW_SNAPSHOT, "resourceId");
|
|
2199
|
-
if (hasResourceId) {
|
|
2200
|
-
conditions.push(`"resourceId" = $${paramIndex}`);
|
|
2201
|
-
values.push(resourceId);
|
|
2202
|
-
paramIndex++;
|
|
2203
|
-
} else {
|
|
2204
|
-
console.warn(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
|
|
2346
|
+
const { input, ...rest } = score;
|
|
2347
|
+
await this.operations.insert({
|
|
2348
|
+
tableName: storage.TABLE_SCORERS,
|
|
2349
|
+
record: {
|
|
2350
|
+
...rest,
|
|
2351
|
+
input: JSON.stringify(input),
|
|
2352
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2353
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2205
2354
|
}
|
|
2206
|
-
}
|
|
2207
|
-
if (fromDate) {
|
|
2208
|
-
conditions.push(`"createdAt" >= $${paramIndex}`);
|
|
2209
|
-
values.push(fromDate);
|
|
2210
|
-
paramIndex++;
|
|
2211
|
-
}
|
|
2212
|
-
if (toDate) {
|
|
2213
|
-
conditions.push(`"createdAt" <= $${paramIndex}`);
|
|
2214
|
-
values.push(toDate);
|
|
2215
|
-
paramIndex++;
|
|
2216
|
-
}
|
|
2217
|
-
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2218
|
-
let total = 0;
|
|
2219
|
-
if (limit !== void 0 && offset !== void 0) {
|
|
2220
|
-
const countResult = await this.db.one(
|
|
2221
|
-
`SELECT COUNT(*) as count FROM ${this.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT)} ${whereClause}`,
|
|
2222
|
-
values
|
|
2223
|
-
);
|
|
2224
|
-
total = Number(countResult.count);
|
|
2225
|
-
}
|
|
2226
|
-
const query = `
|
|
2227
|
-
SELECT * FROM ${this.getTableName(storage.TABLE_WORKFLOW_SNAPSHOT)}
|
|
2228
|
-
${whereClause}
|
|
2229
|
-
ORDER BY "createdAt" DESC
|
|
2230
|
-
${limit !== void 0 && offset !== void 0 ? ` LIMIT $${paramIndex} OFFSET $${paramIndex + 1}` : ""}
|
|
2231
|
-
`;
|
|
2232
|
-
const queryValues = limit !== void 0 && offset !== void 0 ? [...values, limit, offset] : values;
|
|
2233
|
-
const result = await this.db.manyOrNone(query, queryValues);
|
|
2234
|
-
const runs = (result || []).map((row) => {
|
|
2235
|
-
return this.parseWorkflowRun(row);
|
|
2236
2355
|
});
|
|
2237
|
-
|
|
2356
|
+
const scoreFromDb = await this.getScoreById({ id: score.id });
|
|
2357
|
+
return { score: scoreFromDb };
|
|
2238
2358
|
} catch (error$1) {
|
|
2239
2359
|
throw new error.MastraError(
|
|
2240
2360
|
{
|
|
2241
|
-
id: "
|
|
2361
|
+
id: "MASTRA_STORAGE_PG_STORE_SAVE_SCORE_FAILED",
|
|
2242
2362
|
domain: error.ErrorDomain.STORAGE,
|
|
2243
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
2244
|
-
details: {
|
|
2245
|
-
workflowName: workflowName || "all"
|
|
2246
|
-
}
|
|
2363
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2247
2364
|
},
|
|
2248
2365
|
error$1
|
|
2249
2366
|
);
|
|
2250
2367
|
}
|
|
2251
2368
|
}
|
|
2252
|
-
async
|
|
2369
|
+
async getScoresByRunId({
|
|
2253
2370
|
runId,
|
|
2254
|
-
|
|
2371
|
+
pagination
|
|
2255
2372
|
}) {
|
|
2256
2373
|
try {
|
|
2257
|
-
const
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
${whereClause}
|
|
2274
|
-
`;
|
|
2275
|
-
const queryValues = values;
|
|
2276
|
-
const result = await this.db.oneOrNone(query, queryValues);
|
|
2277
|
-
if (!result) {
|
|
2278
|
-
return null;
|
|
2374
|
+
const total = await this.client.oneOrNone(
|
|
2375
|
+
`SELECT COUNT(*) FROM ${storage.TABLE_SCORERS} WHERE "runId" = $1`,
|
|
2376
|
+
[runId]
|
|
2377
|
+
);
|
|
2378
|
+
console.log(`total: ${total?.count}`);
|
|
2379
|
+
console.log(`typeof total: ${typeof total?.count}`);
|
|
2380
|
+
if (total?.count === "0" || !total?.count) {
|
|
2381
|
+
return {
|
|
2382
|
+
pagination: {
|
|
2383
|
+
total: 0,
|
|
2384
|
+
page: pagination.page,
|
|
2385
|
+
perPage: pagination.perPage,
|
|
2386
|
+
hasMore: false
|
|
2387
|
+
},
|
|
2388
|
+
scores: []
|
|
2389
|
+
};
|
|
2279
2390
|
}
|
|
2280
|
-
|
|
2391
|
+
const result = await this.client.manyOrNone(
|
|
2392
|
+
`SELECT * FROM ${storage.TABLE_SCORERS} WHERE "runId" = $1 LIMIT $2 OFFSET $3`,
|
|
2393
|
+
[runId, pagination.perPage, pagination.page * pagination.perPage]
|
|
2394
|
+
);
|
|
2395
|
+
return {
|
|
2396
|
+
pagination: {
|
|
2397
|
+
total: Number(total?.count) || 0,
|
|
2398
|
+
page: pagination.page,
|
|
2399
|
+
perPage: pagination.perPage,
|
|
2400
|
+
hasMore: Number(total?.count) > (pagination.page + 1) * pagination.perPage
|
|
2401
|
+
},
|
|
2402
|
+
scores: result
|
|
2403
|
+
};
|
|
2281
2404
|
} catch (error$1) {
|
|
2282
2405
|
throw new error.MastraError(
|
|
2283
2406
|
{
|
|
2284
|
-
id: "
|
|
2407
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_SCORES_BY_RUN_ID_FAILED",
|
|
2285
2408
|
domain: error.ErrorDomain.STORAGE,
|
|
2286
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
2287
|
-
details: {
|
|
2288
|
-
runId,
|
|
2289
|
-
workflowName: workflowName || ""
|
|
2290
|
-
}
|
|
2409
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2291
2410
|
},
|
|
2292
2411
|
error$1
|
|
2293
2412
|
);
|
|
2294
2413
|
}
|
|
2295
2414
|
}
|
|
2296
|
-
async
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
const fromDate = dateRange?.start;
|
|
2302
|
-
const toDate = dateRange?.end;
|
|
2303
|
-
const conditions = [];
|
|
2304
|
-
const queryParams = [];
|
|
2305
|
-
let paramIndex = 1;
|
|
2306
|
-
if (agentName) {
|
|
2307
|
-
conditions.push(`agent_name = $${paramIndex++}`);
|
|
2308
|
-
queryParams.push(agentName);
|
|
2309
|
-
}
|
|
2310
|
-
if (type === "test") {
|
|
2311
|
-
conditions.push(`(test_info IS NOT NULL AND test_info->>'testPath' IS NOT NULL)`);
|
|
2312
|
-
} else if (type === "live") {
|
|
2313
|
-
conditions.push(`(test_info IS NULL OR test_info->>'testPath' IS NULL)`);
|
|
2314
|
-
}
|
|
2315
|
-
if (fromDate) {
|
|
2316
|
-
conditions.push(`created_at >= $${paramIndex++}`);
|
|
2317
|
-
queryParams.push(fromDate);
|
|
2318
|
-
}
|
|
2319
|
-
if (toDate) {
|
|
2320
|
-
conditions.push(`created_at <= $${paramIndex++}`);
|
|
2321
|
-
queryParams.push(toDate);
|
|
2322
|
-
}
|
|
2323
|
-
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2324
|
-
const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(storage.TABLE_EVALS)} ${whereClause}`;
|
|
2415
|
+
async getScoresByEntityId({
|
|
2416
|
+
entityId,
|
|
2417
|
+
entityType,
|
|
2418
|
+
pagination
|
|
2419
|
+
}) {
|
|
2325
2420
|
try {
|
|
2326
|
-
const
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2421
|
+
const total = await this.client.oneOrNone(
|
|
2422
|
+
`SELECT COUNT(*) FROM ${storage.TABLE_SCORERS} WHERE "entityId" = $1 AND "entityType" = $2`,
|
|
2423
|
+
[entityId, entityType]
|
|
2424
|
+
);
|
|
2425
|
+
if (total?.count === "0" || !total?.count) {
|
|
2330
2426
|
return {
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2427
|
+
pagination: {
|
|
2428
|
+
total: 0,
|
|
2429
|
+
page: pagination.page,
|
|
2430
|
+
perPage: pagination.perPage,
|
|
2431
|
+
hasMore: false
|
|
2432
|
+
},
|
|
2433
|
+
scores: []
|
|
2336
2434
|
};
|
|
2337
2435
|
}
|
|
2338
|
-
const
|
|
2339
|
-
storage.
|
|
2340
|
-
|
|
2341
|
-
|
|
2436
|
+
const result = await this.client.manyOrNone(
|
|
2437
|
+
`SELECT * FROM ${storage.TABLE_SCORERS} WHERE "entityId" = $1 AND "entityType" = $2 LIMIT $3 OFFSET $4`,
|
|
2438
|
+
[entityId, entityType, pagination.perPage, pagination.page * pagination.perPage]
|
|
2439
|
+
);
|
|
2342
2440
|
return {
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2441
|
+
pagination: {
|
|
2442
|
+
total: Number(total?.count) || 0,
|
|
2443
|
+
page: pagination.page,
|
|
2444
|
+
perPage: pagination.perPage,
|
|
2445
|
+
hasMore: Number(total?.count) > (pagination.page + 1) * pagination.perPage
|
|
2446
|
+
},
|
|
2447
|
+
scores: result
|
|
2348
2448
|
};
|
|
2349
2449
|
} catch (error$1) {
|
|
2350
|
-
|
|
2450
|
+
throw new error.MastraError(
|
|
2351
2451
|
{
|
|
2352
|
-
id: "
|
|
2452
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_SCORES_BY_ENTITY_ID_FAILED",
|
|
2353
2453
|
domain: error.ErrorDomain.STORAGE,
|
|
2354
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
2355
|
-
details: {
|
|
2356
|
-
agentName: agentName || "all",
|
|
2357
|
-
type: type || "all",
|
|
2358
|
-
page,
|
|
2359
|
-
perPage
|
|
2360
|
-
}
|
|
2454
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2361
2455
|
},
|
|
2362
2456
|
error$1
|
|
2363
2457
|
);
|
|
2364
|
-
this.logger?.error?.(mastraError.toString());
|
|
2365
|
-
this.logger?.trackException(mastraError);
|
|
2366
|
-
throw mastraError;
|
|
2367
2458
|
}
|
|
2368
2459
|
}
|
|
2369
|
-
|
|
2370
|
-
|
|
2460
|
+
};
|
|
2461
|
+
var TracesPG = class extends storage.TracesStorage {
|
|
2462
|
+
client;
|
|
2463
|
+
operations;
|
|
2464
|
+
schema;
|
|
2465
|
+
constructor({
|
|
2466
|
+
client,
|
|
2467
|
+
operations,
|
|
2468
|
+
schema
|
|
2371
2469
|
}) {
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2470
|
+
super();
|
|
2471
|
+
this.client = client;
|
|
2472
|
+
this.operations = operations;
|
|
2473
|
+
this.schema = schema;
|
|
2474
|
+
}
|
|
2475
|
+
async getTraces(args) {
|
|
2476
|
+
if (args.fromDate || args.toDate) {
|
|
2477
|
+
args.dateRange = {
|
|
2478
|
+
start: args.fromDate,
|
|
2479
|
+
end: args.toDate
|
|
2480
|
+
};
|
|
2382
2481
|
}
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2482
|
+
try {
|
|
2483
|
+
const result = await this.getTracesPaginated(args);
|
|
2484
|
+
return result.traces;
|
|
2485
|
+
} catch (error$1) {
|
|
2486
|
+
throw new error.MastraError(
|
|
2487
|
+
{
|
|
2488
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_TRACES_FAILED",
|
|
2489
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2490
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2491
|
+
},
|
|
2492
|
+
error$1
|
|
2493
|
+
);
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
async getTracesPaginated(args) {
|
|
2497
|
+
const { name, scope, page = 0, perPage = 100, attributes, filters, dateRange } = args;
|
|
2498
|
+
const fromDate = dateRange?.start;
|
|
2499
|
+
const toDate = dateRange?.end;
|
|
2500
|
+
const currentOffset = page * perPage;
|
|
2501
|
+
const queryParams = [];
|
|
2502
|
+
const conditions = [];
|
|
2503
|
+
let paramIndex = 1;
|
|
2504
|
+
if (name) {
|
|
2505
|
+
conditions.push(`name LIKE $${paramIndex++}`);
|
|
2506
|
+
queryParams.push(`${name}%`);
|
|
2507
|
+
}
|
|
2508
|
+
if (scope) {
|
|
2509
|
+
conditions.push(`scope = $${paramIndex++}`);
|
|
2510
|
+
queryParams.push(scope);
|
|
2511
|
+
}
|
|
2512
|
+
if (attributes) {
|
|
2513
|
+
Object.entries(attributes).forEach(([key, value]) => {
|
|
2514
|
+
const parsedKey = utils.parseFieldKey(key);
|
|
2515
|
+
conditions.push(`attributes->>'${parsedKey}' = $${paramIndex++}`);
|
|
2516
|
+
queryParams.push(value);
|
|
2517
|
+
});
|
|
2518
|
+
}
|
|
2519
|
+
if (filters) {
|
|
2520
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
2521
|
+
const parsedKey = utils.parseFieldKey(key);
|
|
2522
|
+
conditions.push(`"${parsedKey}" = $${paramIndex++}`);
|
|
2523
|
+
queryParams.push(value);
|
|
2524
|
+
});
|
|
2525
|
+
}
|
|
2526
|
+
if (fromDate) {
|
|
2527
|
+
conditions.push(`"createdAt" >= $${paramIndex++}`);
|
|
2528
|
+
queryParams.push(fromDate);
|
|
2529
|
+
}
|
|
2530
|
+
if (toDate) {
|
|
2531
|
+
conditions.push(`"createdAt" <= $${paramIndex++}`);
|
|
2532
|
+
queryParams.push(toDate);
|
|
2533
|
+
}
|
|
2534
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2535
|
+
try {
|
|
2536
|
+
const countResult = await this.client.oneOrNone(
|
|
2537
|
+
`SELECT COUNT(*) FROM ${getTableName({ indexName: storage.TABLE_TRACES, schemaName: getSchemaName(this.schema) })} ${whereClause}`,
|
|
2538
|
+
queryParams
|
|
2539
|
+
);
|
|
2540
|
+
const total = Number(countResult?.count ?? 0);
|
|
2541
|
+
if (total === 0) {
|
|
2542
|
+
return {
|
|
2543
|
+
traces: [],
|
|
2544
|
+
total: 0,
|
|
2545
|
+
page,
|
|
2546
|
+
perPage,
|
|
2547
|
+
hasMore: false
|
|
2548
|
+
};
|
|
2389
2549
|
}
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
const
|
|
2395
|
-
|
|
2396
|
-
|
|
2550
|
+
const dataResult = await this.client.manyOrNone(
|
|
2551
|
+
`SELECT * FROM ${getTableName({ indexName: storage.TABLE_TRACES, schemaName: getSchemaName(this.schema) })} ${whereClause} ORDER BY "startTime" DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`,
|
|
2552
|
+
[...queryParams, perPage, currentOffset]
|
|
2553
|
+
);
|
|
2554
|
+
const traces = dataResult.map((row) => ({
|
|
2555
|
+
id: row.id,
|
|
2556
|
+
parentSpanId: row.parentSpanId,
|
|
2557
|
+
traceId: row.traceId,
|
|
2558
|
+
name: row.name,
|
|
2559
|
+
scope: row.scope,
|
|
2560
|
+
kind: row.kind,
|
|
2561
|
+
status: storage.safelyParseJSON(row.status),
|
|
2562
|
+
events: storage.safelyParseJSON(row.events),
|
|
2563
|
+
links: storage.safelyParseJSON(row.links),
|
|
2564
|
+
attributes: storage.safelyParseJSON(row.attributes),
|
|
2565
|
+
startTime: row.startTime,
|
|
2566
|
+
endTime: row.endTime,
|
|
2567
|
+
other: storage.safelyParseJSON(row.other),
|
|
2568
|
+
createdAt: row.createdAtZ || row.createdAt
|
|
2569
|
+
}));
|
|
2570
|
+
return {
|
|
2571
|
+
traces,
|
|
2572
|
+
total,
|
|
2573
|
+
page,
|
|
2574
|
+
perPage,
|
|
2575
|
+
hasMore: currentOffset + traces.length < total
|
|
2397
2576
|
};
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2577
|
+
} catch (error$1) {
|
|
2578
|
+
throw new error.MastraError(
|
|
2579
|
+
{
|
|
2580
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_TRACES_PAGINATED_FAILED",
|
|
2581
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2582
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2583
|
+
},
|
|
2584
|
+
error$1
|
|
2585
|
+
);
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2588
|
+
async batchTraceInsert({ records }) {
|
|
2589
|
+
this.logger.debug("Batch inserting traces", { count: records.length });
|
|
2590
|
+
await this.operations.batchInsert({
|
|
2591
|
+
tableName: storage.TABLE_TRACES,
|
|
2592
|
+
records
|
|
2593
|
+
});
|
|
2594
|
+
}
|
|
2595
|
+
};
|
|
2596
|
+
function parseWorkflowRun(row) {
|
|
2597
|
+
let parsedSnapshot = row.snapshot;
|
|
2598
|
+
if (typeof parsedSnapshot === "string") {
|
|
2599
|
+
try {
|
|
2600
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
2601
|
+
} catch (e) {
|
|
2602
|
+
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
2603
|
+
}
|
|
2604
|
+
}
|
|
2605
|
+
return {
|
|
2606
|
+
workflowName: row.workflow_name,
|
|
2607
|
+
runId: row.run_id,
|
|
2608
|
+
snapshot: parsedSnapshot,
|
|
2609
|
+
resourceId: row.resourceId,
|
|
2610
|
+
createdAt: new Date(row.createdAtZ || row.createdAt),
|
|
2611
|
+
updatedAt: new Date(row.updatedAtZ || row.updatedAt)
|
|
2612
|
+
};
|
|
2613
|
+
}
|
|
2614
|
+
var WorkflowsPG = class extends storage.WorkflowsStorage {
|
|
2615
|
+
client;
|
|
2616
|
+
operations;
|
|
2617
|
+
schema;
|
|
2618
|
+
constructor({
|
|
2619
|
+
client,
|
|
2620
|
+
operations,
|
|
2621
|
+
schema
|
|
2622
|
+
}) {
|
|
2623
|
+
super();
|
|
2624
|
+
this.client = client;
|
|
2625
|
+
this.operations = operations;
|
|
2626
|
+
this.schema = schema;
|
|
2627
|
+
}
|
|
2628
|
+
async persistWorkflowSnapshot({
|
|
2629
|
+
workflowName,
|
|
2630
|
+
runId,
|
|
2631
|
+
snapshot
|
|
2632
|
+
}) {
|
|
2633
|
+
try {
|
|
2634
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2635
|
+
await this.client.none(
|
|
2636
|
+
`INSERT INTO ${storage.TABLE_WORKFLOW_SNAPSHOT} (workflow_name, run_id, snapshot, "createdAt", "updatedAt")
|
|
2637
|
+
VALUES ($1, $2, $3, $4, $5)
|
|
2638
|
+
ON CONFLICT (workflow_name, run_id) DO UPDATE
|
|
2639
|
+
SET snapshot = $3, "updatedAt" = $5`,
|
|
2640
|
+
[workflowName, runId, JSON.stringify(snapshot), now, now]
|
|
2641
|
+
);
|
|
2642
|
+
} catch (error$1) {
|
|
2643
|
+
throw new error.MastraError(
|
|
2644
|
+
{
|
|
2645
|
+
id: "MASTRA_STORAGE_PG_STORE_PERSIST_WORKFLOW_SNAPSHOT_FAILED",
|
|
2646
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2647
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2648
|
+
},
|
|
2649
|
+
error$1
|
|
2650
|
+
);
|
|
2651
|
+
}
|
|
2652
|
+
}
|
|
2653
|
+
async loadWorkflowSnapshot({
|
|
2654
|
+
workflowName,
|
|
2655
|
+
runId
|
|
2656
|
+
}) {
|
|
2657
|
+
try {
|
|
2658
|
+
const result = await this.operations.load({
|
|
2659
|
+
tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
2660
|
+
keys: { workflow_name: workflowName, run_id: runId }
|
|
2661
|
+
});
|
|
2662
|
+
return result ? result.snapshot : null;
|
|
2663
|
+
} catch (error$1) {
|
|
2664
|
+
throw new error.MastraError(
|
|
2665
|
+
{
|
|
2666
|
+
id: "MASTRA_STORAGE_PG_STORE_LOAD_WORKFLOW_SNAPSHOT_FAILED",
|
|
2667
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2668
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2669
|
+
},
|
|
2670
|
+
error$1
|
|
2671
|
+
);
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
async getWorkflowRunById({
|
|
2675
|
+
runId,
|
|
2676
|
+
workflowName
|
|
2677
|
+
}) {
|
|
2678
|
+
try {
|
|
2679
|
+
const conditions = [];
|
|
2680
|
+
const values = [];
|
|
2681
|
+
let paramIndex = 1;
|
|
2682
|
+
if (runId) {
|
|
2683
|
+
conditions.push(`run_id = $${paramIndex}`);
|
|
2684
|
+
values.push(runId);
|
|
2685
|
+
paramIndex++;
|
|
2686
|
+
}
|
|
2687
|
+
if (workflowName) {
|
|
2688
|
+
conditions.push(`workflow_name = $${paramIndex}`);
|
|
2689
|
+
values.push(workflowName);
|
|
2690
|
+
paramIndex++;
|
|
2691
|
+
}
|
|
2692
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2693
|
+
const query = `
|
|
2694
|
+
SELECT * FROM ${getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: this.schema })}
|
|
2695
|
+
${whereClause}
|
|
2696
|
+
`;
|
|
2697
|
+
const queryValues = values;
|
|
2698
|
+
const result = await this.client.oneOrNone(query, queryValues);
|
|
2699
|
+
if (!result) {
|
|
2700
|
+
return null;
|
|
2701
|
+
}
|
|
2702
|
+
return parseWorkflowRun(result);
|
|
2703
|
+
} catch (error$1) {
|
|
2704
|
+
throw new error.MastraError(
|
|
2705
|
+
{
|
|
2706
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
|
|
2707
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2708
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2709
|
+
details: {
|
|
2710
|
+
runId,
|
|
2711
|
+
workflowName: workflowName || ""
|
|
2432
2712
|
}
|
|
2433
|
-
}
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2713
|
+
},
|
|
2714
|
+
error$1
|
|
2715
|
+
);
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
async getWorkflowRuns({
|
|
2719
|
+
workflowName,
|
|
2720
|
+
fromDate,
|
|
2721
|
+
toDate,
|
|
2722
|
+
limit,
|
|
2723
|
+
offset,
|
|
2724
|
+
resourceId
|
|
2725
|
+
} = {}) {
|
|
2726
|
+
try {
|
|
2727
|
+
const conditions = [];
|
|
2728
|
+
const values = [];
|
|
2729
|
+
let paramIndex = 1;
|
|
2730
|
+
if (workflowName) {
|
|
2731
|
+
conditions.push(`workflow_name = $${paramIndex}`);
|
|
2732
|
+
values.push(workflowName);
|
|
2733
|
+
paramIndex++;
|
|
2734
|
+
}
|
|
2735
|
+
if (resourceId) {
|
|
2736
|
+
const hasResourceId = await this.operations.hasColumn(storage.TABLE_WORKFLOW_SNAPSHOT, "resourceId");
|
|
2737
|
+
if (hasResourceId) {
|
|
2738
|
+
conditions.push(`"resourceId" = $${paramIndex}`);
|
|
2739
|
+
values.push(resourceId);
|
|
2740
|
+
paramIndex++;
|
|
2741
|
+
} else {
|
|
2742
|
+
console.warn(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
|
|
2440
2743
|
}
|
|
2441
2744
|
}
|
|
2442
|
-
if (
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
])
|
|
2447
|
-
);
|
|
2745
|
+
if (fromDate) {
|
|
2746
|
+
conditions.push(`"createdAt" >= $${paramIndex}`);
|
|
2747
|
+
values.push(fromDate);
|
|
2748
|
+
paramIndex++;
|
|
2448
2749
|
}
|
|
2449
|
-
if (
|
|
2450
|
-
|
|
2750
|
+
if (toDate) {
|
|
2751
|
+
conditions.push(`"createdAt" <= $${paramIndex}`);
|
|
2752
|
+
values.push(toDate);
|
|
2753
|
+
paramIndex++;
|
|
2451
2754
|
}
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2755
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2756
|
+
let total = 0;
|
|
2757
|
+
if (limit !== void 0 && offset !== void 0) {
|
|
2758
|
+
const countResult = await this.client.one(
|
|
2759
|
+
`SELECT COUNT(*) as count FROM ${getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: this.schema })} ${whereClause}`,
|
|
2760
|
+
values
|
|
2761
|
+
);
|
|
2762
|
+
total = Number(countResult.count);
|
|
2460
2763
|
}
|
|
2461
|
-
|
|
2462
|
-
|
|
2764
|
+
const query = `
|
|
2765
|
+
SELECT * FROM ${getTableName({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: this.schema })}
|
|
2766
|
+
${whereClause}
|
|
2767
|
+
ORDER BY "createdAt" DESC
|
|
2768
|
+
${limit !== void 0 && offset !== void 0 ? ` LIMIT $${paramIndex} OFFSET $${paramIndex + 1}` : ""}
|
|
2769
|
+
`;
|
|
2770
|
+
const queryValues = limit !== void 0 && offset !== void 0 ? [...values, limit, offset] : values;
|
|
2771
|
+
const result = await this.client.manyOrNone(query, queryValues);
|
|
2772
|
+
const runs = (result || []).map((row) => {
|
|
2773
|
+
return parseWorkflowRun(row);
|
|
2774
|
+
});
|
|
2775
|
+
return { runs, total: total || runs.length };
|
|
2776
|
+
} catch (error$1) {
|
|
2777
|
+
throw new error.MastraError(
|
|
2778
|
+
{
|
|
2779
|
+
id: "MASTRA_STORAGE_PG_STORE_GET_WORKFLOW_RUNS_FAILED",
|
|
2780
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2781
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2782
|
+
details: {
|
|
2783
|
+
workflowName: workflowName || "all"
|
|
2784
|
+
}
|
|
2785
|
+
},
|
|
2786
|
+
error$1
|
|
2787
|
+
);
|
|
2788
|
+
}
|
|
2463
2789
|
}
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2790
|
+
};
|
|
2791
|
+
|
|
2792
|
+
// src/storage/index.ts
|
|
2793
|
+
var PostgresStore = class extends storage.MastraStorage {
|
|
2794
|
+
db;
|
|
2795
|
+
pgp;
|
|
2796
|
+
client;
|
|
2797
|
+
schema;
|
|
2798
|
+
stores;
|
|
2799
|
+
constructor(config) {
|
|
2800
|
+
try {
|
|
2801
|
+
if ("connectionString" in config) {
|
|
2802
|
+
if (!config.connectionString || typeof config.connectionString !== "string" || config.connectionString.trim() === "") {
|
|
2803
|
+
throw new Error(
|
|
2804
|
+
"PostgresStore: connectionString must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults."
|
|
2805
|
+
);
|
|
2806
|
+
}
|
|
2807
|
+
} else {
|
|
2808
|
+
const required = ["host", "database", "user", "password"];
|
|
2809
|
+
for (const key of required) {
|
|
2810
|
+
if (!(key in config) || typeof config[key] !== "string" || config[key].trim() === "") {
|
|
2811
|
+
throw new Error(
|
|
2812
|
+
`PostgresStore: ${key} must be provided and cannot be empty. Passing an empty string may cause fallback to local Postgres defaults.`
|
|
2813
|
+
);
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
super({ name: "PostgresStore" });
|
|
2818
|
+
this.pgp = pgPromise__default.default();
|
|
2819
|
+
this.schema = config.schemaName || "public";
|
|
2820
|
+
this.db = this.pgp(
|
|
2821
|
+
`connectionString` in config ? { connectionString: config.connectionString } : {
|
|
2822
|
+
host: config.host,
|
|
2823
|
+
port: config.port,
|
|
2824
|
+
database: config.database,
|
|
2825
|
+
user: config.user,
|
|
2826
|
+
password: config.password,
|
|
2827
|
+
ssl: config.ssl
|
|
2828
|
+
}
|
|
2829
|
+
);
|
|
2830
|
+
this.client = this.db;
|
|
2831
|
+
const operations = new StoreOperationsPG({ client: this.client, schemaName: this.schema });
|
|
2832
|
+
const scores = new ScoresPG({ client: this.client, operations });
|
|
2833
|
+
const traces = new TracesPG({ client: this.client, operations, schema: this.schema });
|
|
2834
|
+
const workflows = new WorkflowsPG({ client: this.client, operations, schema: this.schema });
|
|
2835
|
+
const legacyEvals = new LegacyEvalsPG({ client: this.client, schema: this.schema });
|
|
2836
|
+
const memory = new MemoryPG({ client: this.client, schema: this.schema, operations });
|
|
2837
|
+
this.stores = {
|
|
2838
|
+
operations,
|
|
2839
|
+
scores,
|
|
2840
|
+
traces,
|
|
2841
|
+
workflows,
|
|
2842
|
+
legacyEvals,
|
|
2843
|
+
memory
|
|
2844
|
+
};
|
|
2845
|
+
} catch (e) {
|
|
2846
|
+
throw new error.MastraError(
|
|
2847
|
+
{
|
|
2848
|
+
id: "MASTRA_STORAGE_PG_STORE_INITIALIZATION_FAILED",
|
|
2849
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2850
|
+
category: error.ErrorCategory.USER
|
|
2851
|
+
},
|
|
2852
|
+
e
|
|
2853
|
+
);
|
|
2471
2854
|
}
|
|
2855
|
+
}
|
|
2856
|
+
get supports() {
|
|
2472
2857
|
return {
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2858
|
+
selectByIncludeResourceScope: true,
|
|
2859
|
+
resourceWorkingMemory: true,
|
|
2860
|
+
hasColumn: true,
|
|
2861
|
+
createTable: true
|
|
2477
2862
|
};
|
|
2478
2863
|
}
|
|
2864
|
+
/** @deprecated use getEvals instead */
|
|
2865
|
+
async getEvalsByAgentName(agentName, type) {
|
|
2866
|
+
return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
|
|
2867
|
+
}
|
|
2868
|
+
async getEvals(options = {}) {
|
|
2869
|
+
return this.stores.legacyEvals.getEvals(options);
|
|
2870
|
+
}
|
|
2871
|
+
/**
|
|
2872
|
+
* @deprecated use getTracesPaginated instead
|
|
2873
|
+
*/
|
|
2874
|
+
async getTraces(args) {
|
|
2875
|
+
return this.stores.traces.getTraces(args);
|
|
2876
|
+
}
|
|
2877
|
+
async getTracesPaginated(args) {
|
|
2878
|
+
return this.stores.traces.getTracesPaginated(args);
|
|
2879
|
+
}
|
|
2880
|
+
async batchTraceInsert({ records }) {
|
|
2881
|
+
return this.stores.traces.batchTraceInsert({ records });
|
|
2882
|
+
}
|
|
2883
|
+
async createTable({
|
|
2884
|
+
tableName,
|
|
2885
|
+
schema
|
|
2886
|
+
}) {
|
|
2887
|
+
return this.stores.operations.createTable({ tableName, schema });
|
|
2888
|
+
}
|
|
2889
|
+
async alterTable({
|
|
2890
|
+
tableName,
|
|
2891
|
+
schema,
|
|
2892
|
+
ifNotExists
|
|
2893
|
+
}) {
|
|
2894
|
+
return this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
2895
|
+
}
|
|
2896
|
+
async clearTable({ tableName }) {
|
|
2897
|
+
return this.stores.operations.clearTable({ tableName });
|
|
2898
|
+
}
|
|
2899
|
+
async dropTable({ tableName }) {
|
|
2900
|
+
return this.stores.operations.dropTable({ tableName });
|
|
2901
|
+
}
|
|
2902
|
+
async insert({ tableName, record }) {
|
|
2903
|
+
return this.stores.operations.insert({ tableName, record });
|
|
2904
|
+
}
|
|
2905
|
+
async batchInsert({ tableName, records }) {
|
|
2906
|
+
return this.stores.operations.batchInsert({ tableName, records });
|
|
2907
|
+
}
|
|
2908
|
+
async load({ tableName, keys }) {
|
|
2909
|
+
return this.stores.operations.load({ tableName, keys });
|
|
2910
|
+
}
|
|
2911
|
+
/**
|
|
2912
|
+
* Memory
|
|
2913
|
+
*/
|
|
2914
|
+
async getThreadById({ threadId }) {
|
|
2915
|
+
return this.stores.memory.getThreadById({ threadId });
|
|
2916
|
+
}
|
|
2917
|
+
/**
|
|
2918
|
+
* @deprecated use getThreadsByResourceIdPaginated instead
|
|
2919
|
+
*/
|
|
2920
|
+
async getThreadsByResourceId(args) {
|
|
2921
|
+
return this.stores.memory.getThreadsByResourceId(args);
|
|
2922
|
+
}
|
|
2923
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
2924
|
+
return this.stores.memory.getThreadsByResourceIdPaginated(args);
|
|
2925
|
+
}
|
|
2926
|
+
async saveThread({ thread }) {
|
|
2927
|
+
return this.stores.memory.saveThread({ thread });
|
|
2928
|
+
}
|
|
2929
|
+
async updateThread({
|
|
2930
|
+
id,
|
|
2931
|
+
title,
|
|
2932
|
+
metadata
|
|
2933
|
+
}) {
|
|
2934
|
+
return this.stores.memory.updateThread({ id, title, metadata });
|
|
2935
|
+
}
|
|
2936
|
+
async deleteThread({ threadId }) {
|
|
2937
|
+
return this.stores.memory.deleteThread({ threadId });
|
|
2938
|
+
}
|
|
2939
|
+
async getMessages(args) {
|
|
2940
|
+
return this.stores.memory.getMessages(args);
|
|
2941
|
+
}
|
|
2942
|
+
async getMessagesPaginated(args) {
|
|
2943
|
+
return this.stores.memory.getMessagesPaginated(args);
|
|
2944
|
+
}
|
|
2945
|
+
async saveMessages(args) {
|
|
2946
|
+
return this.stores.memory.saveMessages(args);
|
|
2947
|
+
}
|
|
2948
|
+
async updateMessages({
|
|
2949
|
+
messages
|
|
2950
|
+
}) {
|
|
2951
|
+
return this.stores.memory.updateMessages({ messages });
|
|
2952
|
+
}
|
|
2953
|
+
async getResourceById({ resourceId }) {
|
|
2954
|
+
return this.stores.memory.getResourceById({ resourceId });
|
|
2955
|
+
}
|
|
2479
2956
|
async saveResource({ resource }) {
|
|
2480
|
-
|
|
2481
|
-
await this.db.none(
|
|
2482
|
-
`INSERT INTO ${tableName} (id, "workingMemory", metadata, "createdAt", "updatedAt")
|
|
2483
|
-
VALUES ($1, $2, $3, $4, $5)`,
|
|
2484
|
-
[
|
|
2485
|
-
resource.id,
|
|
2486
|
-
resource.workingMemory,
|
|
2487
|
-
JSON.stringify(resource.metadata),
|
|
2488
|
-
resource.createdAt.toISOString(),
|
|
2489
|
-
resource.updatedAt.toISOString()
|
|
2490
|
-
]
|
|
2491
|
-
);
|
|
2492
|
-
return resource;
|
|
2957
|
+
return this.stores.memory.saveResource({ resource });
|
|
2493
2958
|
}
|
|
2494
2959
|
async updateResource({
|
|
2495
2960
|
resourceId,
|
|
2496
2961
|
workingMemory,
|
|
2497
2962
|
metadata
|
|
2498
2963
|
}) {
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
}
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2964
|
+
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
2965
|
+
}
|
|
2966
|
+
/**
|
|
2967
|
+
* Workflows
|
|
2968
|
+
*/
|
|
2969
|
+
async persistWorkflowSnapshot({
|
|
2970
|
+
workflowName,
|
|
2971
|
+
runId,
|
|
2972
|
+
snapshot
|
|
2973
|
+
}) {
|
|
2974
|
+
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
|
|
2975
|
+
}
|
|
2976
|
+
async loadWorkflowSnapshot({
|
|
2977
|
+
workflowName,
|
|
2978
|
+
runId
|
|
2979
|
+
}) {
|
|
2980
|
+
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2981
|
+
}
|
|
2982
|
+
async getWorkflowRuns({
|
|
2983
|
+
workflowName,
|
|
2984
|
+
fromDate,
|
|
2985
|
+
toDate,
|
|
2986
|
+
limit,
|
|
2987
|
+
offset,
|
|
2988
|
+
resourceId
|
|
2989
|
+
} = {}) {
|
|
2990
|
+
return this.stores.workflows.getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
|
|
2991
|
+
}
|
|
2992
|
+
async getWorkflowRunById({
|
|
2993
|
+
runId,
|
|
2994
|
+
workflowName
|
|
2995
|
+
}) {
|
|
2996
|
+
return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
|
|
2997
|
+
}
|
|
2998
|
+
async close() {
|
|
2999
|
+
this.pgp.end();
|
|
3000
|
+
}
|
|
3001
|
+
/**
|
|
3002
|
+
* Scorers
|
|
3003
|
+
*/
|
|
3004
|
+
async getScoreById({ id: _id }) {
|
|
3005
|
+
return this.stores.scores.getScoreById({ id: _id });
|
|
3006
|
+
}
|
|
3007
|
+
async getScoresByScorerId({
|
|
3008
|
+
scorerId: _scorerId,
|
|
3009
|
+
pagination: _pagination
|
|
3010
|
+
}) {
|
|
3011
|
+
return this.stores.scores.getScoresByScorerId({ scorerId: _scorerId, pagination: _pagination });
|
|
3012
|
+
}
|
|
3013
|
+
async saveScore(_score) {
|
|
3014
|
+
return this.stores.scores.saveScore(_score);
|
|
3015
|
+
}
|
|
3016
|
+
async getScoresByRunId({
|
|
3017
|
+
runId: _runId,
|
|
3018
|
+
pagination: _pagination
|
|
3019
|
+
}) {
|
|
3020
|
+
return this.stores.scores.getScoresByRunId({ runId: _runId, pagination: _pagination });
|
|
3021
|
+
}
|
|
3022
|
+
async getScoresByEntityId({
|
|
3023
|
+
entityId: _entityId,
|
|
3024
|
+
entityType: _entityType,
|
|
3025
|
+
pagination: _pagination
|
|
3026
|
+
}) {
|
|
3027
|
+
return this.stores.scores.getScoresByEntityId({
|
|
3028
|
+
entityId: _entityId,
|
|
3029
|
+
entityType: _entityType,
|
|
3030
|
+
pagination: _pagination
|
|
3031
|
+
});
|
|
2539
3032
|
}
|
|
2540
3033
|
};
|
|
2541
3034
|
|