@mastra/libsql 1.10.0 → 1.10.1-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @mastra/libsql
2
2
 
3
+ ## 1.10.1-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - **Fixed** Workflow runs no longer fail to persist when request context contains non-serializable values (for example functions, circular references, or platform proxy objects). This prevents errors when saving workflow snapshots and scorer results. See #12301. ([#12573](https://github.com/mastra-ai/mastra/pull/12573))
8
+
9
+ - Updated dependencies [[`6742347`](https://github.com/mastra-ai/mastra/commit/6742347d71955d7639adc9ddf6ff8282de7ee3ba), [`7b0ad1f`](https://github.com/mastra-ai/mastra/commit/7b0ad1f5c53dc118c6da12ae82ae2587037dc2b8), [`62666c3`](https://github.com/mastra-ai/mastra/commit/62666c367eaeac3941ead454b1d38810cc855721), [`4af2160`](https://github.com/mastra-ai/mastra/commit/4af2160322f4718cac421930cce85641e9512389), [`136c959`](https://github.com/mastra-ai/mastra/commit/136c9592fb0eeb0cd212f28629d8a29b7557a2fc), [`4df7cc7`](https://github.com/mastra-ai/mastra/commit/4df7cc79342fd065fe7fdeef93c094db14b12bcd), [`aca3121`](https://github.com/mastra-ai/mastra/commit/aca31211233dac25459f140ea4fcfb3a5af64c18), [`9cdf38e`](https://github.com/mastra-ai/mastra/commit/9cdf38e58506e1109c8b38f97cd7770978a4218e), [`990851e`](https://github.com/mastra-ai/mastra/commit/990851edcb0e30be5c2c18b6532f1a876cc2d335), [`6068a6c`](https://github.com/mastra-ai/mastra/commit/6068a6c42950fad3ebfc92346417896ba60803d2), [`00106be`](https://github.com/mastra-ai/mastra/commit/00106bede59b81e5b0e9cd6aad8d3b5dbc336387), [`e2a079c`](https://github.com/mastra-ai/mastra/commit/e2a079cc3755b1895f7bd5dc36e9be81b11c7c22), [`534a456`](https://github.com/mastra-ai/mastra/commit/534a456a25e4df1e5407e7e632f4cb3b1fa14f9d), [`36bae07`](https://github.com/mastra-ai/mastra/commit/36bae07c0e70b1b3006f2fd20830e8883dcbd066)]:
10
+ - @mastra/core@1.33.0-alpha.7
11
+
12
+ ## 1.10.1-alpha.0
13
+
14
+ ### Patch Changes
15
+
16
+ - Track `suspendedAt` and `suspendPayload` on background tasks. SQL adapters auto-migrate the new columns via `alterTable`. ([#16260](https://github.com/mastra-ai/mastra/pull/16260))
17
+
18
+ - Updated dependencies [[`9f17410`](https://github.com/mastra-ai/mastra/commit/9f1741080def23d42ee50b39887a385ae316a3c6), [`c6eb39e`](https://github.com/mastra-ai/mastra/commit/c6eb39ea6dca381c6563cb240237fbe608e02f93), [`900d086`](https://github.com/mastra-ai/mastra/commit/900d086bb737b9cf2fcf68f11b0389b801a2738c), [`4c0e286`](https://github.com/mastra-ai/mastra/commit/4c0e28637c9cfb4f416549b55e97ebfa13319dfc), [`25184ff`](https://github.com/mastra-ai/mastra/commit/25184ffaf1293ec95119426eb1a1f8d38831b96c), [`aebde9c`](https://github.com/mastra-ai/mastra/commit/aebde9cfacf56592c6b6350cae721740fe090b8a)]:
19
+ - @mastra/core@1.33.0-alpha.4
20
+
3
21
  ## 1.10.0
4
22
 
5
23
  ### Minor Changes
@@ -3,7 +3,7 @@ name: mastra-libsql
3
3
  description: Documentation for @mastra/libsql. Use when working with @mastra/libsql APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/libsql"
6
- version: "1.10.0"
6
+ version: "1.10.1-alpha.1"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.10.0",
2
+ "version": "1.10.1-alpha.1",
3
3
  "package": "@mastra/libsql",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -237,4 +237,5 @@ export const memoryAgent = new Agent({
237
237
 
238
238
  - [`Memory` reference](https://mastra.ai/reference/memory/memory-class)
239
239
  - [Tracing](https://mastra.ai/docs/observability/tracing/overview)
240
- - [Request Context](https://mastra.ai/docs/server/request-context)
240
+ - [Request Context](https://mastra.ai/docs/server/request-context)
241
+ - [Mastra Code](https://code.mastra.ai/): A coding agent using Mastra's memory system
@@ -121,26 +121,88 @@ Each vector store page below includes installation instructions, configuration p
121
121
 
122
122
  ## Recall configuration
123
123
 
124
- The three main parameters that control semantic recall behavior are:
124
+ The following options control semantic recall behavior:
125
125
 
126
- 1. **topK**: How many semantically similar messages to retrieve
127
- 2. **messageRange**: How much surrounding context to include with each match
128
- 3. **scope**: Whether to search within the current thread or across all threads owned by a resource (the default is resource scope).
126
+ 1. **topK**: The number of similar messages to retrieve
127
+ 2. **messageRange**: The surrounding messages to include with each match
128
+ 3. **scope**: Whether to search the current thread or all threads for a resource
129
+ 4. **filter**: Metadata criteria that restrict search results
129
130
 
130
131
  ```typescript
131
132
  const agent = new Agent({
132
133
  memory: new Memory({
133
134
  options: {
134
135
  semanticRecall: {
135
- topK: 3, // Retrieve 3 most similar messages
136
+ topK: 3, // Retrieve 3 similar messages
136
137
  messageRange: 2, // Include 2 messages before and after each match
137
- scope: 'resource', // Search across all threads for this user (default setting if omitted)
138
+ scope: 'resource', // Search all threads for this resource
139
+ filter: { projectId: { $eq: 'project-a' } },
138
140
  },
139
141
  },
140
142
  }),
141
143
  })
142
144
  ```
143
145
 
146
+ > **Note:** `scope: 'resource'` is supported by the LibSQL, PostgreSQL, and Upstash storage adapters.
147
+
148
+ ### Metadata filtering
149
+
150
+ The `filter` option restricts semantic recall results to messages with matching thread metadata.
151
+
152
+ ```typescript
153
+ const agent = new Agent({
154
+ memory: new Memory({
155
+ options: {
156
+ semanticRecall: {
157
+ scope: 'resource',
158
+ filter: {
159
+ projectId: { $eq: 'project-a' },
160
+ category: { $in: ['work', 'personal'] },
161
+ },
162
+ },
163
+ },
164
+ }),
165
+ })
166
+ ```
167
+
168
+ Filters match metadata stored on message embeddings when messages are saved. If thread metadata changes later, existing embeddings keep their previous metadata until those messages are saved or indexed again.
169
+
170
+ Supported filter operators:
171
+
172
+ - `$and`: Logical AND
173
+ - `$eq`: Equal to
174
+ - `$gt`: Greater than
175
+ - `$gte`: Greater than or equal
176
+ - `$in`: In array
177
+ - `$lt`: Less than
178
+ - `$lte`: Less than or equal
179
+ - `$ne`: Not equal to
180
+ - `$nin`: Not in array
181
+ - `$or`: Logical OR
182
+
183
+ The following example demonstrates metadata filters for common use cases:
184
+
185
+ ```typescript
186
+ // Filter by project
187
+ const options = {
188
+ semanticRecall: { filter: { projectId: { $eq: 'my-project' } } },
189
+ }
190
+
191
+ // Filter by multiple categories
192
+ const options = {
193
+ semanticRecall: { filter: { category: { $in: ['work', 'research'] } } },
194
+ }
195
+
196
+ // Filter by project and priority
197
+ const options = {
198
+ semanticRecall: {
199
+ filter: {
200
+ $and: [{ projectId: { $eq: 'project-a' } }, { priority: { $gte: 3 } }],
201
+ },
202
+ },
203
+ }
204
+ ```
205
+
144
206
  ## Embedder configuration
145
207
 
146
208
  Semantic recall relies on an [embedding model](https://mastra.ai/reference/memory/memory-class) to convert messages into embeddings. Mastra supports embedding models through the model router using `provider/model` strings, or you can use any [embedding model](https://sdk.vercel.ai/docs/ai-sdk-core/embeddings) compatible with the AI SDK.
package/dist/index.cjs CHANGED
@@ -1172,6 +1172,33 @@ var LibSQLVector = class extends vector.MastraVector {
1172
1172
  });
1173
1173
  }
1174
1174
  };
1175
+ var safeStringify = (value) => {
1176
+ const seen = /* @__PURE__ */ new WeakSet();
1177
+ const sanitize = (val) => {
1178
+ if (val === null || val === void 0) return val;
1179
+ if (typeof val === "function") return void 0;
1180
+ if (typeof val === "symbol") return void 0;
1181
+ if (typeof val === "bigint") return val.toString();
1182
+ if (typeof val !== "object") return val;
1183
+ if (seen.has(val)) return void 0;
1184
+ seen.add(val);
1185
+ if (typeof val.toJSON === "function") {
1186
+ return sanitize(val.toJSON());
1187
+ }
1188
+ if (Array.isArray(val)) {
1189
+ return val.map((item) => sanitize(item));
1190
+ }
1191
+ const result = {};
1192
+ for (const key of Object.keys(val)) {
1193
+ const sanitized = sanitize(val[key]);
1194
+ if (sanitized !== void 0) {
1195
+ result[key] = sanitized;
1196
+ }
1197
+ }
1198
+ return result;
1199
+ };
1200
+ return JSON.stringify(sanitize(value)) ?? "null";
1201
+ };
1175
1202
  function buildSelectColumns(tableName) {
1176
1203
  const schema = storage.TABLE_SCHEMAS[tableName];
1177
1204
  return Object.keys(schema).map((col) => {
@@ -1238,12 +1265,12 @@ function prepareStatement({ tableName, record }) {
1238
1265
  }
1239
1266
  const colDef = schema[col];
1240
1267
  if (colDef?.type === "jsonb") {
1241
- return JSON.stringify(v);
1268
+ return safeStringify(v);
1242
1269
  }
1243
1270
  if (v instanceof Date) {
1244
1271
  return v.toISOString();
1245
1272
  }
1246
- return typeof v === "object" ? JSON.stringify(v) : v;
1273
+ return typeof v === "object" ? safeStringify(v) : v;
1247
1274
  });
1248
1275
  const placeholders = columnNames.map((col) => {
1249
1276
  const colDef = schema[col];
@@ -1286,12 +1313,12 @@ function transformToSqlValue(value, forceJsonStringify = false) {
1286
1313
  return null;
1287
1314
  }
1288
1315
  if (forceJsonStringify) {
1289
- return JSON.stringify(value);
1316
+ return safeStringify(value);
1290
1317
  }
1291
1318
  if (value instanceof Date) {
1292
1319
  return value.toISOString();
1293
1320
  }
1294
- return typeof value === "object" ? JSON.stringify(value) : value;
1321
+ return typeof value === "object" ? safeStringify(value) : value;
1295
1322
  }
1296
1323
  function prepareDeleteStatement({ tableName, keys }) {
1297
1324
  const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
@@ -2993,11 +3020,13 @@ function rowToTask(row) {
2993
3020
  runId: String(row.run_id),
2994
3021
  result: parseJson(row.result),
2995
3022
  error: parseJson(row.error),
3023
+ suspendPayload: parseJson(row.suspend_payload),
2996
3024
  retryCount: Number(row.retry_count),
2997
3025
  maxRetries: Number(row.max_retries),
2998
3026
  timeoutMs: Number(row.timeout_ms),
2999
3027
  createdAt: new Date(String(row.createdAt)),
3000
3028
  startedAt: row.startedAt ? new Date(String(row.startedAt)) : void 0,
3029
+ suspendedAt: row.suspendedAt ? new Date(String(row.suspendedAt)) : void 0,
3001
3030
  completedAt: row.completedAt ? new Date(String(row.completedAt)) : void 0
3002
3031
  };
3003
3032
  }
@@ -3015,6 +3044,11 @@ var BackgroundTasksLibSQL = class extends storage.BackgroundTasksStorage {
3015
3044
  tableName: storage.TABLE_BACKGROUND_TASKS,
3016
3045
  schema: storage.TABLE_SCHEMAS[storage.TABLE_BACKGROUND_TASKS]
3017
3046
  });
3047
+ await this.#db.alterTable({
3048
+ tableName: storage.TABLE_BACKGROUND_TASKS,
3049
+ schema: storage.TABLE_SCHEMAS[storage.TABLE_BACKGROUND_TASKS],
3050
+ ifNotExists: ["suspend_payload", "suspendedAt"]
3051
+ });
3018
3052
  }
3019
3053
  async dangerouslyClearAll() {
3020
3054
  await this.#db.deleteData({ tableName: storage.TABLE_BACKGROUND_TASKS });
@@ -3034,11 +3068,13 @@ var BackgroundTasksLibSQL = class extends storage.BackgroundTasksStorage {
3034
3068
  args: task.args,
3035
3069
  result: task.result ?? null,
3036
3070
  error: task.error ?? null,
3071
+ suspend_payload: task.suspendPayload ?? null,
3037
3072
  retry_count: task.retryCount,
3038
3073
  max_retries: task.maxRetries,
3039
3074
  timeout_ms: task.timeoutMs,
3040
3075
  createdAt: task.createdAt.toISOString(),
3041
3076
  startedAt: task.startedAt?.toISOString() ?? null,
3077
+ suspendedAt: task.suspendedAt?.toISOString() ?? null,
3042
3078
  completedAt: task.completedAt?.toISOString() ?? null
3043
3079
  }
3044
3080
  });
@@ -3058,6 +3094,10 @@ var BackgroundTasksLibSQL = class extends storage.BackgroundTasksStorage {
3058
3094
  setClauses.push("error = jsonb(?)");
3059
3095
  params.push(serializeJson(update.error));
3060
3096
  }
3097
+ if ("suspendPayload" in update) {
3098
+ setClauses.push("suspend_payload = jsonb(?)");
3099
+ params.push(serializeJson(update.suspendPayload));
3100
+ }
3061
3101
  if ("retryCount" in update) {
3062
3102
  setClauses.push("retry_count = ?");
3063
3103
  params.push(update.retryCount);
@@ -3066,6 +3106,10 @@ var BackgroundTasksLibSQL = class extends storage.BackgroundTasksStorage {
3066
3106
  setClauses.push("startedAt = ?");
3067
3107
  params.push(update.startedAt?.toISOString() ?? null);
3068
3108
  }
3109
+ if ("suspendedAt" in update) {
3110
+ setClauses.push("suspendedAt = ?");
3111
+ params.push(update.suspendedAt?.toISOString() ?? null);
3112
+ }
3069
3113
  if ("completedAt" in update) {
3070
3114
  setClauses.push("completedAt = ?");
3071
3115
  params.push(update.completedAt?.toISOString() ?? null);
@@ -3113,7 +3157,11 @@ var BackgroundTasksLibSQL = class extends storage.BackgroundTasksStorage {
3113
3157
  conditions.push("tool_name = ?");
3114
3158
  params.push(filter.toolName);
3115
3159
  }
3116
- const dateCol = filter.dateFilterBy === "startedAt" ? "startedAt" : filter.dateFilterBy === "completedAt" ? "completedAt" : "createdAt";
3160
+ if (filter.toolCallId) {
3161
+ conditions.push("tool_call_id = ?");
3162
+ params.push(filter.toolCallId);
3163
+ }
3164
+ const dateCol = filter.dateFilterBy === "startedAt" ? "startedAt" : filter.dateFilterBy === "suspendedAt" ? "suspendedAt" : filter.dateFilterBy === "completedAt" ? "completedAt" : "createdAt";
3117
3165
  if (filter.fromDate) {
3118
3166
  conditions.push(`${dateCol} >= ?`);
3119
3167
  params.push(filter.fromDate.toISOString());
@@ -3128,7 +3176,7 @@ var BackgroundTasksLibSQL = class extends storage.BackgroundTasksStorage {
3128
3176
  args: [...params]
3129
3177
  });
3130
3178
  const total = Number(countResult.rows[0]?.count ?? 0);
3131
- const orderCol = filter.orderBy === "startedAt" ? "startedAt" : filter.orderBy === "completedAt" ? "completedAt" : "createdAt";
3179
+ const orderCol = filter.orderBy === "startedAt" ? "startedAt" : filter.orderBy === "suspendedAt" ? "suspendedAt" : filter.orderBy === "completedAt" ? "completedAt" : "createdAt";
3132
3180
  const direction = filter.orderDirection === "desc" ? "DESC" : "ASC";
3133
3181
  let sql = `SELECT ${buildSelectColumns(storage.TABLE_BACKGROUND_TASKS)} FROM ${storage.TABLE_BACKGROUND_TASKS} ${where} ORDER BY ${orderCol} ${direction}`;
3134
3182
  if (filter.perPage != null) {
@@ -3156,7 +3204,7 @@ var BackgroundTasksLibSQL = class extends storage.BackgroundTasksStorage {
3156
3204
  conditions.push(`status IN (${statuses.map(() => "?").join(", ")})`);
3157
3205
  params.push(...statuses);
3158
3206
  }
3159
- const dateCol = filter.dateFilterBy === "startedAt" ? "startedAt" : filter.dateFilterBy === "completedAt" ? "completedAt" : "createdAt";
3207
+ const dateCol = filter.dateFilterBy === "startedAt" ? "startedAt" : filter.dateFilterBy === "suspendedAt" ? "suspendedAt" : filter.dateFilterBy === "completedAt" ? "completedAt" : "createdAt";
3160
3208
  if (filter.fromDate) {
3161
3209
  conditions.push(`${dateCol} >= ?`);
3162
3210
  params.push(filter.fromDate.toISOString());
@@ -10586,7 +10634,7 @@ var WorkflowsLibSQL = class extends storage.WorkflowsStorage {
10586
10634
  VALUES (?, ?, jsonb(?), ?, ?)
10587
10635
  ON CONFLICT(workflow_name, run_id)
10588
10636
  DO UPDATE SET snapshot = excluded.snapshot, updatedAt = excluded.updatedAt`,
10589
- args: [workflowName, runId, JSON.stringify(snapshot), now, now]
10637
+ args: [workflowName, runId, safeStringify(snapshot), now, now]
10590
10638
  });
10591
10639
  await tx.commit();
10592
10640
  return snapshot.context;
@@ -10623,7 +10671,7 @@ var WorkflowsLibSQL = class extends storage.WorkflowsStorage {
10623
10671
  const updatedSnapshot = { ...snapshot, ...opts };
10624
10672
  await tx.execute({
10625
10673
  sql: `UPDATE ${storage.TABLE_WORKFLOW_SNAPSHOT} SET snapshot = jsonb(?) WHERE workflow_name = ? AND run_id = ?`,
10626
- args: [JSON.stringify(updatedSnapshot), workflowName, runId]
10674
+ args: [safeStringify(updatedSnapshot), workflowName, runId]
10627
10675
  });
10628
10676
  await tx.commit();
10629
10677
  return updatedSnapshot;