@mastra/libsql 0.10.1 → 0.10.2-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +27 -0
- package/dist/_tsup-dts-rollup.d.cts +53 -3
- package/dist/_tsup-dts-rollup.d.ts +53 -3
- package/dist/index.cjs +347 -129
- package/dist/index.js +347 -129
- package/package.json +10 -10
- package/src/storage/index.test.ts +356 -6
- package/src/storage/index.ts +437 -157
package/dist/index.cjs
CHANGED
|
@@ -851,6 +851,52 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
851
851
|
throw error;
|
|
852
852
|
}
|
|
853
853
|
}
|
|
854
|
+
getSqlType(type) {
|
|
855
|
+
switch (type) {
|
|
856
|
+
case "bigint":
|
|
857
|
+
return "INTEGER";
|
|
858
|
+
// SQLite uses INTEGER for all integer sizes
|
|
859
|
+
case "jsonb":
|
|
860
|
+
return "TEXT";
|
|
861
|
+
// Store JSON as TEXT in SQLite
|
|
862
|
+
default:
|
|
863
|
+
return super.getSqlType(type);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Alters table schema to add columns if they don't exist
|
|
868
|
+
* @param tableName Name of the table
|
|
869
|
+
* @param schema Schema of the table
|
|
870
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
871
|
+
*/
|
|
872
|
+
async alterTable({
|
|
873
|
+
tableName,
|
|
874
|
+
schema,
|
|
875
|
+
ifNotExists
|
|
876
|
+
}) {
|
|
877
|
+
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
878
|
+
try {
|
|
879
|
+
const pragmaQuery = `PRAGMA table_info(${parsedTableName})`;
|
|
880
|
+
const result = await this.client.execute(pragmaQuery);
|
|
881
|
+
const existingColumnNames = new Set(result.rows.map((row) => row.name.toLowerCase()));
|
|
882
|
+
for (const columnName of ifNotExists) {
|
|
883
|
+
if (!existingColumnNames.has(columnName.toLowerCase()) && schema[columnName]) {
|
|
884
|
+
const columnDef = schema[columnName];
|
|
885
|
+
const sqlType = this.getSqlType(columnDef.type);
|
|
886
|
+
const nullable = columnDef.nullable === false ? "NOT NULL" : "";
|
|
887
|
+
const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
|
|
888
|
+
const alterSql = `ALTER TABLE ${parsedTableName} ADD COLUMN "${columnName}" ${sqlType} ${nullable} ${defaultValue}`.trim();
|
|
889
|
+
await this.client.execute(alterSql);
|
|
890
|
+
this.logger?.debug?.(`Added column ${columnName} to table ${parsedTableName}`);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
} catch (error) {
|
|
894
|
+
this.logger?.error?.(
|
|
895
|
+
`Error altering table ${tableName}: ${error instanceof Error ? error.message : String(error)}`
|
|
896
|
+
);
|
|
897
|
+
throw new Error(`Failed to alter table ${tableName}: ${error}`);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
854
900
|
async clearTable({ tableName }) {
|
|
855
901
|
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
856
902
|
try {
|
|
@@ -964,22 +1010,83 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
964
1010
|
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
|
|
965
1011
|
};
|
|
966
1012
|
}
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
}
|
|
972
|
-
|
|
1013
|
+
/**
|
|
1014
|
+
* @deprecated use getThreadsByResourceIdPaginated instead for paginated results.
|
|
1015
|
+
*/
|
|
1016
|
+
async getThreadsByResourceId(args) {
|
|
1017
|
+
const { resourceId } = args;
|
|
1018
|
+
try {
|
|
1019
|
+
const baseQuery = `FROM ${storage.TABLE_THREADS} WHERE resourceId = ?`;
|
|
1020
|
+
const queryParams = [resourceId];
|
|
1021
|
+
const mapRowToStorageThreadType = (row) => ({
|
|
1022
|
+
id: row.id,
|
|
1023
|
+
resourceId: row.resourceId,
|
|
1024
|
+
title: row.title,
|
|
1025
|
+
createdAt: new Date(row.createdAt),
|
|
1026
|
+
// Convert string to Date
|
|
1027
|
+
updatedAt: new Date(row.updatedAt),
|
|
1028
|
+
// Convert string to Date
|
|
1029
|
+
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata
|
|
1030
|
+
});
|
|
1031
|
+
const result = await this.client.execute({
|
|
1032
|
+
sql: `SELECT * ${baseQuery} ORDER BY createdAt DESC`,
|
|
1033
|
+
args: queryParams
|
|
1034
|
+
});
|
|
1035
|
+
if (!result.rows) {
|
|
1036
|
+
return [];
|
|
1037
|
+
}
|
|
1038
|
+
return result.rows.map(mapRowToStorageThreadType);
|
|
1039
|
+
} catch (error) {
|
|
1040
|
+
this.logger.error(`Error getting threads for resource ${resourceId}:`, error);
|
|
973
1041
|
return [];
|
|
974
1042
|
}
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1043
|
+
}
|
|
1044
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
1045
|
+
const { resourceId, page = 0, perPage = 100 } = args;
|
|
1046
|
+
try {
|
|
1047
|
+
const baseQuery = `FROM ${storage.TABLE_THREADS} WHERE resourceId = ?`;
|
|
1048
|
+
const queryParams = [resourceId];
|
|
1049
|
+
const mapRowToStorageThreadType = (row) => ({
|
|
1050
|
+
id: row.id,
|
|
1051
|
+
resourceId: row.resourceId,
|
|
1052
|
+
title: row.title,
|
|
1053
|
+
createdAt: new Date(row.createdAt),
|
|
1054
|
+
// Convert string to Date
|
|
1055
|
+
updatedAt: new Date(row.updatedAt),
|
|
1056
|
+
// Convert string to Date
|
|
1057
|
+
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata
|
|
1058
|
+
});
|
|
1059
|
+
const currentOffset = page * perPage;
|
|
1060
|
+
const countResult = await this.client.execute({
|
|
1061
|
+
sql: `SELECT COUNT(*) as count ${baseQuery}`,
|
|
1062
|
+
args: queryParams
|
|
1063
|
+
});
|
|
1064
|
+
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
1065
|
+
if (total === 0) {
|
|
1066
|
+
return {
|
|
1067
|
+
threads: [],
|
|
1068
|
+
total: 0,
|
|
1069
|
+
page,
|
|
1070
|
+
perPage,
|
|
1071
|
+
hasMore: false
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
const dataResult = await this.client.execute({
|
|
1075
|
+
sql: `SELECT * ${baseQuery} ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
|
|
1076
|
+
args: [...queryParams, perPage, currentOffset]
|
|
1077
|
+
});
|
|
1078
|
+
const threads = (dataResult.rows || []).map(mapRowToStorageThreadType);
|
|
1079
|
+
return {
|
|
1080
|
+
threads,
|
|
1081
|
+
total,
|
|
1082
|
+
page,
|
|
1083
|
+
perPage,
|
|
1084
|
+
hasMore: currentOffset + threads.length < total
|
|
1085
|
+
};
|
|
1086
|
+
} catch (error) {
|
|
1087
|
+
this.logger.error(`Error getting threads for resource ${resourceId}:`, error);
|
|
1088
|
+
return { threads: [], total: 0, page, perPage, hasMore: false };
|
|
1089
|
+
}
|
|
983
1090
|
}
|
|
984
1091
|
async saveThread({ thread }) {
|
|
985
1092
|
await this.insert({
|
|
@@ -1015,6 +1122,10 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
1015
1122
|
return updatedThread;
|
|
1016
1123
|
}
|
|
1017
1124
|
async deleteThread({ threadId }) {
|
|
1125
|
+
await this.client.execute({
|
|
1126
|
+
sql: `DELETE FROM ${storage.TABLE_MESSAGES} WHERE thread_id = ?`,
|
|
1127
|
+
args: [threadId]
|
|
1128
|
+
});
|
|
1018
1129
|
await this.client.execute({
|
|
1019
1130
|
sql: `DELETE FROM ${storage.TABLE_THREADS} WHERE id = ?`,
|
|
1020
1131
|
args: [threadId]
|
|
@@ -1031,11 +1142,42 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
1031
1142
|
content,
|
|
1032
1143
|
role: row.role,
|
|
1033
1144
|
createdAt: new Date(row.createdAt),
|
|
1034
|
-
threadId: row.thread_id
|
|
1145
|
+
threadId: row.thread_id,
|
|
1146
|
+
resourceId: row.resourceId
|
|
1035
1147
|
};
|
|
1036
1148
|
if (row.type && row.type !== `v2`) result.type = row.type;
|
|
1037
1149
|
return result;
|
|
1038
1150
|
}
|
|
1151
|
+
async _getIncludedMessages(threadId, selectBy) {
|
|
1152
|
+
const include = selectBy?.include;
|
|
1153
|
+
if (!include) return null;
|
|
1154
|
+
const includeIds = include.map((i) => i.id);
|
|
1155
|
+
const maxPrev = Math.max(...include.map((i) => i.withPreviousMessages || 0));
|
|
1156
|
+
const maxNext = Math.max(...include.map((i) => i.withNextMessages || 0));
|
|
1157
|
+
const includeResult = await this.client.execute({
|
|
1158
|
+
sql: `
|
|
1159
|
+
WITH numbered_messages AS (
|
|
1160
|
+
SELECT
|
|
1161
|
+
id, content, role, type, "createdAt", thread_id,
|
|
1162
|
+
ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
|
|
1163
|
+
FROM "${storage.TABLE_MESSAGES}"
|
|
1164
|
+
WHERE thread_id = ?
|
|
1165
|
+
),
|
|
1166
|
+
target_positions AS (
|
|
1167
|
+
SELECT row_num as target_pos
|
|
1168
|
+
FROM numbered_messages
|
|
1169
|
+
WHERE id IN (${includeIds.map(() => "?").join(", ")})
|
|
1170
|
+
)
|
|
1171
|
+
SELECT DISTINCT m.*
|
|
1172
|
+
FROM numbered_messages m
|
|
1173
|
+
CROSS JOIN target_positions t
|
|
1174
|
+
WHERE m.row_num BETWEEN (t.target_pos - ?) AND (t.target_pos + ?)
|
|
1175
|
+
ORDER BY m."createdAt" ASC
|
|
1176
|
+
`,
|
|
1177
|
+
args: [threadId, ...includeIds, maxPrev, maxNext]
|
|
1178
|
+
});
|
|
1179
|
+
return includeResult.rows?.map((row) => this.parseRow(row));
|
|
1180
|
+
}
|
|
1039
1181
|
async getMessages({
|
|
1040
1182
|
threadId,
|
|
1041
1183
|
selectBy,
|
|
@@ -1045,60 +1187,21 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
1045
1187
|
const messages = [];
|
|
1046
1188
|
const limit = typeof selectBy?.last === `number` ? selectBy.last : 40;
|
|
1047
1189
|
if (selectBy?.include?.length) {
|
|
1048
|
-
const
|
|
1049
|
-
|
|
1050
|
-
|
|
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)));
|
|
1190
|
+
const includeMessages = await this._getIncludedMessages(threadId, selectBy);
|
|
1191
|
+
if (includeMessages) {
|
|
1192
|
+
messages.push(...includeMessages);
|
|
1080
1193
|
}
|
|
1081
1194
|
}
|
|
1082
1195
|
const excludeIds = messages.map((m) => m.id);
|
|
1083
1196
|
const remainingSql = `
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
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
|
-
`;
|
|
1197
|
+
SELECT id, content, role, type, "createdAt", thread_id
|
|
1198
|
+
FROM "${storage.TABLE_MESSAGES}"
|
|
1199
|
+
WHERE thread_id = ?
|
|
1200
|
+
${excludeIds.length ? `AND id NOT IN (${excludeIds.map(() => "?").join(", ")})` : ""}
|
|
1201
|
+
ORDER BY "createdAt" DESC LIMIT ?
|
|
1202
|
+
`;
|
|
1097
1203
|
const remainingArgs = [threadId, ...excludeIds.length ? excludeIds : [], limit];
|
|
1098
|
-
const remainingResult = await this.client.execute({
|
|
1099
|
-
sql: remainingSql,
|
|
1100
|
-
args: remainingArgs
|
|
1101
|
-
});
|
|
1204
|
+
const remainingResult = await this.client.execute({ sql: remainingSql, args: remainingArgs });
|
|
1102
1205
|
if (remainingResult.rows) {
|
|
1103
1206
|
messages.push(...remainingResult.rows.map((row) => this.parseRow(row)));
|
|
1104
1207
|
}
|
|
@@ -1111,6 +1214,63 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
1111
1214
|
throw error;
|
|
1112
1215
|
}
|
|
1113
1216
|
}
|
|
1217
|
+
async getMessagesPaginated(args) {
|
|
1218
|
+
const { threadId, format, selectBy } = args;
|
|
1219
|
+
const { page = 0, perPage = 40, dateRange } = selectBy?.pagination || {};
|
|
1220
|
+
const fromDate = dateRange?.start;
|
|
1221
|
+
const toDate = dateRange?.end;
|
|
1222
|
+
const messages = [];
|
|
1223
|
+
if (selectBy?.include?.length) {
|
|
1224
|
+
const includeMessages = await this._getIncludedMessages(threadId, selectBy);
|
|
1225
|
+
if (includeMessages) {
|
|
1226
|
+
messages.push(...includeMessages);
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
try {
|
|
1230
|
+
const currentOffset = page * perPage;
|
|
1231
|
+
const conditions = [`thread_id = ?`];
|
|
1232
|
+
const queryParams = [threadId];
|
|
1233
|
+
if (fromDate) {
|
|
1234
|
+
conditions.push(`"createdAt" >= ?`);
|
|
1235
|
+
queryParams.push(fromDate.toISOString());
|
|
1236
|
+
}
|
|
1237
|
+
if (toDate) {
|
|
1238
|
+
conditions.push(`"createdAt" <= ?`);
|
|
1239
|
+
queryParams.push(toDate.toISOString());
|
|
1240
|
+
}
|
|
1241
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1242
|
+
const countResult = await this.client.execute({
|
|
1243
|
+
sql: `SELECT COUNT(*) as count FROM ${storage.TABLE_MESSAGES} ${whereClause}`,
|
|
1244
|
+
args: queryParams
|
|
1245
|
+
});
|
|
1246
|
+
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
1247
|
+
if (total === 0) {
|
|
1248
|
+
return {
|
|
1249
|
+
messages: [],
|
|
1250
|
+
total: 0,
|
|
1251
|
+
page,
|
|
1252
|
+
perPage,
|
|
1253
|
+
hasMore: false
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
const dataResult = await this.client.execute({
|
|
1257
|
+
sql: `SELECT id, content, role, type, "createdAt", thread_id FROM ${storage.TABLE_MESSAGES} ${whereClause} ORDER BY "createdAt" DESC LIMIT ? OFFSET ?`,
|
|
1258
|
+
args: [...queryParams, perPage, currentOffset]
|
|
1259
|
+
});
|
|
1260
|
+
messages.push(...(dataResult.rows || []).map((row) => this.parseRow(row)));
|
|
1261
|
+
const messagesToReturn = format === "v1" ? new agent.MessageList().add(messages, "memory").get.all.v1() : new agent.MessageList().add(messages, "memory").get.all.v2();
|
|
1262
|
+
return {
|
|
1263
|
+
messages: messagesToReturn,
|
|
1264
|
+
total,
|
|
1265
|
+
page,
|
|
1266
|
+
perPage,
|
|
1267
|
+
hasMore: currentOffset + messages.length < total
|
|
1268
|
+
};
|
|
1269
|
+
} catch (error) {
|
|
1270
|
+
this.logger.error("Error getting paginated messages:", error);
|
|
1271
|
+
return { messages: [], total: 0, page, perPage, hasMore: false };
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1114
1274
|
async saveMessages({
|
|
1115
1275
|
messages,
|
|
1116
1276
|
format
|
|
@@ -1169,6 +1329,7 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
1169
1329
|
createdAt: row.created_at
|
|
1170
1330
|
};
|
|
1171
1331
|
}
|
|
1332
|
+
/** @deprecated use getEvals instead */
|
|
1172
1333
|
async getEvalsByAgentName(agentName, type) {
|
|
1173
1334
|
try {
|
|
1174
1335
|
const baseQuery = `SELECT * FROM ${storage.TABLE_EVALS} WHERE agent_name = ?`;
|
|
@@ -1186,93 +1347,150 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
1186
1347
|
throw error;
|
|
1187
1348
|
}
|
|
1188
1349
|
}
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
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 = [];
|
|
1350
|
+
async getEvals(options = {}) {
|
|
1351
|
+
const { agentName, type, page = 0, perPage = 100, dateRange } = options;
|
|
1352
|
+
const fromDate = dateRange?.start;
|
|
1353
|
+
const toDate = dateRange?.end;
|
|
1206
1354
|
const conditions = [];
|
|
1207
|
-
|
|
1208
|
-
|
|
1355
|
+
const queryParams = [];
|
|
1356
|
+
if (agentName) {
|
|
1357
|
+
conditions.push(`agent_name = ?`);
|
|
1358
|
+
queryParams.push(agentName);
|
|
1209
1359
|
}
|
|
1210
|
-
if (
|
|
1211
|
-
conditions.push(
|
|
1212
|
-
}
|
|
1213
|
-
|
|
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
|
-
});
|
|
1360
|
+
if (type === "test") {
|
|
1361
|
+
conditions.push(`(test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL)`);
|
|
1362
|
+
} else if (type === "live") {
|
|
1363
|
+
conditions.push(`(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)`);
|
|
1222
1364
|
}
|
|
1223
1365
|
if (fromDate) {
|
|
1224
|
-
conditions.push(
|
|
1366
|
+
conditions.push(`created_at >= ?`);
|
|
1367
|
+
queryParams.push(fromDate.toISOString());
|
|
1225
1368
|
}
|
|
1226
1369
|
if (toDate) {
|
|
1227
|
-
conditions.push(
|
|
1370
|
+
conditions.push(`created_at <= ?`);
|
|
1371
|
+
queryParams.push(toDate.toISOString());
|
|
1228
1372
|
}
|
|
1229
1373
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1374
|
+
const countResult = await this.client.execute({
|
|
1375
|
+
sql: `SELECT COUNT(*) as count FROM ${storage.TABLE_EVALS} ${whereClause}`,
|
|
1376
|
+
args: queryParams
|
|
1377
|
+
});
|
|
1378
|
+
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
1379
|
+
const currentOffset = page * perPage;
|
|
1380
|
+
const hasMore = currentOffset + perPage < total;
|
|
1381
|
+
if (total === 0) {
|
|
1382
|
+
return {
|
|
1383
|
+
evals: [],
|
|
1384
|
+
total: 0,
|
|
1385
|
+
page,
|
|
1386
|
+
perPage,
|
|
1387
|
+
hasMore: false
|
|
1388
|
+
};
|
|
1389
|
+
}
|
|
1390
|
+
const dataResult = await this.client.execute({
|
|
1391
|
+
sql: `SELECT * FROM ${storage.TABLE_EVALS} ${whereClause} ORDER BY created_at DESC LIMIT ? OFFSET ?`,
|
|
1392
|
+
args: [...queryParams, perPage, currentOffset]
|
|
1393
|
+
});
|
|
1394
|
+
return {
|
|
1395
|
+
evals: dataResult.rows?.map((row) => this.transformEvalRow(row)) ?? [],
|
|
1396
|
+
total,
|
|
1397
|
+
page,
|
|
1398
|
+
perPage,
|
|
1399
|
+
hasMore
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
/**
|
|
1403
|
+
* @deprecated use getTracesPaginated instead.
|
|
1404
|
+
*/
|
|
1405
|
+
async getTraces(args) {
|
|
1406
|
+
if (args.fromDate || args.toDate) {
|
|
1407
|
+
args.dateRange = {
|
|
1408
|
+
start: args.fromDate,
|
|
1409
|
+
end: args.toDate
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
const result = await this.getTracesPaginated(args);
|
|
1413
|
+
return result.traces;
|
|
1414
|
+
}
|
|
1415
|
+
async getTracesPaginated(args) {
|
|
1416
|
+
const { name, scope, page = 0, perPage = 100, attributes, filters, dateRange } = args;
|
|
1417
|
+
const fromDate = dateRange?.start;
|
|
1418
|
+
const toDate = dateRange?.end;
|
|
1419
|
+
const currentOffset = page * perPage;
|
|
1420
|
+
const queryArgs = [];
|
|
1421
|
+
const conditions = [];
|
|
1230
1422
|
if (name) {
|
|
1231
|
-
|
|
1423
|
+
conditions.push("name LIKE ?");
|
|
1424
|
+
queryArgs.push(`${name}%`);
|
|
1232
1425
|
}
|
|
1233
1426
|
if (scope) {
|
|
1234
|
-
|
|
1427
|
+
conditions.push("scope = ?");
|
|
1428
|
+
queryArgs.push(scope);
|
|
1235
1429
|
}
|
|
1236
1430
|
if (attributes) {
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1431
|
+
Object.entries(attributes).forEach(([key, value]) => {
|
|
1432
|
+
conditions.push(`json_extract(attributes, '$.${key}') = ?`);
|
|
1433
|
+
queryArgs.push(value);
|
|
1434
|
+
});
|
|
1240
1435
|
}
|
|
1241
1436
|
if (filters) {
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1437
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
1438
|
+
conditions.push(`${utils.parseSqlIdentifier(key, "filter key")} = ?`);
|
|
1439
|
+
queryArgs.push(value);
|
|
1440
|
+
});
|
|
1245
1441
|
}
|
|
1246
1442
|
if (fromDate) {
|
|
1247
|
-
|
|
1443
|
+
conditions.push("createdAt >= ?");
|
|
1444
|
+
queryArgs.push(fromDate.toISOString());
|
|
1248
1445
|
}
|
|
1249
1446
|
if (toDate) {
|
|
1250
|
-
|
|
1447
|
+
conditions.push("createdAt <= ?");
|
|
1448
|
+
queryArgs.push(toDate.toISOString());
|
|
1251
1449
|
}
|
|
1252
|
-
|
|
1253
|
-
const
|
|
1254
|
-
sql: `SELECT * FROM ${storage.TABLE_TRACES} ${whereClause}
|
|
1255
|
-
args
|
|
1450
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1451
|
+
const countResult = await this.client.execute({
|
|
1452
|
+
sql: `SELECT COUNT(*) as count FROM ${storage.TABLE_TRACES} ${whereClause}`,
|
|
1453
|
+
args: queryArgs
|
|
1256
1454
|
});
|
|
1257
|
-
|
|
1258
|
-
|
|
1455
|
+
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
1456
|
+
if (total === 0) {
|
|
1457
|
+
return {
|
|
1458
|
+
traces: [],
|
|
1459
|
+
total: 0,
|
|
1460
|
+
page,
|
|
1461
|
+
perPage,
|
|
1462
|
+
hasMore: false
|
|
1463
|
+
};
|
|
1259
1464
|
}
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1465
|
+
const dataResult = await this.client.execute({
|
|
1466
|
+
sql: `SELECT * FROM ${storage.TABLE_TRACES} ${whereClause} ORDER BY "startTime" DESC LIMIT ? OFFSET ?`,
|
|
1467
|
+
args: [...queryArgs, perPage, currentOffset]
|
|
1468
|
+
});
|
|
1469
|
+
const traces = dataResult.rows?.map(
|
|
1470
|
+
(row) => ({
|
|
1471
|
+
id: row.id,
|
|
1472
|
+
parentSpanId: row.parentSpanId,
|
|
1473
|
+
traceId: row.traceId,
|
|
1474
|
+
name: row.name,
|
|
1475
|
+
scope: row.scope,
|
|
1476
|
+
kind: row.kind,
|
|
1477
|
+
status: safelyParseJSON(row.status),
|
|
1478
|
+
events: safelyParseJSON(row.events),
|
|
1479
|
+
links: safelyParseJSON(row.links),
|
|
1480
|
+
attributes: safelyParseJSON(row.attributes),
|
|
1481
|
+
startTime: row.startTime,
|
|
1482
|
+
endTime: row.endTime,
|
|
1483
|
+
other: safelyParseJSON(row.other),
|
|
1484
|
+
createdAt: row.createdAt
|
|
1485
|
+
})
|
|
1486
|
+
) ?? [];
|
|
1487
|
+
return {
|
|
1488
|
+
traces,
|
|
1489
|
+
total,
|
|
1490
|
+
page,
|
|
1491
|
+
perPage,
|
|
1492
|
+
hasMore: currentOffset + traces.length < total
|
|
1493
|
+
};
|
|
1276
1494
|
}
|
|
1277
1495
|
async getWorkflowRuns({
|
|
1278
1496
|
workflowName,
|