@mastra/libsql 1.27.0-alpha.3 → 1.27.0-alpha.4
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/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-memory-semantic-recall.md +20 -0
- package/dist/docs/references/reference-core-mastra-class.md +2 -2
- package/dist/docs/references/reference-memory-memory-class.md +2 -0
- package/dist/index.cjs +59 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +59 -40
- package/dist/index.js.map +1 -1
- package/dist/vector/index.d.ts.map +1 -1
- package/package.json +6 -4
package/dist/docs/SKILL.md
CHANGED
|
@@ -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.
|
|
@@ -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
|
-
|
|
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
|
|
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))
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
else
|
|
477
|
-
|
|
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,
|
|
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:
|
|
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
|
-
|
|
1538
|
+
const current = row ? {
|
|
1534
1539
|
generation: Number(row.generation),
|
|
1535
1540
|
ownerId: String(row.ownerId)
|
|
1536
|
-
} : null
|
|
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
|
|
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)
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
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)
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
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
|
|
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
|
|
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)
|
|
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
|
-
|
|
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)
|
|
13251
|
-
|
|
13252
|
-
|
|
13253
|
-
|
|
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)
|
|
13256
|
-
|
|
13257
|
-
|
|
13258
|
-
|
|
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)
|
|
15682
|
-
|
|
15683
|
-
|
|
15684
|
-
|
|
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);
|