@mastra/libsql 1.27.0-alpha.3 → 1.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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.27.0-alpha.3"
6
+ version: "1.27.0"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.27.0-alpha.3",
2
+ "version": "1.27.0",
3
3
  "package": "@mastra/libsql",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -28,13 +28,15 @@ Retrieves message history and persists new messages.
28
28
 
29
29
  ```typescript
30
30
  memory: new Memory({
31
- lastMessages: 10,
31
+ options: {
32
+ lastMessages: 10,
33
+ },
32
34
  })
33
35
  ```
34
36
 
35
37
  **Mastra internally:**
36
38
 
37
- 1. Creates a `MessageHistory` processor with `limit: 10`
39
+ 1. Creates a `MessageHistory` processor with `lastMessages: 10`
38
40
  2. Adds it to the agent's input processors (runs before the LLM)
39
41
  3. Adds it to the agent's output processors (runs after the LLM)
40
42
 
@@ -61,7 +63,9 @@ const agent = new Agent({
61
63
  id: 'memory-store',
62
64
  url: 'file:memory.db',
63
65
  }),
64
- lastMessages: 10, // MessageHistory processor automatically added
66
+ options: {
67
+ lastMessages: 10, // MessageHistory processor automatically added
68
+ },
65
69
  }),
66
70
  })
67
71
  ```
@@ -85,7 +89,7 @@ memory: new Memory({
85
89
  1. Creates a `SemanticRecall` processor
86
90
  2. Adds it to the agent's input processors (runs before the LLM)
87
91
  3. Adds it to the agent's output processors (runs after the LLM)
88
- 4. Requires both a vector store and embedder to be configured
92
+ 4. Requires a vector store, plus an embedder unless the vector store generates embeddings itself
89
93
 
90
94
  **What it does:**
91
95
 
@@ -190,7 +194,9 @@ const agent = new Agent({
190
194
  model: 'openai/gpt-5.6-sol',
191
195
  memory: new Memory({
192
196
  storage: new LibSQLStore({ id: 'memory-store', url: 'file:memory.db' }),
193
- lastMessages: 10, // This would normally add MessageHistory(10)
197
+ options: {
198
+ lastMessages: 10, // This would normally add MessageHistory(10)
199
+ },
194
200
  }),
195
201
  inputProcessors: [
196
202
  customMessageHistory, // Your custom one is used instead
@@ -259,7 +265,7 @@ const agent = new Agent({
259
265
  name: 'safe-agent',
260
266
  instructions: 'You are a helpful assistant',
261
267
  model: 'openai/gpt-5.6-sol',
262
- memory: new Memory({ lastMessages: 10 }),
268
+ memory: new Memory({ options: { lastMessages: 10 } }),
263
269
  // Your guardrail runs BEFORE memory saves
264
270
  outputProcessors: [contentBlocker],
265
271
  })
@@ -299,7 +305,7 @@ const agent = new Agent({
299
305
  name: 'validated-agent',
300
306
  instructions: 'You are a helpful assistant',
301
307
  model: 'openai/gpt-5.6-sol',
302
- memory: new Memory({ lastMessages: 10 }),
308
+ memory: new Memory({ options: { lastMessages: 10 } }),
303
309
  // Your guardrail runs AFTER memory loads history
304
310
  inputProcessors: [inputValidator],
305
311
  })
@@ -376,7 +382,7 @@ export const supportAgent = new Agent({
376
382
  name: 'Support agent',
377
383
  instructions: 'Answer customer support questions.',
378
384
  model: 'openai/gpt-5.6-sol',
379
- memory: new Memory({ lastMessages: 10 }),
385
+ memory: new Memory({ options: { lastMessages: 10 } }),
380
386
  inputProcessors: [new AttachmentUploader()],
381
387
  })
382
388
  ```
@@ -405,6 +405,26 @@ Multilingual E5 produces 1024-dimensional vectors. Your vector index must be cre
405
405
 
406
406
  FastEmbed models embed at most 512 tokens per input (roughly 2,000 to 2,500 characters of English text). Longer inputs are truncated, so text past the limit doesn't affect the embedding and can't be found by semantic recall. The AI SDK v3 FastEmbed models return a warning when this happens. The legacy v1 and v2 models don't. If you embed long documents with FastEmbed, chunk them to fit the window, for example with `maxSize: 1500` in `MDocument.chunk()`.
407
407
 
