@mastra/libsql 0.0.0-mcp-changeset-20250707162621 → 0.0.0-memory-system-message-error-20250813233316
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/CHANGELOG.md +288 -9
- package/LICENSE.md +12 -4
- package/dist/index.cjs +1469 -868
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +4 -6
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1460 -859
- package/dist/index.js.map +1 -0
- package/dist/storage/domains/legacy-evals/index.d.ts +18 -0
- package/dist/storage/domains/legacy-evals/index.d.ts.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +87 -0
- package/dist/storage/domains/memory/index.d.ts.map +1 -0
- package/dist/storage/domains/operations/index.d.ts +61 -0
- package/dist/storage/domains/operations/index.d.ts.map +1 -0
- package/dist/storage/domains/scores/index.d.ts +46 -0
- package/dist/storage/domains/scores/index.d.ts.map +1 -0
- package/dist/storage/domains/traces/index.d.ts +21 -0
- package/dist/storage/domains/traces/index.d.ts.map +1 -0
- package/dist/storage/domains/utils.d.ts +16 -0
- package/dist/storage/domains/utils.d.ts.map +1 -0
- package/dist/storage/domains/workflows/index.d.ts +34 -0
- package/dist/storage/domains/workflows/index.d.ts.map +1 -0
- package/dist/storage/index.d.ts +222 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/vector/filter.d.ts +29 -0
- package/dist/vector/filter.d.ts.map +1 -0
- package/dist/vector/index.d.ts +72 -0
- package/dist/vector/index.d.ts.map +1 -0
- package/dist/vector/prompt.d.ts +6 -0
- package/dist/vector/prompt.d.ts.map +1 -0
- package/dist/vector/sql-builder.d.ts +9 -0
- package/dist/vector/sql-builder.d.ts.map +1 -0
- package/package.json +11 -10
- package/src/storage/domains/legacy-evals/index.ts +149 -0
- package/src/storage/domains/memory/index.ts +881 -0
- package/src/storage/domains/operations/index.ts +296 -0
- package/src/storage/domains/scores/index.ts +226 -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 -573
- package/src/storage/index.ts +194 -1336
- package/src/vector/index.test.ts +22 -1
- package/src/vector/index.ts +2 -2
- package/src/vector/sql-builder.ts +51 -33
- package/tsconfig.build.json +9 -0
- package/tsconfig.json +1 -1
- package/tsup.config.ts +17 -0
- package/dist/_tsup-dts-rollup.d.cts +0 -332
- package/dist/_tsup-dts-rollup.d.ts +0 -332
- package/dist/index.d.cts +0 -6
package/dist/index.js
CHANGED
|
@@ -3,8 +3,9 @@ import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
|
3
3
|
import { parseSqlIdentifier, parseFieldKey } from '@mastra/core/utils';
|
|
4
4
|
import { MastraVector } from '@mastra/core/vector';
|
|
5
5
|
import { BaseFilterTranslator } from '@mastra/core/vector/filter';
|
|
6
|
+
import { MastraStorage, StoreOperations, TABLE_WORKFLOW_SNAPSHOT, ScoresStorage, TABLE_SCORERS, safelyParseJSON, TracesStorage, TABLE_TRACES, WorkflowsStorage, MemoryStorage, resolveMessageLimit, TABLE_MESSAGES, TABLE_THREADS, TABLE_RESOURCES, LegacyEvalsStorage, TABLE_EVALS } from '@mastra/core/storage';
|
|
7
|
+
import { parseSqlIdentifier as parseSqlIdentifier$1 } from '@mastra/core';
|
|
6
8
|
import { MessageList } from '@mastra/core/agent';
|
|
7
|
-
import { MastraStorage, TABLE_WORKFLOW_SNAPSHOT, TABLE_THREADS, TABLE_MESSAGES, TABLE_EVALS, TABLE_TRACES, TABLE_RESOURCES } from '@mastra/core/storage';
|
|
8
9
|
|
|
9
10
|
// src/vector/index.ts
|
|
10
11
|
var LibSQLFilterTranslator = class extends BaseFilterTranslator {
|
|
@@ -75,11 +76,11 @@ var LibSQLFilterTranslator = class extends BaseFilterTranslator {
|
|
|
75
76
|
};
|
|
76
77
|
var createBasicOperator = (symbol) => {
|
|
77
78
|
return (key, value) => {
|
|
78
|
-
const
|
|
79
|
+
const jsonPath = getJsonPath(key);
|
|
79
80
|
return {
|
|
80
81
|
sql: `CASE
|
|
81
|
-
WHEN ? IS NULL THEN json_extract(metadata,
|
|
82
|
-
ELSE json_extract(metadata,
|
|
82
|
+
WHEN ? IS NULL THEN json_extract(metadata, ${jsonPath}) IS ${symbol === "=" ? "" : "NOT"} NULL
|
|
83
|
+
ELSE json_extract(metadata, ${jsonPath}) ${symbol} ?
|
|
83
84
|
END`,
|
|
84
85
|
needsValue: true,
|
|
85
86
|
transformValue: () => {
|
|
@@ -90,16 +91,19 @@ var createBasicOperator = (symbol) => {
|
|
|
90
91
|
};
|
|
91
92
|
var createNumericOperator = (symbol) => {
|
|
92
93
|
return (key) => {
|
|
93
|
-
const
|
|
94
|
+
const jsonPath = getJsonPath(key);
|
|
94
95
|
return {
|
|
95
|
-
sql: `CAST(json_extract(metadata,
|
|
96
|
+
sql: `CAST(json_extract(metadata, ${jsonPath}) AS NUMERIC) ${symbol} ?`,
|
|
96
97
|
needsValue: true
|
|
97
98
|
};
|
|
98
99
|
};
|
|
99
100
|
};
|
|
100
|
-
var validateJsonArray = (key) =>
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
var validateJsonArray = (key) => {
|
|
102
|
+
const jsonPath = getJsonPath(key);
|
|
103
|
+
return `json_valid(json_extract(metadata, ${jsonPath}))
|
|
104
|
+
AND json_type(json_extract(metadata, ${jsonPath})) = 'array'`;
|
|
105
|
+
};
|
|
106
|
+
var pattern = /json_extract\(metadata, '\$\.(?:"[^"]*"(?:\."[^"]*")*|[^']+)'\)/g;
|
|
103
107
|
function buildElemMatchConditions(value) {
|
|
104
108
|
const conditions = Object.entries(value).map(([field, fieldValue]) => {
|
|
105
109
|
if (field.startsWith("$")) {
|
|
@@ -108,12 +112,13 @@ function buildElemMatchConditions(value) {
|
|
|
108
112
|
return { sql: elemSql, values };
|
|
109
113
|
} else if (typeof fieldValue === "object" && !Array.isArray(fieldValue)) {
|
|
110
114
|
const { sql, values } = buildCondition(field, fieldValue);
|
|
111
|
-
const
|
|
115
|
+
const jsonPath = parseJsonPathKey(field);
|
|
116
|
+
const elemSql = sql.replace(pattern, `json_extract(elem.value, '$.${jsonPath}')`);
|
|
112
117
|
return { sql: elemSql, values };
|
|
113
118
|
} else {
|
|
114
|
-
const
|
|
119
|
+
const jsonPath = parseJsonPathKey(field);
|
|
115
120
|
return {
|
|
116
|
-
sql: `json_extract(elem.value, '
|
|
121
|
+
sql: `json_extract(elem.value, '$.${jsonPath}') = ?`,
|
|
117
122
|
values: [fieldValue]
|
|
118
123
|
};
|
|
119
124
|
}
|
|
@@ -129,7 +134,7 @@ var FILTER_OPERATORS = {
|
|
|
129
134
|
$lte: createNumericOperator("<="),
|
|
130
135
|
// Array Operators
|
|
131
136
|
$in: (key, value) => {
|
|
132
|
-
const
|
|
137
|
+
const jsonPath = getJsonPath(key);
|
|
133
138
|
const arr = Array.isArray(value) ? value : [value];
|
|
134
139
|
if (arr.length === 0) {
|
|
135
140
|
return { sql: "1 = 0", needsValue: true, transformValue: () => [] };
|
|
@@ -138,12 +143,12 @@ var FILTER_OPERATORS = {
|
|
|
138
143
|
return {
|
|
139
144
|
sql: `(
|
|
140
145
|
CASE
|
|
141
|
-
WHEN ${validateJsonArray(
|
|
146
|
+
WHEN ${validateJsonArray(key)} THEN
|
|
142
147
|
EXISTS (
|
|
143
|
-
SELECT 1 FROM json_each(json_extract(metadata,
|
|
148
|
+
SELECT 1 FROM json_each(json_extract(metadata, ${jsonPath})) as elem
|
|
144
149
|
WHERE elem.value IN (SELECT value FROM json_each(?))
|
|
145
150
|
)
|
|
146
|
-
ELSE json_extract(metadata,
|
|
151
|
+
ELSE json_extract(metadata, ${jsonPath}) IN (${paramPlaceholders})
|
|
147
152
|
END
|
|
148
153
|
)`,
|
|
149
154
|
needsValue: true,
|
|
@@ -151,7 +156,7 @@ var FILTER_OPERATORS = {
|
|
|
151
156
|
};
|
|
152
157
|
},
|
|
153
158
|
$nin: (key, value) => {
|
|
154
|
-
const
|
|
159
|
+
const jsonPath = getJsonPath(key);
|
|
155
160
|
const arr = Array.isArray(value) ? value : [value];
|
|
156
161
|
if (arr.length === 0) {
|
|
157
162
|
return { sql: "1 = 1", needsValue: true, transformValue: () => [] };
|
|
@@ -160,12 +165,12 @@ var FILTER_OPERATORS = {
|
|
|
160
165
|
return {
|
|
161
166
|
sql: `(
|
|
162
167
|
CASE
|
|
163
|
-
WHEN ${validateJsonArray(
|
|
168
|
+
WHEN ${validateJsonArray(key)} THEN
|
|
164
169
|
NOT EXISTS (
|
|
165
|
-
SELECT 1 FROM json_each(json_extract(metadata,
|
|
170
|
+
SELECT 1 FROM json_each(json_extract(metadata, ${jsonPath})) as elem
|
|
166
171
|
WHERE elem.value IN (SELECT value FROM json_each(?))
|
|
167
172
|
)
|
|
168
|
-
ELSE json_extract(metadata,
|
|
173
|
+
ELSE json_extract(metadata, ${jsonPath}) NOT IN (${paramPlaceholders})
|
|
169
174
|
END
|
|
170
175
|
)`,
|
|
171
176
|
needsValue: true,
|
|
@@ -173,7 +178,7 @@ var FILTER_OPERATORS = {
|
|
|
173
178
|
};
|
|
174
179
|
},
|
|
175
180
|
$all: (key, value) => {
|
|
176
|
-
const
|
|
181
|
+
const jsonPath = getJsonPath(key);
|
|
177
182
|
let sql;
|
|
178
183
|
const arrayValue = Array.isArray(value) ? value : [value];
|
|
179
184
|
if (arrayValue.length === 0) {
|
|
@@ -181,13 +186,13 @@ var FILTER_OPERATORS = {
|
|
|
181
186
|
} else {
|
|
182
187
|
sql = `(
|
|
183
188
|
CASE
|
|
184
|
-
WHEN ${validateJsonArray(
|
|
189
|
+
WHEN ${validateJsonArray(key)} THEN
|
|
185
190
|
NOT EXISTS (
|
|
186
191
|
SELECT value
|
|
187
192
|
FROM json_each(?)
|
|
188
193
|
WHERE value NOT IN (
|
|
189
194
|
SELECT value
|
|
190
|
-
FROM json_each(json_extract(metadata,
|
|
195
|
+
FROM json_each(json_extract(metadata, ${jsonPath}))
|
|
191
196
|
)
|
|
192
197
|
)
|
|
193
198
|
ELSE FALSE
|
|
@@ -206,7 +211,7 @@ var FILTER_OPERATORS = {
|
|
|
206
211
|
};
|
|
207
212
|
},
|
|
208
213
|
$elemMatch: (key, value) => {
|
|
209
|
-
const
|
|
214
|
+
const jsonPath = getJsonPath(key);
|
|
210
215
|
if (typeof value !== "object" || Array.isArray(value)) {
|
|
211
216
|
throw new Error("$elemMatch requires an object with conditions");
|
|
212
217
|
}
|
|
@@ -214,10 +219,10 @@ var FILTER_OPERATORS = {
|
|
|
214
219
|
return {
|
|
215
220
|
sql: `(
|
|
216
221
|
CASE
|
|
217
|
-
WHEN ${validateJsonArray(
|
|
222
|
+
WHEN ${validateJsonArray(key)} THEN
|
|
218
223
|
EXISTS (
|
|
219
224
|
SELECT 1
|
|
220
|
-
FROM json_each(json_extract(metadata,
|
|
225
|
+
FROM json_each(json_extract(metadata, ${jsonPath})) as elem
|
|
221
226
|
WHERE ${conditions.map((c) => c.sql).join(" AND ")}
|
|
222
227
|
)
|
|
223
228
|
ELSE FALSE
|
|
@@ -229,9 +234,9 @@ var FILTER_OPERATORS = {
|
|
|
229
234
|
},
|
|
230
235
|
// Element Operators
|
|
231
236
|
$exists: (key) => {
|
|
232
|
-
const
|
|
237
|
+
const jsonPath = getJsonPath(key);
|
|
233
238
|
return {
|
|
234
|
-
sql: `json_extract(metadata,
|
|
239
|
+
sql: `json_extract(metadata, ${jsonPath}) IS NOT NULL`,
|
|
235
240
|
needsValue: false
|
|
236
241
|
};
|
|
237
242
|
},
|
|
@@ -250,12 +255,12 @@ var FILTER_OPERATORS = {
|
|
|
250
255
|
needsValue: false
|
|
251
256
|
}),
|
|
252
257
|
$size: (key, paramIndex) => {
|
|
253
|
-
const
|
|
258
|
+
const jsonPath = getJsonPath(key);
|
|
254
259
|
return {
|
|
255
260
|
sql: `(
|
|
256
261
|
CASE
|
|
257
|
-
WHEN json_type(json_extract(metadata,
|
|
258
|
-
json_array_length(json_extract(metadata,
|
|
262
|
+
WHEN json_type(json_extract(metadata, ${jsonPath})) = 'array' THEN
|
|
263
|
+
json_array_length(json_extract(metadata, ${jsonPath})) = $${paramIndex}
|
|
259
264
|
ELSE FALSE
|
|
260
265
|
END
|
|
261
266
|
)`,
|
|
@@ -374,7 +379,14 @@ function isFilterResult(obj) {
|
|
|
374
379
|
}
|
|
375
380
|
var parseJsonPathKey = (key) => {
|
|
376
381
|
const parsedKey = parseFieldKey(key);
|
|
377
|
-
|
|
382
|
+
if (parsedKey.includes(".")) {
|
|
383
|
+
return parsedKey.split(".").map((segment) => `"${segment}"`).join(".");
|
|
384
|
+
}
|
|
385
|
+
return parsedKey;
|
|
386
|
+
};
|
|
387
|
+
var getJsonPath = (key) => {
|
|
388
|
+
const jsonPathKey = parseJsonPathKey(key);
|
|
389
|
+
return `'$.${jsonPathKey}'`;
|
|
378
390
|
};
|
|
379
391
|
function escapeLikePattern(str) {
|
|
380
392
|
return str.replace(/([%_\\])/g, "\\$1");
|
|
@@ -399,8 +411,9 @@ function buildCondition(key, value, parentPath) {
|
|
|
399
411
|
return handleLogicalOperator(key, value);
|
|
400
412
|
}
|
|
401
413
|
if (!value || typeof value !== "object") {
|
|
414
|
+
const jsonPath = getJsonPath(key);
|
|
402
415
|
return {
|
|
403
|
-
sql: `json_extract(metadata,
|
|
416
|
+
sql: `json_extract(metadata, ${jsonPath}) = ?`,
|
|
404
417
|
values: [value]
|
|
405
418
|
};
|
|
406
419
|
}
|
|
@@ -546,7 +559,8 @@ var LibSQLVector = class extends MastraVector {
|
|
|
546
559
|
topK = 10,
|
|
547
560
|
filter,
|
|
548
561
|
includeVector = false,
|
|
549
|
-
minScore =
|
|
562
|
+
minScore = -1
|
|
563
|
+
// Default to -1 to include all results (cosine similarity ranges from -1 to 1)
|
|
550
564
|
}) {
|
|
551
565
|
try {
|
|
552
566
|
if (!Number.isInteger(topK) || topK <= 0) {
|
|
@@ -649,7 +663,7 @@ var LibSQLVector = class extends MastraVector {
|
|
|
649
663
|
await tx.commit();
|
|
650
664
|
return vectorIds;
|
|
651
665
|
} catch (error) {
|
|
652
|
-
await tx.rollback();
|
|
666
|
+
!tx.closed && await tx.rollback();
|
|
653
667
|
if (error instanceof Error && error.message?.includes("dimensions are different")) {
|
|
654
668
|
const match = error.message.match(/dimensions are different: (\d+) != (\d+)/);
|
|
655
669
|
if (match) {
|
|
@@ -904,270 +918,235 @@ var LibSQLVector = class extends MastraVector {
|
|
|
904
918
|
});
|
|
905
919
|
}
|
|
906
920
|
};
|
|
907
|
-
function
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
921
|
+
function transformEvalRow(row) {
|
|
922
|
+
const resultValue = JSON.parse(row.result);
|
|
923
|
+
const testInfoValue = row.test_info ? JSON.parse(row.test_info) : void 0;
|
|
924
|
+
if (!resultValue || typeof resultValue !== "object" || !("score" in resultValue)) {
|
|
925
|
+
throw new Error(`Invalid MetricResult format: ${JSON.stringify(resultValue)}`);
|
|
912
926
|
}
|
|
927
|
+
return {
|
|
928
|
+
input: row.input,
|
|
929
|
+
output: row.output,
|
|
930
|
+
result: resultValue,
|
|
931
|
+
agentName: row.agent_name,
|
|
932
|
+
metricName: row.metric_name,
|
|
933
|
+
instructions: row.instructions,
|
|
934
|
+
testInfo: testInfoValue,
|
|
935
|
+
globalRunId: row.global_run_id,
|
|
936
|
+
runId: row.run_id,
|
|
937
|
+
createdAt: row.created_at
|
|
938
|
+
};
|
|
913
939
|
}
|
|
914
|
-
var
|
|
940
|
+
var LegacyEvalsLibSQL = class extends LegacyEvalsStorage {
|
|
915
941
|
client;
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
super({ name: `LibSQLStore` });
|
|
920
|
-
this.maxRetries = config.maxRetries ?? 5;
|
|
921
|
-
this.initialBackoffMs = config.initialBackoffMs ?? 100;
|
|
922
|
-
if (config.url.endsWith(":memory:")) {
|
|
923
|
-
this.shouldCacheInit = false;
|
|
924
|
-
}
|
|
925
|
-
this.client = createClient(config);
|
|
926
|
-
if (config.url.startsWith("file:") || config.url.includes(":memory:")) {
|
|
927
|
-
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));
|
|
928
|
-
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));
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
get supports() {
|
|
932
|
-
return {
|
|
933
|
-
selectByIncludeResourceScope: true,
|
|
934
|
-
resourceWorkingMemory: true
|
|
935
|
-
};
|
|
936
|
-
}
|
|
937
|
-
getCreateTableSQL(tableName, schema) {
|
|
938
|
-
const parsedTableName = parseSqlIdentifier(tableName, "table name");
|
|
939
|
-
const columns = Object.entries(schema).map(([name, col]) => {
|
|
940
|
-
const parsedColumnName = parseSqlIdentifier(name, "column name");
|
|
941
|
-
let type = col.type.toUpperCase();
|
|
942
|
-
if (type === "TEXT") type = "TEXT";
|
|
943
|
-
if (type === "TIMESTAMP") type = "TEXT";
|
|
944
|
-
const nullable = col.nullable ? "" : "NOT NULL";
|
|
945
|
-
const primaryKey = col.primaryKey ? "PRIMARY KEY" : "";
|
|
946
|
-
return `${parsedColumnName} ${type} ${nullable} ${primaryKey}`.trim();
|
|
947
|
-
});
|
|
948
|
-
if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
|
|
949
|
-
const stmnt = `CREATE TABLE IF NOT EXISTS ${parsedTableName} (
|
|
950
|
-
${columns.join(",\n")},
|
|
951
|
-
PRIMARY KEY (workflow_name, run_id)
|
|
952
|
-
)`;
|
|
953
|
-
return stmnt;
|
|
954
|
-
}
|
|
955
|
-
return `CREATE TABLE IF NOT EXISTS ${parsedTableName} (${columns.join(", ")})`;
|
|
942
|
+
constructor({ client }) {
|
|
943
|
+
super();
|
|
944
|
+
this.client = client;
|
|
956
945
|
}
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
schema
|
|
960
|
-
}) {
|
|
946
|
+
/** @deprecated use getEvals instead */
|
|
947
|
+
async getEvalsByAgentName(agentName, type) {
|
|
961
948
|
try {
|
|
962
|
-
|
|
963
|
-
const
|
|
964
|
-
await this.client.execute(
|
|
949
|
+
const baseQuery = `SELECT * FROM ${TABLE_EVALS} WHERE agent_name = ?`;
|
|
950
|
+
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)" : "";
|
|
951
|
+
const result = await this.client.execute({
|
|
952
|
+
sql: `${baseQuery}${typeCondition} ORDER BY created_at DESC`,
|
|
953
|
+
args: [agentName]
|
|
954
|
+
});
|
|
955
|
+
return result.rows?.map((row) => transformEvalRow(row)) ?? [];
|
|
965
956
|
} catch (error) {
|
|
957
|
+
if (error instanceof Error && error.message.includes("no such table")) {
|
|
958
|
+
return [];
|
|
959
|
+
}
|
|
966
960
|
throw new MastraError(
|
|
967
961
|
{
|
|
968
|
-
id: "
|
|
962
|
+
id: "LIBSQL_STORE_GET_EVALS_BY_AGENT_NAME_FAILED",
|
|
969
963
|
domain: ErrorDomain.STORAGE,
|
|
970
964
|
category: ErrorCategory.THIRD_PARTY,
|
|
971
|
-
details: {
|
|
972
|
-
tableName
|
|
973
|
-
}
|
|
965
|
+
details: { agentName }
|
|
974
966
|
},
|
|
975
967
|
error
|
|
976
968
|
);
|
|
977
969
|
}
|
|
978
970
|
}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
return super.getSqlType(type);
|
|
971
|
+
async getEvals(options = {}) {
|
|
972
|
+
const { agentName, type, page = 0, perPage = 100, dateRange } = options;
|
|
973
|
+
const fromDate = dateRange?.start;
|
|
974
|
+
const toDate = dateRange?.end;
|
|
975
|
+
const conditions = [];
|
|
976
|
+
const queryParams = [];
|
|
977
|
+
if (agentName) {
|
|
978
|
+
conditions.push(`agent_name = ?`);
|
|
979
|
+
queryParams.push(agentName);
|
|
989
980
|
}
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
981
|
+
if (type === "test") {
|
|
982
|
+
conditions.push(`(test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL)`);
|
|
983
|
+
} else if (type === "live") {
|
|
984
|
+
conditions.push(`(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)`);
|
|
985
|
+
}
|
|
986
|
+
if (fromDate) {
|
|
987
|
+
conditions.push(`created_at >= ?`);
|
|
988
|
+
queryParams.push(fromDate.toISOString());
|
|
989
|
+
}
|
|
990
|
+
if (toDate) {
|
|
991
|
+
conditions.push(`created_at <= ?`);
|
|
992
|
+
queryParams.push(toDate.toISOString());
|
|
993
|
+
}
|
|
994
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1003
995
|
try {
|
|
1004
|
-
const
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
996
|
+
const countResult = await this.client.execute({
|
|
997
|
+
sql: `SELECT COUNT(*) as count FROM ${TABLE_EVALS} ${whereClause}`,
|
|
998
|
+
args: queryParams
|
|
999
|
+
});
|
|
1000
|
+
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
1001
|
+
const currentOffset = page * perPage;
|
|
1002
|
+
const hasMore = currentOffset + perPage < total;
|
|
1003
|
+
if (total === 0) {
|
|
1004
|
+
return {
|
|
1005
|
+
evals: [],
|
|
1006
|
+
total: 0,
|
|
1007
|
+
page,
|
|
1008
|
+
perPage,
|
|
1009
|
+
hasMore: false
|
|
1010
|
+
};
|
|
1017
1011
|
}
|
|
1012
|
+
const dataResult = await this.client.execute({
|
|
1013
|
+
sql: `SELECT * FROM ${TABLE_EVALS} ${whereClause} ORDER BY created_at DESC LIMIT ? OFFSET ?`,
|
|
1014
|
+
args: [...queryParams, perPage, currentOffset]
|
|
1015
|
+
});
|
|
1016
|
+
return {
|
|
1017
|
+
evals: dataResult.rows?.map((row) => transformEvalRow(row)) ?? [],
|
|
1018
|
+
total,
|
|
1019
|
+
page,
|
|
1020
|
+
perPage,
|
|
1021
|
+
hasMore
|
|
1022
|
+
};
|
|
1018
1023
|
} catch (error) {
|
|
1019
1024
|
throw new MastraError(
|
|
1020
1025
|
{
|
|
1021
|
-
id: "
|
|
1026
|
+
id: "LIBSQL_STORE_GET_EVALS_FAILED",
|
|
1022
1027
|
domain: ErrorDomain.STORAGE,
|
|
1023
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1024
|
-
details: {
|
|
1025
|
-
tableName
|
|
1026
|
-
}
|
|
1028
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1027
1029
|
},
|
|
1028
1030
|
error
|
|
1029
1031
|
);
|
|
1030
1032
|
}
|
|
1031
1033
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
+
};
|
|
1035
|
+
var MemoryLibSQL = class extends MemoryStorage {
|
|
1036
|
+
client;
|
|
1037
|
+
operations;
|
|
1038
|
+
constructor({ client, operations }) {
|
|
1039
|
+
super();
|
|
1040
|
+
this.client = client;
|
|
1041
|
+
this.operations = operations;
|
|
1042
|
+
}
|
|
1043
|
+
parseRow(row) {
|
|
1044
|
+
let content = row.content;
|
|
1034
1045
|
try {
|
|
1035
|
-
|
|
1036
|
-
} catch
|
|
1037
|
-
const mastraError = new MastraError(
|
|
1038
|
-
{
|
|
1039
|
-
id: "LIBSQL_STORE_CLEAR_TABLE_FAILED",
|
|
1040
|
-
domain: ErrorDomain.STORAGE,
|
|
1041
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1042
|
-
details: {
|
|
1043
|
-
tableName
|
|
1044
|
-
}
|
|
1045
|
-
},
|
|
1046
|
-
e
|
|
1047
|
-
);
|
|
1048
|
-
this.logger?.trackException?.(mastraError);
|
|
1049
|
-
this.logger?.error?.(mastraError.toString());
|
|
1046
|
+
content = JSON.parse(row.content);
|
|
1047
|
+
} catch {
|
|
1050
1048
|
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
}
|
|
1059
|
-
if (v instanceof Date) {
|
|
1060
|
-
return v.toISOString();
|
|
1061
|
-
}
|
|
1062
|
-
return typeof v === "object" ? JSON.stringify(v) : v;
|
|
1063
|
-
});
|
|
1064
|
-
const placeholders = values.map(() => "?").join(", ");
|
|
1065
|
-
return {
|
|
1066
|
-
sql: `INSERT OR REPLACE INTO ${parsedTableName} (${columns.join(", ")}) VALUES (${placeholders})`,
|
|
1067
|
-
args: values
|
|
1049
|
+
const result = {
|
|
1050
|
+
id: row.id,
|
|
1051
|
+
content,
|
|
1052
|
+
role: row.role,
|
|
1053
|
+
createdAt: new Date(row.createdAt),
|
|
1054
|
+
threadId: row.thread_id,
|
|
1055
|
+
resourceId: row.resourceId
|
|
1068
1056
|
};
|
|
1057
|
+
if (row.type && row.type !== `v2`) result.type = row.type;
|
|
1058
|
+
return result;
|
|
1069
1059
|
}
|
|
1070
|
-
async
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1060
|
+
async _getIncludedMessages({
|
|
1061
|
+
threadId,
|
|
1062
|
+
selectBy
|
|
1063
|
+
}) {
|
|
1064
|
+
const include = selectBy?.include;
|
|
1065
|
+
if (!include) return null;
|
|
1066
|
+
const unionQueries = [];
|
|
1067
|
+
const params = [];
|
|
1068
|
+
for (const inc of include) {
|
|
1069
|
+
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
1070
|
+
const searchId = inc.threadId || threadId;
|
|
1071
|
+
unionQueries.push(
|
|
1072
|
+
`
|
|
1073
|
+
SELECT * FROM (
|
|
1074
|
+
WITH numbered_messages AS (
|
|
1075
|
+
SELECT
|
|
1076
|
+
id, content, role, type, "createdAt", thread_id, "resourceId",
|
|
1077
|
+
ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
|
|
1078
|
+
FROM "${TABLE_MESSAGES}"
|
|
1079
|
+
WHERE thread_id = ?
|
|
1080
|
+
),
|
|
1081
|
+
target_positions AS (
|
|
1082
|
+
SELECT row_num as target_pos
|
|
1083
|
+
FROM numbered_messages
|
|
1084
|
+
WHERE id = ?
|
|
1085
|
+
)
|
|
1086
|
+
SELECT DISTINCT m.*
|
|
1087
|
+
FROM numbered_messages m
|
|
1088
|
+
CROSS JOIN target_positions t
|
|
1089
|
+
WHERE m.row_num BETWEEN (t.target_pos - ?) AND (t.target_pos + ?)
|
|
1090
|
+
)
|
|
1091
|
+
`
|
|
1092
|
+
// Keep ASC for final sorting after fetching context
|
|
1093
|
+
);
|
|
1094
|
+
params.push(searchId, id, withPreviousMessages, withNextMessages);
|
|
1088
1095
|
}
|
|
1096
|
+
const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
|
|
1097
|
+
const includedResult = await this.client.execute({ sql: finalQuery, args: params });
|
|
1098
|
+
const includedRows = includedResult.rows?.map((row) => this.parseRow(row));
|
|
1099
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1100
|
+
const dedupedRows = includedRows.filter((row) => {
|
|
1101
|
+
if (seen.has(row.id)) return false;
|
|
1102
|
+
seen.add(row.id);
|
|
1103
|
+
return true;
|
|
1104
|
+
});
|
|
1105
|
+
return dedupedRows;
|
|
1089
1106
|
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
tableName,
|
|
1095
|
-
record
|
|
1107
|
+
async getMessages({
|
|
1108
|
+
threadId,
|
|
1109
|
+
selectBy,
|
|
1110
|
+
format
|
|
1096
1111
|
}) {
|
|
1097
|
-
await this.client.execute(
|
|
1098
|
-
this.prepareStatement({
|
|
1099
|
-
tableName,
|
|
1100
|
-
record
|
|
1101
|
-
})
|
|
1102
|
-
);
|
|
1103
|
-
}
|
|
1104
|
-
batchInsert(args) {
|
|
1105
|
-
return this.executeWriteOperationWithRetry(
|
|
1106
|
-
() => this.doBatchInsert(args),
|
|
1107
|
-
`batch insert into table ${args.tableName}`
|
|
1108
|
-
).catch((error) => {
|
|
1109
|
-
throw new MastraError(
|
|
1110
|
-
{
|
|
1111
|
-
id: "LIBSQL_STORE_BATCH_INSERT_FAILED",
|
|
1112
|
-
domain: ErrorDomain.STORAGE,
|
|
1113
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1114
|
-
details: {
|
|
1115
|
-
tableName: args.tableName
|
|
1116
|
-
}
|
|
1117
|
-
},
|
|
1118
|
-
error
|
|
1119
|
-
);
|
|
1120
|
-
});
|
|
1121
|
-
}
|
|
1122
|
-
async doBatchInsert({
|
|
1123
|
-
tableName,
|
|
1124
|
-
records
|
|
1125
|
-
}) {
|
|
1126
|
-
if (records.length === 0) return;
|
|
1127
|
-
const batchStatements = records.map((r) => this.prepareStatement({ tableName, record: r }));
|
|
1128
|
-
await this.client.batch(batchStatements, "write");
|
|
1129
|
-
}
|
|
1130
|
-
async load({ tableName, keys }) {
|
|
1131
|
-
const parsedTableName = parseSqlIdentifier(tableName, "table name");
|
|
1132
|
-
const parsedKeys = Object.keys(keys).map((key) => parseSqlIdentifier(key, "column name"));
|
|
1133
|
-
const conditions = parsedKeys.map((key) => `${key} = ?`).join(" AND ");
|
|
1134
|
-
const values = Object.values(keys);
|
|
1135
|
-
const result = await this.client.execute({
|
|
1136
|
-
sql: `SELECT * FROM ${parsedTableName} WHERE ${conditions} ORDER BY createdAt DESC LIMIT 1`,
|
|
1137
|
-
args: values
|
|
1138
|
-
});
|
|
1139
|
-
if (!result.rows || result.rows.length === 0) {
|
|
1140
|
-
return null;
|
|
1141
|
-
}
|
|
1142
|
-
const row = result.rows[0];
|
|
1143
|
-
const parsed = Object.fromEntries(
|
|
1144
|
-
Object.entries(row || {}).map(([k, v]) => {
|
|
1145
|
-
try {
|
|
1146
|
-
return [k, typeof v === "string" ? v.startsWith("{") || v.startsWith("[") ? JSON.parse(v) : v : v];
|
|
1147
|
-
} catch {
|
|
1148
|
-
return [k, v];
|
|
1149
|
-
}
|
|
1150
|
-
})
|
|
1151
|
-
);
|
|
1152
|
-
return parsed;
|
|
1153
|
-
}
|
|
1154
|
-
async getThreadById({ threadId }) {
|
|
1155
1112
|
try {
|
|
1156
|
-
const
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1113
|
+
const messages = [];
|
|
1114
|
+
const limit = resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
1115
|
+
if (selectBy?.include?.length) {
|
|
1116
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
|
|
1117
|
+
if (includeMessages) {
|
|
1118
|
+
messages.push(...includeMessages);
|
|
1119
|
+
}
|
|
1162
1120
|
}
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1121
|
+
const excludeIds = messages.map((m) => m.id);
|
|
1122
|
+
const remainingSql = `
|
|
1123
|
+
SELECT
|
|
1124
|
+
id,
|
|
1125
|
+
content,
|
|
1126
|
+
role,
|
|
1127
|
+
type,
|
|
1128
|
+
"createdAt",
|
|
1129
|
+
thread_id,
|
|
1130
|
+
"resourceId"
|
|
1131
|
+
FROM "${TABLE_MESSAGES}"
|
|
1132
|
+
WHERE thread_id = ?
|
|
1133
|
+
${excludeIds.length ? `AND id NOT IN (${excludeIds.map(() => "?").join(", ")})` : ""}
|
|
1134
|
+
ORDER BY "createdAt" DESC
|
|
1135
|
+
LIMIT ?
|
|
1136
|
+
`;
|
|
1137
|
+
const remainingArgs = [threadId, ...excludeIds.length ? excludeIds : [], limit];
|
|
1138
|
+
const remainingResult = await this.client.execute({ sql: remainingSql, args: remainingArgs });
|
|
1139
|
+
if (remainingResult.rows) {
|
|
1140
|
+
messages.push(...remainingResult.rows.map((row) => this.parseRow(row)));
|
|
1141
|
+
}
|
|
1142
|
+
messages.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
1143
|
+
const list = new MessageList().add(messages, "memory");
|
|
1144
|
+
if (format === `v2`) return list.get.all.v2();
|
|
1145
|
+
return list.get.all.v1();
|
|
1167
1146
|
} catch (error) {
|
|
1168
1147
|
throw new MastraError(
|
|
1169
1148
|
{
|
|
1170
|
-
id: "
|
|
1149
|
+
id: "LIBSQL_STORE_GET_MESSAGES_FAILED",
|
|
1171
1150
|
domain: ErrorDomain.STORAGE,
|
|
1172
1151
|
category: ErrorCategory.THIRD_PARTY,
|
|
1173
1152
|
details: { threadId }
|
|
@@ -1176,130 +1155,517 @@ var LibSQLStore = class extends MastraStorage {
|
|
|
1176
1155
|
);
|
|
1177
1156
|
}
|
|
1178
1157
|
}
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
const
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
return [];
|
|
1158
|
+
async getMessagesPaginated(args) {
|
|
1159
|
+
const { threadId, format, selectBy } = args;
|
|
1160
|
+
const { page = 0, perPage: perPageInput, dateRange } = selectBy?.pagination || {};
|
|
1161
|
+
const perPage = perPageInput !== void 0 ? perPageInput : resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
1162
|
+
const fromDate = dateRange?.start;
|
|
1163
|
+
const toDate = dateRange?.end;
|
|
1164
|
+
const messages = [];
|
|
1165
|
+
if (selectBy?.include?.length) {
|
|
1166
|
+
try {
|
|
1167
|
+
const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
|
|
1168
|
+
if (includeMessages) {
|
|
1169
|
+
messages.push(...includeMessages);
|
|
1170
|
+
}
|
|
1171
|
+
} catch (error) {
|
|
1172
|
+
throw new MastraError(
|
|
1173
|
+
{
|
|
1174
|
+
id: "LIBSQL_STORE_GET_MESSAGES_PAGINATED_GET_INCLUDE_MESSAGES_FAILED",
|
|
1175
|
+
domain: ErrorDomain.STORAGE,
|
|
1176
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1177
|
+
details: { threadId }
|
|
1178
|
+
},
|
|
1179
|
+
error
|
|
1180
|
+
);
|
|
1203
1181
|
}
|
|
1204
|
-
return result.rows.map(mapRowToStorageThreadType);
|
|
1205
|
-
} catch (error) {
|
|
1206
|
-
const mastraError = new MastraError(
|
|
1207
|
-
{
|
|
1208
|
-
id: "LIBSQL_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED",
|
|
1209
|
-
domain: ErrorDomain.STORAGE,
|
|
1210
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1211
|
-
details: { resourceId }
|
|
1212
|
-
},
|
|
1213
|
-
error
|
|
1214
|
-
);
|
|
1215
|
-
this.logger?.trackException?.(mastraError);
|
|
1216
|
-
this.logger?.error?.(mastraError.toString());
|
|
1217
|
-
return [];
|
|
1218
1182
|
}
|
|
1219
|
-
}
|
|
1220
|
-
async getThreadsByResourceIdPaginated(args) {
|
|
1221
|
-
const { resourceId, page = 0, perPage = 100 } = args;
|
|
1222
1183
|
try {
|
|
1223
|
-
const baseQuery = `FROM ${TABLE_THREADS} WHERE resourceId = ?`;
|
|
1224
|
-
const queryParams = [resourceId];
|
|
1225
|
-
const mapRowToStorageThreadType = (row) => ({
|
|
1226
|
-
id: row.id,
|
|
1227
|
-
resourceId: row.resourceId,
|
|
1228
|
-
title: row.title,
|
|
1229
|
-
createdAt: new Date(row.createdAt),
|
|
1230
|
-
// Convert string to Date
|
|
1231
|
-
updatedAt: new Date(row.updatedAt),
|
|
1232
|
-
// Convert string to Date
|
|
1233
|
-
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata
|
|
1234
|
-
});
|
|
1235
1184
|
const currentOffset = page * perPage;
|
|
1185
|
+
const conditions = [`thread_id = ?`];
|
|
1186
|
+
const queryParams = [threadId];
|
|
1187
|
+
if (fromDate) {
|
|
1188
|
+
conditions.push(`"createdAt" >= ?`);
|
|
1189
|
+
queryParams.push(fromDate.toISOString());
|
|
1190
|
+
}
|
|
1191
|
+
if (toDate) {
|
|
1192
|
+
conditions.push(`"createdAt" <= ?`);
|
|
1193
|
+
queryParams.push(toDate.toISOString());
|
|
1194
|
+
}
|
|
1195
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1236
1196
|
const countResult = await this.client.execute({
|
|
1237
|
-
sql: `SELECT COUNT(*) as count ${
|
|
1197
|
+
sql: `SELECT COUNT(*) as count FROM ${TABLE_MESSAGES} ${whereClause}`,
|
|
1238
1198
|
args: queryParams
|
|
1239
1199
|
});
|
|
1240
1200
|
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
1241
|
-
if (total === 0) {
|
|
1201
|
+
if (total === 0 && messages.length === 0) {
|
|
1242
1202
|
return {
|
|
1243
|
-
|
|
1203
|
+
messages: [],
|
|
1244
1204
|
total: 0,
|
|
1245
1205
|
page,
|
|
1246
1206
|
perPage,
|
|
1247
1207
|
hasMore: false
|
|
1248
1208
|
};
|
|
1249
1209
|
}
|
|
1210
|
+
const excludeIds = messages.map((m) => m.id);
|
|
1211
|
+
const excludeIdsParam = excludeIds.map((_, idx) => `$${idx + queryParams.length + 1}`).join(", ");
|
|
1250
1212
|
const dataResult = await this.client.execute({
|
|
1251
|
-
sql: `SELECT
|
|
1252
|
-
args: [...queryParams, perPage, currentOffset]
|
|
1213
|
+
sql: `SELECT id, content, role, type, "createdAt", "resourceId", "thread_id" FROM ${TABLE_MESSAGES} ${whereClause} ${excludeIds.length ? `AND id NOT IN (${excludeIdsParam})` : ""} ORDER BY "createdAt" DESC LIMIT ? OFFSET ?`,
|
|
1214
|
+
args: [...queryParams, ...excludeIds, perPage, currentOffset]
|
|
1253
1215
|
});
|
|
1254
|
-
|
|
1216
|
+
messages.push(...(dataResult.rows || []).map((row) => this.parseRow(row)));
|
|
1217
|
+
const messagesToReturn = format === "v1" ? new MessageList().add(messages, "memory").get.all.v1() : new MessageList().add(messages, "memory").get.all.v2();
|
|
1255
1218
|
return {
|
|
1256
|
-
|
|
1219
|
+
messages: messagesToReturn,
|
|
1257
1220
|
total,
|
|
1258
1221
|
page,
|
|
1259
1222
|
perPage,
|
|
1260
|
-
hasMore: currentOffset +
|
|
1223
|
+
hasMore: currentOffset + messages.length < total
|
|
1261
1224
|
};
|
|
1262
1225
|
} catch (error) {
|
|
1263
1226
|
const mastraError = new MastraError(
|
|
1264
1227
|
{
|
|
1265
|
-
id: "
|
|
1228
|
+
id: "LIBSQL_STORE_GET_MESSAGES_PAGINATED_FAILED",
|
|
1266
1229
|
domain: ErrorDomain.STORAGE,
|
|
1267
1230
|
category: ErrorCategory.THIRD_PARTY,
|
|
1268
|
-
details: {
|
|
1231
|
+
details: { threadId }
|
|
1269
1232
|
},
|
|
1270
1233
|
error
|
|
1271
1234
|
);
|
|
1272
1235
|
this.logger?.trackException?.(mastraError);
|
|
1273
1236
|
this.logger?.error?.(mastraError.toString());
|
|
1274
|
-
return {
|
|
1237
|
+
return { messages: [], total: 0, page, perPage, hasMore: false };
|
|
1275
1238
|
}
|
|
1276
1239
|
}
|
|
1277
|
-
async
|
|
1240
|
+
async saveMessages({
|
|
1241
|
+
messages,
|
|
1242
|
+
format
|
|
1243
|
+
}) {
|
|
1244
|
+
if (messages.length === 0) return messages;
|
|
1278
1245
|
try {
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1246
|
+
const threadId = messages[0]?.threadId;
|
|
1247
|
+
if (!threadId) {
|
|
1248
|
+
throw new Error("Thread ID is required");
|
|
1249
|
+
}
|
|
1250
|
+
const batchStatements = messages.map((message) => {
|
|
1251
|
+
const time = message.createdAt || /* @__PURE__ */ new Date();
|
|
1252
|
+
if (!message.threadId) {
|
|
1253
|
+
throw new Error(
|
|
1254
|
+
`Expected to find a threadId for message, but couldn't find one. An unexpected error has occurred.`
|
|
1255
|
+
);
|
|
1256
|
+
}
|
|
1257
|
+
if (!message.resourceId) {
|
|
1258
|
+
throw new Error(
|
|
1259
|
+
`Expected to find a resourceId for message, but couldn't find one. An unexpected error has occurred.`
|
|
1260
|
+
);
|
|
1284
1261
|
}
|
|
1262
|
+
return {
|
|
1263
|
+
sql: `INSERT INTO "${TABLE_MESSAGES}" (id, thread_id, content, role, type, "createdAt", "resourceId")
|
|
1264
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
1265
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
1266
|
+
thread_id=excluded.thread_id,
|
|
1267
|
+
content=excluded.content,
|
|
1268
|
+
role=excluded.role,
|
|
1269
|
+
type=excluded.type,
|
|
1270
|
+
"resourceId"=excluded."resourceId"
|
|
1271
|
+
`,
|
|
1272
|
+
args: [
|
|
1273
|
+
message.id,
|
|
1274
|
+
message.threadId,
|
|
1275
|
+
typeof message.content === "object" ? JSON.stringify(message.content) : message.content,
|
|
1276
|
+
message.role,
|
|
1277
|
+
message.type || "v2",
|
|
1278
|
+
time instanceof Date ? time.toISOString() : time,
|
|
1279
|
+
message.resourceId
|
|
1280
|
+
]
|
|
1281
|
+
};
|
|
1285
1282
|
});
|
|
1286
|
-
|
|
1283
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1284
|
+
batchStatements.push({
|
|
1285
|
+
sql: `UPDATE "${TABLE_THREADS}" SET "updatedAt" = ? WHERE id = ?`,
|
|
1286
|
+
args: [now, threadId]
|
|
1287
|
+
});
|
|
1288
|
+
const BATCH_SIZE = 50;
|
|
1289
|
+
const messageStatements = batchStatements.slice(0, -1);
|
|
1290
|
+
const threadUpdateStatement = batchStatements[batchStatements.length - 1];
|
|
1291
|
+
for (let i = 0; i < messageStatements.length; i += BATCH_SIZE) {
|
|
1292
|
+
const batch = messageStatements.slice(i, i + BATCH_SIZE);
|
|
1293
|
+
if (batch.length > 0) {
|
|
1294
|
+
await this.client.batch(batch, "write");
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
if (threadUpdateStatement) {
|
|
1298
|
+
await this.client.execute(threadUpdateStatement);
|
|
1299
|
+
}
|
|
1300
|
+
const list = new MessageList().add(messages, "memory");
|
|
1301
|
+
if (format === `v2`) return list.get.all.v2();
|
|
1302
|
+
return list.get.all.v1();
|
|
1287
1303
|
} catch (error) {
|
|
1288
|
-
|
|
1304
|
+
throw new MastraError(
|
|
1289
1305
|
{
|
|
1290
|
-
id: "
|
|
1306
|
+
id: "LIBSQL_STORE_SAVE_MESSAGES_FAILED",
|
|
1291
1307
|
domain: ErrorDomain.STORAGE,
|
|
1292
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1293
|
-
details: { threadId: thread.id }
|
|
1308
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1294
1309
|
},
|
|
1295
1310
|
error
|
|
1296
1311
|
);
|
|
1297
|
-
this.logger?.trackException?.(mastraError);
|
|
1298
|
-
this.logger?.error?.(mastraError.toString());
|
|
1299
|
-
throw mastraError;
|
|
1300
1312
|
}
|
|
1301
1313
|
}
|
|
1302
|
-
async
|
|
1314
|
+
async updateMessages({
|
|
1315
|
+
messages
|
|
1316
|
+
}) {
|
|
1317
|
+
if (messages.length === 0) {
|
|
1318
|
+
return [];
|
|
1319
|
+
}
|
|
1320
|
+
const messageIds = messages.map((m) => m.id);
|
|
1321
|
+
const placeholders = messageIds.map(() => "?").join(",");
|
|
1322
|
+
const selectSql = `SELECT * FROM ${TABLE_MESSAGES} WHERE id IN (${placeholders})`;
|
|
1323
|
+
const existingResult = await this.client.execute({ sql: selectSql, args: messageIds });
|
|
1324
|
+
const existingMessages = existingResult.rows.map((row) => this.parseRow(row));
|
|
1325
|
+
if (existingMessages.length === 0) {
|
|
1326
|
+
return [];
|
|
1327
|
+
}
|
|
1328
|
+
const batchStatements = [];
|
|
1329
|
+
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
1330
|
+
const columnMapping = {
|
|
1331
|
+
threadId: "thread_id"
|
|
1332
|
+
};
|
|
1333
|
+
for (const existingMessage of existingMessages) {
|
|
1334
|
+
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
1335
|
+
if (!updatePayload) continue;
|
|
1336
|
+
const { id, ...fieldsToUpdate } = updatePayload;
|
|
1337
|
+
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
1338
|
+
threadIdsToUpdate.add(existingMessage.threadId);
|
|
1339
|
+
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
1340
|
+
threadIdsToUpdate.add(updatePayload.threadId);
|
|
1341
|
+
}
|
|
1342
|
+
const setClauses = [];
|
|
1343
|
+
const args = [];
|
|
1344
|
+
const updatableFields = { ...fieldsToUpdate };
|
|
1345
|
+
if (updatableFields.content) {
|
|
1346
|
+
const newContent = {
|
|
1347
|
+
...existingMessage.content,
|
|
1348
|
+
...updatableFields.content,
|
|
1349
|
+
// Deep merge metadata if it exists on both
|
|
1350
|
+
...existingMessage.content?.metadata && updatableFields.content.metadata ? {
|
|
1351
|
+
metadata: {
|
|
1352
|
+
...existingMessage.content.metadata,
|
|
1353
|
+
...updatableFields.content.metadata
|
|
1354
|
+
}
|
|
1355
|
+
} : {}
|
|
1356
|
+
};
|
|
1357
|
+
setClauses.push(`${parseSqlIdentifier$1("content", "column name")} = ?`);
|
|
1358
|
+
args.push(JSON.stringify(newContent));
|
|
1359
|
+
delete updatableFields.content;
|
|
1360
|
+
}
|
|
1361
|
+
for (const key in updatableFields) {
|
|
1362
|
+
if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
|
|
1363
|
+
const dbKey = columnMapping[key] || key;
|
|
1364
|
+
setClauses.push(`${parseSqlIdentifier$1(dbKey, "column name")} = ?`);
|
|
1365
|
+
let value = updatableFields[key];
|
|
1366
|
+
if (typeof value === "object" && value !== null) {
|
|
1367
|
+
value = JSON.stringify(value);
|
|
1368
|
+
}
|
|
1369
|
+
args.push(value);
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
if (setClauses.length === 0) continue;
|
|
1373
|
+
args.push(id);
|
|
1374
|
+
const sql = `UPDATE ${TABLE_MESSAGES} SET ${setClauses.join(", ")} WHERE id = ?`;
|
|
1375
|
+
batchStatements.push({ sql, args });
|
|
1376
|
+
}
|
|
1377
|
+
if (batchStatements.length === 0) {
|
|
1378
|
+
return existingMessages;
|
|
1379
|
+
}
|
|
1380
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1381
|
+
for (const threadId of threadIdsToUpdate) {
|
|
1382
|
+
if (threadId) {
|
|
1383
|
+
batchStatements.push({
|
|
1384
|
+
sql: `UPDATE ${TABLE_THREADS} SET updatedAt = ? WHERE id = ?`,
|
|
1385
|
+
args: [now, threadId]
|
|
1386
|
+
});
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
await this.client.batch(batchStatements, "write");
|
|
1390
|
+
const updatedResult = await this.client.execute({ sql: selectSql, args: messageIds });
|
|
1391
|
+
return updatedResult.rows.map((row) => this.parseRow(row));
|
|
1392
|
+
}
|
|
1393
|
+
async deleteMessages(messageIds) {
|
|
1394
|
+
if (!messageIds || messageIds.length === 0) {
|
|
1395
|
+
return;
|
|
1396
|
+
}
|
|
1397
|
+
try {
|
|
1398
|
+
const BATCH_SIZE = 100;
|
|
1399
|
+
const threadIds = /* @__PURE__ */ new Set();
|
|
1400
|
+
const tx = await this.client.transaction("write");
|
|
1401
|
+
try {
|
|
1402
|
+
for (let i = 0; i < messageIds.length; i += BATCH_SIZE) {
|
|
1403
|
+
const batch = messageIds.slice(i, i + BATCH_SIZE);
|
|
1404
|
+
const placeholders = batch.map(() => "?").join(",");
|
|
1405
|
+
const result = await tx.execute({
|
|
1406
|
+
sql: `SELECT DISTINCT thread_id FROM "${TABLE_MESSAGES}" WHERE id IN (${placeholders})`,
|
|
1407
|
+
args: batch
|
|
1408
|
+
});
|
|
1409
|
+
result.rows?.forEach((row) => {
|
|
1410
|
+
if (row.thread_id) threadIds.add(row.thread_id);
|
|
1411
|
+
});
|
|
1412
|
+
await tx.execute({
|
|
1413
|
+
sql: `DELETE FROM "${TABLE_MESSAGES}" WHERE id IN (${placeholders})`,
|
|
1414
|
+
args: batch
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1417
|
+
if (threadIds.size > 0) {
|
|
1418
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1419
|
+
for (const threadId of threadIds) {
|
|
1420
|
+
await tx.execute({
|
|
1421
|
+
sql: `UPDATE "${TABLE_THREADS}" SET "updatedAt" = ? WHERE id = ?`,
|
|
1422
|
+
args: [now, threadId]
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
await tx.commit();
|
|
1427
|
+
} catch (error) {
|
|
1428
|
+
await tx.rollback();
|
|
1429
|
+
throw error;
|
|
1430
|
+
}
|
|
1431
|
+
} catch (error) {
|
|
1432
|
+
throw new MastraError(
|
|
1433
|
+
{
|
|
1434
|
+
id: "LIBSQL_STORE_DELETE_MESSAGES_FAILED",
|
|
1435
|
+
domain: ErrorDomain.STORAGE,
|
|
1436
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1437
|
+
details: { messageIds: messageIds.join(", ") }
|
|
1438
|
+
},
|
|
1439
|
+
error
|
|
1440
|
+
);
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
async getResourceById({ resourceId }) {
|
|
1444
|
+
const result = await this.operations.load({
|
|
1445
|
+
tableName: TABLE_RESOURCES,
|
|
1446
|
+
keys: { id: resourceId }
|
|
1447
|
+
});
|
|
1448
|
+
if (!result) {
|
|
1449
|
+
return null;
|
|
1450
|
+
}
|
|
1451
|
+
return {
|
|
1452
|
+
...result,
|
|
1453
|
+
// Ensure workingMemory is always returned as a string, even if auto-parsed as JSON
|
|
1454
|
+
workingMemory: result.workingMemory && typeof result.workingMemory === "object" ? JSON.stringify(result.workingMemory) : result.workingMemory,
|
|
1455
|
+
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata,
|
|
1456
|
+
createdAt: new Date(result.createdAt),
|
|
1457
|
+
updatedAt: new Date(result.updatedAt)
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
async saveResource({ resource }) {
|
|
1461
|
+
await this.operations.insert({
|
|
1462
|
+
tableName: TABLE_RESOURCES,
|
|
1463
|
+
record: {
|
|
1464
|
+
...resource,
|
|
1465
|
+
metadata: JSON.stringify(resource.metadata)
|
|
1466
|
+
}
|
|
1467
|
+
});
|
|
1468
|
+
return resource;
|
|
1469
|
+
}
|
|
1470
|
+
async updateResource({
|
|
1471
|
+
resourceId,
|
|
1472
|
+
workingMemory,
|
|
1473
|
+
metadata
|
|
1474
|
+
}) {
|
|
1475
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
1476
|
+
if (!existingResource) {
|
|
1477
|
+
const newResource = {
|
|
1478
|
+
id: resourceId,
|
|
1479
|
+
workingMemory,
|
|
1480
|
+
metadata: metadata || {},
|
|
1481
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
1482
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1483
|
+
};
|
|
1484
|
+
return this.saveResource({ resource: newResource });
|
|
1485
|
+
}
|
|
1486
|
+
const updatedResource = {
|
|
1487
|
+
...existingResource,
|
|
1488
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
1489
|
+
metadata: {
|
|
1490
|
+
...existingResource.metadata,
|
|
1491
|
+
...metadata
|
|
1492
|
+
},
|
|
1493
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1494
|
+
};
|
|
1495
|
+
const updates = [];
|
|
1496
|
+
const values = [];
|
|
1497
|
+
if (workingMemory !== void 0) {
|
|
1498
|
+
updates.push("workingMemory = ?");
|
|
1499
|
+
values.push(workingMemory);
|
|
1500
|
+
}
|
|
1501
|
+
if (metadata) {
|
|
1502
|
+
updates.push("metadata = ?");
|
|
1503
|
+
values.push(JSON.stringify(updatedResource.metadata));
|
|
1504
|
+
}
|
|
1505
|
+
updates.push("updatedAt = ?");
|
|
1506
|
+
values.push(updatedResource.updatedAt.toISOString());
|
|
1507
|
+
values.push(resourceId);
|
|
1508
|
+
await this.client.execute({
|
|
1509
|
+
sql: `UPDATE ${TABLE_RESOURCES} SET ${updates.join(", ")} WHERE id = ?`,
|
|
1510
|
+
args: values
|
|
1511
|
+
});
|
|
1512
|
+
return updatedResource;
|
|
1513
|
+
}
|
|
1514
|
+
async getThreadById({ threadId }) {
|
|
1515
|
+
try {
|
|
1516
|
+
const result = await this.operations.load({
|
|
1517
|
+
tableName: TABLE_THREADS,
|
|
1518
|
+
keys: { id: threadId }
|
|
1519
|
+
});
|
|
1520
|
+
if (!result) {
|
|
1521
|
+
return null;
|
|
1522
|
+
}
|
|
1523
|
+
return {
|
|
1524
|
+
...result,
|
|
1525
|
+
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata,
|
|
1526
|
+
createdAt: new Date(result.createdAt),
|
|
1527
|
+
updatedAt: new Date(result.updatedAt)
|
|
1528
|
+
};
|
|
1529
|
+
} catch (error) {
|
|
1530
|
+
throw new MastraError(
|
|
1531
|
+
{
|
|
1532
|
+
id: "LIBSQL_STORE_GET_THREAD_BY_ID_FAILED",
|
|
1533
|
+
domain: ErrorDomain.STORAGE,
|
|
1534
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1535
|
+
details: { threadId }
|
|
1536
|
+
},
|
|
1537
|
+
error
|
|
1538
|
+
);
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
/**
|
|
1542
|
+
* @deprecated use getThreadsByResourceIdPaginated instead for paginated results.
|
|
1543
|
+
*/
|
|
1544
|
+
async getThreadsByResourceId(args) {
|
|
1545
|
+
const resourceId = args.resourceId;
|
|
1546
|
+
const orderBy = this.castThreadOrderBy(args.orderBy);
|
|
1547
|
+
const sortDirection = this.castThreadSortDirection(args.sortDirection);
|
|
1548
|
+
try {
|
|
1549
|
+
const baseQuery = `FROM ${TABLE_THREADS} WHERE resourceId = ?`;
|
|
1550
|
+
const queryParams = [resourceId];
|
|
1551
|
+
const mapRowToStorageThreadType = (row) => ({
|
|
1552
|
+
id: row.id,
|
|
1553
|
+
resourceId: row.resourceId,
|
|
1554
|
+
title: row.title,
|
|
1555
|
+
createdAt: new Date(row.createdAt),
|
|
1556
|
+
// Convert string to Date
|
|
1557
|
+
updatedAt: new Date(row.updatedAt),
|
|
1558
|
+
// Convert string to Date
|
|
1559
|
+
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata
|
|
1560
|
+
});
|
|
1561
|
+
const result = await this.client.execute({
|
|
1562
|
+
sql: `SELECT * ${baseQuery} ORDER BY ${orderBy} ${sortDirection}`,
|
|
1563
|
+
args: queryParams
|
|
1564
|
+
});
|
|
1565
|
+
if (!result.rows) {
|
|
1566
|
+
return [];
|
|
1567
|
+
}
|
|
1568
|
+
return result.rows.map(mapRowToStorageThreadType);
|
|
1569
|
+
} catch (error) {
|
|
1570
|
+
const mastraError = new MastraError(
|
|
1571
|
+
{
|
|
1572
|
+
id: "LIBSQL_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED",
|
|
1573
|
+
domain: ErrorDomain.STORAGE,
|
|
1574
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1575
|
+
details: { resourceId }
|
|
1576
|
+
},
|
|
1577
|
+
error
|
|
1578
|
+
);
|
|
1579
|
+
this.logger?.trackException?.(mastraError);
|
|
1580
|
+
this.logger?.error?.(mastraError.toString());
|
|
1581
|
+
return [];
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
1585
|
+
const { resourceId, page = 0, perPage = 100 } = args;
|
|
1586
|
+
const orderBy = this.castThreadOrderBy(args.orderBy);
|
|
1587
|
+
const sortDirection = this.castThreadSortDirection(args.sortDirection);
|
|
1588
|
+
try {
|
|
1589
|
+
const baseQuery = `FROM ${TABLE_THREADS} WHERE resourceId = ?`;
|
|
1590
|
+
const queryParams = [resourceId];
|
|
1591
|
+
const mapRowToStorageThreadType = (row) => ({
|
|
1592
|
+
id: row.id,
|
|
1593
|
+
resourceId: row.resourceId,
|
|
1594
|
+
title: row.title,
|
|
1595
|
+
createdAt: new Date(row.createdAt),
|
|
1596
|
+
// Convert string to Date
|
|
1597
|
+
updatedAt: new Date(row.updatedAt),
|
|
1598
|
+
// Convert string to Date
|
|
1599
|
+
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata
|
|
1600
|
+
});
|
|
1601
|
+
const currentOffset = page * perPage;
|
|
1602
|
+
const countResult = await this.client.execute({
|
|
1603
|
+
sql: `SELECT COUNT(*) as count ${baseQuery}`,
|
|
1604
|
+
args: queryParams
|
|
1605
|
+
});
|
|
1606
|
+
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
1607
|
+
if (total === 0) {
|
|
1608
|
+
return {
|
|
1609
|
+
threads: [],
|
|
1610
|
+
total: 0,
|
|
1611
|
+
page,
|
|
1612
|
+
perPage,
|
|
1613
|
+
hasMore: false
|
|
1614
|
+
};
|
|
1615
|
+
}
|
|
1616
|
+
const dataResult = await this.client.execute({
|
|
1617
|
+
sql: `SELECT * ${baseQuery} ORDER BY ${orderBy} ${sortDirection} LIMIT ? OFFSET ?`,
|
|
1618
|
+
args: [...queryParams, perPage, currentOffset]
|
|
1619
|
+
});
|
|
1620
|
+
const threads = (dataResult.rows || []).map(mapRowToStorageThreadType);
|
|
1621
|
+
return {
|
|
1622
|
+
threads,
|
|
1623
|
+
total,
|
|
1624
|
+
page,
|
|
1625
|
+
perPage,
|
|
1626
|
+
hasMore: currentOffset + threads.length < total
|
|
1627
|
+
};
|
|
1628
|
+
} catch (error) {
|
|
1629
|
+
const mastraError = new MastraError(
|
|
1630
|
+
{
|
|
1631
|
+
id: "LIBSQL_STORE_GET_THREADS_BY_RESOURCE_ID_FAILED",
|
|
1632
|
+
domain: ErrorDomain.STORAGE,
|
|
1633
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1634
|
+
details: { resourceId }
|
|
1635
|
+
},
|
|
1636
|
+
error
|
|
1637
|
+
);
|
|
1638
|
+
this.logger?.trackException?.(mastraError);
|
|
1639
|
+
this.logger?.error?.(mastraError.toString());
|
|
1640
|
+
return { threads: [], total: 0, page, perPage, hasMore: false };
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
async saveThread({ thread }) {
|
|
1644
|
+
try {
|
|
1645
|
+
await this.operations.insert({
|
|
1646
|
+
tableName: TABLE_THREADS,
|
|
1647
|
+
record: {
|
|
1648
|
+
...thread,
|
|
1649
|
+
metadata: JSON.stringify(thread.metadata)
|
|
1650
|
+
}
|
|
1651
|
+
});
|
|
1652
|
+
return thread;
|
|
1653
|
+
} catch (error) {
|
|
1654
|
+
const mastraError = new MastraError(
|
|
1655
|
+
{
|
|
1656
|
+
id: "LIBSQL_STORE_SAVE_THREAD_FAILED",
|
|
1657
|
+
domain: ErrorDomain.STORAGE,
|
|
1658
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1659
|
+
details: { threadId: thread.id }
|
|
1660
|
+
},
|
|
1661
|
+
error
|
|
1662
|
+
);
|
|
1663
|
+
this.logger?.trackException?.(mastraError);
|
|
1664
|
+
this.logger?.error?.(mastraError.toString());
|
|
1665
|
+
throw mastraError;
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
async updateThread({
|
|
1303
1669
|
id,
|
|
1304
1670
|
title,
|
|
1305
1671
|
metadata
|
|
@@ -1357,268 +1723,329 @@ var LibSQLStore = class extends MastraStorage {
|
|
|
1357
1723
|
} catch (error) {
|
|
1358
1724
|
throw new MastraError(
|
|
1359
1725
|
{
|
|
1360
|
-
id: "LIBSQL_STORE_DELETE_THREAD_FAILED",
|
|
1726
|
+
id: "LIBSQL_STORE_DELETE_THREAD_FAILED",
|
|
1727
|
+
domain: ErrorDomain.STORAGE,
|
|
1728
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1729
|
+
details: { threadId }
|
|
1730
|
+
},
|
|
1731
|
+
error
|
|
1732
|
+
);
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
};
|
|
1736
|
+
function createExecuteWriteOperationWithRetry({
|
|
1737
|
+
logger,
|
|
1738
|
+
maxRetries,
|
|
1739
|
+
initialBackoffMs
|
|
1740
|
+
}) {
|
|
1741
|
+
return async function executeWriteOperationWithRetry(operationFn, operationDescription) {
|
|
1742
|
+
let retries = 0;
|
|
1743
|
+
while (true) {
|
|
1744
|
+
try {
|
|
1745
|
+
return await operationFn();
|
|
1746
|
+
} catch (error) {
|
|
1747
|
+
if (error.message && (error.message.includes("SQLITE_BUSY") || error.message.includes("database is locked")) && retries < maxRetries) {
|
|
1748
|
+
retries++;
|
|
1749
|
+
const backoffTime = initialBackoffMs * Math.pow(2, retries - 1);
|
|
1750
|
+
logger.warn(
|
|
1751
|
+
`LibSQLStore: Encountered SQLITE_BUSY during ${operationDescription}. Retrying (${retries}/${maxRetries}) in ${backoffTime}ms...`
|
|
1752
|
+
);
|
|
1753
|
+
await new Promise((resolve) => setTimeout(resolve, backoffTime));
|
|
1754
|
+
} else {
|
|
1755
|
+
logger.error(`LibSQLStore: Error during ${operationDescription} after ${retries} retries: ${error}`);
|
|
1756
|
+
throw error;
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
};
|
|
1761
|
+
}
|
|
1762
|
+
function prepareStatement({ tableName, record }) {
|
|
1763
|
+
const parsedTableName = parseSqlIdentifier(tableName, "table name");
|
|
1764
|
+
const columns = Object.keys(record).map((col) => parseSqlIdentifier(col, "column name"));
|
|
1765
|
+
const values = Object.values(record).map((v) => {
|
|
1766
|
+
if (typeof v === `undefined`) {
|
|
1767
|
+
return null;
|
|
1768
|
+
}
|
|
1769
|
+
if (v instanceof Date) {
|
|
1770
|
+
return v.toISOString();
|
|
1771
|
+
}
|
|
1772
|
+
return typeof v === "object" ? JSON.stringify(v) : v;
|
|
1773
|
+
});
|
|
1774
|
+
const placeholders = values.map(() => "?").join(", ");
|
|
1775
|
+
return {
|
|
1776
|
+
sql: `INSERT OR REPLACE INTO ${parsedTableName} (${columns.join(", ")}) VALUES (${placeholders})`,
|
|
1777
|
+
args: values
|
|
1778
|
+
};
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
// src/storage/domains/operations/index.ts
|
|
1782
|
+
var StoreOperationsLibSQL = class extends StoreOperations {
|
|
1783
|
+
client;
|
|
1784
|
+
/**
|
|
1785
|
+
* Maximum number of retries for write operations if an SQLITE_BUSY error occurs.
|
|
1786
|
+
* @default 5
|
|
1787
|
+
*/
|
|
1788
|
+
maxRetries;
|
|
1789
|
+
/**
|
|
1790
|
+
* Initial backoff time in milliseconds for retrying write operations on SQLITE_BUSY.
|
|
1791
|
+
* The backoff time will double with each retry (exponential backoff).
|
|
1792
|
+
* @default 100
|
|
1793
|
+
*/
|
|
1794
|
+
initialBackoffMs;
|
|
1795
|
+
constructor({
|
|
1796
|
+
client,
|
|
1797
|
+
maxRetries,
|
|
1798
|
+
initialBackoffMs
|
|
1799
|
+
}) {
|
|
1800
|
+
super();
|
|
1801
|
+
this.client = client;
|
|
1802
|
+
this.maxRetries = maxRetries ?? 5;
|
|
1803
|
+
this.initialBackoffMs = initialBackoffMs ?? 100;
|
|
1804
|
+
}
|
|
1805
|
+
async hasColumn(table, column) {
|
|
1806
|
+
const result = await this.client.execute({
|
|
1807
|
+
sql: `PRAGMA table_info(${table})`
|
|
1808
|
+
});
|
|
1809
|
+
return (await result.rows)?.some((row) => row.name === column);
|
|
1810
|
+
}
|
|
1811
|
+
getCreateTableSQL(tableName, schema) {
|
|
1812
|
+
const parsedTableName = parseSqlIdentifier(tableName, "table name");
|
|
1813
|
+
const columns = Object.entries(schema).map(([name, col]) => {
|
|
1814
|
+
const parsedColumnName = parseSqlIdentifier(name, "column name");
|
|
1815
|
+
let type = col.type.toUpperCase();
|
|
1816
|
+
if (type === "TEXT") type = "TEXT";
|
|
1817
|
+
if (type === "TIMESTAMP") type = "TEXT";
|
|
1818
|
+
const nullable = col.nullable ? "" : "NOT NULL";
|
|
1819
|
+
const primaryKey = col.primaryKey ? "PRIMARY KEY" : "";
|
|
1820
|
+
return `${parsedColumnName} ${type} ${nullable} ${primaryKey}`.trim();
|
|
1821
|
+
});
|
|
1822
|
+
if (tableName === TABLE_WORKFLOW_SNAPSHOT) {
|
|
1823
|
+
const stmnt = `CREATE TABLE IF NOT EXISTS ${parsedTableName} (
|
|
1824
|
+
${columns.join(",\n")},
|
|
1825
|
+
PRIMARY KEY (workflow_name, run_id)
|
|
1826
|
+
)`;
|
|
1827
|
+
return stmnt;
|
|
1828
|
+
}
|
|
1829
|
+
return `CREATE TABLE IF NOT EXISTS ${parsedTableName} (${columns.join(", ")})`;
|
|
1830
|
+
}
|
|
1831
|
+
async createTable({
|
|
1832
|
+
tableName,
|
|
1833
|
+
schema
|
|
1834
|
+
}) {
|
|
1835
|
+
try {
|
|
1836
|
+
this.logger.debug(`Creating database table`, { tableName, operation: "schema init" });
|
|
1837
|
+
const sql = this.getCreateTableSQL(tableName, schema);
|
|
1838
|
+
await this.client.execute(sql);
|
|
1839
|
+
} catch (error) {
|
|
1840
|
+
throw new MastraError(
|
|
1841
|
+
{
|
|
1842
|
+
id: "LIBSQL_STORE_CREATE_TABLE_FAILED",
|
|
1843
|
+
domain: ErrorDomain.STORAGE,
|
|
1844
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1845
|
+
details: {
|
|
1846
|
+
tableName
|
|
1847
|
+
}
|
|
1848
|
+
},
|
|
1849
|
+
error
|
|
1850
|
+
);
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
getSqlType(type) {
|
|
1854
|
+
switch (type) {
|
|
1855
|
+
case "bigint":
|
|
1856
|
+
return "INTEGER";
|
|
1857
|
+
// SQLite uses INTEGER for all integer sizes
|
|
1858
|
+
case "jsonb":
|
|
1859
|
+
return "TEXT";
|
|
1860
|
+
// Store JSON as TEXT in SQLite
|
|
1861
|
+
default:
|
|
1862
|
+
return super.getSqlType(type);
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
async doInsert({
|
|
1866
|
+
tableName,
|
|
1867
|
+
record
|
|
1868
|
+
}) {
|
|
1869
|
+
await this.client.execute(
|
|
1870
|
+
prepareStatement({
|
|
1871
|
+
tableName,
|
|
1872
|
+
record
|
|
1873
|
+
})
|
|
1874
|
+
);
|
|
1875
|
+
}
|
|
1876
|
+
insert(args) {
|
|
1877
|
+
const executeWriteOperationWithRetry = createExecuteWriteOperationWithRetry({
|
|
1878
|
+
logger: this.logger,
|
|
1879
|
+
maxRetries: this.maxRetries,
|
|
1880
|
+
initialBackoffMs: this.initialBackoffMs
|
|
1881
|
+
});
|
|
1882
|
+
return executeWriteOperationWithRetry(() => this.doInsert(args), `insert into table ${args.tableName}`);
|
|
1883
|
+
}
|
|
1884
|
+
async load({ tableName, keys }) {
|
|
1885
|
+
const parsedTableName = parseSqlIdentifier(tableName, "table name");
|
|
1886
|
+
const parsedKeys = Object.keys(keys).map((key) => parseSqlIdentifier(key, "column name"));
|
|
1887
|
+
const conditions = parsedKeys.map((key) => `${key} = ?`).join(" AND ");
|
|
1888
|
+
const values = Object.values(keys);
|
|
1889
|
+
const result = await this.client.execute({
|
|
1890
|
+
sql: `SELECT * FROM ${parsedTableName} WHERE ${conditions} ORDER BY createdAt DESC LIMIT 1`,
|
|
1891
|
+
args: values
|
|
1892
|
+
});
|
|
1893
|
+
if (!result.rows || result.rows.length === 0) {
|
|
1894
|
+
return null;
|
|
1895
|
+
}
|
|
1896
|
+
const row = result.rows[0];
|
|
1897
|
+
const parsed = Object.fromEntries(
|
|
1898
|
+
Object.entries(row || {}).map(([k, v]) => {
|
|
1899
|
+
try {
|
|
1900
|
+
return [k, typeof v === "string" ? v.startsWith("{") || v.startsWith("[") ? JSON.parse(v) : v : v];
|
|
1901
|
+
} catch {
|
|
1902
|
+
return [k, v];
|
|
1903
|
+
}
|
|
1904
|
+
})
|
|
1905
|
+
);
|
|
1906
|
+
return parsed;
|
|
1907
|
+
}
|
|
1908
|
+
async doBatchInsert({
|
|
1909
|
+
tableName,
|
|
1910
|
+
records
|
|
1911
|
+
}) {
|
|
1912
|
+
if (records.length === 0) return;
|
|
1913
|
+
const batchStatements = records.map((r) => prepareStatement({ tableName, record: r }));
|
|
1914
|
+
await this.client.batch(batchStatements, "write");
|
|
1915
|
+
}
|
|
1916
|
+
batchInsert(args) {
|
|
1917
|
+
const executeWriteOperationWithRetry = createExecuteWriteOperationWithRetry({
|
|
1918
|
+
logger: this.logger,
|
|
1919
|
+
maxRetries: this.maxRetries,
|
|
1920
|
+
initialBackoffMs: this.initialBackoffMs
|
|
1921
|
+
});
|
|
1922
|
+
return executeWriteOperationWithRetry(
|
|
1923
|
+
() => this.doBatchInsert(args),
|
|
1924
|
+
`batch insert into table ${args.tableName}`
|
|
1925
|
+
).catch((error) => {
|
|
1926
|
+
throw new MastraError(
|
|
1927
|
+
{
|
|
1928
|
+
id: "LIBSQL_STORE_BATCH_INSERT_FAILED",
|
|
1361
1929
|
domain: ErrorDomain.STORAGE,
|
|
1362
1930
|
category: ErrorCategory.THIRD_PARTY,
|
|
1363
|
-
details: {
|
|
1931
|
+
details: {
|
|
1932
|
+
tableName: args.tableName
|
|
1933
|
+
}
|
|
1364
1934
|
},
|
|
1365
1935
|
error
|
|
1366
1936
|
);
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
parseRow(row) {
|
|
1370
|
-
let content = row.content;
|
|
1371
|
-
try {
|
|
1372
|
-
content = JSON.parse(row.content);
|
|
1373
|
-
} catch {
|
|
1374
|
-
}
|
|
1375
|
-
const result = {
|
|
1376
|
-
id: row.id,
|
|
1377
|
-
content,
|
|
1378
|
-
role: row.role,
|
|
1379
|
-
createdAt: new Date(row.createdAt),
|
|
1380
|
-
threadId: row.thread_id,
|
|
1381
|
-
resourceId: row.resourceId
|
|
1382
|
-
};
|
|
1383
|
-
if (row.type && row.type !== `v2`) result.type = row.type;
|
|
1384
|
-
return result;
|
|
1385
|
-
}
|
|
1386
|
-
async _getIncludedMessages({
|
|
1387
|
-
threadId,
|
|
1388
|
-
selectBy
|
|
1389
|
-
}) {
|
|
1390
|
-
const include = selectBy?.include;
|
|
1391
|
-
if (!include) return null;
|
|
1392
|
-
const unionQueries = [];
|
|
1393
|
-
const params = [];
|
|
1394
|
-
for (const inc of include) {
|
|
1395
|
-
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
1396
|
-
const searchId = inc.threadId || threadId;
|
|
1397
|
-
unionQueries.push(
|
|
1398
|
-
`
|
|
1399
|
-
SELECT * FROM (
|
|
1400
|
-
WITH numbered_messages AS (
|
|
1401
|
-
SELECT
|
|
1402
|
-
id, content, role, type, "createdAt", thread_id, "resourceId",
|
|
1403
|
-
ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
|
|
1404
|
-
FROM "${TABLE_MESSAGES}"
|
|
1405
|
-
WHERE thread_id = ?
|
|
1406
|
-
),
|
|
1407
|
-
target_positions AS (
|
|
1408
|
-
SELECT row_num as target_pos
|
|
1409
|
-
FROM numbered_messages
|
|
1410
|
-
WHERE id = ?
|
|
1411
|
-
)
|
|
1412
|
-
SELECT DISTINCT m.*
|
|
1413
|
-
FROM numbered_messages m
|
|
1414
|
-
CROSS JOIN target_positions t
|
|
1415
|
-
WHERE m.row_num BETWEEN (t.target_pos - ?) AND (t.target_pos + ?)
|
|
1416
|
-
)
|
|
1417
|
-
`
|
|
1418
|
-
// Keep ASC for final sorting after fetching context
|
|
1419
|
-
);
|
|
1420
|
-
params.push(searchId, id, withPreviousMessages, withNextMessages);
|
|
1421
|
-
}
|
|
1422
|
-
const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
|
|
1423
|
-
const includedResult = await this.client.execute({ sql: finalQuery, args: params });
|
|
1424
|
-
const includedRows = includedResult.rows?.map((row) => this.parseRow(row));
|
|
1425
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1426
|
-
const dedupedRows = includedRows.filter((row) => {
|
|
1427
|
-
if (seen.has(row.id)) return false;
|
|
1428
|
-
seen.add(row.id);
|
|
1429
|
-
return true;
|
|
1430
1937
|
});
|
|
1431
|
-
return dedupedRows;
|
|
1432
1938
|
}
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1939
|
+
/**
|
|
1940
|
+
* Alters table schema to add columns if they don't exist
|
|
1941
|
+
* @param tableName Name of the table
|
|
1942
|
+
* @param schema Schema of the table
|
|
1943
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
1944
|
+
*/
|
|
1945
|
+
async alterTable({
|
|
1946
|
+
tableName,
|
|
1947
|
+
schema,
|
|
1948
|
+
ifNotExists
|
|
1437
1949
|
}) {
|
|
1950
|
+
const parsedTableName = parseSqlIdentifier(tableName, "table name");
|
|
1438
1951
|
try {
|
|
1439
|
-
const
|
|
1440
|
-
const
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
if (
|
|
1444
|
-
|
|
1952
|
+
const pragmaQuery = `PRAGMA table_info(${parsedTableName})`;
|
|
1953
|
+
const result = await this.client.execute(pragmaQuery);
|
|
1954
|
+
const existingColumnNames = new Set(result.rows.map((row) => row.name.toLowerCase()));
|
|
1955
|
+
for (const columnName of ifNotExists) {
|
|
1956
|
+
if (!existingColumnNames.has(columnName.toLowerCase()) && schema[columnName]) {
|
|
1957
|
+
const columnDef = schema[columnName];
|
|
1958
|
+
const sqlType = this.getSqlType(columnDef.type);
|
|
1959
|
+
const nullable = columnDef.nullable === false ? "NOT NULL" : "";
|
|
1960
|
+
const defaultValue = columnDef.nullable === false ? this.getDefaultValue(columnDef.type) : "";
|
|
1961
|
+
const alterSql = `ALTER TABLE ${parsedTableName} ADD COLUMN "${columnName}" ${sqlType} ${nullable} ${defaultValue}`.trim();
|
|
1962
|
+
await this.client.execute(alterSql);
|
|
1963
|
+
this.logger?.debug?.(`Added column ${columnName} to table ${parsedTableName}`);
|
|
1445
1964
|
}
|
|
1446
1965
|
}
|
|
1447
|
-
const excludeIds = messages.map((m) => m.id);
|
|
1448
|
-
const remainingSql = `
|
|
1449
|
-
SELECT
|
|
1450
|
-
id,
|
|
1451
|
-
content,
|
|
1452
|
-
role,
|
|
1453
|
-
type,
|
|
1454
|
-
"createdAt",
|
|
1455
|
-
thread_id,
|
|
1456
|
-
"resourceId"
|
|
1457
|
-
FROM "${TABLE_MESSAGES}"
|
|
1458
|
-
WHERE thread_id = ?
|
|
1459
|
-
${excludeIds.length ? `AND id NOT IN (${excludeIds.map(() => "?").join(", ")})` : ""}
|
|
1460
|
-
ORDER BY "createdAt" DESC
|
|
1461
|
-
LIMIT ?
|
|
1462
|
-
`;
|
|
1463
|
-
const remainingArgs = [threadId, ...excludeIds.length ? excludeIds : [], limit];
|
|
1464
|
-
const remainingResult = await this.client.execute({ sql: remainingSql, args: remainingArgs });
|
|
1465
|
-
if (remainingResult.rows) {
|
|
1466
|
-
messages.push(...remainingResult.rows.map((row) => this.parseRow(row)));
|
|
1467
|
-
}
|
|
1468
|
-
messages.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
|
|
1469
|
-
const list = new MessageList().add(messages, "memory");
|
|
1470
|
-
if (format === `v2`) return list.get.all.v2();
|
|
1471
|
-
return list.get.all.v1();
|
|
1472
1966
|
} catch (error) {
|
|
1473
1967
|
throw new MastraError(
|
|
1474
1968
|
{
|
|
1475
|
-
id: "
|
|
1969
|
+
id: "LIBSQL_STORE_ALTER_TABLE_FAILED",
|
|
1476
1970
|
domain: ErrorDomain.STORAGE,
|
|
1477
1971
|
category: ErrorCategory.THIRD_PARTY,
|
|
1478
|
-
details: {
|
|
1972
|
+
details: {
|
|
1973
|
+
tableName
|
|
1974
|
+
}
|
|
1479
1975
|
},
|
|
1480
1976
|
error
|
|
1481
1977
|
);
|
|
1482
1978
|
}
|
|
1483
1979
|
}
|
|
1484
|
-
async
|
|
1485
|
-
const
|
|
1486
|
-
const { page = 0, perPage: perPageInput, dateRange } = selectBy?.pagination || {};
|
|
1487
|
-
const perPage = perPageInput !== void 0 ? perPageInput : this.resolveMessageLimit({ last: selectBy?.last, defaultLimit: 40 });
|
|
1488
|
-
const fromDate = dateRange?.start;
|
|
1489
|
-
const toDate = dateRange?.end;
|
|
1490
|
-
const messages = [];
|
|
1491
|
-
if (selectBy?.include?.length) {
|
|
1492
|
-
try {
|
|
1493
|
-
const includeMessages = await this._getIncludedMessages({ threadId, selectBy });
|
|
1494
|
-
if (includeMessages) {
|
|
1495
|
-
messages.push(...includeMessages);
|
|
1496
|
-
}
|
|
1497
|
-
} catch (error) {
|
|
1498
|
-
throw new MastraError(
|
|
1499
|
-
{
|
|
1500
|
-
id: "LIBSQL_STORE_GET_MESSAGES_PAGINATED_GET_INCLUDE_MESSAGES_FAILED",
|
|
1501
|
-
domain: ErrorDomain.STORAGE,
|
|
1502
|
-
category: ErrorCategory.THIRD_PARTY,
|
|
1503
|
-
details: { threadId }
|
|
1504
|
-
},
|
|
1505
|
-
error
|
|
1506
|
-
);
|
|
1507
|
-
}
|
|
1508
|
-
}
|
|
1980
|
+
async clearTable({ tableName }) {
|
|
1981
|
+
const parsedTableName = parseSqlIdentifier(tableName, "table name");
|
|
1509
1982
|
try {
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
const queryParams = [threadId];
|
|
1513
|
-
if (fromDate) {
|
|
1514
|
-
conditions.push(`"createdAt" >= ?`);
|
|
1515
|
-
queryParams.push(fromDate.toISOString());
|
|
1516
|
-
}
|
|
1517
|
-
if (toDate) {
|
|
1518
|
-
conditions.push(`"createdAt" <= ?`);
|
|
1519
|
-
queryParams.push(toDate.toISOString());
|
|
1520
|
-
}
|
|
1521
|
-
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1522
|
-
const countResult = await this.client.execute({
|
|
1523
|
-
sql: `SELECT COUNT(*) as count FROM ${TABLE_MESSAGES} ${whereClause}`,
|
|
1524
|
-
args: queryParams
|
|
1525
|
-
});
|
|
1526
|
-
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
1527
|
-
if (total === 0 && messages.length === 0) {
|
|
1528
|
-
return {
|
|
1529
|
-
messages: [],
|
|
1530
|
-
total: 0,
|
|
1531
|
-
page,
|
|
1532
|
-
perPage,
|
|
1533
|
-
hasMore: false
|
|
1534
|
-
};
|
|
1535
|
-
}
|
|
1536
|
-
const excludeIds = messages.map((m) => m.id);
|
|
1537
|
-
const excludeIdsParam = excludeIds.map((_, idx) => `$${idx + queryParams.length + 1}`).join(", ");
|
|
1538
|
-
const dataResult = await this.client.execute({
|
|
1539
|
-
sql: `SELECT id, content, role, type, "createdAt", "resourceId", "thread_id" FROM ${TABLE_MESSAGES} ${whereClause} ${excludeIds.length ? `AND id NOT IN (${excludeIdsParam})` : ""} ORDER BY "createdAt" DESC LIMIT ? OFFSET ?`,
|
|
1540
|
-
args: [...queryParams, ...excludeIds, perPage, currentOffset]
|
|
1541
|
-
});
|
|
1542
|
-
messages.push(...(dataResult.rows || []).map((row) => this.parseRow(row)));
|
|
1543
|
-
const messagesToReturn = format === "v1" ? new MessageList().add(messages, "memory").get.all.v1() : new MessageList().add(messages, "memory").get.all.v2();
|
|
1544
|
-
return {
|
|
1545
|
-
messages: messagesToReturn,
|
|
1546
|
-
total,
|
|
1547
|
-
page,
|
|
1548
|
-
perPage,
|
|
1549
|
-
hasMore: currentOffset + messages.length < total
|
|
1550
|
-
};
|
|
1551
|
-
} catch (error) {
|
|
1983
|
+
await this.client.execute(`DELETE FROM ${parsedTableName}`);
|
|
1984
|
+
} catch (e) {
|
|
1552
1985
|
const mastraError = new MastraError(
|
|
1553
1986
|
{
|
|
1554
|
-
id: "
|
|
1987
|
+
id: "LIBSQL_STORE_CLEAR_TABLE_FAILED",
|
|
1555
1988
|
domain: ErrorDomain.STORAGE,
|
|
1556
1989
|
category: ErrorCategory.THIRD_PARTY,
|
|
1557
|
-
details: {
|
|
1990
|
+
details: {
|
|
1991
|
+
tableName
|
|
1992
|
+
}
|
|
1558
1993
|
},
|
|
1559
|
-
|
|
1994
|
+
e
|
|
1560
1995
|
);
|
|
1561
1996
|
this.logger?.trackException?.(mastraError);
|
|
1562
1997
|
this.logger?.error?.(mastraError.toString());
|
|
1563
|
-
return { messages: [], total: 0, page, perPage, hasMore: false };
|
|
1564
1998
|
}
|
|
1565
1999
|
}
|
|
1566
|
-
async
|
|
1567
|
-
|
|
1568
|
-
format
|
|
1569
|
-
}) {
|
|
1570
|
-
if (messages.length === 0) return messages;
|
|
2000
|
+
async dropTable({ tableName }) {
|
|
2001
|
+
const parsedTableName = parseSqlIdentifier(tableName, "table name");
|
|
1571
2002
|
try {
|
|
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
|
-
|
|
1604
|
-
time instanceof Date ? time.toISOString() : time,
|
|
1605
|
-
message.resourceId
|
|
1606
|
-
]
|
|
1607
|
-
};
|
|
1608
|
-
});
|
|
1609
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1610
|
-
batchStatements.push({
|
|
1611
|
-
sql: `UPDATE ${TABLE_THREADS} SET updatedAt = ? WHERE id = ?`,
|
|
1612
|
-
args: [now, threadId]
|
|
2003
|
+
await this.client.execute(`DROP TABLE IF EXISTS ${parsedTableName}`);
|
|
2004
|
+
} catch (e) {
|
|
2005
|
+
throw new MastraError(
|
|
2006
|
+
{
|
|
2007
|
+
id: "LIBSQL_STORE_DROP_TABLE_FAILED",
|
|
2008
|
+
domain: ErrorDomain.STORAGE,
|
|
2009
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
2010
|
+
details: {
|
|
2011
|
+
tableName
|
|
2012
|
+
}
|
|
2013
|
+
},
|
|
2014
|
+
e
|
|
2015
|
+
);
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
};
|
|
2019
|
+
var ScoresLibSQL = class extends ScoresStorage {
|
|
2020
|
+
operations;
|
|
2021
|
+
client;
|
|
2022
|
+
constructor({ client, operations }) {
|
|
2023
|
+
super();
|
|
2024
|
+
this.operations = operations;
|
|
2025
|
+
this.client = client;
|
|
2026
|
+
}
|
|
2027
|
+
async getScoresByRunId({
|
|
2028
|
+
runId,
|
|
2029
|
+
pagination
|
|
2030
|
+
}) {
|
|
2031
|
+
try {
|
|
2032
|
+
const result = await this.client.execute({
|
|
2033
|
+
sql: `SELECT * FROM ${TABLE_SCORERS} WHERE runId = ? ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
|
|
2034
|
+
args: [runId, pagination.perPage + 1, pagination.page * pagination.perPage]
|
|
1613
2035
|
});
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
2036
|
+
return {
|
|
2037
|
+
scores: result.rows?.slice(0, pagination.perPage).map((row) => this.transformScoreRow(row)) ?? [],
|
|
2038
|
+
pagination: {
|
|
2039
|
+
total: result.rows?.length ?? 0,
|
|
2040
|
+
page: pagination.page,
|
|
2041
|
+
perPage: pagination.perPage,
|
|
2042
|
+
hasMore: result.rows?.length > pagination.perPage
|
|
2043
|
+
}
|
|
2044
|
+
};
|
|
1618
2045
|
} catch (error) {
|
|
1619
2046
|
throw new MastraError(
|
|
1620
2047
|
{
|
|
1621
|
-
id: "
|
|
2048
|
+
id: "LIBSQL_STORE_GET_SCORES_BY_RUN_ID_FAILED",
|
|
1622
2049
|
domain: ErrorDomain.STORAGE,
|
|
1623
2050
|
category: ErrorCategory.THIRD_PARTY
|
|
1624
2051
|
},
|
|
@@ -1626,185 +2053,151 @@ var LibSQLStore = class extends MastraStorage {
|
|
|
1626
2053
|
);
|
|
1627
2054
|
}
|
|
1628
2055
|
}
|
|
1629
|
-
async
|
|
1630
|
-
|
|
2056
|
+
async getScoresByScorerId({
|
|
2057
|
+
scorerId,
|
|
2058
|
+
entityId,
|
|
2059
|
+
entityType,
|
|
2060
|
+
source,
|
|
2061
|
+
pagination
|
|
1631
2062
|
}) {
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
const existingResult = await this.client.execute({ sql: selectSql, args: messageIds });
|
|
1639
|
-
const existingMessages = existingResult.rows.map((row) => this.parseRow(row));
|
|
1640
|
-
if (existingMessages.length === 0) {
|
|
1641
|
-
return [];
|
|
1642
|
-
}
|
|
1643
|
-
const batchStatements = [];
|
|
1644
|
-
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
1645
|
-
const columnMapping = {
|
|
1646
|
-
threadId: "thread_id"
|
|
1647
|
-
};
|
|
1648
|
-
for (const existingMessage of existingMessages) {
|
|
1649
|
-
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
1650
|
-
if (!updatePayload) continue;
|
|
1651
|
-
const { id, ...fieldsToUpdate } = updatePayload;
|
|
1652
|
-
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
1653
|
-
threadIdsToUpdate.add(existingMessage.threadId);
|
|
1654
|
-
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
1655
|
-
threadIdsToUpdate.add(updatePayload.threadId);
|
|
2063
|
+
try {
|
|
2064
|
+
const conditions = [];
|
|
2065
|
+
const queryParams = [];
|
|
2066
|
+
if (scorerId) {
|
|
2067
|
+
conditions.push(`scorerId = ?`);
|
|
2068
|
+
queryParams.push(scorerId);
|
|
1656
2069
|
}
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
if (updatableFields.content) {
|
|
1661
|
-
const newContent = {
|
|
1662
|
-
...existingMessage.content,
|
|
1663
|
-
...updatableFields.content,
|
|
1664
|
-
// Deep merge metadata if it exists on both
|
|
1665
|
-
...existingMessage.content?.metadata && updatableFields.content.metadata ? {
|
|
1666
|
-
metadata: {
|
|
1667
|
-
...existingMessage.content.metadata,
|
|
1668
|
-
...updatableFields.content.metadata
|
|
1669
|
-
}
|
|
1670
|
-
} : {}
|
|
1671
|
-
};
|
|
1672
|
-
setClauses.push(`${parseSqlIdentifier("content", "column name")} = ?`);
|
|
1673
|
-
args.push(JSON.stringify(newContent));
|
|
1674
|
-
delete updatableFields.content;
|
|
2070
|
+
if (entityId) {
|
|
2071
|
+
conditions.push(`entityId = ?`);
|
|
2072
|
+
queryParams.push(entityId);
|
|
1675
2073
|
}
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
setClauses.push(`${parseSqlIdentifier(dbKey, "column name")} = ?`);
|
|
1680
|
-
let value = updatableFields[key];
|
|
1681
|
-
if (typeof value === "object" && value !== null) {
|
|
1682
|
-
value = JSON.stringify(value);
|
|
1683
|
-
}
|
|
1684
|
-
args.push(value);
|
|
1685
|
-
}
|
|
2074
|
+
if (entityType) {
|
|
2075
|
+
conditions.push(`entityType = ?`);
|
|
2076
|
+
queryParams.push(entityType);
|
|
1686
2077
|
}
|
|
1687
|
-
if (
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
batchStatements.push({ sql, args });
|
|
1691
|
-
}
|
|
1692
|
-
if (batchStatements.length === 0) {
|
|
1693
|
-
return existingMessages;
|
|
1694
|
-
}
|
|
1695
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1696
|
-
for (const threadId of threadIdsToUpdate) {
|
|
1697
|
-
if (threadId) {
|
|
1698
|
-
batchStatements.push({
|
|
1699
|
-
sql: `UPDATE ${TABLE_THREADS} SET updatedAt = ? WHERE id = ?`,
|
|
1700
|
-
args: [now, threadId]
|
|
1701
|
-
});
|
|
2078
|
+
if (source) {
|
|
2079
|
+
conditions.push(`source = ?`);
|
|
2080
|
+
queryParams.push(source);
|
|
1702
2081
|
}
|
|
2082
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2083
|
+
const result = await this.client.execute({
|
|
2084
|
+
sql: `SELECT * FROM ${TABLE_SCORERS} ${whereClause} ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
|
|
2085
|
+
args: [...queryParams, pagination.perPage + 1, pagination.page * pagination.perPage]
|
|
2086
|
+
});
|
|
2087
|
+
return {
|
|
2088
|
+
scores: result.rows?.slice(0, pagination.perPage).map((row) => this.transformScoreRow(row)) ?? [],
|
|
2089
|
+
pagination: {
|
|
2090
|
+
total: result.rows?.length ?? 0,
|
|
2091
|
+
page: pagination.page,
|
|
2092
|
+
perPage: pagination.perPage,
|
|
2093
|
+
hasMore: result.rows?.length > pagination.perPage
|
|
2094
|
+
}
|
|
2095
|
+
};
|
|
2096
|
+
} catch (error) {
|
|
2097
|
+
throw new MastraError(
|
|
2098
|
+
{
|
|
2099
|
+
id: "LIBSQL_STORE_GET_SCORES_BY_SCORER_ID_FAILED",
|
|
2100
|
+
domain: ErrorDomain.STORAGE,
|
|
2101
|
+
category: ErrorCategory.THIRD_PARTY
|
|
2102
|
+
},
|
|
2103
|
+
error
|
|
2104
|
+
);
|
|
1703
2105
|
}
|
|
1704
|
-
await this.client.batch(batchStatements, "write");
|
|
1705
|
-
const updatedResult = await this.client.execute({ sql: selectSql, args: messageIds });
|
|
1706
|
-
return updatedResult.rows.map((row) => this.parseRow(row));
|
|
1707
2106
|
}
|
|
1708
|
-
|
|
1709
|
-
const
|
|
1710
|
-
const
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
2107
|
+
transformScoreRow(row) {
|
|
2108
|
+
const scorerValue = safelyParseJSON(row.scorer);
|
|
2109
|
+
const inputValue = safelyParseJSON(row.input ?? "{}");
|
|
2110
|
+
const outputValue = safelyParseJSON(row.output ?? "{}");
|
|
2111
|
+
const additionalLLMContextValue = row.additionalLLMContext ? safelyParseJSON(row.additionalLLMContext) : null;
|
|
2112
|
+
const runtimeContextValue = row.runtimeContext ? safelyParseJSON(row.runtimeContext) : null;
|
|
2113
|
+
const metadataValue = row.metadata ? safelyParseJSON(row.metadata) : null;
|
|
2114
|
+
const entityValue = row.entity ? safelyParseJSON(row.entity) : null;
|
|
2115
|
+
const preprocessStepResultValue = row.preprocessStepResult ? safelyParseJSON(row.preprocessStepResult) : null;
|
|
2116
|
+
const analyzeStepResultValue = row.analyzeStepResult ? safelyParseJSON(row.analyzeStepResult) : null;
|
|
1714
2117
|
return {
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
2118
|
+
id: row.id,
|
|
2119
|
+
traceId: row.traceId,
|
|
2120
|
+
runId: row.runId,
|
|
2121
|
+
scorer: scorerValue,
|
|
2122
|
+
score: row.score,
|
|
2123
|
+
reason: row.reason,
|
|
2124
|
+
preprocessStepResult: preprocessStepResultValue,
|
|
2125
|
+
analyzeStepResult: analyzeStepResultValue,
|
|
2126
|
+
analyzePrompt: row.analyzePrompt,
|
|
2127
|
+
preprocessPrompt: row.preprocessPrompt,
|
|
2128
|
+
generateScorePrompt: row.generateScorePrompt,
|
|
2129
|
+
generateReasonPrompt: row.generateReasonPrompt,
|
|
2130
|
+
metadata: metadataValue,
|
|
2131
|
+
input: inputValue,
|
|
2132
|
+
output: outputValue,
|
|
2133
|
+
additionalContext: additionalLLMContextValue,
|
|
2134
|
+
runtimeContext: runtimeContextValue,
|
|
2135
|
+
entityType: row.entityType,
|
|
2136
|
+
entity: entityValue,
|
|
2137
|
+
entityId: row.entityId,
|
|
2138
|
+
scorerId: row.scorerId,
|
|
2139
|
+
source: row.source,
|
|
2140
|
+
resourceId: row.resourceId,
|
|
2141
|
+
threadId: row.threadId,
|
|
2142
|
+
createdAt: row.createdAt,
|
|
2143
|
+
updatedAt: row.updatedAt
|
|
1725
2144
|
};
|
|
1726
2145
|
}
|
|
1727
|
-
|
|
1728
|
-
|
|
2146
|
+
async getScoreById({ id }) {
|
|
2147
|
+
const result = await this.client.execute({
|
|
2148
|
+
sql: `SELECT * FROM ${TABLE_SCORERS} WHERE id = ?`,
|
|
2149
|
+
args: [id]
|
|
2150
|
+
});
|
|
2151
|
+
return result.rows?.[0] ? this.transformScoreRow(result.rows[0]) : null;
|
|
2152
|
+
}
|
|
2153
|
+
async saveScore(score) {
|
|
1729
2154
|
try {
|
|
1730
|
-
const
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
2155
|
+
const id = crypto.randomUUID();
|
|
2156
|
+
await this.operations.insert({
|
|
2157
|
+
tableName: TABLE_SCORERS,
|
|
2158
|
+
record: {
|
|
2159
|
+
id,
|
|
2160
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2161
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2162
|
+
...score
|
|
2163
|
+
}
|
|
1735
2164
|
});
|
|
1736
|
-
|
|
2165
|
+
const scoreFromDb = await this.getScoreById({ id });
|
|
2166
|
+
return { score: scoreFromDb };
|
|
1737
2167
|
} catch (error) {
|
|
1738
|
-
if (error instanceof Error && error.message.includes("no such table")) {
|
|
1739
|
-
return [];
|
|
1740
|
-
}
|
|
1741
2168
|
throw new MastraError(
|
|
1742
2169
|
{
|
|
1743
|
-
id: "
|
|
2170
|
+
id: "LIBSQL_STORE_SAVE_SCORE_FAILED",
|
|
1744
2171
|
domain: ErrorDomain.STORAGE,
|
|
1745
|
-
category: ErrorCategory.THIRD_PARTY
|
|
1746
|
-
details: { agentName }
|
|
2172
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1747
2173
|
},
|
|
1748
2174
|
error
|
|
1749
2175
|
);
|
|
1750
2176
|
}
|
|
1751
2177
|
}
|
|
1752
|
-
async
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
const queryParams = [];
|
|
1758
|
-
if (agentName) {
|
|
1759
|
-
conditions.push(`agent_name = ?`);
|
|
1760
|
-
queryParams.push(agentName);
|
|
1761
|
-
}
|
|
1762
|
-
if (type === "test") {
|
|
1763
|
-
conditions.push(`(test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL)`);
|
|
1764
|
-
} else if (type === "live") {
|
|
1765
|
-
conditions.push(`(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)`);
|
|
1766
|
-
}
|
|
1767
|
-
if (fromDate) {
|
|
1768
|
-
conditions.push(`created_at >= ?`);
|
|
1769
|
-
queryParams.push(fromDate.toISOString());
|
|
1770
|
-
}
|
|
1771
|
-
if (toDate) {
|
|
1772
|
-
conditions.push(`created_at <= ?`);
|
|
1773
|
-
queryParams.push(toDate.toISOString());
|
|
1774
|
-
}
|
|
1775
|
-
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2178
|
+
async getScoresByEntityId({
|
|
2179
|
+
entityId,
|
|
2180
|
+
entityType,
|
|
2181
|
+
pagination
|
|
2182
|
+
}) {
|
|
1776
2183
|
try {
|
|
1777
|
-
const
|
|
1778
|
-
sql: `SELECT
|
|
1779
|
-
args:
|
|
1780
|
-
});
|
|
1781
|
-
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
1782
|
-
const currentOffset = page * perPage;
|
|
1783
|
-
const hasMore = currentOffset + perPage < total;
|
|
1784
|
-
if (total === 0) {
|
|
1785
|
-
return {
|
|
1786
|
-
evals: [],
|
|
1787
|
-
total: 0,
|
|
1788
|
-
page,
|
|
1789
|
-
perPage,
|
|
1790
|
-
hasMore: false
|
|
1791
|
-
};
|
|
1792
|
-
}
|
|
1793
|
-
const dataResult = await this.client.execute({
|
|
1794
|
-
sql: `SELECT * FROM ${TABLE_EVALS} ${whereClause} ORDER BY created_at DESC LIMIT ? OFFSET ?`,
|
|
1795
|
-
args: [...queryParams, perPage, currentOffset]
|
|
2184
|
+
const result = await this.client.execute({
|
|
2185
|
+
sql: `SELECT * FROM ${TABLE_SCORERS} WHERE entityId = ? AND entityType = ? ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
|
|
2186
|
+
args: [entityId, entityType, pagination.perPage + 1, pagination.page * pagination.perPage]
|
|
1796
2187
|
});
|
|
1797
2188
|
return {
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
2189
|
+
scores: result.rows?.slice(0, pagination.perPage).map((row) => this.transformScoreRow(row)) ?? [],
|
|
2190
|
+
pagination: {
|
|
2191
|
+
total: result.rows?.length ?? 0,
|
|
2192
|
+
page: pagination.page,
|
|
2193
|
+
perPage: pagination.perPage,
|
|
2194
|
+
hasMore: result.rows?.length > pagination.perPage
|
|
2195
|
+
}
|
|
1803
2196
|
};
|
|
1804
2197
|
} catch (error) {
|
|
1805
2198
|
throw new MastraError(
|
|
1806
2199
|
{
|
|
1807
|
-
id: "
|
|
2200
|
+
id: "LIBSQL_STORE_GET_SCORES_BY_ENTITY_ID_FAILED",
|
|
1808
2201
|
domain: ErrorDomain.STORAGE,
|
|
1809
2202
|
category: ErrorCategory.THIRD_PARTY
|
|
1810
2203
|
},
|
|
@@ -1812,9 +2205,15 @@ var LibSQLStore = class extends MastraStorage {
|
|
|
1812
2205
|
);
|
|
1813
2206
|
}
|
|
1814
2207
|
}
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
2208
|
+
};
|
|
2209
|
+
var TracesLibSQL = class extends TracesStorage {
|
|
2210
|
+
client;
|
|
2211
|
+
operations;
|
|
2212
|
+
constructor({ client, operations }) {
|
|
2213
|
+
super();
|
|
2214
|
+
this.client = client;
|
|
2215
|
+
this.operations = operations;
|
|
2216
|
+
}
|
|
1818
2217
|
async getTraces(args) {
|
|
1819
2218
|
if (args.fromDate || args.toDate) {
|
|
1820
2219
|
args.dateRange = {
|
|
@@ -1891,35 +2290,133 @@ var LibSQLStore = class extends MastraStorage {
|
|
|
1891
2290
|
sql: `SELECT * FROM ${TABLE_TRACES} ${whereClause} ORDER BY "startTime" DESC LIMIT ? OFFSET ?`,
|
|
1892
2291
|
args: [...queryArgs, perPage, currentOffset]
|
|
1893
2292
|
});
|
|
1894
|
-
const traces = dataResult.rows?.map(
|
|
1895
|
-
(row) => ({
|
|
1896
|
-
id: row.id,
|
|
1897
|
-
parentSpanId: row.parentSpanId,
|
|
1898
|
-
traceId: row.traceId,
|
|
1899
|
-
name: row.name,
|
|
1900
|
-
scope: row.scope,
|
|
1901
|
-
kind: row.kind,
|
|
1902
|
-
status: safelyParseJSON(row.status),
|
|
1903
|
-
events: safelyParseJSON(row.events),
|
|
1904
|
-
links: safelyParseJSON(row.links),
|
|
1905
|
-
attributes: safelyParseJSON(row.attributes),
|
|
1906
|
-
startTime: row.startTime,
|
|
1907
|
-
endTime: row.endTime,
|
|
1908
|
-
other: safelyParseJSON(row.other),
|
|
1909
|
-
createdAt: row.createdAt
|
|
1910
|
-
})
|
|
1911
|
-
) ?? [];
|
|
1912
|
-
return {
|
|
1913
|
-
traces,
|
|
1914
|
-
total,
|
|
1915
|
-
page,
|
|
1916
|
-
perPage,
|
|
1917
|
-
hasMore: currentOffset + traces.length < total
|
|
1918
|
-
};
|
|
2293
|
+
const traces = dataResult.rows?.map(
|
|
2294
|
+
(row) => ({
|
|
2295
|
+
id: row.id,
|
|
2296
|
+
parentSpanId: row.parentSpanId,
|
|
2297
|
+
traceId: row.traceId,
|
|
2298
|
+
name: row.name,
|
|
2299
|
+
scope: row.scope,
|
|
2300
|
+
kind: row.kind,
|
|
2301
|
+
status: safelyParseJSON(row.status),
|
|
2302
|
+
events: safelyParseJSON(row.events),
|
|
2303
|
+
links: safelyParseJSON(row.links),
|
|
2304
|
+
attributes: safelyParseJSON(row.attributes),
|
|
2305
|
+
startTime: row.startTime,
|
|
2306
|
+
endTime: row.endTime,
|
|
2307
|
+
other: safelyParseJSON(row.other),
|
|
2308
|
+
createdAt: row.createdAt
|
|
2309
|
+
})
|
|
2310
|
+
) ?? [];
|
|
2311
|
+
return {
|
|
2312
|
+
traces,
|
|
2313
|
+
total,
|
|
2314
|
+
page,
|
|
2315
|
+
perPage,
|
|
2316
|
+
hasMore: currentOffset + traces.length < total
|
|
2317
|
+
};
|
|
2318
|
+
} catch (error) {
|
|
2319
|
+
throw new MastraError(
|
|
2320
|
+
{
|
|
2321
|
+
id: "LIBSQL_STORE_GET_TRACES_PAGINATED_FAILED",
|
|
2322
|
+
domain: ErrorDomain.STORAGE,
|
|
2323
|
+
category: ErrorCategory.THIRD_PARTY
|
|
2324
|
+
},
|
|
2325
|
+
error
|
|
2326
|
+
);
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
async batchTraceInsert({ records }) {
|
|
2330
|
+
this.logger.debug("Batch inserting traces", { count: records.length });
|
|
2331
|
+
await this.operations.batchInsert({
|
|
2332
|
+
tableName: TABLE_TRACES,
|
|
2333
|
+
records
|
|
2334
|
+
});
|
|
2335
|
+
}
|
|
2336
|
+
};
|
|
2337
|
+
function parseWorkflowRun(row) {
|
|
2338
|
+
let parsedSnapshot = row.snapshot;
|
|
2339
|
+
if (typeof parsedSnapshot === "string") {
|
|
2340
|
+
try {
|
|
2341
|
+
parsedSnapshot = JSON.parse(row.snapshot);
|
|
2342
|
+
} catch (e) {
|
|
2343
|
+
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
return {
|
|
2347
|
+
workflowName: row.workflow_name,
|
|
2348
|
+
runId: row.run_id,
|
|
2349
|
+
snapshot: parsedSnapshot,
|
|
2350
|
+
resourceId: row.resourceId,
|
|
2351
|
+
createdAt: new Date(row.createdAt),
|
|
2352
|
+
updatedAt: new Date(row.updatedAt)
|
|
2353
|
+
};
|
|
2354
|
+
}
|
|
2355
|
+
var WorkflowsLibSQL = class extends WorkflowsStorage {
|
|
2356
|
+
operations;
|
|
2357
|
+
client;
|
|
2358
|
+
constructor({ operations, client }) {
|
|
2359
|
+
super();
|
|
2360
|
+
this.operations = operations;
|
|
2361
|
+
this.client = client;
|
|
2362
|
+
}
|
|
2363
|
+
async persistWorkflowSnapshot({
|
|
2364
|
+
workflowName,
|
|
2365
|
+
runId,
|
|
2366
|
+
snapshot
|
|
2367
|
+
}) {
|
|
2368
|
+
const data = {
|
|
2369
|
+
workflow_name: workflowName,
|
|
2370
|
+
run_id: runId,
|
|
2371
|
+
snapshot,
|
|
2372
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
2373
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
2374
|
+
};
|
|
2375
|
+
this.logger.debug("Persisting workflow snapshot", { workflowName, runId, data });
|
|
2376
|
+
await this.operations.insert({
|
|
2377
|
+
tableName: TABLE_WORKFLOW_SNAPSHOT,
|
|
2378
|
+
record: data
|
|
2379
|
+
});
|
|
2380
|
+
}
|
|
2381
|
+
async loadWorkflowSnapshot({
|
|
2382
|
+
workflowName,
|
|
2383
|
+
runId
|
|
2384
|
+
}) {
|
|
2385
|
+
this.logger.debug("Loading workflow snapshot", { workflowName, runId });
|
|
2386
|
+
const d = await this.operations.load({
|
|
2387
|
+
tableName: TABLE_WORKFLOW_SNAPSHOT,
|
|
2388
|
+
keys: { workflow_name: workflowName, run_id: runId }
|
|
2389
|
+
});
|
|
2390
|
+
return d ? d.snapshot : null;
|
|
2391
|
+
}
|
|
2392
|
+
async getWorkflowRunById({
|
|
2393
|
+
runId,
|
|
2394
|
+
workflowName
|
|
2395
|
+
}) {
|
|
2396
|
+
const conditions = [];
|
|
2397
|
+
const args = [];
|
|
2398
|
+
if (runId) {
|
|
2399
|
+
conditions.push("run_id = ?");
|
|
2400
|
+
args.push(runId);
|
|
2401
|
+
}
|
|
2402
|
+
if (workflowName) {
|
|
2403
|
+
conditions.push("workflow_name = ?");
|
|
2404
|
+
args.push(workflowName);
|
|
2405
|
+
}
|
|
2406
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2407
|
+
try {
|
|
2408
|
+
const result = await this.client.execute({
|
|
2409
|
+
sql: `SELECT * FROM ${TABLE_WORKFLOW_SNAPSHOT} ${whereClause}`,
|
|
2410
|
+
args
|
|
2411
|
+
});
|
|
2412
|
+
if (!result.rows?.[0]) {
|
|
2413
|
+
return null;
|
|
2414
|
+
}
|
|
2415
|
+
return parseWorkflowRun(result.rows[0]);
|
|
1919
2416
|
} catch (error) {
|
|
1920
2417
|
throw new MastraError(
|
|
1921
2418
|
{
|
|
1922
|
-
id: "
|
|
2419
|
+
id: "LIBSQL_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
|
|
1923
2420
|
domain: ErrorDomain.STORAGE,
|
|
1924
2421
|
category: ErrorCategory.THIRD_PARTY
|
|
1925
2422
|
},
|
|
@@ -1951,7 +2448,7 @@ var LibSQLStore = class extends MastraStorage {
|
|
|
1951
2448
|
args.push(toDate.toISOString());
|
|
1952
2449
|
}
|
|
1953
2450
|
if (resourceId) {
|
|
1954
|
-
const hasResourceId = await this.hasColumn(TABLE_WORKFLOW_SNAPSHOT, "resourceId");
|
|
2451
|
+
const hasResourceId = await this.operations.hasColumn(TABLE_WORKFLOW_SNAPSHOT, "resourceId");
|
|
1955
2452
|
if (hasResourceId) {
|
|
1956
2453
|
conditions.push("resourceId = ?");
|
|
1957
2454
|
args.push(resourceId);
|
|
@@ -1972,7 +2469,7 @@ var LibSQLStore = class extends MastraStorage {
|
|
|
1972
2469
|
sql: `SELECT * FROM ${TABLE_WORKFLOW_SNAPSHOT} ${whereClause} ORDER BY createdAt DESC${limit !== void 0 && offset !== void 0 ? ` LIMIT ? OFFSET ?` : ""}`,
|
|
1973
2470
|
args: limit !== void 0 && offset !== void 0 ? [...args, limit, offset] : args
|
|
1974
2471
|
});
|
|
1975
|
-
const runs = (result.rows || []).map((row) =>
|
|
2472
|
+
const runs = (result.rows || []).map((row) => parseWorkflowRun(row));
|
|
1976
2473
|
return { runs, total: total || runs.length };
|
|
1977
2474
|
} catch (error) {
|
|
1978
2475
|
throw new MastraError(
|
|
@@ -1985,133 +2482,235 @@ var LibSQLStore = class extends MastraStorage {
|
|
|
1985
2482
|
);
|
|
1986
2483
|
}
|
|
1987
2484
|
}
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
}
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2485
|
+
};
|
|
2486
|
+
|
|
2487
|
+
// src/storage/index.ts
|
|
2488
|
+
var LibSQLStore = class extends MastraStorage {
|
|
2489
|
+
client;
|
|
2490
|
+
maxRetries;
|
|
2491
|
+
initialBackoffMs;
|
|
2492
|
+
stores;
|
|
2493
|
+
constructor(config) {
|
|
2494
|
+
super({ name: `LibSQLStore` });
|
|
2495
|
+
this.maxRetries = config.maxRetries ?? 5;
|
|
2496
|
+
this.initialBackoffMs = config.initialBackoffMs ?? 100;
|
|
2497
|
+
if ("url" in config) {
|
|
2498
|
+
if (config.url.endsWith(":memory:")) {
|
|
2499
|
+
this.shouldCacheInit = false;
|
|
2500
|
+
}
|
|
2501
|
+
this.client = createClient({
|
|
2502
|
+
url: config.url,
|
|
2503
|
+
...config.authToken ? { authToken: config.authToken } : {}
|
|
2007
2504
|
});
|
|
2008
|
-
if (
|
|
2009
|
-
|
|
2505
|
+
if (config.url.startsWith("file:") || config.url.includes(":memory:")) {
|
|
2506
|
+
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));
|
|
2507
|
+
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));
|
|
2010
2508
|
}
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
throw new MastraError(
|
|
2014
|
-
{
|
|
2015
|
-
id: "LIBSQL_STORE_GET_WORKFLOW_RUN_BY_ID_FAILED",
|
|
2016
|
-
domain: ErrorDomain.STORAGE,
|
|
2017
|
-
category: ErrorCategory.THIRD_PARTY
|
|
2018
|
-
},
|
|
2019
|
-
error
|
|
2020
|
-
);
|
|
2509
|
+
} else {
|
|
2510
|
+
this.client = config.client;
|
|
2021
2511
|
}
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
keys: { id: resourceId }
|
|
2512
|
+
const operations = new StoreOperationsLibSQL({
|
|
2513
|
+
client: this.client,
|
|
2514
|
+
maxRetries: this.maxRetries,
|
|
2515
|
+
initialBackoffMs: this.initialBackoffMs
|
|
2027
2516
|
});
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
}
|
|
2517
|
+
const scores = new ScoresLibSQL({ client: this.client, operations });
|
|
2518
|
+
const traces = new TracesLibSQL({ client: this.client, operations });
|
|
2519
|
+
const workflows = new WorkflowsLibSQL({ client: this.client, operations });
|
|
2520
|
+
const memory = new MemoryLibSQL({ client: this.client, operations });
|
|
2521
|
+
const legacyEvals = new LegacyEvalsLibSQL({ client: this.client });
|
|
2522
|
+
this.stores = {
|
|
2523
|
+
operations,
|
|
2524
|
+
scores,
|
|
2525
|
+
traces,
|
|
2526
|
+
workflows,
|
|
2527
|
+
memory,
|
|
2528
|
+
legacyEvals
|
|
2529
|
+
};
|
|
2530
|
+
}
|
|
2531
|
+
get supports() {
|
|
2031
2532
|
return {
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2533
|
+
selectByIncludeResourceScope: true,
|
|
2534
|
+
resourceWorkingMemory: true,
|
|
2535
|
+
hasColumn: true,
|
|
2536
|
+
createTable: true,
|
|
2537
|
+
deleteMessages: true
|
|
2036
2538
|
};
|
|
2037
2539
|
}
|
|
2540
|
+
async createTable({
|
|
2541
|
+
tableName,
|
|
2542
|
+
schema
|
|
2543
|
+
}) {
|
|
2544
|
+
await this.stores.operations.createTable({ tableName, schema });
|
|
2545
|
+
}
|
|
2546
|
+
/**
|
|
2547
|
+
* Alters table schema to add columns if they don't exist
|
|
2548
|
+
* @param tableName Name of the table
|
|
2549
|
+
* @param schema Schema of the table
|
|
2550
|
+
* @param ifNotExists Array of column names to add if they don't exist
|
|
2551
|
+
*/
|
|
2552
|
+
async alterTable({
|
|
2553
|
+
tableName,
|
|
2554
|
+
schema,
|
|
2555
|
+
ifNotExists
|
|
2556
|
+
}) {
|
|
2557
|
+
await this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
2558
|
+
}
|
|
2559
|
+
async clearTable({ tableName }) {
|
|
2560
|
+
await this.stores.operations.clearTable({ tableName });
|
|
2561
|
+
}
|
|
2562
|
+
async dropTable({ tableName }) {
|
|
2563
|
+
await this.stores.operations.dropTable({ tableName });
|
|
2564
|
+
}
|
|
2565
|
+
insert(args) {
|
|
2566
|
+
return this.stores.operations.insert(args);
|
|
2567
|
+
}
|
|
2568
|
+
batchInsert(args) {
|
|
2569
|
+
return this.stores.operations.batchInsert(args);
|
|
2570
|
+
}
|
|
2571
|
+
async load({ tableName, keys }) {
|
|
2572
|
+
return this.stores.operations.load({ tableName, keys });
|
|
2573
|
+
}
|
|
2574
|
+
async getThreadById({ threadId }) {
|
|
2575
|
+
return this.stores.memory.getThreadById({ threadId });
|
|
2576
|
+
}
|
|
2577
|
+
/**
|
|
2578
|
+
* @deprecated use getThreadsByResourceIdPaginated instead for paginated results.
|
|
2579
|
+
*/
|
|
2580
|
+
async getThreadsByResourceId(args) {
|
|
2581
|
+
return this.stores.memory.getThreadsByResourceId(args);
|
|
2582
|
+
}
|
|
2583
|
+
async getThreadsByResourceIdPaginated(args) {
|
|
2584
|
+
return this.stores.memory.getThreadsByResourceIdPaginated(args);
|
|
2585
|
+
}
|
|
2586
|
+
async saveThread({ thread }) {
|
|
2587
|
+
return this.stores.memory.saveThread({ thread });
|
|
2588
|
+
}
|
|
2589
|
+
async updateThread({
|
|
2590
|
+
id,
|
|
2591
|
+
title,
|
|
2592
|
+
metadata
|
|
2593
|
+
}) {
|
|
2594
|
+
return this.stores.memory.updateThread({ id, title, metadata });
|
|
2595
|
+
}
|
|
2596
|
+
async deleteThread({ threadId }) {
|
|
2597
|
+
return this.stores.memory.deleteThread({ threadId });
|
|
2598
|
+
}
|
|
2599
|
+
async getMessages({
|
|
2600
|
+
threadId,
|
|
2601
|
+
selectBy,
|
|
2602
|
+
format
|
|
2603
|
+
}) {
|
|
2604
|
+
return this.stores.memory.getMessages({ threadId, selectBy, format });
|
|
2605
|
+
}
|
|
2606
|
+
async getMessagesPaginated(args) {
|
|
2607
|
+
return this.stores.memory.getMessagesPaginated(args);
|
|
2608
|
+
}
|
|
2609
|
+
async saveMessages(args) {
|
|
2610
|
+
return this.stores.memory.saveMessages(args);
|
|
2611
|
+
}
|
|
2612
|
+
async updateMessages({
|
|
2613
|
+
messages
|
|
2614
|
+
}) {
|
|
2615
|
+
return this.stores.memory.updateMessages({ messages });
|
|
2616
|
+
}
|
|
2617
|
+
async deleteMessages(messageIds) {
|
|
2618
|
+
return this.stores.memory.deleteMessages(messageIds);
|
|
2619
|
+
}
|
|
2620
|
+
/** @deprecated use getEvals instead */
|
|
2621
|
+
async getEvalsByAgentName(agentName, type) {
|
|
2622
|
+
return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
|
|
2623
|
+
}
|
|
2624
|
+
async getEvals(options = {}) {
|
|
2625
|
+
return this.stores.legacyEvals.getEvals(options);
|
|
2626
|
+
}
|
|
2627
|
+
async getScoreById({ id }) {
|
|
2628
|
+
return this.stores.scores.getScoreById({ id });
|
|
2629
|
+
}
|
|
2630
|
+
async saveScore(score) {
|
|
2631
|
+
return this.stores.scores.saveScore(score);
|
|
2632
|
+
}
|
|
2633
|
+
async getScoresByScorerId({
|
|
2634
|
+
scorerId,
|
|
2635
|
+
entityId,
|
|
2636
|
+
entityType,
|
|
2637
|
+
source,
|
|
2638
|
+
pagination
|
|
2639
|
+
}) {
|
|
2640
|
+
return this.stores.scores.getScoresByScorerId({ scorerId, entityId, entityType, source, pagination });
|
|
2641
|
+
}
|
|
2642
|
+
async getScoresByRunId({
|
|
2643
|
+
runId,
|
|
2644
|
+
pagination
|
|
2645
|
+
}) {
|
|
2646
|
+
return this.stores.scores.getScoresByRunId({ runId, pagination });
|
|
2647
|
+
}
|
|
2648
|
+
async getScoresByEntityId({
|
|
2649
|
+
entityId,
|
|
2650
|
+
entityType,
|
|
2651
|
+
pagination
|
|
2652
|
+
}) {
|
|
2653
|
+
return this.stores.scores.getScoresByEntityId({ entityId, entityType, pagination });
|
|
2654
|
+
}
|
|
2655
|
+
/**
|
|
2656
|
+
* TRACES
|
|
2657
|
+
*/
|
|
2658
|
+
/**
|
|
2659
|
+
* @deprecated use getTracesPaginated instead.
|
|
2660
|
+
*/
|
|
2661
|
+
async getTraces(args) {
|
|
2662
|
+
return this.stores.traces.getTraces(args);
|
|
2663
|
+
}
|
|
2664
|
+
async getTracesPaginated(args) {
|
|
2665
|
+
return this.stores.traces.getTracesPaginated(args);
|
|
2666
|
+
}
|
|
2667
|
+
async batchTraceInsert(args) {
|
|
2668
|
+
return this.stores.traces.batchTraceInsert(args);
|
|
2669
|
+
}
|
|
2670
|
+
/**
|
|
2671
|
+
* WORKFLOWS
|
|
2672
|
+
*/
|
|
2673
|
+
async persistWorkflowSnapshot({
|
|
2674
|
+
workflowName,
|
|
2675
|
+
runId,
|
|
2676
|
+
snapshot
|
|
2677
|
+
}) {
|
|
2678
|
+
return this.stores.workflows.persistWorkflowSnapshot({ workflowName, runId, snapshot });
|
|
2679
|
+
}
|
|
2680
|
+
async loadWorkflowSnapshot({
|
|
2681
|
+
workflowName,
|
|
2682
|
+
runId
|
|
2683
|
+
}) {
|
|
2684
|
+
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
2685
|
+
}
|
|
2686
|
+
async getWorkflowRuns({
|
|
2687
|
+
workflowName,
|
|
2688
|
+
fromDate,
|
|
2689
|
+
toDate,
|
|
2690
|
+
limit,
|
|
2691
|
+
offset,
|
|
2692
|
+
resourceId
|
|
2693
|
+
} = {}) {
|
|
2694
|
+
return this.stores.workflows.getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
|
|
2695
|
+
}
|
|
2696
|
+
async getWorkflowRunById({
|
|
2697
|
+
runId,
|
|
2698
|
+
workflowName
|
|
2699
|
+
}) {
|
|
2700
|
+
return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
|
|
2701
|
+
}
|
|
2702
|
+
async getResourceById({ resourceId }) {
|
|
2703
|
+
return this.stores.memory.getResourceById({ resourceId });
|
|
2704
|
+
}
|
|
2038
2705
|
async saveResource({ resource }) {
|
|
2039
|
-
|
|
2040
|
-
tableName: TABLE_RESOURCES,
|
|
2041
|
-
record: {
|
|
2042
|
-
...resource,
|
|
2043
|
-
metadata: JSON.stringify(resource.metadata)
|
|
2044
|
-
}
|
|
2045
|
-
});
|
|
2046
|
-
return resource;
|
|
2706
|
+
return this.stores.memory.saveResource({ resource });
|
|
2047
2707
|
}
|
|
2048
2708
|
async updateResource({
|
|
2049
2709
|
resourceId,
|
|
2050
2710
|
workingMemory,
|
|
2051
2711
|
metadata
|
|
2052
2712
|
}) {
|
|
2053
|
-
|
|
2054
|
-
if (!existingResource) {
|
|
2055
|
-
const newResource = {
|
|
2056
|
-
id: resourceId,
|
|
2057
|
-
workingMemory,
|
|
2058
|
-
metadata: metadata || {},
|
|
2059
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
2060
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
2061
|
-
};
|
|
2062
|
-
return this.saveResource({ resource: newResource });
|
|
2063
|
-
}
|
|
2064
|
-
const updatedResource = {
|
|
2065
|
-
...existingResource,
|
|
2066
|
-
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
2067
|
-
metadata: {
|
|
2068
|
-
...existingResource.metadata,
|
|
2069
|
-
...metadata
|
|
2070
|
-
},
|
|
2071
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
2072
|
-
};
|
|
2073
|
-
const updates = [];
|
|
2074
|
-
const values = [];
|
|
2075
|
-
if (workingMemory !== void 0) {
|
|
2076
|
-
updates.push("workingMemory = ?");
|
|
2077
|
-
values.push(workingMemory);
|
|
2078
|
-
}
|
|
2079
|
-
if (metadata) {
|
|
2080
|
-
updates.push("metadata = ?");
|
|
2081
|
-
values.push(JSON.stringify(updatedResource.metadata));
|
|
2082
|
-
}
|
|
2083
|
-
updates.push("updatedAt = ?");
|
|
2084
|
-
values.push(updatedResource.updatedAt.toISOString());
|
|
2085
|
-
values.push(resourceId);
|
|
2086
|
-
await this.client.execute({
|
|
2087
|
-
sql: `UPDATE ${TABLE_RESOURCES} SET ${updates.join(", ")} WHERE id = ?`,
|
|
2088
|
-
args: values
|
|
2089
|
-
});
|
|
2090
|
-
return updatedResource;
|
|
2091
|
-
}
|
|
2092
|
-
async hasColumn(table, column) {
|
|
2093
|
-
const result = await this.client.execute({
|
|
2094
|
-
sql: `PRAGMA table_info(${table})`
|
|
2095
|
-
});
|
|
2096
|
-
return (await result.rows)?.some((row) => row.name === column);
|
|
2097
|
-
}
|
|
2098
|
-
parseWorkflowRun(row) {
|
|
2099
|
-
let parsedSnapshot = row.snapshot;
|
|
2100
|
-
if (typeof parsedSnapshot === "string") {
|
|
2101
|
-
try {
|
|
2102
|
-
parsedSnapshot = JSON.parse(row.snapshot);
|
|
2103
|
-
} catch (e) {
|
|
2104
|
-
console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
|
|
2105
|
-
}
|
|
2106
|
-
}
|
|
2107
|
-
return {
|
|
2108
|
-
workflowName: row.workflow_name,
|
|
2109
|
-
runId: row.run_id,
|
|
2110
|
-
snapshot: parsedSnapshot,
|
|
2111
|
-
resourceId: row.resourceId,
|
|
2112
|
-
createdAt: new Date(row.createdAt),
|
|
2113
|
-
updatedAt: new Date(row.updatedAt)
|
|
2114
|
-
};
|
|
2713
|
+
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
2115
2714
|
}
|
|
2116
2715
|
};
|
|
2117
2716
|
|
|
@@ -2215,3 +2814,5 @@ Example Complex Query:
|
|
|
2215
2814
|
}`;
|
|
2216
2815
|
|
|
2217
2816
|
export { LibSQLStore as DefaultStorage, LIBSQL_PROMPT, LibSQLStore, LibSQLVector };
|
|
2817
|
+
//# sourceMappingURL=index.js.map
|
|
2818
|
+
//# sourceMappingURL=index.js.map
|