@mastra/mongodb 1.11.1 → 1.12.0-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 +36 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-memory-working-memory.md +2 -0
- package/dist/docs/references/docs-rag-retrieval.md +2 -0
- package/dist/docs/references/docs-rag-vector-databases.md +2 -0
- package/dist/docs/references/reference-storage-mongodb.md +2 -0
- package/dist/docs/references/reference-vectors-mongodb.md +2 -0
- package/dist/index.cjs +304 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +305 -5
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/background-tasks/index.d.ts +13 -0
- package/dist/storage/domains/background-tasks/index.d.ts.map +1 -1
- package/dist/storage/domains/experiments/index.d.ts +22 -1
- package/dist/storage/domains/experiments/index.d.ts.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +14 -1
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/notifications/index.d.ts +5 -1
- package/dist/storage/domains/notifications/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/index.d.ts +5 -1
- package/dist/storage/domains/observability/index.d.ts.map +1 -1
- package/dist/storage/domains/schedules/index.d.ts +11 -1
- package/dist/storage/domains/schedules/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts +5 -1
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +8 -1
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/retention.d.ts +121 -0
- package/dist/storage/retention.d.ts.map +1 -0
- package/dist/storage/types.d.ts +21 -0
- package/dist/storage/types.d.ts.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# @mastra/mongodb
|
|
2
2
|
|
|
3
|
+
## 1.12.0-alpha.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Fixed `createExperiment` in the MongoDB store persisting `agentVersion` as `null` regardless of the input. `listExperiments` already accepts an `agentVersion` filter, but rows created by this backend would never match it. New experiments now round-trip `agentVersion` end-to-end. ([#18769](https://github.com/mastra-ai/mastra/pull/18769))
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`6a61846`](https://github.com/mastra-ai/mastra/commit/6a61846eeda29fb714549b70f1bee2bf6b141c44)]:
|
|
10
|
+
- @mastra/core@1.49.0-alpha.4
|
|
11
|
+
|
|
12
|
+
## 1.12.0-alpha.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- Added storage retention support to MongoDB. When you set a `retention` config, `MongoDBStore` can prune old documents from every growth domain it implements: `memory` (threads, messages, resources by `createdAt`), `observability` (spans by `startedAt`), `scores` (by `createdAt`), `workflows` (run snapshots by `updatedAt`), `backgroundTasks` (by `completedAt`, so in-flight tasks are never pruned), `experiments` (whole runs by `completedAt`, results cascade with their parent — transactional on replica sets), `notifications` (by `createdAt`), and `schedules` fire history (by `actual_fire_at`). ([#18798](https://github.com/mastra-ai/mastra/pull/18798))
|
|
17
|
+
|
|
18
|
+
Deletes run in batches via bounded `find(_id)` + `deleteMany` pairs (bounded, resumable, and cancellable) so they stay safe on large collections. Anchor-field indexes are created lazily on the first `prune()` call — never at init — so deployments that don't configure retention pay no extra index overhead. `prune()` only deletes documents; WiredTiger reuses the freed space for subsequent writes.
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
const storage = new MongoDBStore({
|
|
22
|
+
id: 'mastra-storage',
|
|
23
|
+
uri: process.env.MONGODB_URI,
|
|
24
|
+
dbName: 'mastra',
|
|
25
|
+
retention: {
|
|
26
|
+
memory: { messages: { maxAge: '30d' } },
|
|
27
|
+
observability: { spans: { maxAge: '7d' } },
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
await storage.prune();
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- Updated dependencies [[`700619b`](https://github.com/mastra-ai/mastra/commit/700619b61d572e592cbaaf758121d168844ca4d2), [`0c3d4bc`](https://github.com/mastra-ai/mastra/commit/0c3d4bcae13ea3699d379403e6f350d5cf4efe9f), [`17369b2`](https://github.com/mastra-ai/mastra/commit/17369b25250561e9ed994ae509be1d15bfb33bcb), [`bcae929`](https://github.com/mastra-ai/mastra/commit/bcae929945cbf265bd9f327cc715ecafa072b5b9), [`b33822e`](https://github.com/mastra-ai/mastra/commit/b33822e8d470884954b02f7b0745407ee4ef74b1), [`d5c11e3`](https://github.com/mastra-ai/mastra/commit/d5c11e3ba5045969caa7272a7bd1fd141c93ab6c), [`ff80671`](https://github.com/mastra-ai/mastra/commit/ff8067185e208b27198b4e5b71803013175c3643), [`dab1257`](https://github.com/mastra-ai/mastra/commit/dab1257b64e4ed576dc5038bb7a3f7072338bc9f), [`705ff39`](https://github.com/mastra-ai/mastra/commit/705ff3969e57214ff2fdaf3815d751dd558886ed), [`e6fbd5b`](https://github.com/mastra-ai/mastra/commit/e6fbd5bfdc28e92c0c0433f29aa1bc152d3430f6), [`6f2026c`](https://github.com/mastra-ai/mastra/commit/6f2026cdf114ff1e21e49133ca774ec7d5085059), [`f890eda`](https://github.com/mastra-ai/mastra/commit/f890eda2c8a2ae83d9b30bc6d85842f93b6c266b)]:
|
|
37
|
+
- @mastra/core@1.49.0-alpha.3
|
|
38
|
+
|
|
3
39
|
## 1.11.1
|
|
4
40
|
|
|
5
41
|
### Patch Changes
|
package/dist/docs/SKILL.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
> Discover all available pages from the documentation index: https://mastra.ai/llms.txt
|
|
2
|
+
|
|
1
3
|
# Working Memory
|
|
2
4
|
|
|
3
5
|
While [message history](https://mastra.ai/docs/memory/message-history) and [semantic recall](https://mastra.ai/docs/memory/semantic-recall) help agents remember conversations, working memory allows them to maintain persistent information about users across interactions.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
> Discover all available pages from the documentation index: https://mastra.ai/llms.txt
|
|
2
|
+
|
|
1
3
|
# Storing embeddings in a vector database
|
|
2
4
|
|
|
3
5
|
After generating embeddings, you need to store them in a database that supports vector similarity search. Mastra provides a consistent interface for storing and querying embeddings across various vector databases.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
> Discover all available pages from the documentation index: https://mastra.ai/llms.txt
|
|
2
|
+
|
|
1
3
|
# MongoDB vector store
|
|
2
4
|
|
|
3
5
|
The `MongoDBVector` class provides vector search using [MongoDB Atlas Vector Search](https://www.mongodb.com/docs/atlas/atlas-vector-search/). It enables efficient similarity search and metadata filtering within your MongoDB collections.
|
package/dist/index.cjs
CHANGED
|
@@ -15,7 +15,7 @@ var skills = require('@mastra/core/storage/domains/skills');
|
|
|
15
15
|
|
|
16
16
|
// package.json
|
|
17
17
|
var package_default = {
|
|
18
|
-
version: "1.
|
|
18
|
+
version: "1.12.0-alpha.1"};
|
|
19
19
|
var MongoDBFilterTranslator = class extends filter.BaseFilterTranslator {
|
|
20
20
|
getSupportedOperators() {
|
|
21
21
|
return {
|
|
@@ -1621,6 +1621,126 @@ var MongoDBAgentsStorage = class _MongoDBAgentsStorage extends storage.AgentsSto
|
|
|
1621
1621
|
return result;
|
|
1622
1622
|
}
|
|
1623
1623
|
};
|
|
1624
|
+
var DEFAULT_PRUNE_BATCH_SIZE = 1e3;
|
|
1625
|
+
async function ensureAnchorIndex(connector, target, logger) {
|
|
1626
|
+
if (!target.indexed) return;
|
|
1627
|
+
try {
|
|
1628
|
+
const collection = await connector.getCollection(target.table);
|
|
1629
|
+
await collection.createIndex({ [target.column]: -1 });
|
|
1630
|
+
} catch (error) {
|
|
1631
|
+
logger?.warn?.(`Failed to ensure retention index on ${target.table}(${target.column}):`, error);
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
async function sleep(ms, signal) {
|
|
1635
|
+
if (ms <= 0 || signal?.aborted) return;
|
|
1636
|
+
await new Promise((resolve) => {
|
|
1637
|
+
const timer = setTimeout(() => {
|
|
1638
|
+
signal?.removeEventListener("abort", onAbort);
|
|
1639
|
+
resolve();
|
|
1640
|
+
}, ms);
|
|
1641
|
+
const onAbort = () => {
|
|
1642
|
+
clearTimeout(timer);
|
|
1643
|
+
resolve();
|
|
1644
|
+
};
|
|
1645
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1646
|
+
});
|
|
1647
|
+
}
|
|
1648
|
+
function cutoffFor(policy, encoding, now = Date.now()) {
|
|
1649
|
+
const cutoffMs = now - storage.parseDuration(policy.maxAge);
|
|
1650
|
+
if (encoding === "epoch-ms") return cutoffMs;
|
|
1651
|
+
if (encoding === "iso") return new Date(cutoffMs).toISOString();
|
|
1652
|
+
return new Date(cutoffMs);
|
|
1653
|
+
}
|
|
1654
|
+
async function pruneCollectionBatch({
|
|
1655
|
+
connector,
|
|
1656
|
+
table,
|
|
1657
|
+
column,
|
|
1658
|
+
cutoff,
|
|
1659
|
+
limit
|
|
1660
|
+
}) {
|
|
1661
|
+
const collection = await connector.getCollection(table);
|
|
1662
|
+
const docs = await collection.find({ [column]: { $lt: cutoff } }).project({ _id: 1 }).limit(limit).toArray();
|
|
1663
|
+
if (docs.length === 0) return 0;
|
|
1664
|
+
const result = await collection.deleteMany({ _id: { $in: docs.map((doc) => doc._id) } });
|
|
1665
|
+
return result.deletedCount;
|
|
1666
|
+
}
|
|
1667
|
+
async function runBatchedDelete({
|
|
1668
|
+
deleteBatch,
|
|
1669
|
+
batchSize,
|
|
1670
|
+
options
|
|
1671
|
+
}) {
|
|
1672
|
+
if (!Number.isSafeInteger(batchSize) || batchSize <= 0) {
|
|
1673
|
+
throw new Error(`retention batchSize must be a positive integer; received ${batchSize}`);
|
|
1674
|
+
}
|
|
1675
|
+
let deleted = 0;
|
|
1676
|
+
let batches = 0;
|
|
1677
|
+
while (true) {
|
|
1678
|
+
if (options?.signal?.aborted) return { deleted, done: false };
|
|
1679
|
+
if (options?.maxBatches !== void 0 && batches >= options.maxBatches) return { deleted, done: false };
|
|
1680
|
+
let limit = batchSize;
|
|
1681
|
+
if (options?.maxRows !== void 0) {
|
|
1682
|
+
const remaining = options.maxRows - deleted;
|
|
1683
|
+
if (remaining <= 0) return { deleted, done: false };
|
|
1684
|
+
limit = Math.min(limit, remaining);
|
|
1685
|
+
}
|
|
1686
|
+
const affected = await deleteBatch(limit);
|
|
1687
|
+
deleted += affected;
|
|
1688
|
+
batches += 1;
|
|
1689
|
+
if (affected < limit) return { deleted, done: true };
|
|
1690
|
+
if (options?.pauseMs) {
|
|
1691
|
+
await sleep(options.pauseMs, options.signal);
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
async function runPrune({
|
|
1696
|
+
connector,
|
|
1697
|
+
domain,
|
|
1698
|
+
targets,
|
|
1699
|
+
options,
|
|
1700
|
+
logger
|
|
1701
|
+
}) {
|
|
1702
|
+
const results = [];
|
|
1703
|
+
const now = Date.now();
|
|
1704
|
+
for (const target of targets) {
|
|
1705
|
+
if (options?.signal?.aborted) {
|
|
1706
|
+
results.push({ domain, table: target.table, deleted: 0, done: false });
|
|
1707
|
+
continue;
|
|
1708
|
+
}
|
|
1709
|
+
await ensureAnchorIndex(connector, target, logger);
|
|
1710
|
+
const cutoff = cutoffFor(target.policy, target.encoding, now);
|
|
1711
|
+
const batchSize = target.policy.batchSize ?? DEFAULT_PRUNE_BATCH_SIZE;
|
|
1712
|
+
const { deleted, done } = await runBatchedDelete({
|
|
1713
|
+
deleteBatch: (limit) => pruneCollectionBatch({ connector, table: target.table, column: target.column, cutoff, limit }),
|
|
1714
|
+
batchSize,
|
|
1715
|
+
options
|
|
1716
|
+
});
|
|
1717
|
+
results.push({ domain, table: target.table, deleted, done });
|
|
1718
|
+
}
|
|
1719
|
+
return results;
|
|
1720
|
+
}
|
|
1721
|
+
function resolveTargets({
|
|
1722
|
+
policies,
|
|
1723
|
+
descriptor,
|
|
1724
|
+
order,
|
|
1725
|
+
encodings
|
|
1726
|
+
}) {
|
|
1727
|
+
const targets = [];
|
|
1728
|
+
for (const key of order) {
|
|
1729
|
+
const policy = policies[key];
|
|
1730
|
+
const entry = descriptor[key];
|
|
1731
|
+
if (!policy || !entry) continue;
|
|
1732
|
+
targets.push({
|
|
1733
|
+
table: entry.table,
|
|
1734
|
+
column: entry.column,
|
|
1735
|
+
encoding: encodings?.[key] ?? (entry.anchorType === "epoch-ms" ? "epoch-ms" : "date"),
|
|
1736
|
+
indexed: entry.indexed ?? true,
|
|
1737
|
+
policy
|
|
1738
|
+
});
|
|
1739
|
+
}
|
|
1740
|
+
return targets;
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
// src/storage/domains/background-tasks/index.ts
|
|
1624
1744
|
function toDoc(task) {
|
|
1625
1745
|
return {
|
|
1626
1746
|
id: task.id,
|
|
@@ -1672,6 +1792,14 @@ var BackgroundTasksStorageMongoDB = class _BackgroundTasksStorageMongoDB extends
|
|
|
1672
1792
|
#skipDefaultIndexes;
|
|
1673
1793
|
#indexes;
|
|
1674
1794
|
static MANAGED_COLLECTIONS = [storage.TABLE_BACKGROUND_TASKS];
|
|
1795
|
+
/**
|
|
1796
|
+
* Anchor is `completedAt`, so age is measured from task completion; it stays
|
|
1797
|
+
* `null` while a task is in-flight, and `null $lt cutoff` never matches, so
|
|
1798
|
+
* pending/running tasks are never pruned regardless of age.
|
|
1799
|
+
*/
|
|
1800
|
+
static retentionTables = {
|
|
1801
|
+
backgroundTasks: { table: storage.TABLE_BACKGROUND_TASKS, column: "completedAt", indexed: true }
|
|
1802
|
+
};
|
|
1675
1803
|
constructor(config) {
|
|
1676
1804
|
super();
|
|
1677
1805
|
this.#connector = resolveMongoDBConfig(config);
|
|
@@ -1683,6 +1811,20 @@ var BackgroundTasksStorageMongoDB = class _BackgroundTasksStorageMongoDB extends
|
|
|
1683
1811
|
async getCollection() {
|
|
1684
1812
|
return this.#connector.getCollection(storage.TABLE_BACKGROUND_TASKS);
|
|
1685
1813
|
}
|
|
1814
|
+
/**
|
|
1815
|
+
* Delete tasks completed longer ago than the policy's `maxAge`, batched.
|
|
1816
|
+
* `completedAt` is stored as an ISO-8601 string (see `toDoc`), so the cutoff
|
|
1817
|
+
* uses the `iso` encoding — lexicographic `$lt` on ISO strings is time-ordered.
|
|
1818
|
+
*/
|
|
1819
|
+
async prune(policies, options) {
|
|
1820
|
+
const targets = resolveTargets({
|
|
1821
|
+
policies,
|
|
1822
|
+
descriptor: _BackgroundTasksStorageMongoDB.retentionTables,
|
|
1823
|
+
order: ["backgroundTasks"],
|
|
1824
|
+
encodings: { backgroundTasks: "iso" }
|
|
1825
|
+
});
|
|
1826
|
+
return runPrune({ connector: this.#connector, domain: "backgroundTasks", targets, options, logger: this.logger });
|
|
1827
|
+
}
|
|
1686
1828
|
getDefaultIndexDefinitions() {
|
|
1687
1829
|
return [
|
|
1688
1830
|
{ collection: storage.TABLE_BACKGROUND_TASKS, keys: { id: 1 }, options: { unique: true } },
|
|
@@ -3083,6 +3225,15 @@ var MongoDBExperimentsStorage = class _MongoDBExperimentsStorage extends storage
|
|
|
3083
3225
|
#skipDefaultIndexes;
|
|
3084
3226
|
#indexes;
|
|
3085
3227
|
static MANAGED_COLLECTIONS = [storage.TABLE_EXPERIMENTS, storage.TABLE_EXPERIMENT_RESULTS];
|
|
3228
|
+
/**
|
|
3229
|
+
* Experiments prune as whole units: an experiment and its results are only
|
|
3230
|
+
* deleted together, once the experiment itself is old (anchored on the
|
|
3231
|
+
* parent's `completedAt`, a BSON date that stays `null` while running).
|
|
3232
|
+
* `results` is intentionally not an independent retention key.
|
|
3233
|
+
*/
|
|
3234
|
+
static retentionTables = {
|
|
3235
|
+
experiments: { table: storage.TABLE_EXPERIMENTS, column: "completedAt", indexed: true }
|
|
3236
|
+
};
|
|
3086
3237
|
constructor(config) {
|
|
3087
3238
|
super();
|
|
3088
3239
|
this.#connector = resolveMongoDBConfig(config);
|
|
@@ -3094,6 +3245,57 @@ var MongoDBExperimentsStorage = class _MongoDBExperimentsStorage extends storage
|
|
|
3094
3245
|
async getCollection(name) {
|
|
3095
3246
|
return this.#connector.getCollection(name);
|
|
3096
3247
|
}
|
|
3248
|
+
/**
|
|
3249
|
+
* Prune whole experiments older than the `experiments` policy's `maxAge`.
|
|
3250
|
+
*
|
|
3251
|
+
* Each batch collects up to `batchSize` aged experiment ids
|
|
3252
|
+
* (`completedAt < cutoff`; BSON type bracketing means `null` — still
|
|
3253
|
+
* running — never matches), then deletes their `experiment_results` rows and
|
|
3254
|
+
* the experiment rows for exactly that id set inside
|
|
3255
|
+
* `connector.withTransaction()` — atomic on replica sets, sequential
|
|
3256
|
+
* children-first on standalone — mirroring `deleteExperiment`. Hitting
|
|
3257
|
+
* `maxBatches`/`maxRows` or the abort signal between batches therefore never
|
|
3258
|
+
* leaves a run hollow (parent kept, results gone). Bounds count whole
|
|
3259
|
+
* experiments, not rows.
|
|
3260
|
+
*/
|
|
3261
|
+
async prune(policies, options) {
|
|
3262
|
+
const policy = policies["experiments"];
|
|
3263
|
+
if (!policy || options?.signal?.aborted) {
|
|
3264
|
+
return policy ? [
|
|
3265
|
+
{ domain: "experiments", table: storage.TABLE_EXPERIMENT_RESULTS, deleted: 0, done: false },
|
|
3266
|
+
{ domain: "experiments", table: storage.TABLE_EXPERIMENTS, deleted: 0, done: false }
|
|
3267
|
+
] : [];
|
|
3268
|
+
}
|
|
3269
|
+
await ensureAnchorIndex(
|
|
3270
|
+
this.#connector,
|
|
3271
|
+
{ table: storage.TABLE_EXPERIMENTS, column: "completedAt", indexed: true },
|
|
3272
|
+
this.logger
|
|
3273
|
+
);
|
|
3274
|
+
const cutoff = cutoffFor(policy, "date");
|
|
3275
|
+
const batchSize = policy.batchSize ?? DEFAULT_PRUNE_BATCH_SIZE;
|
|
3276
|
+
const experimentsCollection = await this.getCollection(storage.TABLE_EXPERIMENTS);
|
|
3277
|
+
const resultsCollection = await this.getCollection(storage.TABLE_EXPERIMENT_RESULTS);
|
|
3278
|
+
let childDeleted = 0;
|
|
3279
|
+
const parent = await runBatchedDelete({
|
|
3280
|
+
deleteBatch: async (limit) => {
|
|
3281
|
+
const docs = await experimentsCollection.find({ completedAt: { $lt: cutoff } }).project({ id: 1 }).limit(limit).toArray();
|
|
3282
|
+
if (docs.length === 0) return 0;
|
|
3283
|
+
const ids = docs.map((doc) => doc.id);
|
|
3284
|
+
return this.#connector.withTransaction(async (session) => {
|
|
3285
|
+
const children = await resultsCollection.deleteMany({ experimentId: { $in: ids } }, { session });
|
|
3286
|
+
childDeleted += children.deletedCount;
|
|
3287
|
+
const parents = await experimentsCollection.deleteMany({ id: { $in: ids } }, { session });
|
|
3288
|
+
return parents.deletedCount;
|
|
3289
|
+
});
|
|
3290
|
+
},
|
|
3291
|
+
batchSize,
|
|
3292
|
+
options
|
|
3293
|
+
});
|
|
3294
|
+
return [
|
|
3295
|
+
{ domain: "experiments", table: storage.TABLE_EXPERIMENT_RESULTS, deleted: childDeleted, done: parent.done },
|
|
3296
|
+
{ domain: "experiments", table: storage.TABLE_EXPERIMENTS, deleted: parent.deleted, done: parent.done }
|
|
3297
|
+
];
|
|
3298
|
+
}
|
|
3097
3299
|
// -------------------------------------------------------------------------
|
|
3098
3300
|
// Index Management
|
|
3099
3301
|
// -------------------------------------------------------------------------
|
|
@@ -3160,7 +3362,7 @@ var MongoDBExperimentsStorage = class _MongoDBExperimentsStorage extends storage
|
|
|
3160
3362
|
succeededCount: 0,
|
|
3161
3363
|
failedCount: 0,
|
|
3162
3364
|
skippedCount: 0,
|
|
3163
|
-
agentVersion: null,
|
|
3365
|
+
agentVersion: input.agentVersion ?? null,
|
|
3164
3366
|
startedAt: null,
|
|
3165
3367
|
completedAt: null,
|
|
3166
3368
|
createdAt: now,
|
|
@@ -3185,7 +3387,7 @@ var MongoDBExperimentsStorage = class _MongoDBExperimentsStorage extends storage
|
|
|
3185
3387
|
succeededCount: 0,
|
|
3186
3388
|
failedCount: 0,
|
|
3187
3389
|
skippedCount: 0,
|
|
3188
|
-
agentVersion: null,
|
|
3390
|
+
agentVersion: input.agentVersion ?? null,
|
|
3189
3391
|
startedAt: null,
|
|
3190
3392
|
completedAt: null,
|
|
3191
3393
|
createdAt: now,
|
|
@@ -4691,6 +4893,15 @@ var MemoryStorageMongoDB = class _MemoryStorageMongoDB extends storage.MemorySto
|
|
|
4691
4893
|
#indexes;
|
|
4692
4894
|
/** Collections managed by this domain */
|
|
4693
4895
|
static MANAGED_COLLECTIONS = [storage.TABLE_THREADS, storage.TABLE_MESSAGES, storage.TABLE_RESOURCES, OM_TABLE];
|
|
4896
|
+
/**
|
|
4897
|
+
* Retention-eligible collections. The observational-memory collection is
|
|
4898
|
+
* excluded: it has no timestamp anchor to age on. All anchors are BSON dates.
|
|
4899
|
+
*/
|
|
4900
|
+
static retentionTables = {
|
|
4901
|
+
messages: { table: storage.TABLE_MESSAGES, column: "createdAt", indexed: true },
|
|
4902
|
+
resources: { table: storage.TABLE_RESOURCES, column: "createdAt", indexed: true },
|
|
4903
|
+
threads: { table: storage.TABLE_THREADS, column: "createdAt", indexed: true }
|
|
4904
|
+
};
|
|
4694
4905
|
constructor(config) {
|
|
4695
4906
|
super();
|
|
4696
4907
|
this.#connector = resolveMongoDBConfig(config);
|
|
@@ -4706,6 +4917,21 @@ var MemoryStorageMongoDB = class _MemoryStorageMongoDB extends storage.MemorySto
|
|
|
4706
4917
|
await this.createDefaultIndexes();
|
|
4707
4918
|
await this.createCustomIndexes();
|
|
4708
4919
|
}
|
|
4920
|
+
/**
|
|
4921
|
+
* Delete memory rows older than each table's `maxAge`, batched. Order is
|
|
4922
|
+
* messages → resources → threads so child rows never outlive the delete of
|
|
4923
|
+
* their thread. Like `deleteThread()`, this does not sweep vector-store
|
|
4924
|
+
* embeddings — semantic-recall vectors live in a separate vector store the
|
|
4925
|
+
* memory domain cannot reach; cleaning those up is the operator's concern.
|
|
4926
|
+
*/
|
|
4927
|
+
async prune(policies, options) {
|
|
4928
|
+
const targets = resolveTargets({
|
|
4929
|
+
policies,
|
|
4930
|
+
descriptor: _MemoryStorageMongoDB.retentionTables,
|
|
4931
|
+
order: ["messages", "resources", "threads"]
|
|
4932
|
+
});
|
|
4933
|
+
return runPrune({ connector: this.#connector, domain: "memory", targets, options, logger: this.logger });
|
|
4934
|
+
}
|
|
4709
4935
|
/**
|
|
4710
4936
|
* Returns default index definitions for the memory domain collections.
|
|
4711
4937
|
*/
|
|
@@ -6659,6 +6885,10 @@ var NotificationsMongoDB = class _NotificationsMongoDB extends storage.Notificat
|
|
|
6659
6885
|
#skipDefaultIndexes;
|
|
6660
6886
|
#indexes;
|
|
6661
6887
|
static MANAGED_COLLECTIONS = [storage.TABLE_NOTIFICATIONS];
|
|
6888
|
+
/** Anchor is the notification's creation time, stored as a BSON date. */
|
|
6889
|
+
static retentionTables = {
|
|
6890
|
+
notifications: { table: storage.TABLE_NOTIFICATIONS, column: "createdAt", indexed: true }
|
|
6891
|
+
};
|
|
6662
6892
|
constructor(config) {
|
|
6663
6893
|
super();
|
|
6664
6894
|
this.#connector = resolveMongoDBConfig(config);
|
|
@@ -6670,6 +6900,15 @@ var NotificationsMongoDB = class _NotificationsMongoDB extends storage.Notificat
|
|
|
6670
6900
|
async getCollection() {
|
|
6671
6901
|
return this.#connector.getCollection(storage.TABLE_NOTIFICATIONS);
|
|
6672
6902
|
}
|
|
6903
|
+
/** Delete notifications older than the policy's `maxAge`, batched. */
|
|
6904
|
+
async prune(policies, options) {
|
|
6905
|
+
const targets = resolveTargets({
|
|
6906
|
+
policies,
|
|
6907
|
+
descriptor: _NotificationsMongoDB.retentionTables,
|
|
6908
|
+
order: ["notifications"]
|
|
6909
|
+
});
|
|
6910
|
+
return runPrune({ connector: this.#connector, domain: "notifications", targets, options, logger: this.logger });
|
|
6911
|
+
}
|
|
6673
6912
|
async init() {
|
|
6674
6913
|
await this.createDefaultIndexes();
|
|
6675
6914
|
await this.createCustomIndexes();
|
|
@@ -6862,6 +7101,10 @@ var ObservabilityMongoDB = class _ObservabilityMongoDB extends storage.Observabi
|
|
|
6862
7101
|
#indexes;
|
|
6863
7102
|
/** Collections managed by this domain */
|
|
6864
7103
|
static MANAGED_COLLECTIONS = [storage.TABLE_SPANS];
|
|
7104
|
+
/** Anchor is the span's start time, stored as a BSON date. */
|
|
7105
|
+
static retentionTables = {
|
|
7106
|
+
spans: { table: storage.TABLE_SPANS, column: "startedAt", indexed: true }
|
|
7107
|
+
};
|
|
6865
7108
|
constructor(config) {
|
|
6866
7109
|
super();
|
|
6867
7110
|
this.#connector = resolveMongoDBConfig(config);
|
|
@@ -6873,6 +7116,15 @@ var ObservabilityMongoDB = class _ObservabilityMongoDB extends storage.Observabi
|
|
|
6873
7116
|
async getCollection(name) {
|
|
6874
7117
|
return this.#connector.getCollection(name);
|
|
6875
7118
|
}
|
|
7119
|
+
/** Delete spans older than the `spans` policy's `maxAge`, batched. */
|
|
7120
|
+
async prune(policies, options) {
|
|
7121
|
+
const targets = resolveTargets({
|
|
7122
|
+
policies,
|
|
7123
|
+
descriptor: _ObservabilityMongoDB.retentionTables,
|
|
7124
|
+
order: ["spans"]
|
|
7125
|
+
});
|
|
7126
|
+
return runPrune({ connector: this.#connector, domain: "observability", targets, options, logger: this.logger });
|
|
7127
|
+
}
|
|
6876
7128
|
/**
|
|
6877
7129
|
* Returns default index definitions for the observability domain collections.
|
|
6878
7130
|
* These indexes optimize common query patterns for span and trace lookups.
|
|
@@ -8287,6 +8539,16 @@ var SchedulesMongoDB = class _SchedulesMongoDB extends storage.SchedulesStorage
|
|
|
8287
8539
|
#skipDefaultIndexes;
|
|
8288
8540
|
#indexes;
|
|
8289
8541
|
static MANAGED_COLLECTIONS = [storage.TABLE_SCHEDULES, storage.TABLE_SCHEDULE_TRIGGERS];
|
|
8542
|
+
/**
|
|
8543
|
+
* Only trigger (fire-history) rows are retention-eligible — schedule
|
|
8544
|
+
* definitions are config, not growth. Anchor `actual_fire_at` is stored as a
|
|
8545
|
+
* raw epoch-ms number, so `anchorType: 'epoch-ms'` keeps the cutoff numeric.
|
|
8546
|
+
* The default composite index `(schedule_id, actual_fire_at)` can't serve a
|
|
8547
|
+
* bare `actual_fire_at` range scan, hence the lazy single-field anchor index.
|
|
8548
|
+
*/
|
|
8549
|
+
static retentionTables = {
|
|
8550
|
+
triggers: { table: storage.TABLE_SCHEDULE_TRIGGERS, column: "actual_fire_at", anchorType: "epoch-ms", indexed: true }
|
|
8551
|
+
};
|
|
8290
8552
|
constructor(config) {
|
|
8291
8553
|
super();
|
|
8292
8554
|
this.#connector = resolveMongoDBConfig(config);
|
|
@@ -8301,6 +8563,15 @@ var SchedulesMongoDB = class _SchedulesMongoDB extends storage.SchedulesStorage
|
|
|
8301
8563
|
getTriggersCollection() {
|
|
8302
8564
|
return this.#connector.getCollection(storage.TABLE_SCHEDULE_TRIGGERS);
|
|
8303
8565
|
}
|
|
8566
|
+
/** Delete trigger (fire-history) rows older than the `triggers` policy's `maxAge`, batched. */
|
|
8567
|
+
async prune(policies, options) {
|
|
8568
|
+
const targets = resolveTargets({
|
|
8569
|
+
policies,
|
|
8570
|
+
descriptor: _SchedulesMongoDB.retentionTables,
|
|
8571
|
+
order: ["triggers"]
|
|
8572
|
+
});
|
|
8573
|
+
return runPrune({ connector: this.#connector, domain: "schedules", targets, options, logger: this.logger });
|
|
8574
|
+
}
|
|
8304
8575
|
getDefaultIndexDefinitions() {
|
|
8305
8576
|
return [
|
|
8306
8577
|
{ collection: storage.TABLE_SCHEDULES, keys: { id: 1 }, options: { unique: true } },
|
|
@@ -9004,6 +9275,10 @@ var ScoresStorageMongoDB = class _ScoresStorageMongoDB extends storage.ScoresSto
|
|
|
9004
9275
|
#indexes;
|
|
9005
9276
|
/** Collections managed by this domain */
|
|
9006
9277
|
static MANAGED_COLLECTIONS = [storage.TABLE_SCORERS];
|
|
9278
|
+
/** Anchor is the score row's creation time, stored as a BSON date. */
|
|
9279
|
+
static retentionTables = {
|
|
9280
|
+
scorers: { table: storage.TABLE_SCORERS, column: "createdAt", indexed: true }
|
|
9281
|
+
};
|
|
9007
9282
|
constructor(config) {
|
|
9008
9283
|
super();
|
|
9009
9284
|
this.#connector = resolveMongoDBConfig(config);
|
|
@@ -9015,6 +9290,15 @@ var ScoresStorageMongoDB = class _ScoresStorageMongoDB extends storage.ScoresSto
|
|
|
9015
9290
|
async getCollection(name) {
|
|
9016
9291
|
return this.#connector.getCollection(name);
|
|
9017
9292
|
}
|
|
9293
|
+
/** Delete scorer results older than the `scorers` policy's `maxAge`, batched. */
|
|
9294
|
+
async prune(policies, options) {
|
|
9295
|
+
const targets = resolveTargets({
|
|
9296
|
+
policies,
|
|
9297
|
+
descriptor: _ScoresStorageMongoDB.retentionTables,
|
|
9298
|
+
order: ["scorers"]
|
|
9299
|
+
});
|
|
9300
|
+
return runPrune({ connector: this.#connector, domain: "scores", targets, options, logger: this.logger });
|
|
9301
|
+
}
|
|
9018
9302
|
/**
|
|
9019
9303
|
* Returns default index definitions for the scores domain collections.
|
|
9020
9304
|
* These indexes optimize common query patterns for score lookups.
|
|
@@ -9982,6 +10266,13 @@ var WorkflowsStorageMongoDB = class _WorkflowsStorageMongoDB extends storage.Wor
|
|
|
9982
10266
|
#indexes;
|
|
9983
10267
|
/** Collections managed by this domain */
|
|
9984
10268
|
static MANAGED_COLLECTIONS = [storage.TABLE_WORKFLOW_SNAPSHOT];
|
|
10269
|
+
/**
|
|
10270
|
+
* Anchor is `updatedAt` (BSON date), so the policy reads as inactivity:
|
|
10271
|
+
* a run is pruned only after its snapshot has not been touched for `maxAge`.
|
|
10272
|
+
*/
|
|
10273
|
+
static retentionTables = {
|
|
10274
|
+
workflowSnapshot: { table: storage.TABLE_WORKFLOW_SNAPSHOT, column: "updatedAt", indexed: true }
|
|
10275
|
+
};
|
|
9985
10276
|
constructor(config) {
|
|
9986
10277
|
super();
|
|
9987
10278
|
this.#connector = resolveMongoDBConfig(config);
|
|
@@ -9990,6 +10281,15 @@ var WorkflowsStorageMongoDB = class _WorkflowsStorageMongoDB extends storage.Wor
|
|
|
9990
10281
|
(idx) => _WorkflowsStorageMongoDB.MANAGED_COLLECTIONS.includes(idx.collection)
|
|
9991
10282
|
);
|
|
9992
10283
|
}
|
|
10284
|
+
/** Delete workflow snapshots idle for longer than the policy's `maxAge`, batched. */
|
|
10285
|
+
async prune(policies, options) {
|
|
10286
|
+
const targets = resolveTargets({
|
|
10287
|
+
policies,
|
|
10288
|
+
descriptor: _WorkflowsStorageMongoDB.retentionTables,
|
|
10289
|
+
order: ["workflowSnapshot"]
|
|
10290
|
+
});
|
|
10291
|
+
return runPrune({ connector: this.#connector, domain: "workflows", targets, options, logger: this.logger });
|
|
10292
|
+
}
|
|
9993
10293
|
supportsConcurrentUpdates() {
|
|
9994
10294
|
return true;
|
|
9995
10295
|
}
|
|
@@ -10997,7 +11297,7 @@ var MongoDBStore = class extends storage.MastraCompositeStore {
|
|
|
10997
11297
|
#connector;
|
|
10998
11298
|
stores;
|
|
10999
11299
|
constructor(config) {
|
|
11000
|
-
super({ id: config.id, name: "MongoDBStore", disableInit: config.disableInit });
|
|
11300
|
+
super({ id: config.id, name: "MongoDBStore", disableInit: config.disableInit, retention: config.retention });
|
|
11001
11301
|
this.#connector = resolveMongoDBConfig(config);
|
|
11002
11302
|
const domainConfig = {
|
|
11003
11303
|
connector: this.#connector,
|