@mastra/libsql 1.22.4-alpha.1 → 1.22.5-alpha.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.
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-memory-message-history.md +1 -1
- package/dist/docs/references/docs-memory-multi-user-threads.md +1 -1
- package/dist/docs/references/docs-memory-overview.md +4 -4
- package/dist/index.cjs +98 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +98 -13
- package/dist/index.js.map +1 -1
- package/dist/shared/single-connection-client.d.ts +29 -0
- package/dist/shared/single-connection-client.d.ts.map +1 -0
- package/dist/storage/db/write-lock.d.ts.map +1 -1
- package/dist/storage/factory-storage.d.ts.map +1 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/vector/index.d.ts.map +1 -1
- package/package.json +8 -7
package/dist/docs/SKILL.md
CHANGED
|
@@ -178,7 +178,7 @@ const agent = mastra.getAgentById('test-agent')
|
|
|
178
178
|
const memory = await agent.getMemory()
|
|
179
179
|
```
|
|
180
180
|
|
|
181
|
-
|
|
181
|
+
Use the `Memory` instance to query stored threads and messages or clone a conversation.
|
|
182
182
|
|
|
183
183
|
## Querying
|
|
184
184
|
|
|
@@ -160,7 +160,7 @@ const memory = new Memory({
|
|
|
160
160
|
|
|
161
161
|
OM requires a storage adapter that supports it: `@mastra/libsql`, `@mastra/pg`, `@mastra/mongodb`, or `@mastra/oracledb`.
|
|
162
162
|
|
|
163
|
-
> **Note:** If you switch the Observer to a
|
|
163
|
+
> **Note:** If you switch the Observer to a less capable model and see facts attributed to a generic `User` instead of individual participants, use [`observation.instruction`](https://mastra.ai/reference/memory/observational-memory) to explain how to interpret the `<turn>` tag.
|
|
164
164
|
|
|
165
165
|
### With working memory
|
|
166
166
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
# Memory
|
|
6
6
|
|
|
7
|
-
Memory
|
|
7
|
+
Memory gives your agent access to earlier messages and tool results. The agent can use this context to answer follow-up questions and recall information from previous interactions.
|
|
8
8
|
|
|
9
9
|
Mastra agents can be configured to store [message history](https://mastra.ai/docs/memory/message-history). Additionally, you can enable:
|
|
10
10
|
|
|
@@ -153,7 +153,7 @@ To list all threads for a resource, or retrieve a specific thread, [use the memo
|
|
|
153
153
|
|
|
154
154
|
## Observational Memory
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
Long conversations can fill the context window with raw message history and reduce agent performance. [Observational Memory](https://mastra.ai/docs/memory/observational-memory) uses background agents to compress older messages into observations. This reduces the context used by message history while retaining information for later turns.
|
|
157
157
|
|
|
158
158
|
**For AI agents:** Using Observational Memory requires a storage provider! You either need to set it on the Mastra instance at `src/mastra/index.ts` or pass it to the Agent constructor.
|
|
159
159
|
|
|
@@ -176,7 +176,7 @@ See [Observational Memory](https://mastra.ai/docs/memory/observational-memory) f
|
|
|
176
176
|
|
|
177
177
|
## What the model sees
|
|
178
178
|
|
|
179
|
-
|
|
179
|
+
Memory adds context to the system messages or conversation messages sent to the model. Message history is enabled by default. Other memory features contribute context only when configured. The diagram shows where each feature adds its context, and the list below explains what it contributes:
|
|
180
180
|
|
|
181
181
|

|
|
182
182
|
|
|
@@ -202,7 +202,7 @@ Each delegation creates a fresh `threadId` and a deterministic `resourceId` for
|
|
|
202
202
|
|
|
203
203
|
> **Note:** Title generation (`generateTitle`) is a top-level thread concern and **isn't** applied to inherited subagent threads. Because each delegation creates an ephemeral thread that no one sees, running title generation for it would waste an LLM call per delegation. To generate titles for a subagent's own threads, give that subagent its own memory configuration.
|
|
204
204
|
|
|
205
|
-
The supervisor forwards its conversation context to the subagent so it has enough background to complete the task. Only the delegation prompt and the subagent's response are saved
|
|
205
|
+
The supervisor forwards its conversation context to the subagent so it has enough background to complete the task. Only the delegation prompt and the subagent's response are saved; the full parent conversation isn't stored. You can control which messages reach the subagent with the [`messageFilter`](https://mastra.ai/docs/subagents) callback.
|
|
206
206
|
|
|
207
207
|
> **Note:** Subagent resource IDs are always suffixed with the agent name (`{parentResourceId}-{agentName}`). Different subagents under the same supervisor never share a resource ID through delegation.
|
|
208
208
|
|
package/dist/index.cjs
CHANGED
|
@@ -12,6 +12,84 @@ let crypto$1 = require("crypto");
|
|
|
12
12
|
let _mastra_core_agent = require("@mastra/core/agent");
|
|
13
13
|
let _mastra_core_evals = require("@mastra/core/evals");
|
|
14
14
|
let _mastra_core_storage_domains_skills = require("@mastra/core/storage/domains/skills");
|
|
15
|
+
//#region src/shared/single-connection-client.ts
|
|
16
|
+
/**
|
|
17
|
+
* Whether `@libsql/client` backs this database with exactly one connection.
|
|
18
|
+
*
|
|
19
|
+
* An in-memory database exists only on the connection that opened it, and each
|
|
20
|
+
* embedded-replica connection carries its own sync state, so `@libsql/client`
|
|
21
|
+
* (>= 0.18.0) gives both a pool of one. Any `execute`/`batch` issued while an
|
|
22
|
+
* interactive `transaction()` holds that connection is rejected immediately
|
|
23
|
+
* with `TRANSACTION_ACTIVE` instead of waiting for the transaction to settle.
|
|
24
|
+
*/
|
|
25
|
+
function isSingleConnectionDatabase({ url, syncUrl }) {
|
|
26
|
+
return url.includes(":memory:") || Boolean(syncUrl);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Wraps a single-connection client so client calls queue behind open
|
|
30
|
+
* transactions rather than failing with `TRANSACTION_ACTIVE`.
|
|
31
|
+
*
|
|
32
|
+
* `transaction()` takes the gate and releases it when the transaction commits,
|
|
33
|
+
* rolls back, or closes. `execute`, `batch`, `executeMultiple`, and `migrate`
|
|
34
|
+
* wait for the gate to be free before running but do not hold it — the driver
|
|
35
|
+
* executes them synchronously on the connection, so they cannot interleave
|
|
36
|
+
* with each other. Every other member passes through untouched.
|
|
37
|
+
*
|
|
38
|
+
* Callers must not issue client calls from inside their own open transaction
|
|
39
|
+
* (use `tx.execute`); such a call would wait for the transaction it is part of.
|
|
40
|
+
*/
|
|
41
|
+
function gateSingleConnectionClient(client) {
|
|
42
|
+
let gate = Promise.resolve();
|
|
43
|
+
const waitForGate = (run) => gate.then(run, run);
|
|
44
|
+
const transaction = async (mode) => {
|
|
45
|
+
let release;
|
|
46
|
+
const held = new Promise((resolve) => {
|
|
47
|
+
release = resolve;
|
|
48
|
+
});
|
|
49
|
+
const previous = gate;
|
|
50
|
+
gate = previous.then(() => held, () => held);
|
|
51
|
+
await previous.then(() => void 0, () => void 0);
|
|
52
|
+
let tx;
|
|
53
|
+
try {
|
|
54
|
+
tx = await client.transaction(mode);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
release();
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
return new Proxy(tx, { get(target, prop) {
|
|
60
|
+
if (prop === "commit" || prop === "rollback") return async () => {
|
|
61
|
+
try {
|
|
62
|
+
await target[prop].call(target);
|
|
63
|
+
} finally {
|
|
64
|
+
release();
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
if (prop === "close") return () => {
|
|
68
|
+
try {
|
|
69
|
+
target.close();
|
|
70
|
+
} finally {
|
|
71
|
+
release();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const value = Reflect.get(target, prop);
|
|
75
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
76
|
+
} });
|
|
77
|
+
};
|
|
78
|
+
return new Proxy(client, { get(target, prop) {
|
|
79
|
+
switch (prop) {
|
|
80
|
+
case "transaction": return transaction;
|
|
81
|
+
case "execute":
|
|
82
|
+
case "batch":
|
|
83
|
+
case "executeMultiple":
|
|
84
|
+
case "migrate": return (...args) => waitForGate(() => target[prop].apply(target, args));
|
|
85
|
+
default: {
|
|
86
|
+
const value = Reflect.get(target, prop);
|
|
87
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} });
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
15
93
|
//#region src/vector/filter.ts
|
|
16
94
|
/**
|
|
17
95
|
* Translates MongoDB-style filters to LibSQL compatible filters.
|
|
@@ -427,13 +505,17 @@ var LibSQLVector = class extends _mastra_core_vector.MastraVector {
|
|
|
427
505
|
this.isMemoryDb = url.includes(":memory:");
|
|
428
506
|
const isLocalDb = (url.startsWith("file:") || this.isMemoryDb) && !syncUrl;
|
|
429
507
|
const cwd = process.cwd();
|
|
430
|
-
|
|
508
|
+
const client = (0, _libsql_client.createClient)({
|
|
431
509
|
url,
|
|
432
510
|
syncUrl,
|
|
433
511
|
authToken,
|
|
434
512
|
syncInterval,
|
|
435
513
|
...isLocalDb ? { timeout: 5e3 } : {}
|
|
436
514
|
});
|
|
515
|
+
this.turso = isSingleConnectionDatabase({
|
|
516
|
+
url,
|
|
517
|
+
syncUrl
|
|
518
|
+
}) ? gateSingleConnectionClient(client) : client;
|
|
437
519
|
this.maxRetries = maxRetries;
|
|
438
520
|
this.initialBackoffMs = initialBackoffMs;
|
|
439
521
|
if (!Number.isInteger(vectorTopKOverFetchMultiplier) || vectorTopKOverFetchMultiplier < 1) throw new Error("vectorTopKOverFetchMultiplier must be a positive integer");
|
|
@@ -1280,24 +1362,26 @@ function transformFromSqlRow({ tableName, sqlRow }) {
|
|
|
1280
1362
|
/**
|
|
1281
1363
|
* Per-client write serialization.
|
|
1282
1364
|
*
|
|
1283
|
-
* `@libsql/client`
|
|
1284
|
-
*
|
|
1285
|
-
* `
|
|
1286
|
-
*
|
|
1287
|
-
*
|
|
1288
|
-
*
|
|
1289
|
-
* of as its own statement. Two concurrent interactive transactions collide the
|
|
1290
|
-
* same way ("cannot start a transaction within a transaction").
|
|
1365
|
+
* `@libsql/client` >= 0.18.0 pools connections for local `file:` databases, but
|
|
1366
|
+
* SQLite still admits one writer at a time: an interactive
|
|
1367
|
+
* `client.transaction('write')` holds `BEGIN` open across every
|
|
1368
|
+
* `await tx.execute(...)`, and any other write on the same database in that
|
|
1369
|
+
* window contends on the file lock and can fail with `SQLITE_BUSY` once
|
|
1370
|
+
* `busy_timeout` expires.
|
|
1291
1371
|
*
|
|
1292
1372
|
* This is dormant under the default engine but the evented engine runs many
|
|
1293
1373
|
* concurrent workflow snapshot writes per agent run, so a write issued by an
|
|
1294
|
-
* unrelated domain (e.g. creating a dataset experiment) can
|
|
1374
|
+
* unrelated domain (e.g. creating a dataset experiment) can fail spuriously.
|
|
1295
1375
|
*
|
|
1296
1376
|
* Serializing every write on a given client closes that window: writes — both
|
|
1297
1377
|
* autocommit statements and full interactive transactions — run one at a time,
|
|
1298
1378
|
* so none can interleave with an open transaction. Reads are intentionally not
|
|
1299
1379
|
* gated; WAL readers never observe a partial write and must not queue behind a
|
|
1300
1380
|
* long-running writer.
|
|
1381
|
+
*
|
|
1382
|
+
* `:memory:` databases and embedded replicas get a single pooled connection
|
|
1383
|
+
* instead; see `shared/single-connection-client.ts`, which gates *all* calls
|
|
1384
|
+
* (reads included) behind open transactions for those clients.
|
|
1301
1385
|
*/
|
|
1302
1386
|
const clientWriteChains = /* @__PURE__ */ new WeakMap();
|
|
1303
1387
|
/**
|
|
@@ -14222,11 +14306,12 @@ var LibSQLFactoryStorage = class extends _mastra_core_storage.FactoryStorage {
|
|
|
14222
14306
|
super();
|
|
14223
14307
|
this.#config = config;
|
|
14224
14308
|
const isLocalDb = config.url.startsWith("file:") || config.url.includes(":memory:");
|
|
14225
|
-
|
|
14309
|
+
const client = (0, _libsql_client.createClient)({
|
|
14226
14310
|
url: config.url,
|
|
14227
14311
|
...config.authToken ? { authToken: config.authToken } : {},
|
|
14228
14312
|
...isLocalDb ? { timeout: DEFAULT_CONNECTION_TIMEOUT_MS } : {}
|
|
14229
14313
|
});
|
|
14314
|
+
this.#client = isSingleConnectionDatabase(config) ? gateSingleConnectionClient(client) : client;
|
|
14230
14315
|
this.ops = new LibSQLFactoryStorageOps(this.#client, this.#schemas, (fn) => withClientWriteLock(this.#client, fn));
|
|
14231
14316
|
}
|
|
14232
14317
|
getMastraStorage() {
|
|
@@ -14384,15 +14469,15 @@ var LibSQLStore = class extends _mastra_core_storage.MastraCompositeStore {
|
|
|
14384
14469
|
mmapSize: config.localPragmas?.mmapSize ?? DEFAULT_LOCAL_MMAP_SIZE
|
|
14385
14470
|
};
|
|
14386
14471
|
if ("url" in config) {
|
|
14387
|
-
if (config.url.includes(":memory:")) this.shouldCacheInit = false;
|
|
14388
14472
|
this.isLocalDb = (config.url.startsWith("file:") || config.url.includes(":memory:")) && !config.syncUrl;
|
|
14389
|
-
|
|
14473
|
+
const client = (0, _libsql_client.createClient)({
|
|
14390
14474
|
url: config.url,
|
|
14391
14475
|
...config.authToken ? { authToken: config.authToken } : {},
|
|
14392
14476
|
...config.syncUrl ? { syncUrl: config.syncUrl } : {},
|
|
14393
14477
|
...config.syncInterval !== void 0 ? { syncInterval: config.syncInterval } : {},
|
|
14394
14478
|
...this.isLocalDb ? { timeout: this.connectionTimeoutMs } : {}
|
|
14395
14479
|
});
|
|
14480
|
+
this.client = isSingleConnectionDatabase(config) ? gateSingleConnectionClient(client) : client;
|
|
14396
14481
|
this.pragmasReady = this.isLocalDb ? this.applyLocalPragmas() : Promise.resolve();
|
|
14397
14482
|
} else {
|
|
14398
14483
|
this.client = config.client;
|