408
+ ### Setting the embedding dimension
409
+
410
+ To name the vector index, Memory needs the embedder's output dimension. By default it finds the dimension by embedding a short probe string the first time semantic recall is set up, once per `Memory` instance. If you already know the dimension, set `embeddingDimension`. Memory then skips the probe, so startup makes no embedding call and doesn't depend on the embedding provider being reachable:
411
+
412
+ ```ts
413
+ import { Memory } from '@mastra/memory'
414
+
415
+ const memory = new Memory({
416
+ embedder: 'openai/text-embedding-3-small',
417
+ embeddingDimension: 1536,
418
+ options: {
419
+ semanticRecall: true,
420
+ },
421
+ })
422
+ ```
423
+
424
+ The index name is the same whether the dimension is configured or probed, so existing indexes keep working.
425
+
426
+ The value must match the vectors the embedder returns. Memory compares it with the first real embedding, and on a mismatch it throws a `MASTRA_MEMORY_EMBEDDING_DIMENSION_MISMATCH` error naming both values before creating or querying any index. Update `embeddingDimension` whenever you change the embedding model or its output dimension.
427
+
408
428
  ## PostgreSQL index optimization
409
429
 
410
430
  When using PostgreSQL as your vector store, you can optimize semantic recall performance by configuring the vector index. This is particularly important for large-scale deployments with thousands of messages.
