@mastra/libsql 0.11.0-alpha.3 → 0.11.1-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 +60 -0
- package/LICENSE.md +12 -4
- package/dist/_tsup-dts-rollup.d.cts +336 -30
- package/dist/_tsup-dts-rollup.d.ts +336 -30
- package/dist/index.cjs +1357 -847
- package/dist/index.js +1227 -717
- package/package.json +6 -6
- package/src/storage/domains/legacy-evals/index.ts +149 -0
- package/src/storage/domains/memory/index.ts +786 -0
- package/src/storage/domains/operations/index.ts +296 -0
- package/src/storage/domains/scores/index.ts +217 -0
- package/src/storage/domains/traces/index.ts +150 -0
- package/src/storage/domains/utils.ts +67 -0
- package/src/storage/domains/workflows/index.ts +198 -0
- package/src/storage/index.test.ts +2 -515
- package/src/storage/index.ts +186 -1338
package/dist/index.cjs
CHANGED
|
@@ -5,8 +5,9 @@ var error = require('@mastra/core/error');
|
|
|
5
5
|
var utils = require('@mastra/core/utils');
|
|
6
6
|
var vector = require('@mastra/core/vector');
|
|
7
7
|
var filter = require('@mastra/core/vector/filter');
|
|
8
|
-
var agent = require('@mastra/core/agent');
|
|
9
8
|
var storage = require('@mastra/core/storage');
|
|
9
|
+
var core = require('@mastra/core');
|
|
10
|
+
var agent = require('@mastra/core/agent');
|
|
10
11
|
|
|
11
12
|
// src/vector/index.ts
|
|
12
13
|
var LibSQLFilterTranslator = class extends filter.BaseFilterTranslator {
|
|
@@ -906,394 +907,682 @@ var LibSQLVector = class extends vector.MastraVector {
|
|
|
906
907
|
});
|
|
907
908
|
}
|
|
908
909
|
};
|
|
909
|
-
function
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
910
|
+
function transformEvalRow(row) {
|
|
911
|
+
const resultValue = JSON.parse(row.result);
|
|
912
|
+
const testInfoValue = row.test_info ? JSON.parse(row.test_info) : void 0;
|
|
913
|
+
if (!resultValue || typeof resultValue !== "object" || !("score" in resultValue)) {
|
|
914
|
+
throw new Error(`Invalid MetricResult format: ${JSON.stringify(resultValue)}`);
|
|
914
915
|
}
|
|
916
|
+
return {
|
|
917
|
+
input: row.input,
|
|
918
|
+
output: row.output,
|
|
919
|
+
result: resultValue,
|
|
920
|
+
agentName: row.agent_name,
|
|
921
|
+
metricName: row.metric_name,
|
|
922
|
+
instructions: row.instructions,
|
|
923
|
+
testInfo: testInfoValue,
|
|
924
|
+
globalRunId: row.global_run_id,
|
|
925
|
+
runId: row.run_id,
|
|
926
|
+
createdAt: row.created_at
|
|
927
|
+
};
|
|
915
928
|
}
|
|
916
|
-
var
|
|
929
|
+
var LegacyEvalsLibSQL = class extends storage.LegacyEvalsStorage {
|
|
917
930
|
client;
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
super({ name: `LibSQLStore` });
|
|
922
|
-
this.maxRetries = config.maxRetries ?? 5;
|
|
923
|
-
this.initialBackoffMs = config.initialBackoffMs ?? 100;
|
|
924
|
-
if (config.url.endsWith(":memory:")) {
|
|
925
|
-
this.shouldCacheInit = false;
|
|
926
|
-
}
|
|
927
|
-
this.client = client.createClient(config);
|
|
928
|
-
if (config.url.startsWith("file:") || config.url.includes(":memory:")) {
|
|
929
|
-
this.client.execute("PRAGMA journal_mode=WAL;").then(() => this.logger.debug("LibSQLStore: PRAGMA journal_mode=WAL set.")).catch((err) => this.logger.warn("LibSQLStore: Failed to set PRAGMA journal_mode=WAL.", err));
|
|
930
|
-
this.client.execute("PRAGMA busy_timeout = 5000;").then(() => this.logger.debug("LibSQLStore: PRAGMA busy_timeout=5000 set.")).catch((err) => this.logger.warn("LibSQLStore: Failed to set PRAGMA busy_timeout.", err));
|
|
931
|
-
}
|
|
932
|
-
}
|
|
933
|
-
get supports() {
|
|
934
|
-
return {
|
|
935
|
-
selectByIncludeResourceScope: true,
|
|
936
|
-
resourceWorkingMemory: true
|
|
937
|
-
};
|
|
938
|
-
}
|
|
939
|
-
getCreateTableSQL(tableName, schema) {
|
|
940
|
-
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
941
|
-
const columns = Object.entries(schema).map(([name, col]) => {
|
|
942
|
-
const parsedColumnName = utils.parseSqlIdentifier(name, "column name");
|
|
943
|
-
let type = col.type.toUpperCase();
|
|
944
|
-
if (type === "TEXT") type = "TEXT";
|
|
945
|
-
if (type === "TIMESTAMP") type = "TEXT";
|
|
946
|
-
const nullable = col.nullable ? "" : "NOT NULL";
|
|
947
|
-
const primaryKey = col.primaryKey ? "PRIMARY KEY" : "";
|
|
948
|
-
return `${parsedColumnName} ${type} ${nullable} ${primaryKey}`.trim();
|
|
949
|
-
});
|
|
950
|
-
if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
|
|
951
|
-
const stmnt = `CREATE TABLE IF NOT EXISTS ${parsedTableName} (
|
|
952
|
-
${columns.join(",\n")},
|
|
953
|
-
PRIMARY KEY (workflow_name, run_id)
|
|
954
|
-
)`;
|
|
955
|
-
return stmnt;
|
|
956
|
-
}
|
|
957
|
-
return `CREATE TABLE IF NOT EXISTS ${parsedTableName} (${columns.join(", ")})`;
|
|
931
|
+
constructor({ client }) {
|
|
932
|
+
super();
|
|
933
|
+
this.client = client;
|
|
958
934
|
}
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
schema
|
|
962
|
-
}) {
|
|
935
|
+
/** @deprecated use getEvals instead */
|
|
936
|
+
async getEvalsByAgentName(agentName, type) {
|
|
963
937
|
try {
|
|
964
|
-
|
|
965
|
-
const
|
|
966
|
-
await this.client.execute(
|
|
938
|
+
const baseQuery = `SELECT * FROM ${storage.TABLE_EVALS} WHERE agent_name = ?`;
|
|
939
|
+
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)" : "";
|
|
940
|
+
const result = await this.client.execute({
|
|
941
|
+
sql: `${baseQuery}${typeCondition} ORDER BY created_at DESC`,
|
|
942
|
+
args: [agentName]
|
|
943
|
+
});
|
|
944
|
+
return result.rows?.map((row) => transformEvalRow(row)) ?? [];
|
|
967
945
|
} catch (error$1) {
|
|
946
|
+
if (error$1 instanceof Error && error$1.message.includes("no such table")) {
|
|
947
|
+
return [];
|
|
948
|
+
}
|
|
968
949
|
throw new error.MastraError(
|
|
969
950
|
{
|
|
970
|
-
id: "
|
|
951
|
+
id: "LIBSQL_STORE_GET_EVALS_BY_AGENT_NAME_FAILED",
|
|
971
952
|
domain: error.ErrorDomain.STORAGE,
|
|
972
953
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
973
|
-
details: {
|
|
974
|
-
tableName
|
|
975
|
-
}
|
|
954
|
+
details: { agentName }
|
|
976
955
|
},
|
|
977
956
|
error$1
|
|
978
957
|
);
|
|
979
958
|
}
|
|
980
959
|
}
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
return super.getSqlType(type);
|
|
960
|
+
async getEvals(options = {}) {
|
|
961
|
+
const { agentName, type, page = 0, perPage = 100, dateRange } = options;
|
|
962
|
+
const fromDate = dateRange?.start;
|
|
963
|
+
const toDate = dateRange?.end;
|
|
964
|
+
const conditions = [];
|
|
965
|
+
const queryParams = [];
|
|
966
|
+
if (agentName) {
|
|
967
|
+
conditions.push(`agent_name = ?`);
|
|
968
|
+
queryParams.push(agentName);
|
|
991
969
|
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
970
|
+
if (type === "test") {
|
|
971
|
+
conditions.push(`(test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL)`);
|
|
972
|
+
} else if (type === "live") {
|
|
973
|
+
conditions.push(`(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)`);
|
|
974
|
+
}
|
|
975
|
+
if (fromDate) {
|
|
976
|
+
conditions.push(`created_at >= ?`);
|
|
977
|
+
queryParams.push(fromDate.toISOString());
|
|
978
|
+
}
|
|
979
|
+
if (toDate) {
|
|
980
|
+
conditions.push(`created_at <= ?`);
|
|
981
|
+
queryParams.push(toDate.toISOString());
|
|
982
|
+
}
|
|
983
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1005
984
|
try {
|
|
1006
|
-
const
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
985
|
+
const countResult = await this.client.execute({
|
|
986
|
+
sql: `SELECT COUNT(*) as count FROM ${storage.TABLE_EVALS} ${whereClause}`,
|
|
987
|
+
args: queryParams
|
|
988
|
+
});
|
|
989
|
+
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
990
|
+
const currentOffset = page * perPage;
|
|
991
|
+
const hasMore = currentOffset + perPage < total;
|
|
992
|
+
if (total === 0) {
|
|
993
|
+
return {
|
|
994
|
+
evals: [],
|
|
995
|
+
total: 0,
|
|
996
|
+
page,
|
|
997
|
+
perPage,
|
|
998
|
+
hasMore: false
|
|
999
|
+
};
|
|
1019
1000
|
}
|
|
1001
|
+
const dataResult = await this.client.execute({
|
|
1002
|
+
sql: `SELECT * FROM ${storage.TABLE_EVALS} ${whereClause} ORDER BY created_at DESC LIMIT ? OFFSET ?`,
|
|
1003
|
+
args: [...queryParams, perPage, currentOffset]
|
|
1004
|
+
});
|
|
1005
|
+
return {
|
|
1006
|
+
evals: dataResult.rows?.map((row) => transformEvalRow(row)) ?? [],
|
|
1007
|
+
total,
|
|
1008
|
+
page,
|
|
1009
|
+
perPage,
|
|
1010
|
+
hasMore
|
|
1011
|
+
};
|
|
1020
1012
|
} catch (error$1) {
|
|
1021
1013
|
throw new error.MastraError(
|
|
1022
1014
|
{
|
|
1023
|
-
id: "
|
|
1015
|
+
id: "LIBSQL_STORE_GET_EVALS_FAILED",
|
|
1024
1016
|
domain: error.ErrorDomain.STORAGE,
|
|
1025
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1026
|
-
details: {
|
|
1027
|
-
tableName
|
|
1028
|
-
}
|
|
1017
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1029
1018
|
},
|
|
1030
1019
|
error$1
|
|
1031
1020
|
);
|
|
1032
1021
|
}
|
|
1033
1022
|
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1023
|
+
};
|
|
1024
|
+
var MemoryLibSQL = class extends storage.MemoryStorage {
|
|
1025
|
+
client;
|
|
1026
|
+
operations;
|
|
1027
|
+
constructor({ client, operations }) {
|
|
1028
|
+
super();
|
|
1029
|
+
this.client = client;
|
|
1030
|
+
this.operations = operations;
|
|
1031
|
+
}
|
|
1032
|
+
parseRow(row) {
|
|
1033
|
+
let content = row.content;
|
|
1036
1034
|
try {
|
|
1037
|
-
|
|
1038
|
-
} catch
|
|
1039
|
-
|
|
1035
|
+
content = JSON.parse(row.content);
|
|
1036
|
+
} catch {
|
|
1037
|
+
}
|
|
1038
|
+
const result = {
|
|
1039
|
+
id: row.id,
|
|
1040
|
+
content,
|
|
1041
|
+
role: row.role,
|
|
1042
|
+
createdAt: new Date(row.createdAt),
|
|
1043
|
+
threadId: row.thread_id,
|
|
1044
|
+
resourceId: row.resourceId
|
|
1045
|
+
};
|
|
1046
|
+
if (row.type && row.type !== `v2`) result.type = row.type;
|
|
1047
|
+
return result;
|
|
1048
|
+
}
|
|
1049
|
+
async _getIncludedMessages({
|
|
1050
|
+
threadId,
|
|
1051
|
+
selectBy
|
|
1052
|
+
}) {
|
|
1053
|
+
const include = selectBy?.include;
|
|
1054
|
+
if (!include) return null;
|
|
1055
|
+
const unionQueries = [];
|
|
1056
|
+
const params = [];
|
|
1057
|
+
for (const inc of include) {
|
|
1058
|
+
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
1059
|
+
const searchId = inc.threadId || threadId;
|
|
1060
|
+
unionQueries.push(
|
|
1061
|
+
`
|
|
1062
|
+
SELECT * FROM (
|
|
1063
|
+
WITH numbered_messages AS (
|
|
1064
|
+
SELECT
|
|
1065
|
+
id, content, role, type, "createdAt", thread_id, "resourceId",
|
|
1066
|
+
ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
|
|
1067
|
+
FROM "${storage.TABLE_MESSAGES}"
|
|
1068
|
+
WHERE thread_id = ?
|
|
1069
|
+
),
|
|
1070
|
+
target_positions AS (
|
|
1071
|
+
SELECT row_num as target_pos
|
|
1072
|
+
FROM numbered_messages
|
|
1073
|
+
WHERE id = ?
|
|
1074
|
+
)
|
|
1075
|
+
SELECT DISTINCT m.*
|
|
1076
|
+
FROM numbered_messages m
|
|
1077
|
+
CROSS JOIN target_positions t
|
|
1078
|
+
WHERE m.row_num BETWEEN (t.target_pos - ?) AND (t.target_pos + ?)
|
|
1079
|
+
)
|
|
1080
|
+
`
|
|
1081
|
+
// Keep ASC for final sorting after fetching context
|
|
1082
|
+
);
|
|
1083
|
+
params.push(searchId, id, withPreviousMessages, withNextMessages);
|
|
1084
|
+
}
|
|
1085
|
+
const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
|
|
1086
|
+
const includedResult = await this.client.execute({ sql: finalQuery, args: params });
|
|
1087
|
+
const includedRows = includedResult.rows?.map((row) => this.parseRow(row));
|
|
1088
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1089
|
+
const dedupedRows = includedRows.filter((row) => {
|
|
1090
|
+
if (seen.has(row.id)) return false;
|
|
1091
|
+
seen.add(row.id);
|
|
1092
|
+
return true;
|
|
1093
|
+
});
|
|
1094
|
+
return dedupedRows;
|
|
1095
|
+
}
|
|
1096
|
+
async getMessages({
|
|
1097
|
+
threadId,
|
|
1098
|
+
selectBy,
|
|
1099
|
+
format
|
|
1100
|
+
}) {
|
|
1101
|
+
try {
|
|
1102
|
+
const messages = [];
|
|
1103
|
+
const limit = storage.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
1104
|
+
if (selectBy?.include?.length) {
|
|
1105
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
|
|
1106
|
+
if (includeMessages) {
|
|
1107
|
+
messages.push(...includeMessages);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
const excludeIds = messages.map((m) => m.id);
|
|
1111
|
+
const remainingSql = `
|
|
1112
|
+
SELECT
|
|
1113
|
+
id,
|
|
1114
|
+
content,
|
|
1115
|
+
role,
|
|
1116
|
+
type,
|
|
1117
|
+
"createdAt",
|
|
1118
|
+
thread_id,
|
|
1119
|
+
"resourceId"
|
|
1120
|
+
FROM "${storage.TABLE_MESSAGES}"
|
|
1121
|
+
WHERE thread_id = ?
|
|
1122
|
+
${excludeIds.length ? `AND id NOT IN (${excludeIds.map(() => "?").join(", ")})` : ""}
|
|
1123
|
+
ORDER BY "createdAt" DESC
|
|
1124
|
+
LIMIT ?
|
|
1125
|
+
`;
|
|
1126
|
+
const remainingArgs = [threadId, ...excludeIds.length ? excludeIds : [], limit];
|
|
1127
|
+
const remainingResult = await this.client.execute({ sql: remainingSql, args: remainingArgs });
|
|
1128
|
+
if (remainingResult.rows) {
|
|
1129
|
+
messages.push(...remainingResult.rows.map((row) => this.parseRow(row)));
|
|
1130
|
+
}
|
|
1131
|
+
messages.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
1132
|
+
const list = new agent.MessageList().add(messages, "memory");
|
|
1133
|
+
if (format === `v2`) return list.get.all.v2();
|
|
1134
|
+
return list.get.all.v1();
|
|
1135
|
+
} catch (error$1) {
|
|
1136
|
+
throw new error.MastraError(
|
|
1040
1137
|
{
|
|
1041
|
-
id: "
|
|
1138
|
+
id: "LIBSQL_STORE_GET_MESSAGES_FAILED",
|
|
1042
1139
|
domain: error.ErrorDomain.STORAGE,
|
|
1043
1140
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1044
|
-
details: {
|
|
1045
|
-
tableName
|
|
1046
|
-
}
|
|
1141
|
+
details: { threadId }
|
|
1047
1142
|
},
|
|
1048
|
-
|
|
1143
|
+
error$1
|
|
1049
1144
|
);
|
|
1050
|
-
this.logger?.trackException?.(mastraError);
|
|
1051
|
-
this.logger?.error?.(mastraError.toString());
|
|
1052
1145
|
}
|
|
1053
1146
|
}
|
|
1054
|
-
|
|
1055
|
-
const
|
|
1056
|
-
const
|
|
1057
|
-
const
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
return v.toISOString();
|
|
1063
|
-
}
|
|
1064
|
-
return typeof v === "object" ? JSON.stringify(v) : v;
|
|
1065
|
-
});
|
|
1066
|
-
const placeholders = values.map(() => "?").join(", ");
|
|
1067
|
-
return {
|
|
1068
|
-
sql: `INSERT OR REPLACE INTO ${parsedTableName} (${columns.join(", ")}) VALUES (${placeholders})`,
|
|
1069
|
-
args: values
|
|
1070
|
-
};
|
|
1071
|
-
}
|
|
1072
|
-
async executeWriteOperationWithRetry(operationFn, operationDescription) {
|
|
1073
|
-
let retries = 0;
|
|
1074
|
-
while (true) {
|
|
1147
|
+
async getMessagesPaginated(args) {
|
|
1148
|
+
const { threadId, format, selectBy } = args;
|
|
1149
|
+
const { page = 0, perPage: perPageInput, dateRange } = selectBy?.pagination || {};
|
|
1150
|
+
const perPage = perPageInput !== void 0 ? perPageInput : storage.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
1151
|
+
const fromDate = dateRange?.start;
|
|
1152
|
+
const toDate = dateRange?.end;
|
|
1153
|
+
const messages = [];
|
|
1154
|
+
if (selectBy?.include?.length) {
|
|
1075
1155
|
try {
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
retries++;
|
|
1080
|
-
const backoffTime = this.initialBackoffMs * Math.pow(2, retries - 1);
|
|
1081
|
-
this.logger.warn(
|
|
1082
|
-
`LibSQLStore: Encountered SQLITE_BUSY during ${operationDescription}. Retrying (${retries}/${this.maxRetries}) in ${backoffTime}ms...`
|
|
1083
|
-
);
|
|
1084
|
-
await new Promise((resolve) => setTimeout(resolve, backoffTime));
|
|
1085
|
-
} else {
|
|
1086
|
-
this.logger.error(`LibSQLStore: Error during ${operationDescription} after ${retries} retries: ${error}`);
|
|
1087
|
-
throw error;
|
|
1156
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
|
|
1157
|
+
if (includeMessages) {
|
|
1158
|
+
messages.push(...includeMessages);
|
|
1088
1159
|
}
|
|
1160
|
+
} catch (error$1) {
|
|
1161
|
+
throw new error.MastraError(
|
|
1162
|
+
{
|
|
1163
|
+
id: "LIBSQL_STORE_GET_MESSAGES_PAGINATED_GET_INCLUDE_MESSAGES_FAILED",
|
|
1164
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1165
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1166
|
+
details: { threadId }
|
|
1167
|
+
},
|
|
1168
|
+
error$1
|
|
1169
|
+
);
|
|
1089
1170
|
}
|
|
1090
1171
|
}
|
|
1091
|
-
}
|
|
1092
|
-
insert(args) {
|
|
1093
|
-
return this.executeWriteOperationWithRetry(() => this.doInsert(args), `insert into table ${args.tableName}`);
|
|
1094
|
-
}
|
|
1095
|
-
async doInsert({
|
|
1096
|
-
tableName,
|
|
1097
|
-
record
|
|
1098
|
-
}) {
|
|
1099
|
-
await this.client.execute(
|
|
1100
|
-
this.prepareStatement({
|
|
1101
|
-
tableName,
|
|
1102
|
-
record
|
|
1103
|
-
})
|
|
1104
|
-
);
|
|
1105
|
-
}
|
|
1106
|
-
batchInsert(args) {
|
|
1107
|
-
return this.executeWriteOperationWithRetry(
|
|
1108
|
-
() => this.doBatchInsert(args),
|
|
1109
|
-
`batch insert into table ${args.tableName}`
|
|
1110
|
-
).catch((error$1) => {
|
|
1111
|
-
throw new error.MastraError(
|
|
1112
|
-
{
|
|
1113
|
-
id: "LIBSQL_STORE_BATCH_INSERT_FAILED",
|
|
1114
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1115
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
1116
|
-
details: {
|
|
1117
|
-
tableName: args.tableName
|
|
1118
|
-
}
|
|
1119
|
-
},
|
|
1120
|
-
error$1
|
|
1121
|
-
);
|
|
1122
|
-
});
|
|
1123
|
-
}
|
|
1124
|
-
async doBatchInsert({
|
|
1125
|
-
tableName,
|
|
1126
|
-
records
|
|
1127
|
-
}) {
|
|
1128
|
-
if (records.length === 0) return;
|
|
1129
|
-
const batchStatements = records.map((r) => this.prepareStatement({ tableName, record: r }));
|
|
1130
|
-
await this.client.batch(batchStatements, "write");
|
|
1131
|
-
}
|
|
1132
|
-
async load({ tableName, keys }) {
|
|
1133
|
-
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1134
|
-
const parsedKeys = Object.keys(keys).map((key) => utils.parseSqlIdentifier(key, "column name"));
|
|
1135
|
-
const conditions = parsedKeys.map((key) => `${key} = ?`).join(" AND ");
|
|
1136
|
-
const values = Object.values(keys);
|
|
1137
|
-
const result = await this.client.execute({
|
|
1138
|
-
sql: `SELECT * FROM ${parsedTableName} WHERE ${conditions} ORDER BY createdAt DESC LIMIT 1`,
|
|
1139
|
-
args: values
|
|
1140
|
-
});
|
|
1141
|
-
if (!result.rows || result.rows.length === 0) {
|
|
1142
|
-
return null;
|
|
1143
|
-
}
|
|
1144
|
-
const row = result.rows[0];
|
|
1145
|
-
const parsed = Object.fromEntries(
|
|
1146
|
-
Object.entries(row || {}).map(([k, v]) => {
|
|
1147
|
-
try {
|
|
1148
|
-
return [k, typeof v === "string" ? v.startsWith("{") || v.startsWith("[") ? JSON.parse(v) : v : v];
|
|
1149
|
-
} catch {
|
|
1150
|
-
return [k, v];
|
|
1151
|
-
}
|
|
1152
|
-
})
|
|
1153
|
-
);
|
|
1154
|
-
return parsed;
|
|
1155
|
-
}
|
|
1156
|
-
async getThreadById({ threadId }) {
|
|
1157
1172
|
try {
|
|
1158
|
-
const
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1173
|
+
const currentOffset = page * perPage;
|
|
1174
|
+
const conditions = [`thread_id = ?`];
|
|
1175
|
+
const queryParams = [threadId];
|
|
1176
|
+
if (fromDate) {
|
|
1177
|
+
conditions.push(`"createdAt" >= ?`);
|
|
1178
|
+
queryParams.push(fromDate.toISOString());
|
|
1164
1179
|
}
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
};
|
|
1169
|
-
} catch (error$1) {
|
|
1170
|
-
throw new error.MastraError(
|
|
1171
|
-
{
|
|
1172
|
-
id: "LIBSQL_STORE_GET_THREAD_BY_ID_FAILED",
|
|
1173
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1174
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
1175
|
-
details: { threadId }
|
|
1176
|
-
},
|
|
1177
|
-
error$1
|
|
1178
|
-
);
|
|
1179
|
-
}
|
|
1180
|
-
}
|
|
1181
|
-
/**
|
|
1182
|
-
* @deprecated use getThreadsByResourceIdPaginated instead for paginated results.
|
|
1183
|
-
*/
|
|
1184
|
-
async getThreadsByResourceId(args) {
|
|
1185
|
-
const { resourceId } = args;
|
|
1186
|
-
try {
|
|
1187
|
-
const baseQuery = `FROM ${storage.TABLE_THREADS} WHERE resourceId = ?`;
|
|
1188
|
-
const queryParams = [resourceId];
|
|
1189
|
-
const mapRowToStorageThreadType = (row) => ({
|
|
1190
|
-
id: row.id,
|
|
1191
|
-
resourceId: row.resourceId,
|
|
1192
|
-
title: row.title,
|
|
1193
|
-
createdAt: new Date(row.createdAt),
|
|
1194
|
-
// Convert string to Date
|
|
1195
|
-
updatedAt: new Date(row.updatedAt),
|
|
1196
|
-
// Convert string to Date
|
|
1197
|
-
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata
|
|
1198
|
-
});
|
|
1199
|
-
const result = await this.client.execute({
|
|
1200
|
-
sql: `SELECT * ${baseQuery} ORDER BY createdAt DESC`,
|
|
1201
|
-
args: queryParams
|
|
1202
|
-
});
|
|
1203
|
-
if (!result.rows) {
|
|
1204
|
-
return [];
|
|
1180
|
+
if (toDate) {
|
|
1181
|
+
conditions.push(`"createdAt" <= ?`);
|
|
1182
|
+
queryParams.push(toDate.toISOString());
|
|
1205
1183
|
}
|
|
1206
|
-
|
|
1207
|
-
} catch (error$1) {
|
|
1208
|
-
const mastraError = new error.MastraError(
|
|
1209
|
-
{
|
|
1210
|
-
id: "LIBSQL_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED",
|
|
1211
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1212
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
1213
|
-
details: { resourceId }
|
|
1214
|
-
},
|
|
1215
|
-
error$1
|
|
1216
|
-
);
|
|
1217
|
-
this.logger?.trackException?.(mastraError);
|
|
1218
|
-
this.logger?.error?.(mastraError.toString());
|
|
1219
|
-
return [];
|
|
1220
|
-
}
|
|
1221
|
-
}
|
|
1222
|
-
async getThreadsByResourceIdPaginated(args) {
|
|
1223
|
-
const { resourceId, page = 0, perPage = 100 } = args;
|
|
1224
|
-
try {
|
|
1225
|
-
const baseQuery = `FROM ${storage.TABLE_THREADS} WHERE resourceId = ?`;
|
|
1226
|
-
const queryParams = [resourceId];
|
|
1227
|
-
const mapRowToStorageThreadType = (row) => ({
|
|
1228
|
-
id: row.id,
|
|
1229
|
-
resourceId: row.resourceId,
|
|
1230
|
-
title: row.title,
|
|
1231
|
-
createdAt: new Date(row.createdAt),
|
|
1232
|
-
// Convert string to Date
|
|
1233
|
-
updatedAt: new Date(row.updatedAt),
|
|
1234
|
-
// Convert string to Date
|
|
1235
|
-
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata
|
|
1236
|
-
});
|
|
1237
|
-
const currentOffset = page * perPage;
|
|
1184
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1238
1185
|
const countResult = await this.client.execute({
|
|
1239
|
-
sql: `SELECT COUNT(*) as count ${
|
|
1186
|
+
sql: `SELECT COUNT(*) as count FROM ${storage.TABLE_MESSAGES} ${whereClause}`,
|
|
1240
1187
|
args: queryParams
|
|
1241
1188
|
});
|
|
1242
1189
|
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
1243
|
-
if (total === 0) {
|
|
1190
|
+
if (total === 0 && messages.length === 0) {
|
|
1244
1191
|
return {
|
|
1245
|
-
|
|
1192
|
+
messages: [],
|
|
1246
1193
|
total: 0,
|
|
1247
1194
|
page,
|
|
1248
1195
|
perPage,
|
|
1249
1196
|
hasMore: false
|
|
1250
1197
|
};
|
|
1251
1198
|
}
|
|
1199
|
+
const excludeIds = messages.map((m) => m.id);
|
|
1200
|
+
const excludeIdsParam = excludeIds.map((_, idx) => `$${idx + queryParams.length + 1}`).join(", ");
|
|
1252
1201
|
const dataResult = await this.client.execute({
|
|
1253
|
-
sql: `SELECT
|
|
1254
|
-
args: [...queryParams, perPage, currentOffset]
|
|
1202
|
+
sql: `SELECT id, content, role, type, "createdAt", "resourceId", "thread_id" FROM ${storage.TABLE_MESSAGES} ${whereClause} ${excludeIds.length ? `AND id NOT IN (${excludeIdsParam})` : ""} ORDER BY "createdAt" DESC LIMIT ? OFFSET ?`,
|
|
1203
|
+
args: [...queryParams, ...excludeIds, perPage, currentOffset]
|
|
1255
1204
|
});
|
|
1256
|
-
|
|
1205
|
+
messages.push(...(dataResult.rows || []).map((row) => this.parseRow(row)));
|
|
1206
|
+
const messagesToReturn = format === "v1" ? new agent.MessageList().add(messages, "memory").get.all.v1() : new agent.MessageList().add(messages, "memory").get.all.v2();
|
|
1257
1207
|
return {
|
|
1258
|
-
|
|
1208
|
+
messages: messagesToReturn,
|
|
1259
1209
|
total,
|
|
1260
1210
|
page,
|
|
1261
1211
|
perPage,
|
|
1262
|
-
hasMore: currentOffset +
|
|
1212
|
+
hasMore: currentOffset + messages.length < total
|
|
1263
1213
|
};
|
|
1264
1214
|
} catch (error$1) {
|
|
1265
1215
|
const mastraError = new error.MastraError(
|
|
1266
1216
|
{
|
|
1267
|
-
id: "
|
|
1217
|
+
id: "LIBSQL_STORE_GET_MESSAGES_PAGINATED_FAILED",
|
|
1268
1218
|
domain: error.ErrorDomain.STORAGE,
|
|
1269
1219
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1270
|
-
details: {
|
|
1220
|
+
details: { threadId }
|
|
1271
1221
|
},
|
|
1272
1222
|
error$1
|
|
1273
1223
|
);
|
|
1274
1224
|
this.logger?.trackException?.(mastraError);
|
|
1275
1225
|
this.logger?.error?.(mastraError.toString());
|
|
1276
|
-
return {
|
|
1226
|
+
return { messages: [], total: 0, page, perPage, hasMore: false };
|
|
1277
1227
|
}
|
|
1278
1228
|
}
|
|
1279
|
-
async
|
|
1229
|
+
async saveMessages({
|
|
1230
|
+
messages,
|
|
1231
|
+
format
|
|
1232
|
+
}) {
|
|
1233
|
+
if (messages.length === 0) return messages;
|
|
1280
1234
|
try {
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1235
|
+
const threadId = messages[0]?.threadId;
|
|
1236
|
+
if (!threadId) {
|
|
1237
|
+
throw new Error("Thread ID is required");
|
|
1238
|
+
}
|
|
1239
|
+
const batchStatements = messages.map((message) => {
|
|
1240
|
+
const time = message.createdAt || /* @__PURE__ */ new Date();
|
|
1241
|
+
if (!message.threadId) {
|
|
1242
|
+
throw new Error(
|
|
1243
|
+
`Expected to find a threadId for message, but couldn't find one. An unexpected error has occurred.`
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
if (!message.resourceId) {
|
|
1247
|
+
throw new Error(
|
|
1248
|
+
`Expected to find a resourceId for message, but couldn't find one. An unexpected error has occurred.`
|
|
1249
|
+
);
|
|
1286
1250
|
}
|
|
1251
|
+
return {
|
|
1252
|
+
sql: `INSERT INTO ${storage.TABLE_MESSAGES} (id, thread_id, content, role, type, createdAt, resourceId)
|
|
1253
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
1254
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
1255
|
+
thread_id=excluded.thread_id,
|
|
1256
|
+
content=excluded.content,
|
|
1257
|
+
role=excluded.role,
|
|
1258
|
+
type=excluded.type,
|
|
1259
|
+
resourceId=excluded.resourceId
|
|
1260
|
+
`,
|
|
1261
|
+
args: [
|
|
1262
|
+
message.id,
|
|
1263
|
+
message.threadId,
|
|
1264
|
+
typeof message.content === "object" ? JSON.stringify(message.content) : message.content,
|
|
1265
|
+
message.role,
|
|
1266
|
+
message.type || "v2",
|
|
1267
|
+
time instanceof Date ? time.toISOString() : time,
|
|
1268
|
+
message.resourceId
|
|
1269
|
+
]
|
|
1270
|
+
};
|
|
1287
1271
|
});
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1272
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1273
|
+
batchStatements.push({
|
|
1274
|
+
sql: `UPDATE ${storage.TABLE_THREADS} SET updatedAt = ? WHERE id = ?`,
|
|
1275
|
+
args: [now, threadId]
|
|
1276
|
+
});
|
|
1277
|
+
await this.client.batch(batchStatements, "write");
|
|
1278
|
+
const list = new agent.MessageList().add(messages, "memory");
|
|
1279
|
+
if (format === `v2`) return list.get.all.v2();
|
|
1280
|
+
return list.get.all.v1();
|
|
1281
|
+
} catch (error$1) {
|
|
1282
|
+
throw new error.MastraError(
|
|
1283
|
+
{
|
|
1284
|
+
id: "LIBSQL_STORE_SAVE_MESSAGES_FAILED",
|
|
1285
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1286
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1287
|
+
},
|
|
1288
|
+
error$1
|
|
1289
|
+
);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
async updateMessages({
|
|
1293
|
+
messages
|
|
1294
|
+
}) {
|
|
1295
|
+
if (messages.length === 0) {
|
|
1296
|
+
return [];
|
|
1297
|
+
}
|
|
1298
|
+
const messageIds = messages.map((m) => m.id);
|
|
1299
|
+
const placeholders = messageIds.map(() => "?").join(",");
|
|
1300
|
+
const selectSql = `SELECT * FROM ${storage.TABLE_MESSAGES} WHERE id IN (${placeholders})`;
|
|
1301
|
+
const existingResult = await this.client.execute({ sql: selectSql, args: messageIds });
|
|
1302
|
+
const existingMessages = existingResult.rows.map((row) => this.parseRow(row));
|
|
1303
|
+
if (existingMessages.length === 0) {
|
|
1304
|
+
return [];
|
|
1305
|
+
}
|
|
1306
|
+
const batchStatements = [];
|
|
1307
|
+
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
1308
|
+
const columnMapping = {
|
|
1309
|
+
threadId: "thread_id"
|
|
1310
|
+
};
|
|
1311
|
+
for (const existingMessage of existingMessages) {
|
|
1312
|
+
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
1313
|
+
if (!updatePayload) continue;
|
|
1314
|
+
const { id, ...fieldsToUpdate } = updatePayload;
|
|
1315
|
+
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
1316
|
+
threadIdsToUpdate.add(existingMessage.threadId);
|
|
1317
|
+
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
1318
|
+
threadIdsToUpdate.add(updatePayload.threadId);
|
|
1319
|
+
}
|
|
1320
|
+
const setClauses = [];
|
|
1321
|
+
const args = [];
|
|
1322
|
+
const updatableFields = { ...fieldsToUpdate };
|
|
1323
|
+
if (updatableFields.content) {
|
|
1324
|
+
const newContent = {
|
|
1325
|
+
...existingMessage.content,
|
|
1326
|
+
...updatableFields.content,
|
|
1327
|
+
// Deep merge metadata if it exists on both
|
|
1328
|
+
...existingMessage.content?.metadata && updatableFields.content.metadata ? {
|
|
1329
|
+
metadata: {
|
|
1330
|
+
...existingMessage.content.metadata,
|
|
1331
|
+
...updatableFields.content.metadata
|
|
1332
|
+
}
|
|
1333
|
+
} : {}
|
|
1334
|
+
};
|
|
1335
|
+
setClauses.push(`${core.parseSqlIdentifier("content", "column name")} = ?`);
|
|
1336
|
+
args.push(JSON.stringify(newContent));
|
|
1337
|
+
delete updatableFields.content;
|
|
1338
|
+
}
|
|
1339
|
+
for (const key in updatableFields) {
|
|
1340
|
+
if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
|
|
1341
|
+
const dbKey = columnMapping[key] || key;
|
|
1342
|
+
setClauses.push(`${core.parseSqlIdentifier(dbKey, "column name")} = ?`);
|
|
1343
|
+
let value = updatableFields[key];
|
|
1344
|
+
if (typeof value === "object" && value !== null) {
|
|
1345
|
+
value = JSON.stringify(value);
|
|
1346
|
+
}
|
|
1347
|
+
args.push(value);
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
if (setClauses.length === 0) continue;
|
|
1351
|
+
args.push(id);
|
|
1352
|
+
const sql = `UPDATE ${storage.TABLE_MESSAGES} SET ${setClauses.join(", ")} WHERE id = ?`;
|
|
1353
|
+
batchStatements.push({ sql, args });
|
|
1354
|
+
}
|
|
1355
|
+
if (batchStatements.length === 0) {
|
|
1356
|
+
return existingMessages;
|
|
1357
|
+
}
|
|
1358
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1359
|
+
for (const threadId of threadIdsToUpdate) {
|
|
1360
|
+
if (threadId) {
|
|
1361
|
+
batchStatements.push({
|
|
1362
|
+
sql: `UPDATE ${storage.TABLE_THREADS} SET updatedAt = ? WHERE id = ?`,
|
|
1363
|
+
args: [now, threadId]
|
|
1364
|
+
});
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
await this.client.batch(batchStatements, "write");
|
|
1368
|
+
const updatedResult = await this.client.execute({ sql: selectSql, args: messageIds });
|
|
1369
|
+
return updatedResult.rows.map((row) => this.parseRow(row));
|
|
1370
|
+
}
|
|
1371
|
+
async getResourceById({ resourceId }) {
|
|
1372
|
+
const result = await this.operations.load({
|
|
1373
|
+
tableName: storage.TABLE_RESOURCES,
|
|
1374
|
+
keys: { id: resourceId }
|
|
1375
|
+
});
|
|
1376
|
+
if (!result) {
|
|
1377
|
+
return null;
|
|
1378
|
+
}
|
|
1379
|
+
return {
|
|
1380
|
+
...result,
|
|
1381
|
+
// Ensure workingMemory is always returned as a string, even if auto-parsed as JSON
|
|
1382
|
+
workingMemory: result.workingMemory && typeof result.workingMemory === "object" ? JSON.stringify(result.workingMemory) : result.workingMemory,
|
|
1383
|
+
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata,
|
|
1384
|
+
createdAt: new Date(result.createdAt),
|
|
1385
|
+
updatedAt: new Date(result.updatedAt)
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
async saveResource({ resource }) {
|
|
1389
|
+
console.log("resource", resource);
|
|
1390
|
+
await this.operations.insert({
|
|
1391
|
+
tableName: storage.TABLE_RESOURCES,
|
|
1392
|
+
record: {
|
|
1393
|
+
...resource,
|
|
1394
|
+
metadata: JSON.stringify(resource.metadata)
|
|
1395
|
+
}
|
|
1396
|
+
});
|
|
1397
|
+
return resource;
|
|
1398
|
+
}
|
|
1399
|
+
async updateResource({
|
|
1400
|
+
resourceId,
|
|
1401
|
+
workingMemory,
|
|
1402
|
+
metadata
|
|
1403
|
+
}) {
|
|
1404
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
1405
|
+
if (!existingResource) {
|
|
1406
|
+
const newResource = {
|
|
1407
|
+
id: resourceId,
|
|
1408
|
+
workingMemory,
|
|
1409
|
+
metadata: metadata || {},
|
|
1410
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1411
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1412
|
+
};
|
|
1413
|
+
return this.saveResource({ resource: newResource });
|
|
1414
|
+
}
|
|
1415
|
+
const updatedResource = {
|
|
1416
|
+
...existingResource,
|
|
1417
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
1418
|
+
metadata: {
|
|
1419
|
+
...existingResource.metadata,
|
|
1420
|
+
...metadata
|
|
1421
|
+
},
|
|
1422
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1423
|
+
};
|
|
1424
|
+
const updates = [];
|
|
1425
|
+
const values = [];
|
|
1426
|
+
if (workingMemory !== void 0) {
|
|
1427
|
+
updates.push("workingMemory = ?");
|
|
1428
|
+
values.push(workingMemory);
|
|
1429
|
+
}
|
|
1430
|
+
if (metadata) {
|
|
1431
|
+
updates.push("metadata = ?");
|
|
1432
|
+
values.push(JSON.stringify(updatedResource.metadata));
|
|
1433
|
+
}
|
|
1434
|
+
updates.push("updatedAt = ?");
|
|
1435
|
+
values.push(updatedResource.updatedAt.toISOString());
|
|
1436
|
+
values.push(resourceId);
|
|
1437
|
+
await this.client.execute({
|
|
1438
|
+
sql: `UPDATE ${storage.TABLE_RESOURCES} SET ${updates.join(", ")} WHERE id = ?`,
|
|
1439
|
+
args: values
|
|
1440
|
+
});
|
|
1441
|
+
return updatedResource;
|
|
1442
|
+
}
|
|
1443
|
+
async getThreadById({ threadId }) {
|
|
1444
|
+
try {
|
|
1445
|
+
const result = await this.operations.load({
|
|
1446
|
+
tableName: storage.TABLE_THREADS,
|
|
1447
|
+
keys: { id: threadId }
|
|
1448
|
+
});
|
|
1449
|
+
if (!result) {
|
|
1450
|
+
return null;
|
|
1451
|
+
}
|
|
1452
|
+
return {
|
|
1453
|
+
...result,
|
|
1454
|
+
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata,
|
|
1455
|
+
createdAt: new Date(result.createdAt),
|
|
1456
|
+
updatedAt: new Date(result.updatedAt)
|
|
1457
|
+
};
|
|
1458
|
+
} catch (error$1) {
|
|
1459
|
+
throw new error.MastraError(
|
|
1460
|
+
{
|
|
1461
|
+
id: "LIBSQL_STORE_GET_THREAD_BY_ID_FAILED",
|
|
1462
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1463
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1464
|
+
details: { threadId }
|
|
1465
|
+
},
|
|
1466
|
+
error$1
|
|
1467
|
+
);
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* @deprecated use getThreadsByResourceIdPaginated instead for paginated results.
|
|
1472
|
+
*/
|
|
1473
|
+
async getThreadsByResourceId(args) {
|
|
1474
|
+
const { resourceId } = args;
|
|
1475
|
+
try {
|
|
1476
|
+
const baseQuery = `FROM ${storage.TABLE_THREADS} WHERE resourceId = ?`;
|
|
1477
|
+
const queryParams = [resourceId];
|
|
1478
|
+
const mapRowToStorageThreadType = (row) => ({
|
|
1479
|
+
id: row.id,
|
|
1480
|
+
resourceId: row.resourceId,
|
|
1481
|
+
title: row.title,
|
|
1482
|
+
createdAt: new Date(row.createdAt),
|
|
1483
|
+
// Convert string to Date
|
|
1484
|
+
updatedAt: new Date(row.updatedAt),
|
|
1485
|
+
// Convert string to Date
|
|
1486
|
+
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata
|
|
1487
|
+
});
|
|
1488
|
+
const result = await this.client.execute({
|
|
1489
|
+
sql: `SELECT * ${baseQuery} ORDER BY createdAt DESC`,
|
|
1490
|
+
args: queryParams
|
|
1491
|
+
});
|
|
1492
|
+
if (!result.rows) {
|
|
1493
|
+
return [];
|
|
1494
|
+
}
|
|
1495
|
+
return result.rows.map(mapRowToStorageThreadType);
|
|
1496
|
+
} catch (error$1) {
|
|
1497
|
+
const mastraError = new error.MastraError(
|
|
1498
|
+
{
|
|
1499
|
+
id: "LIBSQL_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED",
|
|
1500
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1501
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1502
|
+
details: { resourceId }
|
|
1503
|
+
},
|
|
1504
|
+
error$1
|
|
1505
|
+
);
|
|
1506
|
+
this.logger?.trackException?.(mastraError);
|
|
1507
|
+
this.logger?.error?.(mastraError.toString());
|
|
1508
|
+
return [];
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
1512
|
+
const { resourceId, page = 0, perPage = 100 } = args;
|
|
1513
|
+
try {
|
|
1514
|
+
const baseQuery = `FROM ${storage.TABLE_THREADS} WHERE resourceId = ?`;
|
|
1515
|
+
const queryParams = [resourceId];
|
|
1516
|
+
const mapRowToStorageThreadType = (row) => ({
|
|
1517
|
+
id: row.id,
|
|
1518
|
+
resourceId: row.resourceId,
|
|
1519
|
+
title: row.title,
|
|
1520
|
+
createdAt: new Date(row.createdAt),
|
|
1521
|
+
// Convert string to Date
|
|
1522
|
+
updatedAt: new Date(row.updatedAt),
|
|
1523
|
+
// Convert string to Date
|
|
1524
|
+
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata
|
|
1525
|
+
});
|
|
1526
|
+
const currentOffset = page * perPage;
|
|
1527
|
+
const countResult = await this.client.execute({
|
|
1528
|
+
sql: `SELECT COUNT(*) as count ${baseQuery}`,
|
|
1529
|
+
args: queryParams
|
|
1530
|
+
});
|
|
1531
|
+
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
1532
|
+
if (total === 0) {
|
|
1533
|
+
return {
|
|
1534
|
+
threads: [],
|
|
1535
|
+
total: 0,
|
|
1536
|
+
page,
|
|
1537
|
+
perPage,
|
|
1538
|
+
hasMore: false
|
|
1539
|
+
};
|
|
1540
|
+
}
|
|
1541
|
+
const dataResult = await this.client.execute({
|
|
1542
|
+
sql: `SELECT * ${baseQuery} ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
|
|
1543
|
+
args: [...queryParams, perPage, currentOffset]
|
|
1544
|
+
});
|
|
1545
|
+
const threads = (dataResult.rows || []).map(mapRowToStorageThreadType);
|
|
1546
|
+
return {
|
|
1547
|
+
threads,
|
|
1548
|
+
total,
|
|
1549
|
+
page,
|
|
1550
|
+
perPage,
|
|
1551
|
+
hasMore: currentOffset + threads.length < total
|
|
1552
|
+
};
|
|
1553
|
+
} catch (error$1) {
|
|
1554
|
+
const mastraError = new error.MastraError(
|
|
1555
|
+
{
|
|
1556
|
+
id: "LIBSQL_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED",
|
|
1557
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1558
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1559
|
+
details: { resourceId }
|
|
1560
|
+
},
|
|
1561
|
+
error$1
|
|
1562
|
+
);
|
|
1563
|
+
this.logger?.trackException?.(mastraError);
|
|
1564
|
+
this.logger?.error?.(mastraError.toString());
|
|
1565
|
+
return { threads: [], total: 0, page, perPage, hasMore: false };
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
async saveThread({ thread }) {
|
|
1569
|
+
try {
|
|
1570
|
+
await this.operations.insert({
|
|
1571
|
+
tableName: storage.TABLE_THREADS,
|
|
1572
|
+
record: {
|
|
1573
|
+
...thread,
|
|
1574
|
+
metadata: JSON.stringify(thread.metadata)
|
|
1575
|
+
}
|
|
1576
|
+
});
|
|
1577
|
+
return thread;
|
|
1578
|
+
} catch (error$1) {
|
|
1579
|
+
const mastraError = new error.MastraError(
|
|
1580
|
+
{
|
|
1581
|
+
id: "LIBSQL_STORE_SAVE_THREAD_FAILED",
|
|
1582
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1583
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1584
|
+
details: { threadId: thread.id }
|
|
1585
|
+
},
|
|
1297
1586
|
error$1
|
|
1298
1587
|
);
|
|
1299
1588
|
this.logger?.trackException?.(mastraError);
|
|
@@ -1313,7 +1602,10 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
1313
1602
|
domain: error.ErrorDomain.STORAGE,
|
|
1314
1603
|
category: error.ErrorCategory.USER,
|
|
1315
1604
|
text: `Thread ${id} not found`,
|
|
1316
|
-
details: {
|
|
1605
|
+
details: {
|
|
1606
|
+
status: 404,
|
|
1607
|
+
threadId: id
|
|
1608
|
+
}
|
|
1317
1609
|
});
|
|
1318
1610
|
}
|
|
1319
1611
|
const updatedThread = {
|
|
@@ -1343,281 +1635,342 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
1343
1635
|
);
|
|
1344
1636
|
}
|
|
1345
1637
|
}
|
|
1346
|
-
async deleteThread({ threadId }) {
|
|
1347
|
-
try {
|
|
1348
|
-
await this.client.execute({
|
|
1349
|
-
sql: `DELETE FROM ${storage.TABLE_MESSAGES} WHERE thread_id = ?`,
|
|
1350
|
-
args: [threadId]
|
|
1351
|
-
});
|
|
1352
|
-
await this.client.execute({
|
|
1353
|
-
sql: `DELETE FROM ${storage.TABLE_THREADS} WHERE id = ?`,
|
|
1354
|
-
args: [threadId]
|
|
1355
|
-
});
|
|
1356
|
-
} catch (error$1) {
|
|
1638
|
+
async deleteThread({ threadId }) {
|
|
1639
|
+
try {
|
|
1640
|
+
await this.client.execute({
|
|
1641
|
+
sql: `DELETE FROM ${storage.TABLE_MESSAGES} WHERE thread_id = ?`,
|
|
1642
|
+
args: [threadId]
|
|
1643
|
+
});
|
|
1644
|
+
await this.client.execute({
|
|
1645
|
+
sql: `DELETE FROM ${storage.TABLE_THREADS} WHERE id = ?`,
|
|
1646
|
+
args: [threadId]
|
|
1647
|
+
});
|
|
1648
|
+
} catch (error$1) {
|
|
1649
|
+
throw new error.MastraError(
|
|
1650
|
+
{
|
|
1651
|
+
id: "LIBSQL_STORE_DELETE_THREAD_FAILED",
|
|
1652
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1653
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1654
|
+
details: { threadId }
|
|
1655
|
+
},
|
|
1656
|
+
error$1
|
|
1657
|
+
);
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
};
|
|
1661
|
+
function createExecuteWriteOperationWithRetry({
|
|
1662
|
+
logger,
|
|
1663
|
+
maxRetries,
|
|
1664
|
+
initialBackoffMs
|
|
1665
|
+
}) {
|
|
1666
|
+
return async function executeWriteOperationWithRetry(operationFn, operationDescription) {
|
|
1667
|
+
let retries = 0;
|
|
1668
|
+
while (true) {
|
|
1669
|
+
try {
|
|
1670
|
+
return await operationFn();
|
|
1671
|
+
} catch (error) {
|
|
1672
|
+
if (error.message && (error.message.includes("SQLITE_BUSY") || error.message.includes("database is locked")) && retries < maxRetries) {
|
|
1673
|
+
retries++;
|
|
1674
|
+
const backoffTime = initialBackoffMs * Math.pow(2, retries - 1);
|
|
1675
|
+
logger.warn(
|
|
1676
|
+
`LibSQLStore: Encountered SQLITE_BUSY during ${operationDescription}. Retrying (${retries}/${maxRetries}) in ${backoffTime}ms...`
|
|
1677
|
+
);
|
|
1678
|
+
await new Promise((resolve) => setTimeout(resolve, backoffTime));
|
|
1679
|
+
} else {
|
|
1680
|
+
logger.error(`LibSQLStore: Error during ${operationDescription} after ${retries} retries: ${error}`);
|
|
1681
|
+
throw error;
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
};
|
|
1686
|
+
}
|
|
1687
|
+
function prepareStatement({ tableName, record }) {
|
|
1688
|
+
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1689
|
+
const columns = Object.keys(record).map((col) => utils.parseSqlIdentifier(col, "column name"));
|
|
1690
|
+
const values = Object.values(record).map((v) => {
|
|
1691
|
+
if (typeof v === `undefined`) {
|
|
1692
|
+
return null;
|
|
1693
|
+
}
|
|
1694
|
+
if (v instanceof Date) {
|
|
1695
|
+
return v.toISOString();
|
|
1696
|
+
}
|
|
1697
|
+
return typeof v === "object" ? JSON.stringify(v) : v;
|
|
1698
|
+
});
|
|
1699
|
+
const placeholders = values.map(() => "?").join(", ");
|
|
1700
|
+
return {
|
|
1701
|
+
sql: `INSERT OR REPLACE INTO ${parsedTableName} (${columns.join(", ")}) VALUES (${placeholders})`,
|
|
1702
|
+
args: values
|
|
1703
|
+
};
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
// src/storage/domains/operations/index.ts
|
|
1707
|
+
var StoreOperationsLibSQL = class extends storage.StoreOperations {
|
|
1708
|
+
client;
|
|
1709
|
+
/**
|
|
1710
|
+
* Maximum number of retries for write operations if an SQLITE_BUSY error occurs.
|
|
1711
|
+
* @default 5
|
|
1712
|
+
*/
|
|
1713
|
+
maxRetries;
|
|
1714
|
+
/**
|
|
1715
|
+
* Initial backoff time in milliseconds for retrying write operations on SQLITE_BUSY.
|
|
1716
|
+
* The backoff time will double with each retry (exponential backoff).
|
|
1717
|
+
* @default 100
|
|
1718
|
+
*/
|
|
1719
|
+
initialBackoffMs;
|
|
1720
|
+
constructor({
|
|
1721
|
+
client,
|
|
1722
|
+
maxRetries,
|
|
1723
|
+
initialBackoffMs
|
|
1724
|
+
}) {
|
|
1725
|
+
super();
|
|
1726
|
+
this.client = client;
|
|
1727
|
+
this.maxRetries = maxRetries ?? 5;
|
|
1728
|
+
this.initialBackoffMs = initialBackoffMs ?? 100;
|
|
1729
|
+
}
|
|
1730
|
+
async hasColumn(table, column) {
|
|
1731
|
+
const result = await this.client.execute({
|
|
1732
|
+
sql: `PRAGMA table_info(${table})`
|
|
1733
|
+
});
|
|
1734
|
+
return (await result.rows)?.some((row) => row.name === column);
|
|
1735
|
+
}
|
|
1736
|
+
getCreateTableSQL(tableName, schema) {
|
|
1737
|
+
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1738
|
+
const columns = Object.entries(schema).map(([name, col]) => {
|
|
1739
|
+
const parsedColumnName = utils.parseSqlIdentifier(name, "column name");
|
|
1740
|
+
let type = col.type.toUpperCase();
|
|
1741
|
+
if (type === "TEXT") type = "TEXT";
|
|
1742
|
+
if (type === "TIMESTAMP") type = "TEXT";
|
|
1743
|
+
const nullable = col.nullable ? "" : "NOT NULL";
|
|
1744
|
+
const primaryKey = col.primaryKey ? "PRIMARY KEY" : "";
|
|
1745
|
+
return `${parsedColumnName} ${type} ${nullable} ${primaryKey}`.trim();
|
|
1746
|
+
});
|
|
1747
|
+
if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
|
|
1748
|
+
const stmnt = `CREATE TABLE IF NOT EXISTS ${parsedTableName} (
|
|
1749
|
+
${columns.join(",\n")},
|
|
1750
|
+
PRIMARY KEY (workflow_name, run_id)
|
|
1751
|
+
)`;
|
|
1752
|
+
return stmnt;
|
|
1753
|
+
}
|
|
1754
|
+
return `CREATE TABLE IF NOT EXISTS ${parsedTableName} (${columns.join(", ")})`;
|
|
1755
|
+
}
|
|
1756
|
+
async createTable({
|
|
1757
|
+
tableName,
|
|
1758
|
+
schema
|
|
1759
|
+
}) {
|
|
1760
|
+
try {
|
|
1761
|
+
this.logger.debug(`Creating database table`, { tableName, operation: "schema init" });
|
|
1762
|
+
const sql = this.getCreateTableSQL(tableName, schema);
|
|
1763
|
+
await this.client.execute(sql);
|
|
1764
|
+
} catch (error$1) {
|
|
1765
|
+
throw new error.MastraError(
|
|
1766
|
+
{
|
|
1767
|
+
id: "LIBSQL_STORE_CREATE_TABLE_FAILED",
|
|
1768
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1769
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1770
|
+
details: {
|
|
1771
|
+
tableName
|
|
1772
|
+
}
|
|
1773
|
+
},
|
|
1774
|
+
error$1
|
|
1775
|
+
);
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
getSqlType(type) {
|
|
1779
|
+
switch (type) {
|
|
1780
|
+
case "bigint":
|
|
1781
|
+
return "INTEGER";
|
|
1782
|
+
// SQLite uses INTEGER for all integer sizes
|
|
1783
|
+
case "jsonb":
|
|
1784
|
+
return "TEXT";
|
|
1785
|
+
// Store JSON as TEXT in SQLite
|
|
1786
|
+
default:
|
|
1787
|
+
return super.getSqlType(type);
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
async doInsert({
|
|
1791
|
+
tableName,
|
|
1792
|
+
record
|
|
1793
|
+
}) {
|
|
1794
|
+
await this.client.execute(
|
|
1795
|
+
prepareStatement({
|
|
1796
|
+
tableName,
|
|
1797
|
+
record
|
|
1798
|
+
})
|
|
1799
|
+
);
|
|
1800
|
+
}
|
|
1801
|
+
insert(args) {
|
|
1802
|
+
const executeWriteOperationWithRetry = createExecuteWriteOperationWithRetry({
|
|
1803
|
+
logger: this.logger,
|
|
1804
|
+
maxRetries: this.maxRetries,
|
|
1805
|
+
initialBackoffMs: this.initialBackoffMs
|
|
1806
|
+
});
|
|
1807
|
+
return executeWriteOperationWithRetry(() => this.doInsert(args), `insert into table ${args.tableName}`);
|
|
1808
|
+
}
|
|
1809
|
+
async load({ tableName, keys }) {
|
|
1810
|
+
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1811
|
+
const parsedKeys = Object.keys(keys).map((key) => utils.parseSqlIdentifier(key, "column name"));
|
|
1812
|
+
const conditions = parsedKeys.map((key) => `${key} = ?`).join(" AND ");
|
|
1813
|
+
const values = Object.values(keys);
|
|
1814
|
+
const result = await this.client.execute({
|
|
1815
|
+
sql: `SELECT * FROM ${parsedTableName} WHERE ${conditions} ORDER BY createdAt DESC LIMIT 1`,
|
|
1816
|
+
args: values
|
|
1817
|
+
});
|
|
1818
|
+
if (!result.rows || result.rows.length === 0) {
|
|
1819
|
+
return null;
|
|
1820
|
+
}
|
|
1821
|
+
const row = result.rows[0];
|
|
1822
|
+
const parsed = Object.fromEntries(
|
|
1823
|
+
Object.entries(row || {}).map(([k, v]) => {
|
|
1824
|
+
try {
|
|
1825
|
+
return [k, typeof v === "string" ? v.startsWith("{") || v.startsWith("[") ? JSON.parse(v) : v : v];
|
|
1826
|
+
} catch {
|
|
1827
|
+
return [k, v];
|
|
1828
|
+
}
|
|
1829
|
+
})
|
|
1830
|
+
);
|
|
1831
|
+
return parsed;
|
|
1832
|
+
}
|
|
1833
|
+
async doBatchInsert({
|
|
1834
|
+
tableName,
|
|
1835
|
+
records
|
|
1836
|
+
}) {
|
|
1837
|
+
if (records.length === 0) return;
|
|
1838
|
+
const batchStatements = records.map((r) => prepareStatement({ tableName, record: r }));
|
|
1839
|
+
await this.client.batch(batchStatements, "write");
|
|
1840
|
+
}
|
|
1841
|
+
batchInsert(args) {
|
|
1842
|
+
const executeWriteOperationWithRetry = createExecuteWriteOperationWithRetry({
|
|
1843
|
+
logger: this.logger,
|
|
1844
|
+
maxRetries: this.maxRetries,
|
|
1845
|
+
initialBackoffMs: this.initialBackoffMs
|
|
1846
|
+
});
|
|
1847
|
+
return executeWriteOperationWithRetry(
|
|
1848
|
+
() => this.doBatchInsert(args),
|
|
1849
|
+
`batch insert into table ${args.tableName}`
|
|
1850
|
+
).catch((error$1) => {
|
|
1357
1851
|
throw new error.MastraError(
|
|
1358
1852
|
{
|
|
1359
|
-
id: "
|
|
1853
|
+
id: "LIBSQL_STORE_BATCH_INSERT_FAILED",
|
|
1360
1854
|
domain: error.ErrorDomain.STORAGE,
|
|
1361
1855
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1362
|
-
details: {
|
|
1856
|
+
details: {
|
|
1857
|
+
tableName: args.tableName
|
|
1858
|
+
}
|
|
1363
1859
|
},
|
|
1364
1860
|
error$1
|
|
1365
1861
|
);
|
|
1366
|
-
}
|
|
1367
|
-
}
|
|
1368
|
-
parseRow(row) {
|
|
1369
|
-
let content = row.content;
|
|
1370
|
-
try {
|
|
1371
|
-
content = JSON.parse(row.content);
|
|
1372
|
-
} catch {
|
|
1373
|
-
}
|
|
1374
|
-
const result = {
|
|
1375
|
-
id: row.id,
|
|
1376
|
-
content,
|
|
1377
|
-
role: row.role,
|
|
1378
|
-
createdAt: new Date(row.createdAt),
|
|
1379
|
-
threadId: row.thread_id,
|
|
1380
|
-
resourceId: row.resourceId
|
|
1381
|
-
};
|
|
1382
|
-
if (row.type && row.type !== `v2`) result.type = row.type;
|
|
1383
|
-
return result;
|
|
1384
|
-
}
|
|
1385
|
-
async _getIncludedMessages({
|
|
1386
|
-
threadId,
|
|
1387
|
-
selectBy
|
|
1388
|
-
}) {
|
|
1389
|
-
const include = selectBy?.include;
|
|
1390
|
-
if (!include) return null;
|
|
1391
|
-
const unionQueries = [];
|
|
1392
|
-
const params = [];
|
|
1393
|
-
for (const inc of include) {
|
|
1394
|
-
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
1395
|
-
const searchId = inc.threadId || threadId;
|
|
1396
|
-
unionQueries.push(
|
|
1397
|
-
`
|
|
1398
|
-
SELECT * FROM (
|
|
1399
|
-
WITH numbered_messages AS (
|
|
1400
|
-
SELECT
|
|
1401
|
-
id, content, role, type, "createdAt", thread_id, "resourceId",
|
|
1402
|
-
ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
|
|
1403
|
-
FROM "${storage.TABLE_MESSAGES}"
|
|
1404
|
-
WHERE thread_id = ?
|
|
1405
|
-
),
|
|
1406
|
-
target_positions AS (
|
|
1407
|
-
SELECT row_num as target_pos
|
|
1408
|
-
FROM numbered_messages
|
|
1409
|
-
WHERE id = ?
|
|
1410
|
-
)
|
|
1411
|
-
SELECT DISTINCT m.*
|
|
1412
|
-
FROM numbered_messages m
|
|
1413
|
-
CROSS JOIN target_positions t
|
|
1414
|
-
WHERE m.row_num BETWEEN (t.target_pos - ?) AND (t.target_pos + ?)
|
|
1415
|
-
)
|
|
1416
|
-
`
|
|
1417
|
-
// Keep ASC for final sorting after fetching context
|
|
1418
|
-
);
|
|
1419
|
-
params.push(searchId, id, withPreviousMessages, withNextMessages);
|
|
1420
|
-
}
|
|
1421
|
-
const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
|
|
1422
|
-
const includedResult = await this.client.execute({ sql: finalQuery, args: params });
|
|
1423
|
-
const includedRows = includedResult.rows?.map((row) => this.parseRow(row));
|
|
1424
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1425
|
-
const dedupedRows = includedRows.filter((row) => {
|
|
1426
|
-
if (seen.has(row.id)) return false;
|
|
1427
|
-
seen.add(row.id);
|
|
1428
|
-
return true;
|
|
1429
1862
|
});
|
|
1430
|
-
return dedupedRows;
|
|
1431
1863
|
}
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1864
|
+
/**
|
|
1865
|
+
* Alters table schema to add columns if they don't exist
|
|
1866
|
+
* @param tableName Name of the table
|
|
1867
|
+
* @param schema Schema of the table
|
|
1868
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
1869
|
+
*/
|
|
1870
|
+
async alterTable({
|
|
1871
|
+
tableName,
|
|
1872
|
+
schema,
|
|
1873
|
+
ifNotExists
|
|
1436
1874
|
}) {
|
|
1875
|
+
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1437
1876
|
try {
|
|
1438
|
-
const
|
|
1439
|
-
const
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
if (
|
|
1443
|
-
|
|
1877
|
+
const pragmaQuery = `PRAGMA table_info(${parsedTableName})`;
|
|
1878
|
+
const result = await this.client.execute(pragmaQuery);
|
|
1879
|
+
const existingColumnNames = new Set(result.rows.map((row) => row.name.toLowerCase()));
|
|
1880
|
+
for (const columnName of ifNotExists) {
|
|
1881
|
+
if (!existingColumnNames.has(columnName.toLowerCase()) && schema[columnName]) {
|
|
1882
|
+
const columnDef = schema[columnName];
|
|
1883
|
+
const sqlType = this.getSqlType(columnDef.type);
|
|
1884
|
+
const nullable = columnDef.nullable === false ? "NOT NULL" : "";
|
|
1885
|
+
const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
|
|
1886
|
+
const alterSql = `ALTER TABLE ${parsedTableName} ADD COLUMN "${columnName}" ${sqlType} ${nullable} ${defaultValue}`.trim();
|
|
1887
|
+
await this.client.execute(alterSql);
|
|
1888
|
+
this.logger?.debug?.(`Added column ${columnName} to table ${parsedTableName}`);
|
|
1444
1889
|
}
|
|
1445
1890
|
}
|
|
1446
|
-
const excludeIds = messages.map((m) => m.id);
|
|
1447
|
-
const remainingSql = `
|
|
1448
|
-
SELECT
|
|
1449
|
-
id,
|
|
1450
|
-
content,
|
|
1451
|
-
role,
|
|
1452
|
-
type,
|
|
1453
|
-
"createdAt",
|
|
1454
|
-
thread_id,
|
|
1455
|
-
"resourceId"
|
|
1456
|
-
FROM "${storage.TABLE_MESSAGES}"
|
|
1457
|
-
WHERE thread_id = ?
|
|
1458
|
-
${excludeIds.length ? `AND id NOT IN (${excludeIds.map(() => "?").join(", ")})` : ""}
|
|
1459
|
-
ORDER BY "createdAt" DESC
|
|
1460
|
-
LIMIT ?
|
|
1461
|
-
`;
|
|
1462
|
-
const remainingArgs = [threadId, ...excludeIds.length ? excludeIds : [], limit];
|
|
1463
|
-
const remainingResult = await this.client.execute({ sql: remainingSql, args: remainingArgs });
|
|
1464
|
-
if (remainingResult.rows) {
|
|
1465
|
-
messages.push(...remainingResult.rows.map((row) => this.parseRow(row)));
|
|
1466
|
-
}
|
|
1467
|
-
messages.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
1468
|
-
const list = new agent.MessageList().add(messages, "memory");
|
|
1469
|
-
if (format === `v2`) return list.get.all.v2();
|
|
1470
|
-
return list.get.all.v1();
|
|
1471
1891
|
} catch (error$1) {
|
|
1472
1892
|
throw new error.MastraError(
|
|
1473
1893
|
{
|
|
1474
|
-
id: "
|
|
1894
|
+
id: "LIBSQL_STORE_ALTER_TABLE_FAILED",
|
|
1475
1895
|
domain: error.ErrorDomain.STORAGE,
|
|
1476
1896
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1477
|
-
details: {
|
|
1897
|
+
details: {
|
|
1898
|
+
tableName
|
|
1899
|
+
}
|
|
1478
1900
|
},
|
|
1479
1901
|
error$1
|
|
1480
1902
|
);
|
|
1481
1903
|
}
|
|
1482
1904
|
}
|
|
1483
|
-
async
|
|
1484
|
-
const
|
|
1485
|
-
const { page = 0, perPage: perPageInput, dateRange } = selectBy?.pagination || {};
|
|
1486
|
-
const perPage = perPageInput !== void 0 ? perPageInput : this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
1487
|
-
const fromDate = dateRange?.start;
|
|
1488
|
-
const toDate = dateRange?.end;
|
|
1489
|
-
const messages = [];
|
|
1490
|
-
if (selectBy?.include?.length) {
|
|
1491
|
-
try {
|
|
1492
|
-
const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
|
|
1493
|
-
if (includeMessages) {
|
|
1494
|
-
messages.push(...includeMessages);
|
|
1495
|
-
}
|
|
1496
|
-
} catch (error$1) {
|
|
1497
|
-
throw new error.MastraError(
|
|
1498
|
-
{
|
|
1499
|
-
id: "LIBSQL_STORE_GET_MESSAGES_PAGINATED_GET_INCLUDE_MESSAGES_FAILED",
|
|
1500
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1501
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
1502
|
-
details: { threadId }
|
|
1503
|
-
},
|
|
1504
|
-
error$1
|
|
1505
|
-
);
|
|
1506
|
-
}
|
|
1507
|
-
}
|
|
1905
|
+
async clearTable({ tableName }) {
|
|
1906
|
+
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1508
1907
|
try {
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
const queryParams = [threadId];
|
|
1512
|
-
if (fromDate) {
|
|
1513
|
-
conditions.push(`"createdAt" >= ?`);
|
|
1514
|
-
queryParams.push(fromDate.toISOString());
|
|
1515
|
-
}
|
|
1516
|
-
if (toDate) {
|
|
1517
|
-
conditions.push(`"createdAt" <= ?`);
|
|
1518
|
-
queryParams.push(toDate.toISOString());
|
|
1519
|
-
}
|
|
1520
|
-
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1521
|
-
const countResult = await this.client.execute({
|
|
1522
|
-
sql: `SELECT COUNT(*) as count FROM ${storage.TABLE_MESSAGES} ${whereClause}`,
|
|
1523
|
-
args: queryParams
|
|
1524
|
-
});
|
|
1525
|
-
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
1526
|
-
if (total === 0 && messages.length === 0) {
|
|
1527
|
-
return {
|
|
1528
|
-
messages: [],
|
|
1529
|
-
total: 0,
|
|
1530
|
-
page,
|
|
1531
|
-
perPage,
|
|
1532
|
-
hasMore: false
|
|
1533
|
-
};
|
|
1534
|
-
}
|
|
1535
|
-
const excludeIds = messages.map((m) => m.id);
|
|
1536
|
-
const excludeIdsParam = excludeIds.map((_, idx) => `$${idx + queryParams.length + 1}`).join(", ");
|
|
1537
|
-
const dataResult = await this.client.execute({
|
|
1538
|
-
sql: `SELECT id, content, role, type, "createdAt", "resourceId", "thread_id" FROM ${storage.TABLE_MESSAGES} ${whereClause} ${excludeIds.length ? `AND id NOT IN (${excludeIdsParam})` : ""} ORDER BY "createdAt" DESC LIMIT ? OFFSET ?`,
|
|
1539
|
-
args: [...queryParams, ...excludeIds, perPage, currentOffset]
|
|
1540
|
-
});
|
|
1541
|
-
messages.push(...(dataResult.rows || []).map((row) => this.parseRow(row)));
|
|
1542
|
-
const messagesToReturn = format === "v1" ? new agent.MessageList().add(messages, "memory").get.all.v1() : new agent.MessageList().add(messages, "memory").get.all.v2();
|
|
1543
|
-
return {
|
|
1544
|
-
messages: messagesToReturn,
|
|
1545
|
-
total,
|
|
1546
|
-
page,
|
|
1547
|
-
perPage,
|
|
1548
|
-
hasMore: currentOffset + messages.length < total
|
|
1549
|
-
};
|
|
1550
|
-
} catch (error$1) {
|
|
1908
|
+
await this.client.execute(`DELETE FROM ${parsedTableName}`);
|
|
1909
|
+
} catch (e) {
|
|
1551
1910
|
const mastraError = new error.MastraError(
|
|
1552
1911
|
{
|
|
1553
|
-
id: "
|
|
1912
|
+
id: "LIBSQL_STORE_CLEAR_TABLE_FAILED",
|
|
1554
1913
|
domain: error.ErrorDomain.STORAGE,
|
|
1555
1914
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1556
|
-
details: {
|
|
1915
|
+
details: {
|
|
1916
|
+
tableName
|
|
1917
|
+
}
|
|
1557
1918
|
},
|
|
1558
|
-
|
|
1919
|
+
e
|
|
1559
1920
|
);
|
|
1560
1921
|
this.logger?.trackException?.(mastraError);
|
|
1561
1922
|
this.logger?.error?.(mastraError.toString());
|
|
1562
|
-
return { messages: [], total: 0, page, perPage, hasMore: false };
|
|
1563
1923
|
}
|
|
1564
1924
|
}
|
|
1565
|
-
async
|
|
1566
|
-
|
|
1567
|
-
format
|
|
1568
|
-
}) {
|
|
1569
|
-
if (messages.length === 0) return messages;
|
|
1925
|
+
async dropTable({ tableName }) {
|
|
1926
|
+
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1570
1927
|
try {
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
}
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
time instanceof Date ? time.toISOString() : time,
|
|
1604
|
-
message.resourceId
|
|
1605
|
-
]
|
|
1606
|
-
};
|
|
1607
|
-
});
|
|
1608
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1609
|
-
batchStatements.push({
|
|
1610
|
-
sql: `UPDATE ${storage.TABLE_THREADS} SET updatedAt = ? WHERE id = ?`,
|
|
1611
|
-
args: [now, threadId]
|
|
1928
|
+
await this.client.execute(`DROP TABLE IF EXISTS ${parsedTableName}`);
|
|
1929
|
+
} catch (e) {
|
|
1930
|
+
throw new error.MastraError(
|
|
1931
|
+
{
|
|
1932
|
+
id: "LIBSQL_STORE_DROP_TABLE_FAILED",
|
|
1933
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1934
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1935
|
+
details: {
|
|
1936
|
+
tableName
|
|
1937
|
+
}
|
|
1938
|
+
},
|
|
1939
|
+
e
|
|
1940
|
+
);
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
};
|
|
1944
|
+
var ScoresLibSQL = class extends storage.ScoresStorage {
|
|
1945
|
+
operations;
|
|
1946
|
+
client;
|
|
1947
|
+
constructor({ client, operations }) {
|
|
1948
|
+
super();
|
|
1949
|
+
this.operations = operations;
|
|
1950
|
+
this.client = client;
|
|
1951
|
+
}
|
|
1952
|
+
async getScoresByRunId({
|
|
1953
|
+
runId,
|
|
1954
|
+
pagination
|
|
1955
|
+
}) {
|
|
1956
|
+
try {
|
|
1957
|
+
const result = await this.client.execute({
|
|
1958
|
+
sql: `SELECT * FROM ${storage.TABLE_SCORERS} WHERE runId = ? ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
|
|
1959
|
+
args: [runId, pagination.perPage + 1, pagination.page * pagination.perPage]
|
|
1612
1960
|
});
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1961
|
+
return {
|
|
1962
|
+
scores: result.rows?.slice(0, pagination.perPage).map((row) => this.transformScoreRow(row)) ?? [],
|
|
1963
|
+
pagination: {
|
|
1964
|
+
total: result.rows?.length ?? 0,
|
|
1965
|
+
page: pagination.page,
|
|
1966
|
+
perPage: pagination.perPage,
|
|
1967
|
+
hasMore: result.rows?.length > pagination.perPage
|
|
1968
|
+
}
|
|
1969
|
+
};
|
|
1617
1970
|
} catch (error$1) {
|
|
1618
1971
|
throw new error.MastraError(
|
|
1619
1972
|
{
|
|
1620
|
-
id: "
|
|
1973
|
+
id: "LIBSQL_STORE_GET_SCORES_BY_RUN_ID_FAILED",
|
|
1621
1974
|
domain: error.ErrorDomain.STORAGE,
|
|
1622
1975
|
category: error.ErrorCategory.THIRD_PARTY
|
|
1623
1976
|
},
|
|
@@ -1625,185 +1978,144 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
1625
1978
|
);
|
|
1626
1979
|
}
|
|
1627
1980
|
}
|
|
1628
|
-
async
|
|
1629
|
-
|
|
1981
|
+
async getScoresByScorerId({
|
|
1982
|
+
scorerId,
|
|
1983
|
+
entityId,
|
|
1984
|
+
entityType,
|
|
1985
|
+
pagination
|
|
1630
1986
|
}) {
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
const existingResult = await this.client.execute({ sql: selectSql, args: messageIds });
|
|
1638
|
-
const existingMessages = existingResult.rows.map((row) => this.parseRow(row));
|
|
1639
|
-
if (existingMessages.length === 0) {
|
|
1640
|
-
return [];
|
|
1641
|
-
}
|
|
1642
|
-
const batchStatements = [];
|
|
1643
|
-
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
1644
|
-
const columnMapping = {
|
|
1645
|
-
threadId: "thread_id"
|
|
1646
|
-
};
|
|
1647
|
-
for (const existingMessage of existingMessages) {
|
|
1648
|
-
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
1649
|
-
if (!updatePayload) continue;
|
|
1650
|
-
const { id, ...fieldsToUpdate } = updatePayload;
|
|
1651
|
-
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
1652
|
-
threadIdsToUpdate.add(existingMessage.threadId);
|
|
1653
|
-
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
1654
|
-
threadIdsToUpdate.add(updatePayload.threadId);
|
|
1655
|
-
}
|
|
1656
|
-
const setClauses = [];
|
|
1657
|
-
const args = [];
|
|
1658
|
-
const updatableFields = { ...fieldsToUpdate };
|
|
1659
|
-
if (updatableFields.content) {
|
|
1660
|
-
const newContent = {
|
|
1661
|
-
...existingMessage.content,
|
|
1662
|
-
...updatableFields.content,
|
|
1663
|
-
// Deep merge metadata if it exists on both
|
|
1664
|
-
...existingMessage.content?.metadata && updatableFields.content.metadata ? {
|
|
1665
|
-
metadata: {
|
|
1666
|
-
...existingMessage.content.metadata,
|
|
1667
|
-
...updatableFields.content.metadata
|
|
1668
|
-
}
|
|
1669
|
-
} : {}
|
|
1670
|
-
};
|
|
1671
|
-
setClauses.push(`${utils.parseSqlIdentifier("content", "column name")} = ?`);
|
|
1672
|
-
args.push(JSON.stringify(newContent));
|
|
1673
|
-
delete updatableFields.content;
|
|
1987
|
+
try {
|
|
1988
|
+
const conditions = [];
|
|
1989
|
+
const queryParams = [];
|
|
1990
|
+
if (scorerId) {
|
|
1991
|
+
conditions.push(`scorerId = ?`);
|
|
1992
|
+
queryParams.push(scorerId);
|
|
1674
1993
|
}
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
setClauses.push(`${utils.parseSqlIdentifier(dbKey, "column name")} = ?`);
|
|
1679
|
-
let value = updatableFields[key];
|
|
1680
|
-
if (typeof value === "object" && value !== null) {
|
|
1681
|
-
value = JSON.stringify(value);
|
|
1682
|
-
}
|
|
1683
|
-
args.push(value);
|
|
1684
|
-
}
|
|
1994
|
+
if (entityId) {
|
|
1995
|
+
conditions.push(`entityId = ?`);
|
|
1996
|
+
queryParams.push(entityId);
|
|
1685
1997
|
}
|
|
1686
|
-
if (
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
batchStatements.push({ sql, args });
|
|
1690
|
-
}
|
|
1691
|
-
if (batchStatements.length === 0) {
|
|
1692
|
-
return existingMessages;
|
|
1693
|
-
}
|
|
1694
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1695
|
-
for (const threadId of threadIdsToUpdate) {
|
|
1696
|
-
if (threadId) {
|
|
1697
|
-
batchStatements.push({
|
|
1698
|
-
sql: `UPDATE ${storage.TABLE_THREADS} SET updatedAt = ? WHERE id = ?`,
|
|
1699
|
-
args: [now, threadId]
|
|
1700
|
-
});
|
|
1998
|
+
if (entityType) {
|
|
1999
|
+
conditions.push(`entityType = ?`);
|
|
2000
|
+
queryParams.push(entityType);
|
|
1701
2001
|
}
|
|
2002
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2003
|
+
const result = await this.client.execute({
|
|
2004
|
+
sql: `SELECT * FROM ${storage.TABLE_SCORERS} ${whereClause} ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
|
|
2005
|
+
args: [...queryParams, pagination.perPage + 1, pagination.page * pagination.perPage]
|
|
2006
|
+
});
|
|
2007
|
+
return {
|
|
2008
|
+
scores: result.rows?.slice(0, pagination.perPage).map((row) => this.transformScoreRow(row)) ?? [],
|
|
2009
|
+
pagination: {
|
|
2010
|
+
total: result.rows?.length ?? 0,
|
|
2011
|
+
page: pagination.page,
|
|
2012
|
+
perPage: pagination.perPage,
|
|
2013
|
+
hasMore: result.rows?.length > pagination.perPage
|
|
2014
|
+
}
|
|
2015
|
+
};
|
|
2016
|
+
} catch (error$1) {
|
|
2017
|
+
throw new error.MastraError(
|
|
2018
|
+
{
|
|
2019
|
+
id: "LIBSQL_STORE_GET_SCORES_BY_SCORER_ID_FAILED",
|
|
2020
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2021
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2022
|
+
},
|
|
2023
|
+
error$1
|
|
2024
|
+
);
|
|
1702
2025
|
}
|
|
1703
|
-
await this.client.batch(batchStatements, "write");
|
|
1704
|
-
const updatedResult = await this.client.execute({ sql: selectSql, args: messageIds });
|
|
1705
|
-
return updatedResult.rows.map((row) => this.parseRow(row));
|
|
1706
2026
|
}
|
|
1707
|
-
|
|
1708
|
-
const
|
|
1709
|
-
const
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
2027
|
+
transformScoreRow(row) {
|
|
2028
|
+
const scorerValue = JSON.parse(row.scorer ?? "{}");
|
|
2029
|
+
const inputValue = JSON.parse(row.input ?? "{}");
|
|
2030
|
+
const outputValue = JSON.parse(row.output ?? "{}");
|
|
2031
|
+
const additionalLLMContextValue = row.additionalLLMContext ? JSON.parse(row.additionalLLMContext) : null;
|
|
2032
|
+
const runtimeContextValue = row.runtimeContext ? JSON.parse(row.runtimeContext) : null;
|
|
2033
|
+
const metadataValue = row.metadata ? JSON.parse(row.metadata) : null;
|
|
2034
|
+
const entityValue = row.entity ? JSON.parse(row.entity) : null;
|
|
2035
|
+
const extractStepResultValue = row.extractStepResult ? JSON.parse(row.extractStepResult) : null;
|
|
2036
|
+
const analyzeStepResultValue = row.analyzeStepResult ? JSON.parse(row.analyzeStepResult) : null;
|
|
1713
2037
|
return {
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
2038
|
+
id: row.id,
|
|
2039
|
+
traceId: row.traceId,
|
|
2040
|
+
runId: row.runId,
|
|
2041
|
+
scorer: scorerValue,
|
|
2042
|
+
score: row.score,
|
|
2043
|
+
reason: row.reason,
|
|
2044
|
+
extractStepResult: extractStepResultValue,
|
|
2045
|
+
analyzeStepResult: analyzeStepResultValue,
|
|
2046
|
+
analyzePrompt: row.analyzePrompt,
|
|
2047
|
+
extractPrompt: row.extractPrompt,
|
|
2048
|
+
metadata: metadataValue,
|
|
2049
|
+
input: inputValue,
|
|
2050
|
+
output: outputValue,
|
|
2051
|
+
additionalContext: additionalLLMContextValue,
|
|
2052
|
+
runtimeContext: runtimeContextValue,
|
|
2053
|
+
entityType: row.entityType,
|
|
2054
|
+
entity: entityValue,
|
|
2055
|
+
entityId: row.entityId,
|
|
2056
|
+
scorerId: row.scorerId,
|
|
2057
|
+
source: row.source,
|
|
2058
|
+
resourceId: row.resourceId,
|
|
2059
|
+
threadId: row.threadId,
|
|
2060
|
+
createdAt: row.createdAt,
|
|
2061
|
+
updatedAt: row.updatedAt
|
|
1724
2062
|
};
|
|
1725
2063
|
}
|
|
1726
|
-
|
|
1727
|
-
|
|
2064
|
+
async getScoreById({ id }) {
|
|
2065
|
+
const result = await this.client.execute({
|
|
2066
|
+
sql: `SELECT * FROM ${storage.TABLE_SCORERS} WHERE id = ?`,
|
|
2067
|
+
args: [id]
|
|
2068
|
+
});
|
|
2069
|
+
return result.rows?.[0] ? this.transformScoreRow(result.rows[0]) : null;
|
|
2070
|
+
}
|
|
2071
|
+
async saveScore(score) {
|
|
1728
2072
|
try {
|
|
1729
|
-
const
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
2073
|
+
const id = crypto.randomUUID();
|
|
2074
|
+
await this.operations.insert({
|
|
2075
|
+
tableName: storage.TABLE_SCORERS,
|
|
2076
|
+
record: {
|
|
2077
|
+
id,
|
|
2078
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2079
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2080
|
+
...score
|
|
2081
|
+
}
|
|
1734
2082
|
});
|
|
1735
|
-
|
|
2083
|
+
const scoreFromDb = await this.getScoreById({ id });
|
|
2084
|
+
return { score: scoreFromDb };
|
|
1736
2085
|
} catch (error$1) {
|
|
1737
|
-
if (error$1 instanceof Error && error$1.message.includes("no such table")) {
|
|
1738
|
-
return [];
|
|
1739
|
-
}
|
|
1740
2086
|
throw new error.MastraError(
|
|
1741
2087
|
{
|
|
1742
|
-
id: "
|
|
2088
|
+
id: "LIBSQL_STORE_SAVE_SCORE_FAILED",
|
|
1743
2089
|
domain: error.ErrorDomain.STORAGE,
|
|
1744
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1745
|
-
details: { agentName }
|
|
2090
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1746
2091
|
},
|
|
1747
2092
|
error$1
|
|
1748
2093
|
);
|
|
1749
2094
|
}
|
|
1750
2095
|
}
|
|
1751
|
-
async
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
const queryParams = [];
|
|
1757
|
-
if (agentName) {
|
|
1758
|
-
conditions.push(`agent_name = ?`);
|
|
1759
|
-
queryParams.push(agentName);
|
|
1760
|
-
}
|
|
1761
|
-
if (type === "test") {
|
|
1762
|
-
conditions.push(`(test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL)`);
|
|
1763
|
-
} else if (type === "live") {
|
|
1764
|
-
conditions.push(`(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)`);
|
|
1765
|
-
}
|
|
1766
|
-
if (fromDate) {
|
|
1767
|
-
conditions.push(`created_at >= ?`);
|
|
1768
|
-
queryParams.push(fromDate.toISOString());
|
|
1769
|
-
}
|
|
1770
|
-
if (toDate) {
|
|
1771
|
-
conditions.push(`created_at <= ?`);
|
|
1772
|
-
queryParams.push(toDate.toISOString());
|
|
1773
|
-
}
|
|
1774
|
-
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2096
|
+
async getScoresByEntityId({
|
|
2097
|
+
entityId,
|
|
2098
|
+
entityType,
|
|
2099
|
+
pagination
|
|
2100
|
+
}) {
|
|
1775
2101
|
try {
|
|
1776
|
-
const
|
|
1777
|
-
sql: `SELECT
|
|
1778
|
-
args:
|
|
1779
|
-
});
|
|
1780
|
-
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
1781
|
-
const currentOffset = page * perPage;
|
|
1782
|
-
const hasMore = currentOffset + perPage < total;
|
|
1783
|
-
if (total === 0) {
|
|
1784
|
-
return {
|
|
1785
|
-
evals: [],
|
|
1786
|
-
total: 0,
|
|
1787
|
-
page,
|
|
1788
|
-
perPage,
|
|
1789
|
-
hasMore: false
|
|
1790
|
-
};
|
|
1791
|
-
}
|
|
1792
|
-
const dataResult = await this.client.execute({
|
|
1793
|
-
sql: `SELECT * FROM ${storage.TABLE_EVALS} ${whereClause} ORDER BY created_at DESC LIMIT ? OFFSET ?`,
|
|
1794
|
-
args: [...queryParams, perPage, currentOffset]
|
|
2102
|
+
const result = await this.client.execute({
|
|
2103
|
+
sql: `SELECT * FROM ${storage.TABLE_SCORERS} WHERE entityId = ? AND entityType = ? ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
|
|
2104
|
+
args: [entityId, entityType, pagination.perPage + 1, pagination.page * pagination.perPage]
|
|
1795
2105
|
});
|
|
1796
2106
|
return {
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
2107
|
+
scores: result.rows?.slice(0, pagination.perPage).map((row) => this.transformScoreRow(row)) ?? [],
|
|
2108
|
+
pagination: {
|
|
2109
|
+
total: result.rows?.length ?? 0,
|
|
2110
|
+
page: pagination.page,
|
|
2111
|
+
perPage: pagination.perPage,
|
|
2112
|
+
hasMore: result.rows?.length > pagination.perPage
|
|
2113
|
+
}
|
|
1802
2114
|
};
|
|
1803
2115
|
} catch (error$1) {
|
|
1804
2116
|
throw new error.MastraError(
|
|
1805
2117
|
{
|
|
1806
|
-
id: "
|
|
2118
|
+
id: "LIBSQL_STORE_GET_SCORES_BY_ENTITY_ID_FAILED",
|
|
1807
2119
|
domain: error.ErrorDomain.STORAGE,
|
|
1808
2120
|
category: error.ErrorCategory.THIRD_PARTY
|
|
1809
2121
|
},
|
|
@@ -1811,9 +2123,15 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
1811
2123
|
);
|
|
1812
2124
|
}
|
|
1813
2125
|
}
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
2126
|
+
};
|
|
2127
|
+
var TracesLibSQL = class extends storage.TracesStorage {
|
|
2128
|
+
client;
|
|
2129
|
+
operations;
|
|
2130
|
+
constructor({ client, operations }) {
|
|
2131
|
+
super();
|
|
2132
|
+
this.client = client;
|
|
2133
|
+
this.operations = operations;
|
|
2134
|
+
}
|
|
1817
2135
|
async getTraces(args) {
|
|
1818
2136
|
if (args.fromDate || args.toDate) {
|
|
1819
2137
|
args.dateRange = {
|
|
@@ -1890,35 +2208,133 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
1890
2208
|
sql: `SELECT * FROM ${storage.TABLE_TRACES} ${whereClause} ORDER BY "startTime" DESC LIMIT ? OFFSET ?`,
|
|
1891
2209
|
args: [...queryArgs, perPage, currentOffset]
|
|
1892
2210
|
});
|
|
1893
|
-
const traces = dataResult.rows?.map(
|
|
1894
|
-
(row) => ({
|
|
1895
|
-
id: row.id,
|
|
1896
|
-
parentSpanId: row.parentSpanId,
|
|
1897
|
-
traceId: row.traceId,
|
|
1898
|
-
name: row.name,
|
|
1899
|
-
scope: row.scope,
|
|
1900
|
-
kind: row.kind,
|
|
1901
|
-
status: safelyParseJSON(row.status),
|
|
1902
|
-
events: safelyParseJSON(row.events),
|
|
1903
|
-
links: safelyParseJSON(row.links),
|
|
1904
|
-
attributes: safelyParseJSON(row.attributes),
|
|
1905
|
-
startTime: row.startTime,
|
|
1906
|
-
endTime: row.endTime,
|
|
1907
|
-
other: safelyParseJSON(row.other),
|
|
1908
|
-
createdAt: row.createdAt
|
|
1909
|
-
})
|
|
1910
|
-
) ?? [];
|
|
1911
|
-
return {
|
|
1912
|
-
traces,
|
|
1913
|
-
total,
|
|
1914
|
-
page,
|
|
1915
|
-
perPage,
|
|
1916
|
-
hasMore: currentOffset + traces.length < total
|
|
1917
|
-
};
|
|
2211
|
+
const traces = dataResult.rows?.map(
|
|
2212
|
+
(row) => ({
|
|
2213
|
+
id: row.id,
|
|
2214
|
+
parentSpanId: row.parentSpanId,
|
|
2215
|
+
traceId: row.traceId,
|
|
2216
|
+
name: row.name,
|
|
2217
|
+
scope: row.scope,
|
|
2218
|
+
kind: row.kind,
|
|
2219
|
+
status: storage.safelyParseJSON(row.status),
|
|
2220
|
+
events: storage.safelyParseJSON(row.events),
|
|
2221
|
+
links: storage.safelyParseJSON(row.links),
|
|
2222
|
+
attributes: storage.safelyParseJSON(row.attributes),
|
|
2223
|
+
startTime: row.startTime,
|
|
2224
|
+
endTime: row.endTime,
|
|
2225
|
+
other: storage.safelyParseJSON(row.other),
|
|
2226
|
+
createdAt: row.createdAt
|
|
2227
|
+
})
|
|
2228
|
+
) ?? [];
|
|
2229
|
+
return {
|
|
2230
|
+
traces,
|
|
2231
|
+
total,
|
|
2232
|
+
page,
|
|
2233
|
+
perPage,
|
|
2234
|
+
hasMore: currentOffset + traces.length < total
|
|
2235
|
+
};
|
|
2236
|
+
} catch (error$1) {
|
|
2237
|
+
throw new error.MastraError(
|
|
2238
|
+
{
|
|
2239
|
+
id: "LIBSQL_STORE_GET_TRACES_PAGINATED_FAILED",
|
|
2240
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2241
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2242
|
+
},
|
|
2243
|
+
error$1
|
|
2244
|
+
);
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
async batchTraceInsert({ records }) {
|
|
2248
|
+
this.logger.debug("Batch inserting traces", { count: records.length });
|
|
2249
|
+
await this.operations.batchInsert({
|
|
2250
|
+
tableName: storage.TABLE_TRACES,
|
|
2251
|
+
records
|
|
2252
|
+
});
|
|
2253
|
+
}
|
|
2254
|
+
};
|
|
2255
|
+
function parseWorkflowRun(row) {
|
|
2256
|
+
let parsedSnapshot = row.snapshot;
|
|
2257
|
+
if (typeof parsedSnapshot === "string") {
|
|
2258
|
+
try {
|
|
2259
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
2260
|
+
} catch (e) {
|
|
2261
|
+
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
return {
|
|
2265
|
+
workflowName: row.workflow_name,
|
|
2266
|
+
runId: row.run_id,
|
|
2267
|
+
snapshot: parsedSnapshot,
|
|
2268
|
+
resourceId: row.resourceId,
|
|
2269
|
+
createdAt: new Date(row.createdAt),
|
|
2270
|
+
updatedAt: new Date(row.updatedAt)
|
|
2271
|
+
};
|
|
2272
|
+
}
|
|
2273
|
+
var WorkflowsLibSQL = class extends storage.WorkflowsStorage {
|
|
2274
|
+
operations;
|
|
2275
|
+
client;
|
|
2276
|
+
constructor({ operations, client }) {
|
|
2277
|
+
super();
|
|
2278
|
+
this.operations = operations;
|
|
2279
|
+
this.client = client;
|
|
2280
|
+
}
|
|
2281
|
+
async persistWorkflowSnapshot({
|
|
2282
|
+
workflowName,
|
|
2283
|
+
runId,
|
|
2284
|
+
snapshot
|
|
2285
|
+
}) {
|
|
2286
|
+
const data = {
|
|
2287
|
+
workflow_name: workflowName,
|
|
2288
|
+
run_id: runId,
|
|
2289
|
+
snapshot,
|
|
2290
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
2291
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
2292
|
+
};
|
|
2293
|
+
this.logger.debug("Persisting workflow snapshot", { workflowName, runId, data });
|
|
2294
|
+
await this.operations.insert({
|
|
2295
|
+
tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
2296
|
+
record: data
|
|
2297
|
+
});
|
|
2298
|
+
}
|
|
2299
|
+
async loadWorkflowSnapshot({
|
|
2300
|
+
workflowName,
|
|
2301
|
+
runId
|
|
2302
|
+
}) {
|
|
2303
|
+
this.logger.debug("Loading workflow snapshot", { workflowName, runId });
|
|
2304
|
+
const d = await this.operations.load({
|
|
2305
|
+
tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
2306
|
+
keys: { workflow_name: workflowName, run_id: runId }
|
|
2307
|
+
});
|
|
2308
|
+
return d ? d.snapshot : null;
|
|
2309
|
+
}
|
|
2310
|
+
async getWorkflowRunById({
|
|
2311
|
+
runId,
|
|
2312
|
+
workflowName
|
|
2313
|
+
}) {
|
|
2314
|
+
const conditions = [];
|
|
2315
|
+
const args = [];
|
|
2316
|
+
if (runId) {
|
|
2317
|
+
conditions.push("run_id = ?");
|
|
2318
|
+
args.push(runId);
|
|
2319
|
+
}
|
|
2320
|
+
if (workflowName) {
|
|
2321
|
+
conditions.push("workflow_name = ?");
|
|
2322
|
+
args.push(workflowName);
|
|
2323
|
+
}
|
|
2324
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2325
|
+
try {
|
|
2326
|
+
const result = await this.client.execute({
|
|
2327
|
+
sql: `SELECT * FROM ${storage.TABLE_WORKFLOW_SNAPSHOT} ${whereClause}`,
|
|
2328
|
+
args
|
|
2329
|
+
});
|
|
2330
|
+
if (!result.rows?.[0]) {
|
|
2331
|
+
return null;
|
|
2332
|
+
}
|
|
2333
|
+
return parseWorkflowRun(result.rows[0]);
|
|
1918
2334
|
} catch (error$1) {
|
|
1919
2335
|
throw new error.MastraError(
|
|
1920
2336
|
{
|
|
1921
|
-
id: "
|
|
2337
|
+
id: "LIBSQL_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
|
|
1922
2338
|
domain: error.ErrorDomain.STORAGE,
|
|
1923
2339
|
category: error.ErrorCategory.THIRD_PARTY
|
|
1924
2340
|
},
|
|
@@ -1950,7 +2366,7 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
1950
2366
|
args.push(toDate.toISOString());
|
|
1951
2367
|
}
|
|
1952
2368
|
if (resourceId) {
|
|
1953
|
-
const hasResourceId = await this.hasColumn(storage.TABLE_WORKFLOW_SNAPSHOT, "resourceId");
|
|
2369
|
+
const hasResourceId = await this.operations.hasColumn(storage.TABLE_WORKFLOW_SNAPSHOT, "resourceId");
|
|
1954
2370
|
if (hasResourceId) {
|
|
1955
2371
|
conditions.push("resourceId = ?");
|
|
1956
2372
|
args.push(resourceId);
|
|
@@ -1971,7 +2387,7 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
1971
2387
|
sql: `SELECT * FROM ${storage.TABLE_WORKFLOW_SNAPSHOT} ${whereClause} ORDER BY createdAt DESC${limit !== void 0 && offset !== void 0 ? ` LIMIT ? OFFSET ?` : ""}`,
|
|
1972
2388
|
args: limit !== void 0 && offset !== void 0 ? [...args, limit, offset] : args
|
|
1973
2389
|
});
|
|
1974
|
-
const runs = (result.rows || []).map((row) =>
|
|
2390
|
+
const runs = (result.rows || []).map((row) => parseWorkflowRun(row));
|
|
1975
2391
|
return { runs, total: total || runs.length };
|
|
1976
2392
|
} catch (error$1) {
|
|
1977
2393
|
throw new error.MastraError(
|
|
@@ -1984,133 +2400,227 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
1984
2400
|
);
|
|
1985
2401
|
}
|
|
1986
2402
|
}
|
|
2403
|
+
};
|
|
2404
|
+
|
|
2405
|
+
// src/storage/index.ts
|
|
2406
|
+
var LibSQLStore = class extends storage.MastraStorage {
|
|
2407
|
+
client;
|
|
2408
|
+
maxRetries;
|
|
2409
|
+
initialBackoffMs;
|
|
2410
|
+
stores;
|
|
2411
|
+
constructor(config) {
|
|
2412
|
+
super({ name: `LibSQLStore` });
|
|
2413
|
+
this.maxRetries = config.maxRetries ?? 5;
|
|
2414
|
+
this.initialBackoffMs = config.initialBackoffMs ?? 100;
|
|
2415
|
+
if ("url" in config) {
|
|
2416
|
+
if (config.url.endsWith(":memory:")) {
|
|
2417
|
+
this.shouldCacheInit = false;
|
|
2418
|
+
}
|
|
2419
|
+
this.client = client.createClient({ url: config.url });
|
|
2420
|
+
if (config.url.startsWith("file:") || config.url.includes(":memory:")) {
|
|
2421
|
+
this.client.execute("PRAGMA journal_mode=WAL;").then(() => this.logger.debug("LibSQLStore: PRAGMA journal_mode=WAL set.")).catch((err) => this.logger.warn("LibSQLStore: Failed to set PRAGMA journal_mode=WAL.", err));
|
|
2422
|
+
this.client.execute("PRAGMA busy_timeout = 5000;").then(() => this.logger.debug("LibSQLStore: PRAGMA busy_timeout=5000 set.")).catch((err) => this.logger.warn("LibSQLStore: Failed to set PRAGMA busy_timeout.", err));
|
|
2423
|
+
}
|
|
2424
|
+
} else {
|
|
2425
|
+
this.client = config.client;
|
|
2426
|
+
}
|
|
2427
|
+
const operations = new StoreOperationsLibSQL({
|
|
2428
|
+
client: this.client,
|
|
2429
|
+
maxRetries: this.maxRetries,
|
|
2430
|
+
initialBackoffMs: this.initialBackoffMs
|
|
2431
|
+
});
|
|
2432
|
+
const scores = new ScoresLibSQL({ client: this.client, operations });
|
|
2433
|
+
const traces = new TracesLibSQL({ client: this.client, operations });
|
|
2434
|
+
const workflows = new WorkflowsLibSQL({ client: this.client, operations });
|
|
2435
|
+
const memory = new MemoryLibSQL({ client: this.client, operations });
|
|
2436
|
+
const legacyEvals = new LegacyEvalsLibSQL({ client: this.client });
|
|
2437
|
+
this.stores = {
|
|
2438
|
+
operations,
|
|
2439
|
+
scores,
|
|
2440
|
+
traces,
|
|
2441
|
+
workflows,
|
|
2442
|
+
memory,
|
|
2443
|
+
legacyEvals
|
|
2444
|
+
};
|
|
2445
|
+
}
|
|
2446
|
+
get supports() {
|
|
2447
|
+
return {
|
|
2448
|
+
selectByIncludeResourceScope: true,
|
|
2449
|
+
resourceWorkingMemory: true,
|
|
2450
|
+
hasColumn: true,
|
|
2451
|
+
createTable: true
|
|
2452
|
+
};
|
|
2453
|
+
}
|
|
2454
|
+
async createTable({
|
|
2455
|
+
tableName,
|
|
2456
|
+
schema
|
|
2457
|
+
}) {
|
|
2458
|
+
await this.stores.operations.createTable({ tableName, schema });
|
|
2459
|
+
}
|
|
2460
|
+
/**
|
|
2461
|
+
* Alters table schema to add columns if they don't exist
|
|
2462
|
+
* @param tableName Name of the table
|
|
2463
|
+
* @param schema Schema of the table
|
|
2464
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
2465
|
+
*/
|
|
2466
|
+
async alterTable({
|
|
2467
|
+
tableName,
|
|
2468
|
+
schema,
|
|
2469
|
+
ifNotExists
|
|
2470
|
+
}) {
|
|
2471
|
+
await this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
2472
|
+
}
|
|
2473
|
+
async clearTable({ tableName }) {
|
|
2474
|
+
await this.stores.operations.clearTable({ tableName });
|
|
2475
|
+
}
|
|
2476
|
+
async dropTable({ tableName }) {
|
|
2477
|
+
await this.stores.operations.dropTable({ tableName });
|
|
2478
|
+
}
|
|
2479
|
+
insert(args) {
|
|
2480
|
+
return this.stores.operations.insert(args);
|
|
2481
|
+
}
|
|
2482
|
+
batchInsert(args) {
|
|
2483
|
+
return this.stores.operations.batchInsert(args);
|
|
2484
|
+
}
|
|
2485
|
+
async load({ tableName, keys }) {
|
|
2486
|
+
return this.stores.operations.load({ tableName, keys });
|
|
2487
|
+
}
|
|
2488
|
+
async getThreadById({ threadId }) {
|
|
2489
|
+
return this.stores.memory.getThreadById({ threadId });
|
|
2490
|
+
}
|
|
2491
|
+
/**
|
|
2492
|
+
* @deprecated use getThreadsByResourceIdPaginated instead for paginated results.
|
|
2493
|
+
*/
|
|
2494
|
+
async getThreadsByResourceId(args) {
|
|
2495
|
+
return this.stores.memory.getThreadsByResourceId(args);
|
|
2496
|
+
}
|
|
2497
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
2498
|
+
return this.stores.memory.getThreadsByResourceIdPaginated(args);
|
|
2499
|
+
}
|
|
2500
|
+
async saveThread({ thread }) {
|
|
2501
|
+
return this.stores.memory.saveThread({ thread });
|
|
2502
|
+
}
|
|
2503
|
+
async updateThread({
|
|
2504
|
+
id,
|
|
2505
|
+
title,
|
|
2506
|
+
metadata
|
|
2507
|
+
}) {
|
|
2508
|
+
return this.stores.memory.updateThread({ id, title, metadata });
|
|
2509
|
+
}
|
|
2510
|
+
async deleteThread({ threadId }) {
|
|
2511
|
+
return this.stores.memory.deleteThread({ threadId });
|
|
2512
|
+
}
|
|
2513
|
+
async getMessages({
|
|
2514
|
+
threadId,
|
|
2515
|
+
selectBy,
|
|
2516
|
+
format
|
|
2517
|
+
}) {
|
|
2518
|
+
return this.stores.memory.getMessages({ threadId, selectBy, format });
|
|
2519
|
+
}
|
|
2520
|
+
async getMessagesPaginated(args) {
|
|
2521
|
+
return this.stores.memory.getMessagesPaginated(args);
|
|
2522
|
+
}
|
|
2523
|
+
async saveMessages(args) {
|
|
2524
|
+
return this.stores.memory.saveMessages(args);
|
|
2525
|
+
}
|
|
2526
|
+
async updateMessages({
|
|
2527
|
+
messages
|
|
2528
|
+
}) {
|
|
2529
|
+
return this.stores.memory.updateMessages({ messages });
|
|
2530
|
+
}
|
|
2531
|
+
/** @deprecated use getEvals instead */
|
|
2532
|
+
async getEvalsByAgentName(agentName, type) {
|
|
2533
|
+
return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
|
|
2534
|
+
}
|
|
2535
|
+
async getEvals(options = {}) {
|
|
2536
|
+
return this.stores.legacyEvals.getEvals(options);
|
|
2537
|
+
}
|
|
2538
|
+
async getScoreById({ id }) {
|
|
2539
|
+
return this.stores.scores.getScoreById({ id });
|
|
2540
|
+
}
|
|
2541
|
+
async saveScore(score) {
|
|
2542
|
+
return this.stores.scores.saveScore(score);
|
|
2543
|
+
}
|
|
2544
|
+
async getScoresByScorerId({
|
|
2545
|
+
scorerId,
|
|
2546
|
+
entityId,
|
|
2547
|
+
entityType,
|
|
2548
|
+
pagination
|
|
2549
|
+
}) {
|
|
2550
|
+
return this.stores.scores.getScoresByScorerId({ scorerId, entityId, entityType, pagination });
|
|
2551
|
+
}
|
|
2552
|
+
async getScoresByRunId({
|
|
2553
|
+
runId,
|
|
2554
|
+
pagination
|
|
2555
|
+
}) {
|
|
2556
|
+
return this.stores.scores.getScoresByRunId({ runId, pagination });
|
|
2557
|
+
}
|
|
2558
|
+
async getScoresByEntityId({
|
|
2559
|
+
entityId,
|
|
2560
|
+
entityType,
|
|
2561
|
+
pagination
|
|
2562
|
+
}) {
|
|
2563
|
+
return this.stores.scores.getScoresByEntityId({ entityId, entityType, pagination });
|
|
2564
|
+
}
|
|
2565
|
+
/**
|
|
2566
|
+
* TRACES
|
|
2567
|
+
*/
|
|
2568
|
+
/**
|
|
2569
|
+
* @deprecated use getTracesPaginated instead.
|
|
2570
|
+
*/
|
|
2571
|
+
async getTraces(args) {
|
|
2572
|
+
return this.stores.traces.getTraces(args);
|
|
2573
|
+
}
|
|
2574
|
+
async getTracesPaginated(args) {
|
|
2575
|
+
return this.stores.traces.getTracesPaginated(args);
|
|
2576
|
+
}
|
|
2577
|
+
async batchTraceInsert(args) {
|
|
2578
|
+
return this.stores.traces.batchTraceInsert(args);
|
|
2579
|
+
}
|
|
2580
|
+
/**
|
|
2581
|
+
* WORKFLOWS
|
|
2582
|
+
*/
|
|
2583
|
+
async persistWorkflowSnapshot({
|
|
2584
|
+
workflowName,
|
|
2585
|
+
runId,
|
|
2586
|
+
snapshot
|
|
2587
|
+
}) {
|
|
2588
|
+
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
|
|
2589
|
+
}
|
|
2590
|
+
async loadWorkflowSnapshot({
|
|
2591
|
+
workflowName,
|
|
2592
|
+
runId
|
|
2593
|
+
}) {
|
|
2594
|
+
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2595
|
+
}
|
|
2596
|
+
async getWorkflowRuns({
|
|
2597
|
+
workflowName,
|
|
2598
|
+
fromDate,
|
|
2599
|
+
toDate,
|
|
2600
|
+
limit,
|
|
2601
|
+
offset,
|
|
2602
|
+
resourceId
|
|
2603
|
+
} = {}) {
|
|
2604
|
+
return this.stores.workflows.getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
|
|
2605
|
+
}
|
|
1987
2606
|
async getWorkflowRunById({
|
|
1988
2607
|
runId,
|
|
1989
2608
|
workflowName
|
|
1990
2609
|
}) {
|
|
1991
|
-
|
|
1992
|
-
const args = [];
|
|
1993
|
-
if (runId) {
|
|
1994
|
-
conditions.push("run_id = ?");
|
|
1995
|
-
args.push(runId);
|
|
1996
|
-
}
|
|
1997
|
-
if (workflowName) {
|
|
1998
|
-
conditions.push("workflow_name = ?");
|
|
1999
|
-
args.push(workflowName);
|
|
2000
|
-
}
|
|
2001
|
-
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2002
|
-
try {
|
|
2003
|
-
const result = await this.client.execute({
|
|
2004
|
-
sql: `SELECT * FROM ${storage.TABLE_WORKFLOW_SNAPSHOT} ${whereClause}`,
|
|
2005
|
-
args
|
|
2006
|
-
});
|
|
2007
|
-
if (!result.rows?.[0]) {
|
|
2008
|
-
return null;
|
|
2009
|
-
}
|
|
2010
|
-
return this.parseWorkflowRun(result.rows[0]);
|
|
2011
|
-
} catch (error$1) {
|
|
2012
|
-
throw new error.MastraError(
|
|
2013
|
-
{
|
|
2014
|
-
id: "LIBSQL_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
|
|
2015
|
-
domain: error.ErrorDomain.STORAGE,
|
|
2016
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
2017
|
-
},
|
|
2018
|
-
error$1
|
|
2019
|
-
);
|
|
2020
|
-
}
|
|
2610
|
+
return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
|
|
2021
2611
|
}
|
|
2022
2612
|
async getResourceById({ resourceId }) {
|
|
2023
|
-
|
|
2024
|
-
tableName: storage.TABLE_RESOURCES,
|
|
2025
|
-
keys: { id: resourceId }
|
|
2026
|
-
});
|
|
2027
|
-
if (!result) {
|
|
2028
|
-
return null;
|
|
2029
|
-
}
|
|
2030
|
-
return {
|
|
2031
|
-
...result,
|
|
2032
|
-
// Ensure workingMemory is always returned as a string, even if auto-parsed as JSON
|
|
2033
|
-
workingMemory: typeof result.workingMemory === "object" ? JSON.stringify(result.workingMemory) : result.workingMemory,
|
|
2034
|
-
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
|
|
2035
|
-
};
|
|
2613
|
+
return this.stores.memory.getResourceById({ resourceId });
|
|
2036
2614
|
}
|
|
2037
2615
|
async saveResource({ resource }) {
|
|
2038
|
-
|
|
2039
|
-
tableName: storage.TABLE_RESOURCES,
|
|
2040
|
-
record: {
|
|
2041
|
-
...resource,
|
|
2042
|
-
metadata: JSON.stringify(resource.metadata)
|
|
2043
|
-
}
|
|
2044
|
-
});
|
|
2045
|
-
return resource;
|
|
2616
|
+
return this.stores.memory.saveResource({ resource });
|
|
2046
2617
|
}
|
|
2047
2618
|
async updateResource({
|
|
2048
2619
|
resourceId,
|
|
2049
2620
|
workingMemory,
|
|
2050
2621
|
metadata
|
|
2051
2622
|
}) {
|
|
2052
|
-
|
|
2053
|
-
if (!existingResource) {
|
|
2054
|
-
const newResource = {
|
|
2055
|
-
id: resourceId,
|
|
2056
|
-
workingMemory,
|
|
2057
|
-
metadata: metadata || {},
|
|
2058
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
2059
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
2060
|
-
};
|
|
2061
|
-
return this.saveResource({ resource: newResource });
|
|
2062
|
-
}
|
|
2063
|
-
const updatedResource = {
|
|
2064
|
-
...existingResource,
|
|
2065
|
-
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
2066
|
-
metadata: {
|
|
2067
|
-
...existingResource.metadata,
|
|
2068
|
-
...metadata
|
|
2069
|
-
},
|
|
2070
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
2071
|
-
};
|
|
2072
|
-
const updates = [];
|
|
2073
|
-
const values = [];
|
|
2074
|
-
if (workingMemory !== void 0) {
|
|
2075
|
-
updates.push("workingMemory = ?");
|
|
2076
|
-
values.push(workingMemory);
|
|
2077
|
-
}
|
|
2078
|
-
if (metadata) {
|
|
2079
|
-
updates.push("metadata = ?");
|
|
2080
|
-
values.push(JSON.stringify(updatedResource.metadata));
|
|
2081
|
-
}
|
|
2082
|
-
updates.push("updatedAt = ?");
|
|
2083
|
-
values.push(updatedResource.updatedAt.toISOString());
|
|
2084
|
-
values.push(resourceId);
|
|
2085
|
-
await this.client.execute({
|
|
2086
|
-
sql: `UPDATE ${storage.TABLE_RESOURCES} SET ${updates.join(", ")} WHERE id = ?`,
|
|
2087
|
-
args: values
|
|
2088
|
-
});
|
|
2089
|
-
return updatedResource;
|
|
2090
|
-
}
|
|
2091
|
-
async hasColumn(table, column) {
|
|
2092
|
-
const result = await this.client.execute({
|
|
2093
|
-
sql: `PRAGMA table_info(${table})`
|
|
2094
|
-
});
|
|
2095
|
-
return (await result.rows)?.some((row) => row.name === column);
|
|
2096
|
-
}
|
|
2097
|
-
parseWorkflowRun(row) {
|
|
2098
|
-
let parsedSnapshot = row.snapshot;
|
|
2099
|
-
if (typeof parsedSnapshot === "string") {
|
|
2100
|
-
try {
|
|
2101
|
-
parsedSnapshot = JSON.parse(row.snapshot);
|
|
2102
|
-
} catch (e) {
|
|
2103
|
-
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
2104
|
-
}
|
|
2105
|
-
}
|
|
2106
|
-
return {
|
|
2107
|
-
workflowName: row.workflow_name,
|
|
2108
|
-
runId: row.run_id,
|
|
2109
|
-
snapshot: parsedSnapshot,
|
|
2110
|
-
resourceId: row.resourceId,
|
|
2111
|
-
createdAt: new Date(row.createdAt),
|
|
2112
|
-
updatedAt: new Date(row.updatedAt)
|
|
2113
|
-
};
|
|
2623
|
+
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
2114
2624
|
}
|
|
2115
2625
|
};
|
|
2116
2626
|
|