@mastra/libsql 0.10.1-alpha.3 → 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
@@ -964,22 +964,83 @@ var LibSQLStore = class extends storage.MastraStorage {
964
964
  metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
965
965
  };
966
966
  }
967
- async getThreadsByResourceId({ resourceId }) {
968
- const result = await this.client.execute({
969
- sql: `SELECT * FROM ${storage.TABLE_THREADS} WHERE resourceId = ?`,
970
- args: [resourceId]
971
- });
972
- if (!result.rows) {
967
+ /**
968
+ * @deprecated use getThreadsByResourceIdPaginated instead for paginated results.
969
+ */
970
+ async getThreadsByResourceId(args) {
971
+ const { resourceId } = args;
972
+ try {
973
+ const baseQuery = `FROM ${storage.TABLE_THREADS} WHERE resourceId = ?`;
974
+ const queryParams = [resourceId];
975
+ const mapRowToStorageThreadType = (row) => ({
976
+ id: row.id,
977
+ resourceId: row.resourceId,
978
+ title: row.title,
979
+ createdAt: new Date(row.createdAt),
980
+ // Convert string to Date
981
+ updatedAt: new Date(row.updatedAt),
982
+ // Convert string to Date
983
+ metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata
984
+ });
985
+ const result = await this.client.execute({
986
+ sql: `SELECT * ${baseQuery} ORDER BY createdAt DESC`,
987
+ args: queryParams
988
+ });
989
+ if (!result.rows) {
990
+ return [];
991
+ }
992
+ return result.rows.map(mapRowToStorageThreadType);
993
+ } catch (error) {
994
+ this.logger.error(`Error getting threads for resource ${resourceId}:`, error);
973
995
  return [];
974
996
  }
975
- return result.rows.map((thread) => ({
976
- id: thread.id,
977
- resourceId: thread.resourceId,
978
- title: thread.title,
979
- createdAt: thread.createdAt,
980
- updatedAt: thread.updatedAt,
981
- metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata
982
- }));
997
+ }
998
+ async getThreadsByResourceIdPaginated(args) {
999
+ const { resourceId, page = 0, perPage = 100 } = args;
1000
+ try {
1001
+ const baseQuery = `FROM ${storage.TABLE_THREADS} WHERE resourceId = ?`;
1002
+ const queryParams = [resourceId];
1003
+ const mapRowToStorageThreadType = (row) => ({
1004
+ id: row.id,
1005
+ resourceId: row.resourceId,
1006
+ title: row.title,
1007
+ createdAt: new Date(row.createdAt),
1008
+ // Convert string to Date
1009
+ updatedAt: new Date(row.updatedAt),
1010
+ // Convert string to Date
1011
+ metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata
1012
+ });
1013
+ const currentOffset = page * perPage;
1014
+ const countResult = await this.client.execute({
1015
+ sql: `SELECT COUNT(*) as count ${baseQuery}`,
1016
+ args: queryParams
1017
+ });
1018
+ const total = Number(countResult.rows?.[0]?.count ?? 0);
1019
+ if (total === 0) {
1020
+ return {
1021
+ threads: [],
1022
+ total: 0,
1023
+ page,
1024
+ perPage,
1025
+ hasMore: false
1026
+ };
1027
+ }
1028
+ const dataResult = await this.client.execute({
1029
+ sql: `SELECT * ${baseQuery} ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
1030
+ args: [...queryParams, perPage, currentOffset]
1031
+ });
1032
+ const threads = (dataResult.rows || []).map(mapRowToStorageThreadType);
1033
+ return {
1034
+ threads,
1035
+ total,
1036
+ page,
1037
+ perPage,
1038
+ hasMore: currentOffset + threads.length < total
1039
+ };
1040
+ } catch (error) {
1041
+ this.logger.error(`Error getting threads for resource ${resourceId}:`, error);
1042
+ return { threads: [], total: 0, page, perPage, hasMore: false };
1043
+ }
983
1044
  }
984
1045
  async saveThread({ thread }) {
985
1046
  await this.insert({
@@ -1036,6 +1097,36 @@ var LibSQLStore = class extends storage.MastraStorage {
1036
1097
  if (row.type && row.type !== `v2`) result.type = row.type;
1037
1098
  return result;
1038
1099
  }
1100
+ async _getIncludedMessages(threadId, selectBy) {
1101
+ const include = selectBy?.include;
1102
+ if (!include) return null;
1103
+ const includeIds = include.map((i) => i.id);
1104
+ const maxPrev = Math.max(...include.map((i) => i.withPreviousMessages || 0));
1105
+ const maxNext = Math.max(...include.map((i) => i.withNextMessages || 0));
1106
+ const includeResult = await this.client.execute({
1107
+ sql: `
1108
+ WITH numbered_messages AS (
1109
+ SELECT
1110
+ id, content, role, type, "createdAt", thread_id,
1111
+ ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
1112
+ FROM "${storage.TABLE_MESSAGES}"
1113
+ WHERE thread_id = ?
1114
+ ),
1115
+ target_positions AS (
1116
+ SELECT row_num as target_pos
1117
+ FROM numbered_messages
1118
+ WHERE id IN (${includeIds.map(() => "?").join(", ")})
1119
+ )
1120
+ SELECT DISTINCT m.*
1121
+ FROM numbered_messages m
1122
+ CROSS JOIN target_positions t
1123
+ WHERE m.row_num BETWEEN (t.target_pos - ?) AND (t.target_pos + ?)
1124
+ ORDER BY m."createdAt" ASC
1125
+ `,
1126
+ args: [threadId, ...includeIds, maxPrev, maxNext]
1127
+ });
1128
+ return includeResult.rows?.map((row) => this.parseRow(row));
1129
+ }
1039
1130
  async getMessages({
1040
1131
  threadId,
1041
1132
  selectBy,
@@ -1045,60 +1136,21 @@ var LibSQLStore = class extends storage.MastraStorage {
1045
1136
  const messages = [];
1046
1137
  const limit = typeof selectBy?.last === `number` ? selectBy.last : 40;
1047
1138
  if (selectBy?.include?.length) {
1048
- const includeIds = selectBy.include.map((i) => i.id);
1049
- const maxPrev = Math.max(...selectBy.include.map((i) => i.withPreviousMessages || 0));
1050
- const maxNext = Math.max(...selectBy.include.map((i) => i.withNextMessages || 0));
1051
- const includeResult = await this.client.execute({
1052
- sql: `
1053
- WITH numbered_messages AS (
1054
- SELECT
1055
- id,
1056
- content,
1057
- role,
1058
- type,
1059
- "createdAt",
1060
- thread_id,
1061
- ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
1062
- FROM "${storage.TABLE_MESSAGES}"
1063
- WHERE thread_id = ?
1064
- ),
1065
- target_positions AS (
1066
- SELECT row_num as target_pos
1067
- FROM numbered_messages
1068
- WHERE id IN (${includeIds.map(() => "?").join(", ")})
1069
- )
1070
- SELECT DISTINCT m.*
1071
- FROM numbered_messages m
1072
- CROSS JOIN target_positions t
1073
- WHERE m.row_num BETWEEN (t.target_pos - ?) AND (t.target_pos + ?)
1074
- ORDER BY m."createdAt" ASC
1075
- `,
1076
- args: [threadId, ...includeIds, maxPrev, maxNext]
1077
- });
1078
- if (includeResult.rows) {
1079
- messages.push(...includeResult.rows.map((row) => this.parseRow(row)));
1139
+ const includeMessages = await this._getIncludedMessages(threadId, selectBy);
1140
+ if (includeMessages) {
1141
+ messages.push(...includeMessages);
1080
1142
  }
1081
1143
  }
1082
1144
  const excludeIds = messages.map((m) => m.id);
1083
1145
  const remainingSql = `
1084
- SELECT
1085
- id,
1086
- content,
1087
- role,
1088
- type,
1089
- "createdAt",
1090
- thread_id
1091
- FROM "${storage.TABLE_MESSAGES}"
1092
- WHERE thread_id = ?
1093
- ${excludeIds.length ? `AND id NOT IN (${excludeIds.map(() => "?").join(", ")})` : ""}
1094
- ORDER BY "createdAt" DESC
1095
- LIMIT ?
1096
- `;
1146
+ SELECT id, content, role, type, "createdAt", thread_id
1147
+ FROM "${storage.TABLE_MESSAGES}"
1148
+ WHERE thread_id = ?
1149
+ ${excludeIds.length ? `AND id NOT IN (${excludeIds.map(() => "?").join(", ")})` : ""}
1150
+ ORDER BY "createdAt" DESC LIMIT ?
1151
+ `;
1097
1152
  const remainingArgs = [threadId, ...excludeIds.length ? excludeIds : [], limit];
1098
- const remainingResult = await this.client.execute({
1099
- sql: remainingSql,
1100
- args: remainingArgs
1101
- });
1153
+ const remainingResult = await this.client.execute({ sql: remainingSql, args: remainingArgs });
1102
1154
  if (remainingResult.rows) {
1103
1155
  messages.push(...remainingResult.rows.map((row) => this.parseRow(row)));
1104
1156
  }
@@ -1111,6 +1163,63 @@ var LibSQLStore = class extends storage.MastraStorage {
1111
1163
  throw error;
1112
1164
  }
1113
1165
  }
1166
+ async getMessagesPaginated(args) {
1167
+ const { threadId, format, selectBy } = args;
1168
+ const { page = 0, perPage = 40, dateRange } = selectBy?.pagination || {};
1169
+ const fromDate = dateRange?.start;
1170
+ const toDate = dateRange?.end;
1171
+ const messages = [];
1172
+ if (selectBy?.include?.length) {
1173
+ const includeMessages = await this._getIncludedMessages(threadId, selectBy);
1174
+ if (includeMessages) {
1175
+ messages.push(...includeMessages);
1176
+ }
1177
+ }
1178
+ try {
1179
+ const currentOffset = page * perPage;
1180
+ const conditions = [`thread_id = ?`];
1181
+ const queryParams = [threadId];
1182
+ if (fromDate) {
1183
+ conditions.push(`"createdAt" >= ?`);
1184
+ queryParams.push(fromDate.toISOString());
1185
+ }
1186
+ if (toDate) {
1187
+ conditions.push(`"createdAt" <= ?`);
1188
+ queryParams.push(toDate.toISOString());
1189
+ }
1190
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1191
+ const countResult = await this.client.execute({
1192
+ sql: `SELECT COUNT(*) as count FROM ${storage.TABLE_MESSAGES} ${whereClause}`,
1193
+ args: queryParams
1194
+ });
1195
+ const total = Number(countResult.rows?.[0]?.count ?? 0);
1196
+ if (total === 0) {
1197
+ return {
1198
+ messages: [],
1199
+ total: 0,
1200
+ page,
1201
+ perPage,
1202
+ hasMore: false
1203
+ };
1204
+ }
1205
+ const dataResult = await this.client.execute({
1206
+ sql: `SELECT id, content, role, type, "createdAt", thread_id FROM ${storage.TABLE_MESSAGES} ${whereClause} ORDER BY "createdAt" DESC LIMIT ? OFFSET ?`,
1207
+ args: [...queryParams, perPage, currentOffset]
1208
+ });
1209
+ messages.push(...(dataResult.rows || []).map((row) => this.parseRow(row)));
1210
+ const messagesToReturn = format === "v1" ? new agent.MessageList().add(messages, "memory").get.all.v1() : new agent.MessageList().add(messages, "memory").get.all.v2();
1211
+ return {
1212
+ messages: messagesToReturn,
1213
+ total,
1214
+ page,
1215
+ perPage,
1216
+ hasMore: currentOffset + messages.length < total
1217
+ };
1218
+ } catch (error) {
1219
+ this.logger.error("Error getting paginated messages:", error);
1220
+ return { messages: [], total: 0, page, perPage, hasMore: false };
1221
+ }
1222
+ }
1114
1223
  async saveMessages({
1115
1224
  messages,
1116
1225
  format
@@ -1169,6 +1278,7 @@ var LibSQLStore = class extends storage.MastraStorage {
1169
1278
  createdAt: row.created_at
1170
1279
  };
1171
1280
  }
1281
+ /** @deprecated use getEvals instead */
1172
1282
  async getEvalsByAgentName(agentName, type) {
1173
1283
  try {
1174
1284
  const baseQuery = `SELECT * FROM ${storage.TABLE_EVALS} WHERE agent_name = ?`;
@@ -1186,93 +1296,150 @@ var LibSQLStore = class extends storage.MastraStorage {
1186
1296
  throw error;
1187
1297
  }
1188
1298
  }
1189
- // TODO: add types
1190
- async getTraces({
1191
- name,
1192
- scope,
1193
- page,
1194
- perPage,
1195
- attributes,
1196
- filters,
1197
- fromDate,
1198
- toDate
1199
- } = {
1200
- page: 0,
1201
- perPage: 100
1202
- }) {
1203
- const limit = perPage;
1204
- const offset = page * perPage;
1205
- const args = [];
1299
+ async getEvals(options = {}) {
1300
+ const { agentName, type, page = 0, perPage = 100, dateRange } = options;
1301
+ const fromDate = dateRange?.start;
1302
+ const toDate = dateRange?.end;
1206
1303
  const conditions = [];
1207
- if (name) {
1208
- conditions.push("name LIKE CONCAT(?, '%')");
1304
+ const queryParams = [];
1305
+ if (agentName) {
1306
+ conditions.push(`agent_name = ?`);
1307
+ queryParams.push(agentName);
1209
1308
  }
1210
- if (scope) {
1211
- conditions.push("scope = ?");
1212
- }
1213
- if (attributes) {
1214
- Object.keys(attributes).forEach((key) => {
1215
- conditions.push(`attributes->>'$.${key}' = ?`);
1216
- });
1217
- }
1218
- if (filters) {
1219
- Object.entries(filters).forEach(([key, _value]) => {
1220
- conditions.push(`${key} = ?`);
1221
- });
1309
+ if (type === "test") {
1310
+ conditions.push(`(test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL)`);
1311
+ } else if (type === "live") {
1312
+ conditions.push(`(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)`);
1222
1313
  }
1223
1314
  if (fromDate) {
1224
- conditions.push("createdAt >= ?");
1315
+ conditions.push(`created_at >= ?`);
1316
+ queryParams.push(fromDate.toISOString());
1225
1317
  }
1226
1318
  if (toDate) {
1227
- conditions.push("createdAt <= ?");
1319
+ conditions.push(`created_at <= ?`);
1320
+ queryParams.push(toDate.toISOString());
1228
1321
  }
1229
1322
  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1323
+ const countResult = await this.client.execute({
1324
+ sql: `SELECT COUNT(*) as count FROM ${storage.TABLE_EVALS} ${whereClause}`,
1325
+ args: queryParams
1326
+ });
1327
+ const total = Number(countResult.rows?.[0]?.count ?? 0);
1328
+ const currentOffset = page * perPage;
1329
+ const hasMore = currentOffset + perPage < total;
1330
+ if (total === 0) {
1331
+ return {
1332
+ evals: [],
1333
+ total: 0,
1334
+ page,
1335
+ perPage,
1336
+ hasMore: false
1337
+ };
1338
+ }
1339
+ const dataResult = await this.client.execute({
1340
+ sql: `SELECT * FROM ${storage.TABLE_EVALS} ${whereClause} ORDER BY created_at DESC LIMIT ? OFFSET ?`,
1341
+ args: [...queryParams, perPage, currentOffset]
1342
+ });
1343
+ return {
1344
+ evals: dataResult.rows?.map((row) => this.transformEvalRow(row)) ?? [],
1345
+ total,
1346
+ page,
1347
+ perPage,
1348
+ hasMore
1349
+ };
1350
+ }
1351
+ /**
1352
+ * @deprecated use getTracesPaginated instead.
1353
+ */
1354
+ async getTraces(args) {
1355
+ if (args.fromDate || args.toDate) {
1356
+ args.dateRange = {
1357
+ start: args.fromDate,
1358
+ end: args.toDate
1359
+ };
1360
+ }
1361
+ const result = await this.getTracesPaginated(args);
1362
+ return result.traces;
1363
+ }
1364
+ async getTracesPaginated(args) {
1365
+ const { name, scope, page = 0, perPage = 100, attributes, filters, dateRange } = args;
1366
+ const fromDate = dateRange?.start;
1367
+ const toDate = dateRange?.end;
1368
+ const currentOffset = page * perPage;
1369
+ const queryArgs = [];
1370
+ const conditions = [];
1230
1371
  if (name) {
1231
- args.push(name);
1372
+ conditions.push("name LIKE ?");
1373
+ queryArgs.push(`${name}%`);
1232
1374
  }
1233
1375
  if (scope) {
1234
- args.push(scope);
1376
+ conditions.push("scope = ?");
1377
+ queryArgs.push(scope);
1235
1378
  }
1236
1379
  if (attributes) {
1237
- for (const [, value] of Object.entries(attributes)) {
1238
- args.push(value);
1239
- }
1380
+ Object.entries(attributes).forEach(([key, value]) => {
1381
+ conditions.push(`json_extract(attributes, '$.${key}') = ?`);
1382
+ queryArgs.push(value);
1383
+ });
1240
1384
  }
1241
1385
  if (filters) {
1242
- for (const [, value] of Object.entries(filters)) {
1243
- args.push(value);
1244
- }
1386
+ Object.entries(filters).forEach(([key, value]) => {
1387
+ conditions.push(`${utils.parseSqlIdentifier(key, "filter key")} = ?`);
1388
+ queryArgs.push(value);
1389
+ });
1245
1390
  }
1246
1391
  if (fromDate) {
1247
- args.push(fromDate.toISOString());
1392
+ conditions.push("createdAt >= ?");
1393
+ queryArgs.push(fromDate.toISOString());
1248
1394
  }
1249
1395
  if (toDate) {
1250
- args.push(toDate.toISOString());
1396
+ conditions.push("createdAt <= ?");
1397
+ queryArgs.push(toDate.toISOString());
1251
1398
  }
1252
- args.push(limit, offset);
1253
- const result = await this.client.execute({
1254
- sql: `SELECT * FROM ${storage.TABLE_TRACES} ${whereClause} ORDER BY "startTime" DESC LIMIT ? OFFSET ?`,
1255
- args
1399
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1400
+ const countResult = await this.client.execute({
1401
+ sql: `SELECT COUNT(*) as count FROM ${storage.TABLE_TRACES} ${whereClause}`,
1402
+ args: queryArgs
1256
1403
  });
1257
- if (!result.rows) {
1258
- return [];
1404
+ const total = Number(countResult.rows?.[0]?.count ?? 0);
1405
+ if (total === 0) {
1406
+ return {
1407
+ traces: [],
1408
+ total: 0,
1409
+ page,
1410
+ perPage,
1411
+ hasMore: false
1412
+ };
1259
1413
  }
1260
- return result.rows.map((row) => ({
1261
- id: row.id,
1262
- parentSpanId: row.parentSpanId,
1263
- traceId: row.traceId,
1264
- name: row.name,
1265
- scope: row.scope,
1266
- kind: row.kind,
1267
- status: safelyParseJSON(row.status),
1268
- events: safelyParseJSON(row.events),
1269
- links: safelyParseJSON(row.links),
1270
- attributes: safelyParseJSON(row.attributes),
1271
- startTime: row.startTime,
1272
- endTime: row.endTime,
1273
- other: safelyParseJSON(row.other),
1274
- createdAt: row.createdAt
1275
- }));
1414
+ const dataResult = await this.client.execute({
1415
+ sql: `SELECT * FROM ${storage.TABLE_TRACES} ${whereClause} ORDER BY "startTime" DESC LIMIT ? OFFSET ?`,
1416
+ args: [...queryArgs, perPage, currentOffset]
1417
+ });
1418
+ const traces = dataResult.rows?.map(
1419
+ (row) => ({
1420
+ id: row.id,
1421
+ parentSpanId: row.parentSpanId,
1422
+ traceId: row.traceId,
1423
+ name: row.name,
1424
+ scope: row.scope,
1425
+ kind: row.kind,
1426
+ status: safelyParseJSON(row.status),
1427
+ events: safelyParseJSON(row.events),
1428
+ links: safelyParseJSON(row.links),
1429
+ attributes: safelyParseJSON(row.attributes),
1430
+ startTime: row.startTime,
1431
+ endTime: row.endTime,
1432
+ other: safelyParseJSON(row.other),
1433
+ createdAt: row.createdAt
1434
+ })
1435
+ ) ?? [];
1436
+ return {
1437
+ traces,
1438
+ total,
1439
+ page,
1440
+ perPage,
1441
+ hasMore: currentOffset + traces.length < total
1442
+ };
1276
1443
  }
1277
1444
  async getWorkflowRuns({
1278
1445
  workflowName,