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