@@ -217,7 +217,7 @@ const paragraphMemory = new Memory({
217
217
 
218
218
  Working memory can also be defined using a structured schema instead of a Markdown template. A [Standard JSON Schema](https://standardschema.dev/json-schema) ([Zod](https://zod.dev/), [Valibot](https://valibot.dev/), [ArkType](https://arktype.io/), etc.). When using a schema, the agent will see and update working memory as a JSON object matching your schema.
219
219
 
220
- **Requirement:** You must specify either `template` or `schema`, but not both.
220
+ You can specify either `template` or `schema`, but not both. If you omit both, Mastra uses the default working memory template.
221
221
 
222
222
  ### Example: Schema-Based Working Memory
223
223
 
@@ -147,9 +147,9 @@ Re-drives every orphaned `running` durable-agent run across all registered durab
147
147
 
148
148
  Requires persistent storage. With an in-memory store, there's nothing to recover after a process restart.
149
149
 
150
- Agents and their runs are attempted serially. Each built-in `recoverActiveRuns()` attempt waits up to 30 seconds in total for `recover()` setup and settlement of the whole recovered workflow, then traversal can continue to later runs and agents. This isn't an overall recovery deadline: discovery and overridden custom recovery methods aren't bounded by this budget.
150
+ Recovery processes up to five agents concurrently, with up to five run waits per agent, independently of `recovery.workflowConcurrency`. Each built-in `recoverActiveRuns()` attempt waits up to 30 seconds in total for `recover()` setup and settlement of the whole recovered workflow, then frees its slot for another run. These limits bound waiting, not live executions. This isn't an overall recovery deadline: discovery and overridden custom recovery methods aren't bounded by this budget.
151
151
 
152
- A timed-out attempt continues in the background. Its outcome is `status: 'skipped'` with `reason: 'recovery-timeout'` and no `retryAt`. It contributes only to `skipped`, not `recovered`, `succeeded`, or `failed`, and Mastra doesn't automatically retry it. Late settlement doesn't change the returned counts.
152
+ A timed-out attempt continues in the background. Its outcome is `status: 'skipped'` with `reason: 'recovery-timeout'` and a future `retryAt`. It contributes only to `skipped`, not `recovered`, `succeeded`, or `failed`. Mastra schedules re-checks automatically. While the original attempt is pending, re-checks defer without starting another execution. After it settles, recovery checks the persisted snapshot and ownership before retrying; finished or suspended runs aren't restarted. Late settlement doesn't change the returned counts.
153
153
 
154
154
  When shutdown begins, recovery stops dispatching new agents and runs. The recovery traversal and original attempts, including timed-out setup or execution, participate in the same shared shutdown drain as active executions. A recovery wait timeout doesn't cancel the attempt or give it a separate shutdown drain window.
155
155
 
@@ -37,6 +37,8 @@ export const agent = new Agent({
37
37
 
38
38
  **embedder** (`EmbeddingModel<string> | EmbeddingModelV2<string>`): Embedder instance for vector embeddings. Required when semantic recall is enabled.
39
39
 
40
+ **embeddingDimension** (`number`): Output dimension of the embedder, as a positive integer. When set, Memory uses it to name the semantic recall index instead of embedding a probe string on first use. It must match the vectors the embedder returns: a mismatch throws a MASTRA\_MEMORY\_EMBEDDING\_DIMENSION\_MISMATCH error before any index is created. See Setting the embedding dimension.
41
+
40
42
  **options** (`MemoryConfig`): Memory configuration options.
41
43
 
42
44
  **options.lastMessages** (`number | false`): Number of most recent messages to include in context. Set to false to disable the message history feature entirely (messages are not loaded into context or saved). Use Number.MAX\_SAFE\_INTEGER to retrieve all messages with no limit. To load messages without saving new ones, use the readOnly option. The window slides forward on every request, so once a thread exceeds the limit, each turn invalidates the provider prompt cache. For long-running conversations, use Observational Memory instead.
package/dist/index.cjs CHANGED
@@ -469,12 +469,14 @@ var LibSQLFilterTranslator = class extends _mastra_core_vector_filter.BaseFilter
469
469
  for (const [key, value] of entries) {
470
470
  const newPath = currentPath ? `${currentPath}.${key}` : key;
471
471
  if (this.isLogicalOperator(key)) result[key] = Array.isArray(value) ? value.map((filter) => this.translateNode(filter)) : this.translateNode(value);
472
- else if (this.isOperator(key)) if (this.isArrayOperator(key) && !Array.isArray(value) && key !== "$elemMatch") result[key] = [value];
473
- else if (this.isBasicOperator(key) && Array.isArray(value)) result[key] = JSON.stringify(value);
474
- else result[key] = value;
475
- else if (typeof value === "object" && value !== null) if (Object.keys(value).some((k) => this.isOperator(k))) result[newPath] = this.translateNode(value);
476
- else Object.assign(result, this.translateNode(value, newPath));
477
- else result[newPath] = this.translateNode(value);
472
+ else if (this.isOperator(key)) {
473
+ if (this.isArrayOperator(key) && !Array.isArray(value) && key !== "$elemMatch") result[key] = [value];
474
+ else if (this.isBasicOperator(key) && Array.isArray(value)) result[key] = JSON.stringify(value);
475
+ else result[key] = value;
476
+ } else if (typeof value === "object" && value !== null) {
477
+ if (Object.keys(value).some((k) => this.isOperator(k))) result[newPath] = this.translateNode(value);
478
+ else Object.assign(result, this.translateNode(value, newPath));
479
+ } else result[newPath] = this.translateNode(value);
478
480
  }
479
481
  return result;
480
482
  }
@@ -1011,13 +1013,11 @@ var LibSQLVector = class extends _mastra_core_vector.MastraVector {
1011
1013
  this.logger.warn("LibSQLVector: indexed query failed, falling back to brute-force", err);
1012
1014
  }
1013
1015
  const { sql: filterQuery, values: filterValues } = buildFilterQuery(this.transformFilter(filter));
1014
- filterValues.push(minScore);
1015
- filterValues.push(topK);
1016
1016
  const query = `
1017
1017
  WITH vector_scores AS (
1018
1018
  SELECT
1019
1019
  vector_id as id,
1020
- (1-vector_distance_cos(embedding, '${vectorStr}')) as score,
1020
+ (1-vector_distance_cos(embedding, vector32(?))) as score,
1021
1021
  metadata
1022
1022
  ${includeVector ? ", vector_extract(embedding) as embedding" : ""}
1023
1023
  FROM ${parsedIndexName}
@@ -1030,7 +1030,12 @@ var LibSQLVector = class extends _mastra_core_vector.MastraVector {
1030
1030
  LIMIT ?`;
1031
1031
  return (await this.turso.execute({
1032
1032
  sql: query,
1033
- args: filterValues
1033
+ args: [
1034
+ vectorStr,
1035
+ ...filterValues,
1036
+ minScore,
1037
+ topK
1038
+ ]
1034
1039
  })).rows.map(({ id, score, metadata, embedding }) => ({
1035
1040
  id,
1036
1041
  score,
@@ -1530,10 +1535,11 @@ async function assertRunFence(tx, { claimsTable, fence, operation }) {
1530
1535
  sql: `SELECT generation, ownerId FROM ${claimsTable} WHERE runId = ?`,
1531
1536
  args: [fence.runId]
1532
1537
  })).rows[0];
1533
- if (!(0, _mastra_core_storage.matchesRunFence)(row ? {
1538
+ const current = row ? {
1534
1539
  generation: Number(row.generation),
1535
1540
  ownerId: String(row.ownerId)
1536
- } : null, fence)) throw new _mastra_core_storage.RunFenceConflictError(fence, operation);
1541
+ } : null;
1542
+ if (!(0, _mastra_core_storage.matchesRunFence)(current, fence)) throw new _mastra_core_storage.RunFenceConflictError(fence, operation);
1537
1543
  }
1538
1544
  /**
1539
1545
  * Runs `write` behind the client's write lock: directly when there is no
@@ -2267,7 +2273,8 @@ var LibSQLDB = class extends _mastra_core_base.MastraBase {
2267
2273
  const existingColumns = new Set([...existingColumnsRaw].map((column) => column.toLowerCase()));
2268
2274
  let addedColumns = false;
2269
2275
  for (const [columnName, columnDef] of Object.entries(schema)) if (!existingColumns.has(columnName.toLowerCase())) {
2270
- const alterSql = `ALTER TABLE "${_mastra_core_storage.TABLE_SPANS}" ADD COLUMN "${columnName}" ${this.getSqlType(columnDef.type)}`;
2276
+ const sqlType = this.getSqlType(columnDef.type);
2277
+ const alterSql = `ALTER TABLE "${_mastra_core_storage.TABLE_SPANS}" ADD COLUMN "${columnName}" ${sqlType}`;
2271
2278
  await this.client.execute(alterSql);
2272
2279
  addedColumns = true;
2273
2280
  this.logger.debug(`LibSQLDB: Added column '${columnName}' to ${_mastra_core_storage.TABLE_SPANS}`);
@@ -3534,15 +3541,19 @@ var BackgroundTasksLibSQL = class BackgroundTasksLibSQL extends _mastra_core_sto
3534
3541
  where += " AND status = ?";
3535
3542
  params.push(options.expectedStatus);
3536
3543
  }
3537
- if (options?.expectedOwnerId !== void 0) if (options.expectedOwnerId === null) where += " AND ownerId IS NULL";
3538
- else {
3539
- where += " AND ownerId = ?";
3540
- params.push(options.expectedOwnerId);
3544
+ if (options?.expectedOwnerId !== void 0) {
3545
+ if (options.expectedOwnerId === null) where += " AND ownerId IS NULL";
3546
+ else {
3547
+ where += " AND ownerId = ?";
3548
+ params.push(options.expectedOwnerId);
3549
+ }
3541
3550
  }
3542
- if (options?.expectedLeaseExpiresAt !== void 0) if (options.expectedLeaseExpiresAt === null) where += " AND leaseExpiresAt IS NULL";
3543
- else {
3544
- where += " AND leaseExpiresAt = ?";
3545
- params.push(options.expectedLeaseExpiresAt.toISOString());
3551
+ if (options?.expectedLeaseExpiresAt !== void 0) {
3552
+ if (options.expectedLeaseExpiresAt === null) where += " AND leaseExpiresAt IS NULL";
3553
+ else {
3554
+ where += " AND leaseExpiresAt = ?";
3555
+ params.push(options.expectedLeaseExpiresAt.toISOString());
3556
+ }
3546
3557
  }
3547
3558
  return (await this.#client.execute({
3548
3559
  sql: `UPDATE ${_mastra_core_storage.TABLE_BACKGROUND_TASKS} SET ${setClauses.join(", ")} WHERE ${where}`,
@@ -10102,7 +10113,8 @@ var MemoryLibSQL = class MemoryLibSQL extends _mastra_core_storage.MemoryStorage
10102
10113
  }
10103
10114
  async #updateMessages(writer, messages) {
10104
10115
  const messageIds = messages.map((m) => m.id);
10105
- const selectSql = `SELECT * FROM ${_mastra_core_storage.TABLE_MESSAGES} WHERE id IN (${messageIds.map(() => "?").join(",")})`;
10116
+ const placeholders = messageIds.map(() => "?").join(",");
10117
+ const selectSql = `SELECT * FROM ${_mastra_core_storage.TABLE_MESSAGES} WHERE id IN (${placeholders})`;
10106
10118
  const existingMessages = (await writer.execute({
10107
10119
  sql: selectSql,
10108
10120
  args: messageIds
@@ -10413,7 +10425,8 @@ var MemoryLibSQL = class MemoryLibSQL extends _mastra_core_storage.MemoryStorage
10413
10425
  valueType: typeof value
10414
10426
  }
10415
10427
  });
10416
- const baseQuery = `FROM ${_mastra_core_storage.TABLE_THREADS} ${whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : ""}`;
10428
+ const whereClause = whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : "";
10429
+ const baseQuery = `FROM ${_mastra_core_storage.TABLE_THREADS} ${whereClause}`;
10417
10430
  const mapRowToStorageThreadType = (row) => ({
10418
10431
  id: row.id,
10419
10432
  resourceId: row.resourceId,
@@ -12487,18 +12500,18 @@ var ObservabilityLibSQL = class ObservabilityLibSQL extends _mastra_core_storage
12487
12500
  case _mastra_core_storage.TraceStatus.RUNNING:
12488
12501
  conditions.push(`endedAt IS NULL AND error IS NULL`);
12489
12502
  break;
12490
- case _mastra_core_storage.TraceStatus.SUCCESS:
12491
- conditions.push(`endedAt IS NOT NULL AND error IS NULL`);
12492
- break;
12503
+ case _mastra_core_storage.TraceStatus.SUCCESS: conditions.push(`endedAt IS NOT NULL AND error IS NULL`);
12493
12504
  }
12494
- if (filters.hasChildError !== void 0) if (filters.hasChildError) conditions.push(`EXISTS (
12505
+ if (filters.hasChildError !== void 0) {
12506
+ if (filters.hasChildError) conditions.push(`EXISTS (
12495
12507
  SELECT 1 FROM ${tableName} c
12496
12508
  WHERE c.traceId = ${tableName}.traceId AND c.error IS NOT NULL
12497
12509
  )`);
12498
- else conditions.push(`NOT EXISTS (
12510
+ else conditions.push(`NOT EXISTS (
12499
12511
  SELECT 1 FROM ${tableName} c
12500
12512
  WHERE c.traceId = ${tableName}.traceId AND c.error IS NOT NULL
12501
12513
  )`);
12514
+ }
12502
12515
  }
12503
12516
  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
12504
12517
  const sortField = orderBy?.field ?? "startedAt";
@@ -13247,15 +13260,19 @@ var SchedulesLibSQL = class SchedulesLibSQL extends _mastra_core_storage.Schedul
13247
13260
  conditions.push("json_extract(target, '$.workflowId') = ?");
13248
13261
  params.push(filter.workflowId);
13249
13262
  }
13250
- if (filter?.ownerType !== void 0) if (filter.ownerType === null) conditions.push("owner_type IS NULL");
13251
- else {
13252
- conditions.push("owner_type = ?");
13253
- params.push(filter.ownerType);
13263
+ if (filter?.ownerType !== void 0) {
13264
+ if (filter.ownerType === null) conditions.push("owner_type IS NULL");
13265
+ else {
13266
+ conditions.push("owner_type = ?");
13267
+ params.push(filter.ownerType);
13268
+ }
13254
13269
  }
13255
- if (filter?.ownerId !== void 0) if (filter.ownerId === null) conditions.push("owner_id IS NULL");
13256
- else {
13257
- conditions.push("owner_id = ?");
13258
- params.push(filter.ownerId);
13270
+ if (filter?.ownerId !== void 0) {
13271
+ if (filter.ownerId === null) conditions.push("owner_id IS NULL");
13272
+ else {
13273
+ conditions.push("owner_id = ?");
13274
+ params.push(filter.ownerId);
13275
+ }
13259
13276
  }
13260
13277
  const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
13261
13278
  return (await this.#client.execute({
@@ -15678,10 +15695,12 @@ var WorkflowsLibSQL = class WorkflowsLibSQL extends _mastra_core_storage.Workflo
15678
15695
  conditions.push("createdAt <= ?");
15679
15696
  args.push(toDate.toISOString());
15680
15697
  }
15681
- if (resourceId) if (await this.#db.hasColumn(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, "resourceId")) {
15682
- conditions.push("resourceId = ?");
15683
- args.push(resourceId);
15684
- } else this.logger.warn(`[${_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
15698
+ if (resourceId) {
15699
+ if (await this.#db.hasColumn(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, "resourceId")) {
15700
+ conditions.push("resourceId = ?");
15701
+ args.push(resourceId);
15702
+ } else this.logger.warn(`[${_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
15703
+ }
15685
15704
  if (threadId) {
15686
15705
  conditions.push(`(EXISTS (SELECT 1 FROM json_each(snapshot, '$.context') AS je WHERE json_extract(je.value, '$.status') = 'suspended' AND json_extract(je.value, '$.suspendPayload.__streamState.messageList.memoryInfo.threadId') = ?) OR json_extract(snapshot, '$.context.input.messageListState.memoryInfo.threadId') = ?)`);
15687
15706
  args.push(threadId, threadId);