@mastra/pg 0.10.1-alpha.2 → 0.10.2-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/dist/index.cjs CHANGED
@@ -949,6 +949,7 @@ var PostgresStore = class extends storage.MastraStorage {
949
949
  const parsedSchemaName = this.schema ? utils.parseSqlIdentifier(this.schema, "schema name") : void 0;
950
950
  return parsedSchemaName ? `${parsedSchemaName}."${parsedIndexName}"` : `"${parsedIndexName}"`;
951
951
  }
952
+ /** @deprecated use getEvals instead */
952
953
  async getEvalsByAgentName(agentName, type) {
953
954
  try {
954
955
  const baseQuery = `SELECT * FROM ${this.getTableName(storage.TABLE_EVALS)} WHERE agent_name = $1`;
@@ -999,76 +1000,72 @@ var PostgresStore = class extends storage.MastraStorage {
999
1000
  throw error;
1000
1001
  }
1001
1002
  }
1002
- async getTraces({
1003
- name,
1004
- scope,
1005
- page,
1006
- perPage,
1007
- attributes,
1008
- filters,
1009
- fromDate,
1010
- toDate
1011
- }) {
1012
- let idx = 1;
1013
- const limit = perPage;
1014
- const offset = page * perPage;
1015
- const args = [];
1003
+ async getTraces(args) {
1004
+ const {
1005
+ name,
1006
+ scope,
1007
+ page,
1008
+ perPage: perPageInput,
1009
+ attributes,
1010
+ filters,
1011
+ fromDate,
1012
+ toDate,
1013
+ returnPaginationResults
1014
+ } = args;
1015
+ const perPage = perPageInput !== void 0 ? perPageInput : 100;
1016
+ const currentOffset = page * perPage;
1017
+ const queryParams = [];
1016
1018
  const conditions = [];
1019
+ let paramIndex = 1;
1017
1020
  if (name) {
1018
- conditions.push(`name LIKE CONCAT($${idx++}, '%')`);
1021
+ conditions.push(`name LIKE $${paramIndex++}`);
1022
+ queryParams.push(`${name}%`);
1019
1023
  }
1020
1024
  if (scope) {
1021
- conditions.push(`scope = $${idx++}`);
1025
+ conditions.push(`scope = $${paramIndex++}`);
1026
+ queryParams.push(scope);
1022
1027
  }
1023
1028
  if (attributes) {
1024
- Object.keys(attributes).forEach((key) => {
1029
+ Object.entries(attributes).forEach(([key, value]) => {
1025
1030
  const parsedKey = utils.parseSqlIdentifier(key, "attribute key");
1026
- conditions.push(`attributes->>'${parsedKey}' = $${idx++}`);
1031
+ conditions.push(`attributes->>'${parsedKey}' = $${paramIndex++}`);
1032
+ queryParams.push(value);
1027
1033
  });
1028
1034
  }
1029
1035
  if (filters) {
1030
- Object.entries(filters).forEach(([key]) => {
1036
+ Object.entries(filters).forEach(([key, value]) => {
1031
1037
  const parsedKey = utils.parseSqlIdentifier(key, "filter key");
1032
- conditions.push(`${parsedKey} = $${idx++}`);
1038
+ conditions.push(`"${parsedKey}" = $${paramIndex++}`);
1039
+ queryParams.push(value);
1033
1040
  });
1034
1041
  }
1035
1042
  if (fromDate) {
1036
- conditions.push(`createdAt >= $${idx++}`);
1043
+ conditions.push(`"createdAt" >= $${paramIndex++}`);
1044
+ queryParams.push(fromDate);
1037
1045
  }
1038
1046
  if (toDate) {
1039
- conditions.push(`createdAt <= $${idx++}`);
1047
+ conditions.push(`"createdAt" <= $${paramIndex++}`);
1048
+ queryParams.push(toDate);
1040
1049
  }
1041
1050
  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1042
- if (name) {
1043
- args.push(name);
1044
- }
1045
- if (scope) {
1046
- args.push(scope);
1047
- }
1048
- if (attributes) {
1049
- for (const [_key, value] of Object.entries(attributes)) {
1050
- args.push(value);
1051
- }
1052
- }
1053
- if (filters) {
1054
- for (const [, value] of Object.entries(filters)) {
1055
- args.push(value);
1056
- }
1057
- }
1058
- if (fromDate) {
1059
- args.push(fromDate.toISOString());
1060
- }
1061
- if (toDate) {
1062
- args.push(toDate.toISOString());
1063
- }
1064
- const result = await this.db.manyOrNone(
1065
- `SELECT * FROM ${this.getTableName(storage.TABLE_TRACES)} ${whereClause} ORDER BY "createdAt" DESC LIMIT ${limit} OFFSET ${offset}`,
1066
- args
1067
- );
1068
- if (!result) {
1051
+ const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(storage.TABLE_TRACES)} ${whereClause}`;
1052
+ const countResult = await this.db.one(countQuery, queryParams);
1053
+ const total = parseInt(countResult.count, 10);
1054
+ if (total === 0 && returnPaginationResults) {
1055
+ return {
1056
+ traces: [],
1057
+ total: 0,
1058
+ page,
1059
+ perPage,
1060
+ hasMore: false
1061
+ };
1062
+ } else if (total === 0) {
1069
1063
  return [];
1070
1064
  }
1071
- return result.map((row) => ({
1065
+ const dataQuery = `SELECT * FROM ${this.getTableName(storage.TABLE_TRACES)} ${whereClause} ORDER BY "createdAt" DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
1066
+ const finalQueryParams = [...queryParams, perPage, currentOffset];
1067
+ const rows = await this.db.manyOrNone(dataQuery, finalQueryParams);
1068
+ const traces = rows.map((row) => ({
1072
1069
  id: row.id,
1073
1070
  parentSpanId: row.parentSpanId,
1074
1071
  traceId: row.traceId,
@@ -1084,6 +1081,17 @@ var PostgresStore = class extends storage.MastraStorage {
1084
1081
  other: row.other,
1085
1082
  createdAt: row.createdAt
1086
1083
  }));
1084
+ if (returnPaginationResults) {
1085
+ return {
1086
+ traces,
1087
+ total,
1088
+ page,
1089
+ perPage,
1090
+ hasMore: currentOffset + traces.length < total
1091
+ };
1092
+ } else {
1093
+ return traces;
1094
+ }
1087
1095
  }
1088
1096
  async setupSchema() {
1089
1097
  if (!this.schema || this.schemaSetupComplete) {
@@ -1237,29 +1245,58 @@ var PostgresStore = class extends storage.MastraStorage {
1237
1245
  throw error;
1238
1246
  }
1239
1247
  }
1240
- async getThreadsByResourceId({ resourceId }) {
1248
+ async getThreadsByResourceId(args) {
1249
+ const { resourceId, page, perPage: perPageInput } = args;
1241
1250
  try {
1242
- const threads = await this.db.manyOrNone(
1243
- `SELECT
1244
- id,
1245
- "resourceId",
1246
- title,
1247
- metadata,
1248
- "createdAt",
1249
- "updatedAt"
1250
- FROM ${this.getTableName(storage.TABLE_THREADS)}
1251
- WHERE "resourceId" = $1`,
1252
- [resourceId]
1253
- );
1254
- return threads.map((thread) => ({
1255
- ...thread,
1256
- metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
1257
- createdAt: thread.createdAt,
1258
- updatedAt: thread.updatedAt
1259
- }));
1251
+ const baseQuery = `FROM ${this.getTableName(storage.TABLE_THREADS)} WHERE "resourceId" = $1`;
1252
+ const queryParams = [resourceId];
1253
+ if (page !== void 0) {
1254
+ const perPage = perPageInput !== void 0 ? perPageInput : 100;
1255
+ const currentOffset = page * perPage;
1256
+ const countQuery = `SELECT COUNT(*) ${baseQuery}`;
1257
+ const countResult = await this.db.one(countQuery, queryParams);
1258
+ const total = parseInt(countResult.count, 10);
1259
+ if (total === 0) {
1260
+ return {
1261
+ threads: [],
1262
+ total: 0,
1263
+ page,
1264
+ perPage,
1265
+ hasMore: false
1266
+ };
1267
+ }
1268
+ const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "createdAt" DESC LIMIT $2 OFFSET $3`;
1269
+ const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
1270
+ const threads = (rows || []).map((thread) => ({
1271
+ ...thread,
1272
+ metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
1273
+ createdAt: thread.createdAt,
1274
+ // Assuming already Date objects or ISO strings
1275
+ updatedAt: thread.updatedAt
1276
+ }));
1277
+ return {
1278
+ threads,
1279
+ total,
1280
+ page,
1281
+ perPage,
1282
+ hasMore: currentOffset + threads.length < total
1283
+ };
1284
+ } else {
1285
+ const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "updatedAt" ${baseQuery} ORDER BY "createdAt" DESC`;
1286
+ const rows = await this.db.manyOrNone(dataQuery, queryParams);
1287
+ return (rows || []).map((thread) => ({
1288
+ ...thread,
1289
+ metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
1290
+ createdAt: thread.createdAt,
1291
+ updatedAt: thread.updatedAt
1292
+ }));
1293
+ }
1260
1294
  } catch (error) {
1261
- console.error(`Error getting threads for resource ${resourceId}:`, error);
1262
- throw error;
1295
+ this.logger.error(`Error getting threads for resource ${resourceId}:`, error);
1296
+ if (page !== void 0) {
1297
+ return { threads: [], total: 0, page, perPage: perPageInput || 100, hasMore: false };
1298
+ }
1299
+ return [];
1263
1300
  }
1264
1301
  }
1265
1302
  async saveThread({ thread }) {
@@ -1339,84 +1376,143 @@ var PostgresStore = class extends storage.MastraStorage {
1339
1376
  throw error;
1340
1377
  }
1341
1378
  }
1342
- async getMessages({ threadId, selectBy }) {
1379
+ async getMessages(args) {
1380
+ const { threadId, format, page, perPage: perPageInput, fromDate, toDate, selectBy } = args;
1381
+ const selectStatement = `SELECT id, content, role, type, "createdAt", thread_id AS "threadId"`;
1382
+ const orderByStatement = `ORDER BY "createdAt" DESC`;
1343
1383
  try {
1344
- const messages = [];
1345
- const limit = typeof selectBy?.last === `number` ? selectBy.last : 40;
1346
- const include = selectBy?.include || [];
1347
- if (include.length) {
1348
- const includeResult = await this.db.manyOrNone(
1349
- `
1350
- WITH ordered_messages AS (
1351
- SELECT
1352
- *,
1353
- ROW_NUMBER() OVER (ORDER BY "createdAt" DESC) as row_num
1354
- FROM ${this.getTableName(storage.TABLE_MESSAGES)}
1355
- WHERE thread_id = $1
1356
- )
1357
- SELECT
1358
- m.id,
1359
- m.content,
1360
- m.role,
1361
- m.type,
1362
- m."createdAt",
1363
- m.thread_id AS "threadId"
1364
- FROM ordered_messages m
1365
- WHERE m.id = ANY($2)
1366
- OR EXISTS (
1367
- SELECT 1 FROM ordered_messages target
1368
- WHERE target.id = ANY($2)
1369
- AND (
1370
- -- Get previous messages based on the max withPreviousMessages
1371
- (m.row_num <= target.row_num + $3 AND m.row_num > target.row_num)
1372
- OR
1373
- -- Get next messages based on the max withNextMessages
1374
- (m.row_num >= target.row_num - $4 AND m.row_num < target.row_num)
1384
+ if (page !== void 0) {
1385
+ const perPage = perPageInput !== void 0 ? perPageInput : 40;
1386
+ const currentOffset = page * perPage;
1387
+ const conditions = [`thread_id = $1`];
1388
+ const queryParams = [threadId];
1389
+ let paramIndex = 2;
1390
+ if (fromDate) {
1391
+ conditions.push(`"createdAt" >= $${paramIndex++}`);
1392
+ queryParams.push(fromDate);
1393
+ }
1394
+ if (toDate) {
1395
+ conditions.push(`"createdAt" <= $${paramIndex++}`);
1396
+ queryParams.push(toDate);
1397
+ }
1398
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1399
+ const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(storage.TABLE_MESSAGES)} ${whereClause}`;
1400
+ const countResult = await this.db.one(countQuery, queryParams);
1401
+ const total = parseInt(countResult.count, 10);
1402
+ if (total === 0) {
1403
+ return {
1404
+ messages: [],
1405
+ total: 0,
1406
+ page,
1407
+ perPage,
1408
+ hasMore: false
1409
+ };
1410
+ }
1411
+ const dataQuery = `${selectStatement} FROM ${this.getTableName(storage.TABLE_MESSAGES)} ${whereClause} ${orderByStatement} LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
1412
+ const rows = await this.db.manyOrNone(dataQuery, [...queryParams, perPage, currentOffset]);
1413
+ const fetchedMessages = (rows || []).map((message) => {
1414
+ if (typeof message.content === "string") {
1415
+ try {
1416
+ message.content = JSON.parse(message.content);
1417
+ } catch {
1418
+ }
1419
+ }
1420
+ if (message.type === "v2") delete message.type;
1421
+ return message;
1422
+ });
1423
+ const messagesToReturn = format === "v2" ? fetchedMessages.map(
1424
+ (m) => ({
1425
+ ...m,
1426
+ content: m.content || { format: 2, parts: [{ type: "text", text: "" }] }
1427
+ })
1428
+ ) : fetchedMessages;
1429
+ return {
1430
+ messages: messagesToReturn,
1431
+ total,
1432
+ page,
1433
+ perPage,
1434
+ hasMore: currentOffset + fetchedMessages.length < total
1435
+ };
1436
+ } else {
1437
+ let rows = [];
1438
+ const include = selectBy?.include || [];
1439
+ if (include.length) {
1440
+ rows = await this.db.manyOrNone(
1441
+ `
1442
+ WITH ordered_messages AS (
1443
+ SELECT
1444
+ *,
1445
+ ROW_NUMBER() OVER (${orderByStatement}) as row_num
1446
+ FROM ${this.getTableName(storage.TABLE_MESSAGES)}
1447
+ WHERE thread_id = $1
1375
1448
  )
1376
- )
1377
- ORDER BY m."createdAt" DESC
1378
- `,
1379
- [
1380
- threadId,
1381
- include.map((i) => i.id),
1382
- Math.max(...include.map((i) => i.withPreviousMessages || 0)),
1383
- Math.max(...include.map((i) => i.withNextMessages || 0))
1384
- ]
1385
- );
1386
- messages.push(...includeResult);
1387
- }
1388
- const result = await this.db.manyOrNone(
1389
- `
1390
- SELECT
1391
- id,
1392
- content,
1393
- role,
1394
- type,
1395
- "createdAt",
1396
- thread_id AS "threadId"
1397
- FROM ${this.getTableName(storage.TABLE_MESSAGES)}
1398
- WHERE thread_id = $1
1399
- AND id != ALL($2)
1400
- ORDER BY "createdAt" DESC
1401
- LIMIT $3
1402
- `,
1403
- [threadId, messages.map((m) => m.id), limit]
1404
- );
1405
- messages.push(...result);
1406
- messages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
1407
- messages.forEach((message) => {
1408
- if (typeof message.content === "string") {
1409
- try {
1410
- message.content = JSON.parse(message.content);
1411
- } catch {
1449
+ SELECT
1450
+ m.id,
1451
+ m.content,
1452
+ m.role,
1453
+ m.type,
1454
+ m."createdAt",
1455
+ m.thread_id AS "threadId"
1456
+ FROM ordered_messages m
1457
+ WHERE m.id = ANY($2)
1458
+ OR EXISTS (
1459
+ SELECT 1 FROM ordered_messages target
1460
+ WHERE target.id = ANY($2)
1461
+ AND (
1462
+ -- Get previous messages based on the max withPreviousMessages
1463
+ (m.row_num <= target.row_num + $3 AND m.row_num > target.row_num)
1464
+ OR
1465
+ -- Get next messages based on the max withNextMessages
1466
+ (m.row_num >= target.row_num - $4 AND m.row_num < target.row_num)
1467
+ )
1468
+ )
1469
+ ORDER BY m."createdAt" ASC
1470
+ `,
1471
+ // Keep ASC for final sorting after fetching context
1472
+ [
1473
+ threadId,
1474
+ include.map((i) => i.id),
1475
+ Math.max(0, ...include.map((i) => i.withPreviousMessages || 0)),
1476
+ // Ensure non-negative
1477
+ Math.max(0, ...include.map((i) => i.withNextMessages || 0))
1478
+ // Ensure non-negative
1479
+ ]
1480
+ );
1481
+ } else {
1482
+ const limit = typeof selectBy?.last === `number` ? selectBy.last : 40;
1483
+ if (limit === 0 && selectBy?.last !== false) ; else {
1484
+ let query = `${selectStatement} FROM ${this.getTableName(storage.TABLE_MESSAGES)} WHERE thread_id = $1 ${orderByStatement}`;
1485
+ const queryParams = [threadId];
1486
+ if (limit !== void 0 && selectBy?.last !== false) {
1487
+ query += ` LIMIT $2`;
1488
+ queryParams.push(limit);
1489
+ }
1490
+ rows = await this.db.manyOrNone(query, queryParams);
1412
1491
  }
1413
1492
  }
1414
- if (message.type === `v2`) delete message.type;
1415
- });
1416
- return messages;
1493
+ const fetchedMessages = (rows || []).map((message) => {
1494
+ if (typeof message.content === "string") {
1495
+ try {
1496
+ message.content = JSON.parse(message.content);
1497
+ } catch {
1498
+ }
1499
+ }
1500
+ if (message.type === "v2") delete message.type;
1501
+ return message;
1502
+ });
1503
+ const sortedMessages = fetchedMessages.sort(
1504
+ (a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
1505
+ );
1506
+ return format === "v2" ? sortedMessages.map(
1507
+ (m) => ({ ...m, content: m.content || { format: 2, parts: [{ type: "text", text: "" }] } })
1508
+ ) : sortedMessages;
1509
+ }
1417
1510
  } catch (error) {
1418
- console.error("Error getting messages:", error);
1419
- throw error;
1511
+ this.logger.error("Error getting messages:", error);
1512
+ if (page !== void 0) {
1513
+ return { messages: [], total: 0, page, perPage: perPageInput || 40, hasMore: false };
1514
+ }
1515
+ return [];
1420
1516
  }
1421
1517
  }
1422
1518
  async saveMessages({
@@ -1629,6 +1725,73 @@ var PostgresStore = class extends storage.MastraStorage {
1629
1725
  async close() {
1630
1726
  this.pgp.end();
1631
1727
  }
1728
+ async getEvals(options) {
1729
+ const { agentName, type, page, perPage, limit, offset, fromDate, toDate } = options || {};
1730
+ const conditions = [];
1731
+ const queryParams = [];
1732
+ let paramIndex = 1;
1733
+ if (agentName) {
1734
+ conditions.push(`agent_name = $${paramIndex++}`);
1735
+ queryParams.push(agentName);
1736
+ }
1737
+ if (type === "test") {
1738
+ conditions.push(`(test_info IS NOT NULL AND test_info->>'testPath' IS NOT NULL)`);
1739
+ } else if (type === "live") {
1740
+ conditions.push(`(test_info IS NULL OR test_info->>'testPath' IS NULL)`);
1741
+ }
1742
+ if (fromDate) {
1743
+ conditions.push(`created_at >= $${paramIndex++}`);
1744
+ queryParams.push(fromDate);
1745
+ }
1746
+ if (toDate) {
1747
+ conditions.push(`created_at <= $${paramIndex++}`);
1748
+ queryParams.push(toDate);
1749
+ }
1750
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1751
+ const countQuery = `SELECT COUNT(*) FROM ${this.getTableName(storage.TABLE_EVALS)} ${whereClause}`;
1752
+ const countResult = await this.db.one(countQuery, queryParams);
1753
+ const total = parseInt(countResult.count, 10);
1754
+ let currentLimit;
1755
+ let currentOffset;
1756
+ let currentPage = page;
1757
+ let currentPerPage = perPage;
1758
+ let hasMore = false;
1759
+ if (limit !== void 0 && offset !== void 0) {
1760
+ currentLimit = limit;
1761
+ currentOffset = offset;
1762
+ currentPage = void 0;
1763
+ currentPerPage = void 0;
1764
+ hasMore = currentOffset + currentLimit < total;
1765
+ } else if (page !== void 0 && perPage !== void 0) {
1766
+ currentLimit = perPage;
1767
+ currentOffset = page * perPage;
1768
+ hasMore = currentOffset + currentLimit < total;
1769
+ } else {
1770
+ currentLimit = perPage || 100;
1771
+ currentOffset = (page || 0) * currentLimit;
1772
+ if (page === void 0) currentPage = 0;
1773
+ if (currentPerPage === void 0) currentPerPage = currentLimit;
1774
+ hasMore = currentOffset + currentLimit < total;
1775
+ }
1776
+ if (total === 0) {
1777
+ return {
1778
+ evals: [],
1779
+ total: 0,
1780
+ page: currentPage,
1781
+ perPage: currentPerPage,
1782
+ hasMore: false
1783
+ };
1784
+ }
1785
+ const dataQuery = `SELECT * FROM ${this.getTableName(storage.TABLE_EVALS)} ${whereClause} ORDER BY created_at DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
1786
+ const rows = await this.db.manyOrNone(dataQuery, [...queryParams, currentLimit, currentOffset]);
1787
+ return {
1788
+ evals: rows?.map((row) => this.transformEvalRow(row)) ?? [],
1789
+ total,
1790
+ page: currentPage,
1791
+ perPage: currentPerPage,
1792
+ hasMore
1793
+ };
1794
+ }
1632
1795
  };
1633
1796
 
1634
1797
  // src/vector/prompt.ts