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