@mastra/mongodb 1.23.0 → 1.23.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/dist/_types/@internal_core/dist/memory/index.d.ts +102 -0
- package/dist/_types/@internal_core/package.json +1 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/reference-storage-composite.md +34 -0
- package/dist/docs/references/reference-vectors-mongodb.md +2 -1
- package/dist/index.cjs +1033 -393
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1034 -394
- package/dist/index.js.map +1 -1
- package/dist/storage/connectors/MongoDBConnector.d.ts +10 -3
- package/dist/storage/connectors/MongoDBConnector.d.ts.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +31 -11
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/run-fencing.d.ts +39 -0
- package/dist/storage/domains/run-fencing.d.ts.map +1 -0
- package/dist/storage/domains/workflows/index.d.ts +26 -9
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/retention.d.ts +9 -5
- package/dist/storage/retention.d.ts.map +1 -1
- package/package.json +6 -5
package/dist/index.cjs
CHANGED
|
@@ -5,11 +5,12 @@ let _mastra_core_storage = require("@mastra/core/storage");
|
|
|
5
5
|
let _mastra_core_vector = require("@mastra/core/vector");
|
|
6
6
|
let mongodb = require("mongodb");
|
|
7
7
|
let _mastra_core_vector_filter = require("@mastra/core/vector/filter");
|
|
8
|
+
let crypto$1 = require("crypto");
|
|
8
9
|
let _mastra_core_agent = require("@mastra/core/agent");
|
|
9
10
|
let _mastra_core_evals = require("@mastra/core/evals");
|
|
10
11
|
let _mastra_core_storage_domains_skills = require("@mastra/core/storage/domains/skills");
|
|
11
12
|
//#region package.json
|
|
12
|
-
var version = "1.23.
|
|
13
|
+
var version = "1.23.1-alpha.1";
|
|
13
14
|
//#endregion
|
|
14
15
|
//#region src/vector/filter.ts
|
|
15
16
|
/**
|
|
@@ -1618,20 +1619,29 @@ var MongoDBConnector = class MongoDBConnector {
|
|
|
1618
1619
|
return (await this.getConnection()).listCollections({ name: collectionName }).hasNext();
|
|
1619
1620
|
}
|
|
1620
1621
|
/**
|
|
1621
|
-
*
|
|
1622
|
-
*
|
|
1623
|
-
*
|
|
1622
|
+
* Whether the deployment supports multi-document transactions (replica set
|
|
1623
|
+
* or sharded cluster). Standalone servers and custom connector handlers
|
|
1624
|
+
* don't. The answer is cached once a probe completes; a probe that fails
|
|
1625
|
+
* rejects and is retried on the next call, so the answer never changes.
|
|
1624
1626
|
*/
|
|
1625
|
-
async
|
|
1627
|
+
async probeTransactions() {
|
|
1626
1628
|
if (this.#supportsTransactions !== void 0) return this.#supportsTransactions;
|
|
1627
1629
|
if (!this.#client) {
|
|
1628
1630
|
this.#supportsTransactions = false;
|
|
1629
1631
|
return false;
|
|
1630
1632
|
}
|
|
1633
|
+
const hello = await (await this.getConnection()).admin().command({ hello: 1 });
|
|
1634
|
+
this.#supportsTransactions = Boolean(hello.setName) || hello.msg === "isdbgrid";
|
|
1635
|
+
return this.#supportsTransactions;
|
|
1636
|
+
}
|
|
1637
|
+
/**
|
|
1638
|
+
* Like {@link probeTransactions}, but a failed probe reads as no
|
|
1639
|
+
* transaction support (and is retried on the next call), so a momentary
|
|
1640
|
+
* outage degrades writes to non-atomic instead of failing them.
|
|
1641
|
+
*/
|
|
1642
|
+
async supportsTransactions() {
|
|
1631
1643
|
try {
|
|
1632
|
-
|
|
1633
|
-
this.#supportsTransactions = Boolean(hello.setName) || hello.msg === "isdbgrid";
|
|
1634
|
-
return this.#supportsTransactions;
|
|
1644
|
+
return await this.probeTransactions();
|
|
1635
1645
|
} catch {
|
|
1636
1646
|
return false;
|
|
1637
1647
|
}
|
|
@@ -2278,14 +2288,19 @@ function cutoffFor(policy, encoding, now = Date.now()) {
|
|
|
2278
2288
|
* Delete up to `limit` documents whose anchor field is older than `cutoff`.
|
|
2279
2289
|
*
|
|
2280
2290
|
* `deleteMany` has no limit clause, so each batch first collects `_id`s with a
|
|
2281
|
-
* bounded `find`, then deletes
|
|
2282
|
-
*
|
|
2291
|
+
* bounded `find`, then deletes that set — the Mongo equivalent of the SQL
|
|
2292
|
+
* stores' `DELETE ... WHERE rowid/ctid IN (SELECT ... LIMIT n)` pattern. The
|
|
2293
|
+
* delete re-checks the anchor, so a document updated after the `find` (a
|
|
2294
|
+
* renewed run ownership, a touched snapshot) survives.
|
|
2283
2295
|
*/
|
|
2284
2296
|
async function pruneCollectionBatch({ connector, table, column, cutoff, limit }) {
|
|
2285
2297
|
const collection = await connector.getCollection(table);
|
|
2286
2298
|
const docs = await collection.find({ [column]: { $lt: cutoff } }).project({ _id: 1 }).limit(limit).toArray();
|
|
2287
2299
|
if (docs.length === 0) return 0;
|
|
2288
|
-
return (await collection.deleteMany({
|
|
2300
|
+
return (await collection.deleteMany({
|
|
2301
|
+
_id: { $in: docs.map((doc) => doc._id) },
|
|
2302
|
+
[column]: { $lt: cutoff }
|
|
2303
|
+
})).deletedCount;
|
|
2289
2304
|
}
|
|
2290
2305
|
/**
|
|
2291
2306
|
* Run the bounded/cancellable batched-delete loop for a single logical target,
|
|
@@ -6495,6 +6510,105 @@ var MongoDBMCPServersStorage = class MongoDBMCPServersStorage extends _mastra_co
|
|
|
6495
6510
|
}
|
|
6496
6511
|
};
|
|
6497
6512
|
//#endregion
|
|
6513
|
+
//#region ../../packages/_internal-core/dist/memory/index.js
|
|
6514
|
+
/**
|
|
6515
|
+
* A buffered chunk stores `lastObservedAt = max message time + 1ms`. It is wholly covered
|
|
6516
|
+
* (every message it observed is already at or before the cursor) iff
|
|
6517
|
+
* `cursor >= chunk.lastObservedAt - 1ms`.
|
|
6518
|
+
*/
|
|
6519
|
+
function isBufferedChunkCoveredByCursor(chunkLastObservedAt, cursor) {
|
|
6520
|
+
if (!cursor) return false;
|
|
6521
|
+
return new Date(cursor).getTime() >= new Date(chunkLastObservedAt).getTime() - 1;
|
|
6522
|
+
}
|
|
6523
|
+
/** The later of two cursors; `undefined` only when both are absent. */
|
|
6524
|
+
function maxObservationCursor(a, b) {
|
|
6525
|
+
if (!a) return b ? new Date(b) : void 0;
|
|
6526
|
+
if (!b) return new Date(a);
|
|
6527
|
+
return new Date(Math.max(new Date(a).getTime(), new Date(b).getTime()));
|
|
6528
|
+
}
|
|
6529
|
+
/**
|
|
6530
|
+
* Decide the new generation's text when a reflection built from `snapshot` commits against
|
|
6531
|
+
* the stored record.
|
|
6532
|
+
*
|
|
6533
|
+
* - Stored text equals the snapshot: the reflection replaces it.
|
|
6534
|
+
* - Stored text extends the snapshot (activation only appends): the appended tail is kept
|
|
6535
|
+
* after the reflection, and its tokens are added.
|
|
6536
|
+
* - Anything else (a non-append rewrite): `null` — the reflection must not be applied.
|
|
6537
|
+
*/
|
|
6538
|
+
function planReflectionGenerationText(input) {
|
|
6539
|
+
const stored = input.storedObservations ?? "";
|
|
6540
|
+
const snapshot = input.snapshotObservations ?? "";
|
|
6541
|
+
if (stored === snapshot) return {
|
|
6542
|
+
mode: "equal",
|
|
6543
|
+
observations: input.reflection,
|
|
6544
|
+
tokenCount: input.tokenCount
|
|
6545
|
+
};
|
|
6546
|
+
if (!stored.startsWith(snapshot)) return null;
|
|
6547
|
+
const tail = stored.slice(snapshot.length).trimStart();
|
|
6548
|
+
if (!tail.trim()) return {
|
|
6549
|
+
mode: "equal",
|
|
6550
|
+
observations: input.reflection,
|
|
6551
|
+
tokenCount: input.tokenCount
|
|
6552
|
+
};
|
|
6553
|
+
return {
|
|
6554
|
+
mode: "append",
|
|
6555
|
+
observations: input.reflection ? `${input.reflection}\n\n${tail}` : tail,
|
|
6556
|
+
tokenCount: input.tokenCount + Math.max(0, (input.storedObservationTokenCount ?? 0) - (input.snapshotObservationTokenCount ?? 0))
|
|
6557
|
+
};
|
|
6558
|
+
}
|
|
6559
|
+
/**
|
|
6560
|
+
* Backs `updateActiveObservations` in adapters that implement `commitActiveObservations`.
|
|
6561
|
+
* Callers of `updateActiveObservations` (which resolves `void`) can't see a commit result, so a
|
|
6562
|
+
* write that was not applied throws instead of resolving as if it had committed.
|
|
6563
|
+
*/
|
|
6564
|
+
function assertActiveObservationsApplied(result, id) {
|
|
6565
|
+
if (result.applied) return;
|
|
6566
|
+
throw new Error(result.reason === "retired" ? `Observational memory record ${id} was superseded by a newer generation; observations were not written` : `Observational memory record ${id} changed since the observations were composed; observations were not written`);
|
|
6567
|
+
}
|
|
6568
|
+
/**
|
|
6569
|
+
* Whether the stored text can still accept a reflection built from `snapshot`
|
|
6570
|
+
* (equal, or only appended to since).
|
|
6571
|
+
*/
|
|
6572
|
+
function isAppendOnlySince(storedObservations, snapshotObservations) {
|
|
6573
|
+
const stored = storedObservations ?? "";
|
|
6574
|
+
const snapshot = snapshotObservations ?? "";
|
|
6575
|
+
return stored === snapshot || stored.startsWith(snapshot);
|
|
6576
|
+
}
|
|
6577
|
+
//#endregion
|
|
6578
|
+
//#region src/storage/domains/run-fencing.ts
|
|
6579
|
+
async function getRunClaims(connector, name) {
|
|
6580
|
+
return await connector.getCollection(name);
|
|
6581
|
+
}
|
|
6582
|
+
/** Duplicate-key error: an upsert lost the race to insert the document. */
|
|
6583
|
+
function isDuplicateKeyError(error) {
|
|
6584
|
+
return error?.code === 11e3;
|
|
6585
|
+
}
|
|
6586
|
+
/**
|
|
6587
|
+
* Runs a write, fenced when `check` is set. A fenced write runs in a
|
|
6588
|
+
* transaction that first updates the run's claim document, matching it on
|
|
6589
|
+
* the fence. A fence that is no longer current matches nothing, and the write
|
|
6590
|
+
* throws `RunFenceConflictError` before anything is written. A claim that
|
|
6591
|
+
* changes while the transaction runs makes the update conflict, so the
|
|
6592
|
+
* transaction retries and sees the new claim; a claim attempted after the
|
|
6593
|
+
* update waits until the transaction commits. Updating the claim document,
|
|
6594
|
+
* rather than reading it, is what makes concurrent claims conflict.
|
|
6595
|
+
*
|
|
6596
|
+
* Fencing is declared only on deployments that support transactions.
|
|
6597
|
+
*/
|
|
6598
|
+
async function withRunFence(connector, check, write) {
|
|
6599
|
+
if (!check) return write();
|
|
6600
|
+
const { claims, fence, operation } = check;
|
|
6601
|
+
const collection = await getRunClaims(connector, claims);
|
|
6602
|
+
return connector.withTransaction(async (session) => {
|
|
6603
|
+
if ((await collection.updateOne({
|
|
6604
|
+
_id: fence.runId,
|
|
6605
|
+
generation: fence.generation,
|
|
6606
|
+
ownerId: fence.ownerId
|
|
6607
|
+
}, { $inc: { fencedWrites: 1 } }, { session })).matchedCount === 0) throw new _mastra_core_storage.RunFenceConflictError(fence, operation);
|
|
6608
|
+
return write(session);
|
|
6609
|
+
});
|
|
6610
|
+
}
|
|
6611
|
+
//#endregion
|
|
6498
6612
|
//#region src/storage/domains/memory/index.ts
|
|
6499
6613
|
/**
|
|
6500
6614
|
* Local constant for the observational memory table name.
|
|
@@ -6502,6 +6616,95 @@ var MongoDBMCPServersStorage = class MongoDBMCPServersStorage extends _mastra_co
|
|
|
6502
6616
|
* versions that don't export TABLE_OBSERVATIONAL_MEMORY.
|
|
6503
6617
|
*/
|
|
6504
6618
|
const OM_TABLE = "mastra_observational_memory";
|
|
6619
|
+
/** Canonical head order: newest generation, then earliest createdAt, then lowest id. */
|
|
6620
|
+
const OM_HEAD_SORT = {
|
|
6621
|
+
generationCount: -1,
|
|
6622
|
+
createdAt: 1,
|
|
6623
|
+
id: 1
|
|
6624
|
+
};
|
|
6625
|
+
/** Max redirects when a write aimed at a retired record follows the head. */
|
|
6626
|
+
const OM_MAX_HEAD_HOPS = 3;
|
|
6627
|
+
/** Max read-decide-conditional-update rounds before giving up on a contended record. */
|
|
6628
|
+
const OM_MAX_CONDITIONAL_ATTEMPTS = 3;
|
|
6629
|
+
/** Document `_id` of a key's generation-0 record; see `initializeObservationalMemory`. */
|
|
6630
|
+
function getGeneration0DocumentId(lookupKey) {
|
|
6631
|
+
return `om0_${(0, crypto$1.createHash)("sha256").update(lookupKey).digest("hex").slice(0, 32)}`;
|
|
6632
|
+
}
|
|
6633
|
+
/**
|
|
6634
|
+
* The successor document of a fenced (frozen) document: a pure function of the old document's
|
|
6635
|
+
* final state and the rollover inputs, so concurrent roll-forwards insert identical documents.
|
|
6636
|
+
* Buffered chunks, the cursor, buffering markers, flags, and counters carry over; buffered
|
|
6637
|
+
* reflection state does not.
|
|
6638
|
+
*/
|
|
6639
|
+
function buildSuccessorDocument(old, pending) {
|
|
6640
|
+
let activeObservations = pending.reflection;
|
|
6641
|
+
let observationTokenCount = pending.tokenCount;
|
|
6642
|
+
if (pending.mode === "append") {
|
|
6643
|
+
const tail = String(old.activeObservations ?? "").slice(pending.snapTextLength).trimStart();
|
|
6644
|
+
activeObservations = pending.reflection ? `${pending.reflection}\n\n${tail}` : tail;
|
|
6645
|
+
observationTokenCount = pending.tokenCount + Math.max(0, Number(old.observationTokenCount || 0) - pending.snapObservationTokenCount);
|
|
6646
|
+
}
|
|
6647
|
+
return {
|
|
6648
|
+
id: pending.newId,
|
|
6649
|
+
lookupKey: old.lookupKey,
|
|
6650
|
+
scope: old.scope,
|
|
6651
|
+
resourceId: old.resourceId,
|
|
6652
|
+
threadId: old.threadId ?? null,
|
|
6653
|
+
activeObservations,
|
|
6654
|
+
activeObservationsPendingUpdate: null,
|
|
6655
|
+
originType: "reflection",
|
|
6656
|
+
config: old.config ?? null,
|
|
6657
|
+
generationCount: Number(old.generationCount || 0) + 1,
|
|
6658
|
+
lastObservedAt: old.lastObservedAt ?? null,
|
|
6659
|
+
lastReflectionAt: pending.createdAt,
|
|
6660
|
+
pendingMessageTokens: old.pendingMessageTokens ?? 0,
|
|
6661
|
+
totalTokensObserved: old.totalTokensObserved ?? 0,
|
|
6662
|
+
observationTokenCount,
|
|
6663
|
+
bufferedObservationChunks: Array.isArray(old.bufferedObservationChunks) ? old.bufferedObservationChunks : [],
|
|
6664
|
+
isObserving: false,
|
|
6665
|
+
isReflecting: false,
|
|
6666
|
+
isBufferingObservation: Boolean(old.isBufferingObservation),
|
|
6667
|
+
isBufferingReflection: false,
|
|
6668
|
+
lastBufferedAtTokens: old.lastBufferedAtTokens ?? 0,
|
|
6669
|
+
lastBufferedAtTime: old.lastBufferedAtTime ?? null,
|
|
6670
|
+
observedTimezone: old.observedTimezone ?? null,
|
|
6671
|
+
metadata: old.metadata ?? null,
|
|
6672
|
+
supersededBy: null,
|
|
6673
|
+
createdAt: pending.createdAt,
|
|
6674
|
+
updatedAt: pending.createdAt
|
|
6675
|
+
};
|
|
6676
|
+
}
|
|
6677
|
+
/** Equality filters for `fields` as stored in `doc` (`$exists: false` for absent fields). */
|
|
6678
|
+
function matchStoredFields(doc, fields) {
|
|
6679
|
+
return Object.fromEntries(fields.map((f) => [f, doc[f] === void 0 ? { $exists: false } : doc[f]]));
|
|
6680
|
+
}
|
|
6681
|
+
function omNotFound(operation, id) {
|
|
6682
|
+
return new _mastra_core_error.MastraError({
|
|
6683
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", operation, "NOT_FOUND"),
|
|
6684
|
+
text: `Observational memory record not found: ${id}`,
|
|
6685
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
6686
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
6687
|
+
details: { id }
|
|
6688
|
+
});
|
|
6689
|
+
}
|
|
6690
|
+
function omConflict(operation, id) {
|
|
6691
|
+
return new _mastra_core_error.MastraError({
|
|
6692
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", operation, "CONFLICT"),
|
|
6693
|
+
text: `Observational memory record ${id} kept changing during ${operation}; giving up after ${OM_MAX_CONDITIONAL_ATTEMPTS} attempts`,
|
|
6694
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
6695
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
6696
|
+
details: { id }
|
|
6697
|
+
});
|
|
6698
|
+
}
|
|
6699
|
+
function omNoLiveHead(id) {
|
|
6700
|
+
return new _mastra_core_error.MastraError({
|
|
6701
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "RESOLVE_OBSERVATIONAL_MEMORY_HEAD", "FAILED"),
|
|
6702
|
+
text: `Observational memory record ${id} is superseded but no live head was found`,
|
|
6703
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
6704
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
6705
|
+
details: { id }
|
|
6706
|
+
});
|
|
6707
|
+
}
|
|
6505
6708
|
var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_storage.MemoryStorage {
|
|
6506
6709
|
supportsPartialThreadUpdate = true;
|
|
6507
6710
|
supportsObservationalMemory = true;
|
|
@@ -6514,11 +6717,14 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
6514
6717
|
_mastra_core_storage.TABLE_THREADS,
|
|
6515
6718
|
_mastra_core_storage.TABLE_MESSAGES,
|
|
6516
6719
|
_mastra_core_storage.TABLE_RESOURCES,
|
|
6517
|
-
OM_TABLE
|
|
6720
|
+
OM_TABLE,
|
|
6721
|
+
_mastra_core_storage.TABLE_MEMORY_RUN_FENCES
|
|
6518
6722
|
];
|
|
6519
6723
|
/**
|
|
6520
6724
|
* Retention-eligible collections. The observational-memory collection is
|
|
6521
6725
|
* excluded: it has no timestamp anchor to age on. All anchors are BSON dates.
|
|
6726
|
+
* A run fence's `retiredAt` stays null until the execution holding it
|
|
6727
|
+
* settles, and null is never pruned.
|
|
6522
6728
|
*/
|
|
6523
6729
|
static retentionTables = {
|
|
6524
6730
|
messages: {
|
|
@@ -6535,6 +6741,11 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
6535
6741
|
table: _mastra_core_storage.TABLE_THREADS,
|
|
6536
6742
|
column: "createdAt",
|
|
6537
6743
|
indexed: true
|
|
6744
|
+
},
|
|
6745
|
+
runFences: {
|
|
6746
|
+
table: _mastra_core_storage.TABLE_MEMORY_RUN_FENCES,
|
|
6747
|
+
column: "retiredAt",
|
|
6748
|
+
indexed: true
|
|
6538
6749
|
}
|
|
6539
6750
|
};
|
|
6540
6751
|
constructor(config) {
|
|
@@ -6549,13 +6760,80 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
6549
6760
|
async init() {
|
|
6550
6761
|
await this.createDefaultIndexes();
|
|
6551
6762
|
await this.createCustomIndexes();
|
|
6763
|
+
await this.#warnIfOMIdIndexMissing();
|
|
6764
|
+
await this.#maintainSupersededBy();
|
|
6765
|
+
}
|
|
6766
|
+
/**
|
|
6767
|
+
* Fenced writes need multi-document transactions, so only replica sets and
|
|
6768
|
+
* sharded clusters fence. Rejects while the deployment can't be probed.
|
|
6769
|
+
*/
|
|
6770
|
+
supportsRunFencing() {
|
|
6771
|
+
return this.#connector.probeTransactions();
|
|
6772
|
+
}
|
|
6773
|
+
async raiseRunFence(fence) {
|
|
6774
|
+
try {
|
|
6775
|
+
const fences = await getRunClaims(this.#connector, _mastra_core_storage.TABLE_MEMORY_RUN_FENCES);
|
|
6776
|
+
for (;;) {
|
|
6777
|
+
try {
|
|
6778
|
+
await fences.updateOne({
|
|
6779
|
+
_id: fence.runId,
|
|
6780
|
+
$or: [{ generation: { $lt: fence.generation } }, {
|
|
6781
|
+
generation: fence.generation,
|
|
6782
|
+
ownerId: fence.ownerId
|
|
6783
|
+
}]
|
|
6784
|
+
}, { $set: {
|
|
6785
|
+
generation: fence.generation,
|
|
6786
|
+
ownerId: fence.ownerId,
|
|
6787
|
+
retiredAt: null
|
|
6788
|
+
} }, { upsert: true });
|
|
6789
|
+
return true;
|
|
6790
|
+
} catch (error) {
|
|
6791
|
+
if (!isDuplicateKeyError(error)) throw error;
|
|
6792
|
+
}
|
|
6793
|
+
const current = await fences.findOne({ _id: fence.runId });
|
|
6794
|
+
if (current && current.generation >= fence.generation) return current.generation === fence.generation && current.ownerId === fence.ownerId;
|
|
6795
|
+
}
|
|
6796
|
+
} catch (error) {
|
|
6797
|
+
throw new _mastra_core_error.MastraError({
|
|
6798
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "RAISE_RUN_FENCE", "FAILED"),
|
|
6799
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
6800
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
6801
|
+
details: { runId: fence.runId }
|
|
6802
|
+
}, error);
|
|
6803
|
+
}
|
|
6804
|
+
}
|
|
6805
|
+
async retireRunFence(fence) {
|
|
6806
|
+
try {
|
|
6807
|
+
return (await (await getRunClaims(this.#connector, _mastra_core_storage.TABLE_MEMORY_RUN_FENCES)).updateOne({
|
|
6808
|
+
_id: fence.runId,
|
|
6809
|
+
generation: fence.generation,
|
|
6810
|
+
ownerId: fence.ownerId
|
|
6811
|
+
}, [{ $set: { retiredAt: "$$NOW" } }])).matchedCount > 0;
|
|
6812
|
+
} catch (error) {
|
|
6813
|
+
throw new _mastra_core_error.MastraError({
|
|
6814
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "RETIRE_RUN_FENCE", "FAILED"),
|
|
6815
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
6816
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
6817
|
+
details: { runId: fence.runId }
|
|
6818
|
+
}, error);
|
|
6819
|
+
}
|
|
6820
|
+
}
|
|
6821
|
+
/** The check a write must pass: its own fence, otherwise the one in scope. */
|
|
6822
|
+
#runFenceCheck(fence, operation) {
|
|
6823
|
+
const resolved = (0, _mastra_core_storage.resolveRunFence)(this, fence);
|
|
6824
|
+
return resolved && {
|
|
6825
|
+
claims: _mastra_core_storage.TABLE_MEMORY_RUN_FENCES,
|
|
6826
|
+
fence: resolved,
|
|
6827
|
+
operation
|
|
6828
|
+
};
|
|
6552
6829
|
}
|
|
6553
6830
|
/**
|
|
6554
6831
|
* Delete memory rows older than each table's `maxAge`, batched. Order is
|
|
6555
6832
|
* messages → resources → threads so child rows never outlive the delete of
|
|
6556
|
-
* their thread
|
|
6557
|
-
*
|
|
6558
|
-
*
|
|
6833
|
+
* their thread; run fences are independent and go last. Like
|
|
6834
|
+
* `deleteThread()`, this does not sweep vector-store embeddings —
|
|
6835
|
+
* semantic-recall vectors live in a separate vector store the memory domain
|
|
6836
|
+
* cannot reach; cleaning those up is the operator's concern.
|
|
6559
6837
|
*/
|
|
6560
6838
|
async prune(policies, options) {
|
|
6561
6839
|
const targets = resolveTargets({
|
|
@@ -6564,7 +6842,8 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
6564
6842
|
order: [
|
|
6565
6843
|
"messages",
|
|
6566
6844
|
"resources",
|
|
6567
|
-
"threads"
|
|
6845
|
+
"threads",
|
|
6846
|
+
"runFences"
|
|
6568
6847
|
]
|
|
6569
6848
|
});
|
|
6570
6849
|
return runPrune({
|
|
@@ -6670,17 +6949,19 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
6670
6949
|
}
|
|
6671
6950
|
}
|
|
6672
6951
|
async dangerouslyClearAll() {
|
|
6673
|
-
const [threadsCollection, messagesCollection, resourcesCollection, omCollection] = await Promise.all([
|
|
6952
|
+
const [threadsCollection, messagesCollection, resourcesCollection, omCollection, fencesCollection] = await Promise.all([
|
|
6674
6953
|
this.getCollection(_mastra_core_storage.TABLE_THREADS),
|
|
6675
6954
|
this.getCollection(_mastra_core_storage.TABLE_MESSAGES),
|
|
6676
6955
|
this.getCollection(_mastra_core_storage.TABLE_RESOURCES),
|
|
6677
|
-
this.getCollection(OM_TABLE)
|
|
6956
|
+
this.getCollection(OM_TABLE),
|
|
6957
|
+
this.getCollection(_mastra_core_storage.TABLE_MEMORY_RUN_FENCES)
|
|
6678
6958
|
]);
|
|
6679
6959
|
await Promise.all([
|
|
6680
6960
|
threadsCollection.deleteMany({}),
|
|
6681
6961
|
messagesCollection.deleteMany({}),
|
|
6682
6962
|
resourcesCollection.deleteMany({}),
|
|
6683
|
-
omCollection.deleteMany({})
|
|
6963
|
+
omCollection.deleteMany({}),
|
|
6964
|
+
fencesCollection.deleteMany({})
|
|
6684
6965
|
]);
|
|
6685
6966
|
}
|
|
6686
6967
|
parseRow(row) {
|
|
@@ -7036,7 +7317,7 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7036
7317
|
throw mastraError;
|
|
7037
7318
|
}
|
|
7038
7319
|
}
|
|
7039
|
-
async saveMessages({ messages }) {
|
|
7320
|
+
async saveMessages({ messages, fence }) {
|
|
7040
7321
|
if (messages.length === 0) return { messages: [] };
|
|
7041
7322
|
try {
|
|
7042
7323
|
if (!messages[0]?.threadId) throw new Error("Thread ID is required");
|
|
@@ -7064,12 +7345,16 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7064
7345
|
});
|
|
7065
7346
|
const allThreadIds = new Set(messages.map((m) => m.threadId));
|
|
7066
7347
|
const now = /* @__PURE__ */ new Date();
|
|
7067
|
-
|
|
7348
|
+
const writeMessages = async (session) => {
|
|
7068
7349
|
await collection.bulkWrite(messagesToInsert, { session });
|
|
7069
7350
|
for (const tid of allThreadIds) await threadsCollection.updateOne({ id: tid }, { $set: { updatedAt: now } }, { session });
|
|
7070
|
-
}
|
|
7351
|
+
};
|
|
7352
|
+
const check = this.#runFenceCheck(fence, "saveMessages");
|
|
7353
|
+
if (check) await withRunFence(this.#connector, check, writeMessages);
|
|
7354
|
+
else await this.#connector.withTransaction(writeMessages);
|
|
7071
7355
|
return { messages: new _mastra_core_agent.MessageList().add(messages, "memory").get.all.db() };
|
|
7072
7356
|
} catch (error) {
|
|
7357
|
+
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
7073
7358
|
throw new _mastra_core_error.MastraError({
|
|
7074
7359
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "SAVE_MESSAGES", "FAILED"),
|
|
7075
7360
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -7077,49 +7362,51 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7077
7362
|
}, error);
|
|
7078
7363
|
}
|
|
7079
7364
|
}
|
|
7080
|
-
async updateMessages({ messages }) {
|
|
7365
|
+
async updateMessages({ messages, fence }) {
|
|
7081
7366
|
if (messages.length === 0) return [];
|
|
7082
7367
|
const messageIds = messages.map((m) => m.id);
|
|
7083
7368
|
const collection = await this.getCollection(_mastra_core_storage.TABLE_MESSAGES);
|
|
7084
|
-
|
|
7085
|
-
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
|
|
7089
|
-
const
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
|
|
7099
|
-
|
|
7100
|
-
|
|
7101
|
-
|
|
7102
|
-
...existingMessage.content.metadata
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
const
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7369
|
+
return withRunFence(this.#connector, this.#runFenceCheck(fence, "updateMessages"), async (session) => {
|
|
7370
|
+
const existingMessagesParsed = (await collection.find({ id: { $in: messageIds } }, { session }).toArray()).map((msg) => this.parseRow(msg));
|
|
7371
|
+
if (existingMessagesParsed.length === 0) return [];
|
|
7372
|
+
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
7373
|
+
const bulkOps = [];
|
|
7374
|
+
for (const existingMessage of existingMessagesParsed) {
|
|
7375
|
+
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
7376
|
+
if (!updatePayload) continue;
|
|
7377
|
+
const { id, ...fieldsToUpdate } = updatePayload;
|
|
7378
|
+
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
7379
|
+
threadIdsToUpdate.add(existingMessage.threadId);
|
|
7380
|
+
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) threadIdsToUpdate.add(updatePayload.threadId);
|
|
7381
|
+
const updateDoc = {};
|
|
7382
|
+
const updatableFields = { ...fieldsToUpdate };
|
|
7383
|
+
if (updatableFields.content) {
|
|
7384
|
+
const newContent = {
|
|
7385
|
+
...existingMessage.content,
|
|
7386
|
+
...updatableFields.content,
|
|
7387
|
+
...existingMessage.content?.metadata && updatableFields.content.metadata ? { metadata: {
|
|
7388
|
+
...existingMessage.content.metadata,
|
|
7389
|
+
...updatableFields.content.metadata
|
|
7390
|
+
} } : {}
|
|
7391
|
+
};
|
|
7392
|
+
updateDoc.content = JSON.stringify(newContent);
|
|
7393
|
+
delete updatableFields.content;
|
|
7394
|
+
}
|
|
7395
|
+
for (const key in updatableFields) if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
|
|
7396
|
+
const dbKey = key === "threadId" ? "thread_id" : key;
|
|
7397
|
+
let value = updatableFields[key];
|
|
7398
|
+
if (typeof value === "object" && value !== null) value = JSON.stringify(value);
|
|
7399
|
+
updateDoc[dbKey] = value;
|
|
7400
|
+
}
|
|
7401
|
+
if (Object.keys(updateDoc).length > 0) bulkOps.push({ updateOne: {
|
|
7402
|
+
filter: { id },
|
|
7403
|
+
update: { $set: updateDoc }
|
|
7404
|
+
} });
|
|
7114
7405
|
}
|
|
7115
|
-
if (
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7119
|
-
}
|
|
7120
|
-
if (bulkOps.length > 0) await collection.bulkWrite(bulkOps);
|
|
7121
|
-
if (threadIdsToUpdate.size > 0) await (await this.getCollection(_mastra_core_storage.TABLE_THREADS)).updateMany({ id: { $in: Array.from(threadIdsToUpdate) } }, { $set: { updatedAt: /* @__PURE__ */ new Date() } });
|
|
7122
|
-
return (await collection.find({ id: { $in: messageIds } }).toArray()).map((row) => this.parseRow(row));
|
|
7406
|
+
if (bulkOps.length > 0) await collection.bulkWrite(bulkOps, { session });
|
|
7407
|
+
if (threadIdsToUpdate.size > 0) await (await this.getCollection(_mastra_core_storage.TABLE_THREADS)).updateMany({ id: { $in: Array.from(threadIdsToUpdate) } }, { $set: { updatedAt: /* @__PURE__ */ new Date() } }, { session });
|
|
7408
|
+
return (await collection.find({ id: { $in: messageIds } }, { session }).toArray()).map((row) => this.parseRow(row));
|
|
7409
|
+
});
|
|
7123
7410
|
}
|
|
7124
7411
|
async getResourceById({ resourceId }) {
|
|
7125
7412
|
try {
|
|
@@ -7154,9 +7441,11 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7154
7441
|
}, error);
|
|
7155
7442
|
}
|
|
7156
7443
|
}
|
|
7157
|
-
async updateResource({ resourceId, workingMemory, metadata }) {
|
|
7444
|
+
async updateResource({ resourceId, workingMemory, metadata, fence }) {
|
|
7158
7445
|
try {
|
|
7446
|
+
const check = this.#runFenceCheck(fence, "updateResource");
|
|
7159
7447
|
const existingResource = await this.getResourceById({ resourceId });
|
|
7448
|
+
const collection = await this.getCollection(_mastra_core_storage.TABLE_RESOURCES);
|
|
7160
7449
|
if (!existingResource) {
|
|
7161
7450
|
const newResource = {
|
|
7162
7451
|
id: resourceId,
|
|
@@ -7165,7 +7454,11 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7165
7454
|
createdAt: /* @__PURE__ */ new Date(),
|
|
7166
7455
|
updatedAt: /* @__PURE__ */ new Date()
|
|
7167
7456
|
};
|
|
7168
|
-
|
|
7457
|
+
await withRunFence(this.#connector, check, (session) => collection.updateOne({ id: resourceId }, { $set: { ...newResource } }, {
|
|
7458
|
+
upsert: true,
|
|
7459
|
+
session
|
|
7460
|
+
}));
|
|
7461
|
+
return newResource;
|
|
7169
7462
|
}
|
|
7170
7463
|
const updatedResource = {
|
|
7171
7464
|
...existingResource,
|
|
@@ -7176,13 +7469,13 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7176
7469
|
} : existingResource.metadata,
|
|
7177
7470
|
updatedAt: /* @__PURE__ */ new Date()
|
|
7178
7471
|
};
|
|
7179
|
-
const collection = await this.getCollection(_mastra_core_storage.TABLE_RESOURCES);
|
|
7180
7472
|
const updateDoc = { updatedAt: updatedResource.updatedAt };
|
|
7181
7473
|
if (workingMemory !== void 0) updateDoc.workingMemory = workingMemory;
|
|
7182
7474
|
if (metadata) updateDoc.metadata = updatedResource.metadata;
|
|
7183
|
-
await collection.updateOne({ id: resourceId }, { $set: updateDoc });
|
|
7475
|
+
await withRunFence(this.#connector, check, (session) => collection.updateOne({ id: resourceId }, { $set: updateDoc }, { session }));
|
|
7184
7476
|
return updatedResource;
|
|
7185
7477
|
} catch (error) {
|
|
7478
|
+
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
7186
7479
|
throw new _mastra_core_error.MastraError({
|
|
7187
7480
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "UPDATE_RESOURCE", "FAILED"),
|
|
7188
7481
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -7282,14 +7575,19 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7282
7575
|
throw mastraError;
|
|
7283
7576
|
}
|
|
7284
7577
|
}
|
|
7285
|
-
async saveThread({ thread }) {
|
|
7578
|
+
async saveThread({ thread, fence }) {
|
|
7286
7579
|
try {
|
|
7287
|
-
|
|
7580
|
+
const collection = await this.getCollection(_mastra_core_storage.TABLE_THREADS);
|
|
7581
|
+
await withRunFence(this.#connector, this.#runFenceCheck(fence, "saveThread"), (session) => collection.updateOne({ id: thread.id }, { $set: {
|
|
7288
7582
|
...thread,
|
|
7289
7583
|
metadata: thread.metadata
|
|
7290
|
-
} }, {
|
|
7584
|
+
} }, {
|
|
7585
|
+
upsert: true,
|
|
7586
|
+
session
|
|
7587
|
+
}));
|
|
7291
7588
|
return thread;
|
|
7292
7589
|
} catch (error) {
|
|
7590
|
+
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
7293
7591
|
throw new _mastra_core_error.MastraError({
|
|
7294
7592
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "SAVE_THREAD", "FAILED"),
|
|
7295
7593
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -7298,7 +7596,8 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7298
7596
|
}, error);
|
|
7299
7597
|
}
|
|
7300
7598
|
}
|
|
7301
|
-
async updateThread({ id, title, metadata }) {
|
|
7599
|
+
async updateThread({ id, title, metadata, fence }) {
|
|
7600
|
+
const check = this.#runFenceCheck(fence, "updateThread");
|
|
7302
7601
|
const thread = await this.getThreadById({ threadId: id });
|
|
7303
7602
|
if (!thread) throw new _mastra_core_error.MastraError({
|
|
7304
7603
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "UPDATE_THREAD", "NOT_FOUND"),
|
|
@@ -7321,12 +7620,14 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7321
7620
|
updatedAt: now
|
|
7322
7621
|
};
|
|
7323
7622
|
try {
|
|
7324
|
-
|
|
7623
|
+
const collection = await this.getCollection(_mastra_core_storage.TABLE_THREADS);
|
|
7624
|
+
await withRunFence(this.#connector, check, (session) => collection.updateOne({ id }, { $set: {
|
|
7325
7625
|
title: updatedThread.title,
|
|
7326
7626
|
metadata: updatedThread.metadata,
|
|
7327
7627
|
updatedAt: now
|
|
7328
|
-
} });
|
|
7628
|
+
} }, { session }));
|
|
7329
7629
|
} catch (error) {
|
|
7630
|
+
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
7330
7631
|
throw new _mastra_core_error.MastraError({
|
|
7331
7632
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "UPDATE_THREAD", "FAILED"),
|
|
7332
7633
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -7349,16 +7650,19 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7349
7650
|
}, error);
|
|
7350
7651
|
}
|
|
7351
7652
|
}
|
|
7352
|
-
async deleteMessages(messageIds) {
|
|
7653
|
+
async deleteMessages(messageIds, options) {
|
|
7353
7654
|
if (messageIds.length === 0) return;
|
|
7354
7655
|
try {
|
|
7355
7656
|
const messagesCollection = await this.getCollection(_mastra_core_storage.TABLE_MESSAGES);
|
|
7356
7657
|
const threadsCollection = await this.getCollection(_mastra_core_storage.TABLE_THREADS);
|
|
7357
|
-
|
|
7358
|
-
|
|
7359
|
-
|
|
7360
|
-
|
|
7658
|
+
await withRunFence(this.#connector, this.#runFenceCheck(options?.fence, "deleteMessages"), async (session) => {
|
|
7659
|
+
const messagesToDelete = await messagesCollection.find({ id: { $in: messageIds } }, { session }).toArray();
|
|
7660
|
+
const threadIds = [...new Set(messagesToDelete.map((m) => m.thread_id))];
|
|
7661
|
+
await messagesCollection.deleteMany({ id: { $in: messageIds } }, { session });
|
|
7662
|
+
if (threadIds.length > 0) await threadsCollection.updateMany({ id: { $in: threadIds } }, { $set: { updatedAt: /* @__PURE__ */ new Date() } }, { session });
|
|
7663
|
+
});
|
|
7361
7664
|
} catch (error) {
|
|
7665
|
+
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
7362
7666
|
throw new _mastra_core_error.MastraError({
|
|
7363
7667
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "DELETE_MESSAGES", "FAILED"),
|
|
7364
7668
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -7526,15 +7830,15 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7526
7830
|
config: doc.config || {},
|
|
7527
7831
|
metadata: doc.metadata || void 0,
|
|
7528
7832
|
observedMessageIds: doc.observedMessageIds || void 0,
|
|
7529
|
-
observedTimezone: doc.observedTimezone || void 0
|
|
7833
|
+
observedTimezone: doc.observedTimezone || void 0,
|
|
7834
|
+
supersededBy: doc.supersededBy ?? null
|
|
7530
7835
|
};
|
|
7531
7836
|
}
|
|
7532
7837
|
async getObservationalMemory(threadId, resourceId) {
|
|
7533
7838
|
try {
|
|
7534
|
-
const
|
|
7535
|
-
const doc = await (
|
|
7536
|
-
|
|
7537
|
-
return this.parseOMDocument(doc);
|
|
7839
|
+
const collection = await this.getCollection(OM_TABLE);
|
|
7840
|
+
const doc = await this.#getHeadDoc(collection, this.getOMKey(threadId, resourceId));
|
|
7841
|
+
return doc ? this.parseOMDocument(doc) : null;
|
|
7538
7842
|
} catch (error) {
|
|
7539
7843
|
throw new _mastra_core_error.MastraError({
|
|
7540
7844
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "GET_OBSERVATIONAL_MEMORY", "FAILED"),
|
|
@@ -7597,60 +7901,55 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7597
7901
|
}
|
|
7598
7902
|
async initializeObservationalMemory(input) {
|
|
7599
7903
|
try {
|
|
7904
|
+
const lookupKey = this.getOMKey(input.threadId, input.resourceId);
|
|
7905
|
+
const collection = await this.getCollection(OM_TABLE);
|
|
7906
|
+
const existing = await this.#getHeadDoc(collection, lookupKey);
|
|
7907
|
+
if (existing) return this.parseOMDocument(existing);
|
|
7600
7908
|
const id = globalThis.crypto.randomUUID();
|
|
7601
7909
|
const now = /* @__PURE__ */ new Date();
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
observationTokenCount: 0,
|
|
7642
|
-
isObserving: false,
|
|
7643
|
-
isReflecting: false,
|
|
7644
|
-
isBufferingObservation: false,
|
|
7645
|
-
isBufferingReflection: false,
|
|
7646
|
-
lastBufferedAtTokens: 0,
|
|
7647
|
-
lastBufferedAtTime: null,
|
|
7648
|
-
observedTimezone: input.observedTimezone || null,
|
|
7649
|
-
createdAt: now,
|
|
7650
|
-
updatedAt: now
|
|
7910
|
+
try {
|
|
7911
|
+
await collection.insertOne({
|
|
7912
|
+
_id: getGeneration0DocumentId(lookupKey),
|
|
7913
|
+
id,
|
|
7914
|
+
lookupKey,
|
|
7915
|
+
scope: input.scope,
|
|
7916
|
+
resourceId: input.resourceId,
|
|
7917
|
+
threadId: input.threadId || null,
|
|
7918
|
+
activeObservations: "",
|
|
7919
|
+
activeObservationsPendingUpdate: null,
|
|
7920
|
+
originType: "initial",
|
|
7921
|
+
config: input.config,
|
|
7922
|
+
generationCount: 0,
|
|
7923
|
+
lastObservedAt: null,
|
|
7924
|
+
lastReflectionAt: null,
|
|
7925
|
+
pendingMessageTokens: 0,
|
|
7926
|
+
totalTokensObserved: 0,
|
|
7927
|
+
observationTokenCount: 0,
|
|
7928
|
+
isObserving: false,
|
|
7929
|
+
isReflecting: false,
|
|
7930
|
+
isBufferingObservation: false,
|
|
7931
|
+
isBufferingReflection: false,
|
|
7932
|
+
lastBufferedAtTokens: 0,
|
|
7933
|
+
lastBufferedAtTime: null,
|
|
7934
|
+
observedTimezone: input.observedTimezone || null,
|
|
7935
|
+
supersededBy: null,
|
|
7936
|
+
createdAt: now,
|
|
7937
|
+
updatedAt: now
|
|
7938
|
+
});
|
|
7939
|
+
} catch (error) {
|
|
7940
|
+
if (!isDuplicateKeyError(error)) throw error;
|
|
7941
|
+
}
|
|
7942
|
+
const head = await this.#getHeadDoc(collection, lookupKey);
|
|
7943
|
+
if (!head) throw new _mastra_core_error.MastraError({
|
|
7944
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "INITIALIZE_OBSERVATIONAL_MEMORY", "NOT_FOUND"),
|
|
7945
|
+
text: `Observational memory record not found after initialization: ${id}`,
|
|
7946
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
7947
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
7948
|
+
details: { id }
|
|
7651
7949
|
});
|
|
7652
|
-
return
|
|
7950
|
+
return this.parseOMDocument(head);
|
|
7653
7951
|
} catch (error) {
|
|
7952
|
+
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
7654
7953
|
throw new _mastra_core_error.MastraError({
|
|
7655
7954
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "INITIALIZE_OBSERVATIONAL_MEMORY", "FAILED"),
|
|
7656
7955
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -7695,6 +7994,7 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7695
7994
|
lastBufferedAtTime: record.lastBufferedAtTime || null,
|
|
7696
7995
|
observedTimezone: record.observedTimezone || null,
|
|
7697
7996
|
metadata: record.metadata || null,
|
|
7997
|
+
supersededBy: record.supersededBy ?? null,
|
|
7698
7998
|
createdAt: record.createdAt,
|
|
7699
7999
|
updatedAt: record.updatedAt
|
|
7700
8000
|
});
|
|
@@ -7712,28 +8012,40 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7712
8012
|
}
|
|
7713
8013
|
}
|
|
7714
8014
|
async updateActiveObservations(input) {
|
|
8015
|
+
assertActiveObservationsApplied(await this.commitActiveObservations(input), input.id);
|
|
8016
|
+
}
|
|
8017
|
+
async commitActiveObservations(input) {
|
|
7715
8018
|
try {
|
|
7716
|
-
const now = /* @__PURE__ */ new Date();
|
|
7717
8019
|
const collection = await this.getCollection(OM_TABLE);
|
|
7718
8020
|
const safeTokenCount = Number.isFinite(input.tokenCount) && input.tokenCount >= 0 ? input.tokenCount : 0;
|
|
7719
|
-
|
|
7720
|
-
|
|
7721
|
-
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
|
|
7731
|
-
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
|
|
7735
|
-
|
|
7736
|
-
|
|
8021
|
+
for (let attempt = 1; attempt <= OM_MAX_CONDITIONAL_ATTEMPTS; attempt++) {
|
|
8022
|
+
const doc = await collection.findOne({ id: input.id });
|
|
8023
|
+
if (!doc) throw omNotFound("UPDATE_ACTIVE_OBSERVATIONS", input.id);
|
|
8024
|
+
if (doc.supersededBy) return {
|
|
8025
|
+
applied: false,
|
|
8026
|
+
reason: "retired"
|
|
8027
|
+
};
|
|
8028
|
+
if (input.expectedActiveObservations !== void 0 && input.expectedActiveObservations !== (doc.activeObservations || "")) return {
|
|
8029
|
+
applied: false,
|
|
8030
|
+
reason: "conflict"
|
|
8031
|
+
};
|
|
8032
|
+
if ((await withRunFence(this.#connector, this.#runFenceCheck(void 0, "updateActiveObservations"), (session) => collection.updateOne({
|
|
8033
|
+
id: input.id,
|
|
8034
|
+
supersededBy: null,
|
|
8035
|
+
...matchStoredFields(doc, ["activeObservations", "lastObservedAt"])
|
|
8036
|
+
}, {
|
|
8037
|
+
$set: {
|
|
8038
|
+
activeObservations: input.observations,
|
|
8039
|
+
lastObservedAt: maxObservationCursor(doc.lastObservedAt, input.lastObservedAt),
|
|
8040
|
+
pendingMessageTokens: 0,
|
|
8041
|
+
observationTokenCount: safeTokenCount,
|
|
8042
|
+
observedMessageIds: input.observedMessageIds ?? null,
|
|
8043
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
8044
|
+
},
|
|
8045
|
+
$inc: { totalTokensObserved: safeTokenCount }
|
|
8046
|
+
}, { session }))).matchedCount === 1) return { applied: true };
|
|
8047
|
+
}
|
|
8048
|
+
throw omConflict("UPDATE_ACTIVE_OBSERVATIONS", input.id);
|
|
7737
8049
|
} catch (error) {
|
|
7738
8050
|
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
7739
8051
|
throw new _mastra_core_error.MastraError({
|
|
@@ -7746,62 +8058,31 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7746
8058
|
}
|
|
7747
8059
|
async createReflectionGeneration(input) {
|
|
7748
8060
|
try {
|
|
7749
|
-
const
|
|
7750
|
-
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
|
|
7761
|
-
|
|
7762
|
-
|
|
7763
|
-
|
|
7764
|
-
|
|
7765
|
-
|
|
7766
|
-
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
|
|
7771
|
-
lastBufferedAtTime: null,
|
|
7772
|
-
config: input.currentRecord.config,
|
|
7773
|
-
metadata: input.currentRecord.metadata,
|
|
7774
|
-
observedTimezone: input.currentRecord.observedTimezone
|
|
7775
|
-
};
|
|
7776
|
-
await (await this.getCollection(OM_TABLE)).insertOne({
|
|
7777
|
-
id,
|
|
7778
|
-
lookupKey,
|
|
7779
|
-
scope: record.scope,
|
|
7780
|
-
resourceId: record.resourceId,
|
|
7781
|
-
threadId: record.threadId || null,
|
|
7782
|
-
activeObservations: input.reflection,
|
|
7783
|
-
activeObservationsPendingUpdate: null,
|
|
7784
|
-
originType: "reflection",
|
|
7785
|
-
config: record.config,
|
|
7786
|
-
generationCount: input.currentRecord.generationCount + 1,
|
|
7787
|
-
lastObservedAt: record.lastObservedAt || null,
|
|
7788
|
-
lastReflectionAt: now,
|
|
7789
|
-
pendingMessageTokens: record.pendingMessageTokens,
|
|
7790
|
-
totalTokensObserved: record.totalTokensObserved,
|
|
7791
|
-
observationTokenCount: record.observationTokenCount,
|
|
7792
|
-
isObserving: false,
|
|
7793
|
-
isReflecting: false,
|
|
7794
|
-
isBufferingObservation: false,
|
|
7795
|
-
isBufferingReflection: false,
|
|
7796
|
-
lastBufferedAtTokens: 0,
|
|
7797
|
-
lastBufferedAtTime: null,
|
|
7798
|
-
observedTimezone: record.observedTimezone || null,
|
|
7799
|
-
createdAt: now,
|
|
7800
|
-
updatedAt: now,
|
|
7801
|
-
metadata: record.metadata || null
|
|
8061
|
+
const { currentRecord } = input;
|
|
8062
|
+
return await this.#rollOver(currentRecord, "createReflectionGeneration", (doc) => {
|
|
8063
|
+
const stored = this.parseOMDocument(doc);
|
|
8064
|
+
const plan = planReflectionGenerationText({
|
|
8065
|
+
storedObservations: stored.activeObservations,
|
|
8066
|
+
storedObservationTokenCount: stored.observationTokenCount,
|
|
8067
|
+
snapshotObservations: currentRecord.activeObservations,
|
|
8068
|
+
snapshotObservationTokenCount: currentRecord.observationTokenCount,
|
|
8069
|
+
reflection: input.reflection,
|
|
8070
|
+
tokenCount: input.tokenCount
|
|
8071
|
+
});
|
|
8072
|
+
if (!plan) return null;
|
|
8073
|
+
return {
|
|
8074
|
+
newId: input.newRecordId ?? globalThis.crypto.randomUUID(),
|
|
8075
|
+
mode: plan.mode,
|
|
8076
|
+
reflection: input.reflection,
|
|
8077
|
+
tokenCount: input.tokenCount,
|
|
8078
|
+
snapTextLength: (currentRecord.activeObservations ?? "").length,
|
|
8079
|
+
snapObservationTokenCount: currentRecord.observationTokenCount ?? 0,
|
|
8080
|
+
clearBufferedReflection: false,
|
|
8081
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
8082
|
+
};
|
|
7802
8083
|
});
|
|
7803
|
-
return record;
|
|
7804
8084
|
} catch (error) {
|
|
8085
|
+
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
7805
8086
|
throw new _mastra_core_error.MastraError({
|
|
7806
8087
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "CREATE_REFLECTION_GENERATION", "FAILED"),
|
|
7807
8088
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -7868,23 +8149,12 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7868
8149
|
}
|
|
7869
8150
|
async setBufferingObservationFlag(id, isBuffering, lastBufferedAtTokens) {
|
|
7870
8151
|
try {
|
|
7871
|
-
const collection = await this.getCollection(OM_TABLE);
|
|
7872
8152
|
const updateDoc = {
|
|
7873
8153
|
isBufferingObservation: isBuffering,
|
|
7874
8154
|
updatedAt: /* @__PURE__ */ new Date()
|
|
7875
8155
|
};
|
|
7876
8156
|
if (lastBufferedAtTokens !== void 0) updateDoc.lastBufferedAtTokens = lastBufferedAtTokens;
|
|
7877
|
-
|
|
7878
|
-
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "SET_BUFFERING_OBSERVATION_FLAG", "NOT_FOUND"),
|
|
7879
|
-
text: `Observational memory record not found: ${id}`,
|
|
7880
|
-
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
7881
|
-
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
7882
|
-
details: {
|
|
7883
|
-
id,
|
|
7884
|
-
isBuffering,
|
|
7885
|
-
lastBufferedAtTokens: lastBufferedAtTokens ?? null
|
|
7886
|
-
}
|
|
7887
|
-
});
|
|
8157
|
+
await this.#updateLiveDoc(id, "SET_BUFFERING_OBSERVATION_FLAG", { $set: updateDoc });
|
|
7888
8158
|
} catch (error) {
|
|
7889
8159
|
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
7890
8160
|
throw new _mastra_core_error.MastraError({
|
|
@@ -7955,19 +8225,10 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
7955
8225
|
}
|
|
7956
8226
|
});
|
|
7957
8227
|
try {
|
|
7958
|
-
|
|
8228
|
+
await this.#updateLiveDoc(id, "SET_PENDING_MESSAGE_TOKENS", { $set: {
|
|
7959
8229
|
pendingMessageTokens: tokenCount,
|
|
7960
8230
|
updatedAt: /* @__PURE__ */ new Date()
|
|
7961
|
-
} })
|
|
7962
|
-
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "SET_PENDING_MESSAGE_TOKENS", "NOT_FOUND"),
|
|
7963
|
-
text: `Observational memory record not found: ${id}`,
|
|
7964
|
-
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
7965
|
-
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
7966
|
-
details: {
|
|
7967
|
-
id,
|
|
7968
|
-
tokenCount
|
|
7969
|
-
}
|
|
7970
|
-
});
|
|
8231
|
+
} });
|
|
7971
8232
|
} catch (error) {
|
|
7972
8233
|
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
7973
8234
|
throw new _mastra_core_error.MastraError({
|
|
@@ -8009,6 +8270,9 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8009
8270
|
}
|
|
8010
8271
|
}
|
|
8011
8272
|
async updateBufferedObservations(input) {
|
|
8273
|
+
await this.appendBufferedObservations(input);
|
|
8274
|
+
}
|
|
8275
|
+
async appendBufferedObservations(input) {
|
|
8012
8276
|
try {
|
|
8013
8277
|
const collection = await this.getCollection(OM_TABLE);
|
|
8014
8278
|
const newChunk = {
|
|
@@ -8026,18 +8290,65 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8026
8290
|
extractedValues: input.chunk.extractedValues,
|
|
8027
8291
|
extractionFailures: input.chunk.extractionFailures
|
|
8028
8292
|
};
|
|
8029
|
-
const
|
|
8030
|
-
|
|
8031
|
-
|
|
8032
|
-
|
|
8033
|
-
|
|
8034
|
-
|
|
8035
|
-
|
|
8036
|
-
|
|
8037
|
-
|
|
8038
|
-
|
|
8039
|
-
|
|
8040
|
-
|
|
8293
|
+
const notCovered = { $or: [{ lastObservedAt: null }, { lastObservedAt: { $lt: /* @__PURE__ */ new Date(new Date(input.chunk.lastObservedAt).getTime() - 1) } }] };
|
|
8294
|
+
const lastBufferedAtTime = input.lastBufferedAtTime ? new Date(input.lastBufferedAtTime) : void 0;
|
|
8295
|
+
let targetId = input.id;
|
|
8296
|
+
let hops = 0;
|
|
8297
|
+
let retries = 0;
|
|
8298
|
+
for (;;) {
|
|
8299
|
+
if ((await withRunFence(this.#connector, this.#runFenceCheck(void 0, "updateBufferedObservations"), (session) => collection.updateOne({
|
|
8300
|
+
id: targetId,
|
|
8301
|
+
supersededBy: null,
|
|
8302
|
+
"bufferedObservationChunks.cycleId": { $ne: input.chunk.cycleId },
|
|
8303
|
+
...notCovered,
|
|
8304
|
+
$and: [{ $or: [
|
|
8305
|
+
{ bufferedObservationChunks: { $exists: false } },
|
|
8306
|
+
{ bufferedObservationChunks: null },
|
|
8307
|
+
{ bufferedObservationChunks: { $type: "array" } }
|
|
8308
|
+
] }]
|
|
8309
|
+
}, [{ $set: {
|
|
8310
|
+
bufferedObservationChunks: { $concatArrays: [{ $ifNull: ["$bufferedObservationChunks", []] }, { $literal: [newChunk] }] },
|
|
8311
|
+
...lastBufferedAtTime ? { lastBufferedAtTime: { $max: ["$lastBufferedAtTime", { $literal: lastBufferedAtTime }] } } : {},
|
|
8312
|
+
updatedAt: { $literal: /* @__PURE__ */ new Date() }
|
|
8313
|
+
} }], { session }))).matchedCount === 1) return {
|
|
8314
|
+
persisted: true,
|
|
8315
|
+
recordId: targetId
|
|
8316
|
+
};
|
|
8317
|
+
const doc = await collection.findOne({ id: targetId });
|
|
8318
|
+
if (!doc) throw omNotFound("UPDATE_BUFFERED_OBSERVATIONS", targetId);
|
|
8319
|
+
if (doc.supersededBy) {
|
|
8320
|
+
const head = hops < OM_MAX_HEAD_HOPS ? await this.#getHeadDoc(collection, doc.lookupKey) : null;
|
|
8321
|
+
if (!head || head.supersededBy || head.id === targetId) throw omNoLiveHead(input.id);
|
|
8322
|
+
targetId = head.id;
|
|
8323
|
+
hops++;
|
|
8324
|
+
continue;
|
|
8325
|
+
}
|
|
8326
|
+
const stored = doc.bufferedObservationChunks;
|
|
8327
|
+
if (Array.isArray(stored) && stored.some((c) => c?.cycleId === input.chunk.cycleId)) return {
|
|
8328
|
+
persisted: false,
|
|
8329
|
+
recordId: targetId
|
|
8330
|
+
};
|
|
8331
|
+
if (isBufferedChunkCoveredByCursor(input.chunk.lastObservedAt, doc.lastObservedAt)) return {
|
|
8332
|
+
persisted: false,
|
|
8333
|
+
recordId: targetId
|
|
8334
|
+
};
|
|
8335
|
+
if (stored !== void 0 && stored !== null && !Array.isArray(stored)) {
|
|
8336
|
+
if ((await withRunFence(this.#connector, this.#runFenceCheck(void 0, "updateBufferedObservations"), (session) => collection.updateOne({
|
|
8337
|
+
id: targetId,
|
|
8338
|
+
supersededBy: null,
|
|
8339
|
+
bufferedObservationChunks: stored,
|
|
8340
|
+
...notCovered
|
|
8341
|
+
}, { $set: {
|
|
8342
|
+
bufferedObservationChunks: [newChunk],
|
|
8343
|
+
...lastBufferedAtTime ? { lastBufferedAtTime: maxObservationCursor(doc.lastBufferedAtTime, lastBufferedAtTime) } : {},
|
|
8344
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
8345
|
+
} }, { session }))).matchedCount === 1) return {
|
|
8346
|
+
persisted: true,
|
|
8347
|
+
recordId: targetId
|
|
8348
|
+
};
|
|
8349
|
+
}
|
|
8350
|
+
if (++retries >= OM_MAX_CONDITIONAL_ATTEMPTS) throw omConflict("UPDATE_BUFFERED_OBSERVATIONS", targetId);
|
|
8351
|
+
}
|
|
8041
8352
|
} catch (error) {
|
|
8042
8353
|
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
8043
8354
|
throw new _mastra_core_error.MastraError({
|
|
@@ -8051,16 +8362,7 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8051
8362
|
async swapBufferedToActive(input) {
|
|
8052
8363
|
try {
|
|
8053
8364
|
const collection = await this.getCollection(OM_TABLE);
|
|
8054
|
-
const
|
|
8055
|
-
if (!doc) throw new _mastra_core_error.MastraError({
|
|
8056
|
-
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "SWAP_BUFFERED_TO_ACTIVE", "NOT_FOUND"),
|
|
8057
|
-
text: `Observational memory record not found: ${input.id}`,
|
|
8058
|
-
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
8059
|
-
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
8060
|
-
details: { id: input.id }
|
|
8061
|
-
});
|
|
8062
|
-
const chunks = Array.isArray(doc.bufferedObservationChunks) ? doc.bufferedObservationChunks : [];
|
|
8063
|
-
if (chunks.length === 0) return {
|
|
8365
|
+
const emptyResult = {
|
|
8064
8366
|
chunksActivated: 0,
|
|
8065
8367
|
messageTokensActivated: 0,
|
|
8066
8368
|
observationTokensActivated: 0,
|
|
@@ -8068,95 +8370,107 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8068
8370
|
activatedCycleIds: [],
|
|
8069
8371
|
activatedMessageIds: []
|
|
8070
8372
|
};
|
|
8071
|
-
|
|
8072
|
-
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
|
|
8076
|
-
|
|
8077
|
-
|
|
8078
|
-
|
|
8079
|
-
|
|
8080
|
-
const
|
|
8081
|
-
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
|
|
8373
|
+
for (let attempt = 1; attempt <= OM_MAX_CONDITIONAL_ATTEMPTS; attempt++) {
|
|
8374
|
+
const doc = await collection.findOne({ id: input.id });
|
|
8375
|
+
if (!doc) throw omNotFound("SWAP_BUFFERED_TO_ACTIVE", input.id);
|
|
8376
|
+
if (doc.supersededBy) return {
|
|
8377
|
+
...emptyResult,
|
|
8378
|
+
retired: true
|
|
8379
|
+
};
|
|
8380
|
+
const persistedChunks = Array.isArray(doc.bufferedObservationChunks) ? doc.bufferedObservationChunks : [];
|
|
8381
|
+
const refreshedWeights = new Map((Array.isArray(input.bufferedChunks) ? input.bufferedChunks : []).map((c) => [c.id, c.messageTokens]));
|
|
8382
|
+
const chunks = persistedChunks.map((c) => refreshedWeights.has(c.id) ? {
|
|
8383
|
+
...c,
|
|
8384
|
+
messageTokens: refreshedWeights.get(c.id)
|
|
8385
|
+
} : c);
|
|
8386
|
+
if (chunks.length === 0) return emptyResult;
|
|
8387
|
+
const retentionFloor = input.messageTokensThreshold * (1 - input.activationRatio);
|
|
8388
|
+
const targetMessageTokens = Math.max(0, input.currentPendingTokens - retentionFloor);
|
|
8389
|
+
let cumulativeMessageTokens = 0;
|
|
8390
|
+
let bestOverBoundary = 0;
|
|
8391
|
+
let bestOverTokens = 0;
|
|
8392
|
+
let bestUnderBoundary = 0;
|
|
8393
|
+
let bestUnderTokens = 0;
|
|
8394
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
8395
|
+
cumulativeMessageTokens += chunks[i].messageTokens ?? 0;
|
|
8396
|
+
const boundary = i + 1;
|
|
8397
|
+
if (cumulativeMessageTokens >= targetMessageTokens) {
|
|
8398
|
+
if (bestOverBoundary === 0 || cumulativeMessageTokens < bestOverTokens) {
|
|
8399
|
+
bestOverBoundary = boundary;
|
|
8400
|
+
bestOverTokens = cumulativeMessageTokens;
|
|
8401
|
+
}
|
|
8402
|
+
} else if (cumulativeMessageTokens > bestUnderTokens) {
|
|
8403
|
+
bestUnderBoundary = boundary;
|
|
8404
|
+
bestUnderTokens = cumulativeMessageTokens;
|
|
8085
8405
|
}
|
|
8086
|
-
} else if (cumulativeMessageTokens > bestUnderTokens) {
|
|
8087
|
-
bestUnderBoundary = boundary;
|
|
8088
|
-
bestUnderTokens = cumulativeMessageTokens;
|
|
8089
8406
|
}
|
|
8407
|
+
const maxOvershoot = retentionFloor * .95;
|
|
8408
|
+
const overshoot = bestOverTokens - targetMessageTokens;
|
|
8409
|
+
const remainingAfterOver = input.currentPendingTokens - bestOverTokens;
|
|
8410
|
+
const remainingAfterUnder = input.currentPendingTokens - bestUnderTokens;
|
|
8411
|
+
const minRemaining = Math.min(1e3, retentionFloor);
|
|
8412
|
+
let chunksToActivate;
|
|
8413
|
+
if (input.forceMaxActivation && bestOverBoundary > 0 && remainingAfterOver >= minRemaining) chunksToActivate = bestOverBoundary;
|
|
8414
|
+
else if (bestOverBoundary > 0 && overshoot <= maxOvershoot && remainingAfterOver >= minRemaining) chunksToActivate = bestOverBoundary;
|
|
8415
|
+
else if (bestUnderBoundary > 0 && remainingAfterUnder >= minRemaining) chunksToActivate = bestUnderBoundary;
|
|
8416
|
+
else if (bestOverBoundary > 0) chunksToActivate = bestOverBoundary;
|
|
8417
|
+
else chunksToActivate = 1;
|
|
8418
|
+
const activatedChunks = chunks.slice(0, chunksToActivate);
|
|
8419
|
+
const remainingChunks = persistedChunks.slice(chunksToActivate);
|
|
8420
|
+
const activatedContent = activatedChunks.map((c) => c.observations).join("\n\n");
|
|
8421
|
+
const activatedTokens = activatedChunks.reduce((sum, c) => sum + c.tokenCount, 0);
|
|
8422
|
+
const activatedMessageTokens = activatedChunks.reduce((sum, c) => sum + (c.messageTokens ?? 0), 0);
|
|
8423
|
+
const activatedMessageCount = activatedChunks.reduce((sum, c) => sum + c.messageIds.length, 0);
|
|
8424
|
+
const activatedCycleIds = activatedChunks.map((c) => c.cycleId).filter((id) => !!id);
|
|
8425
|
+
const activatedMessageIds = activatedChunks.flatMap((c) => c.messageIds ?? []);
|
|
8426
|
+
const latestChunk = activatedChunks[activatedChunks.length - 1];
|
|
8427
|
+
const lastObservedAt = input.lastObservedAt ?? (latestChunk?.lastObservedAt ? new Date(latestChunk.lastObservedAt) : /* @__PURE__ */ new Date());
|
|
8428
|
+
const existingActive = doc.activeObservations || "";
|
|
8429
|
+
const existingTokenCount = Number(doc.observationTokenCount || 0);
|
|
8430
|
+
const boundary = `\n\n--- message boundary (${lastObservedAt.toISOString()}) ---\n\n`;
|
|
8431
|
+
const newActive = existingActive ? `${existingActive}${boundary}${activatedContent}` : activatedContent;
|
|
8432
|
+
const newTokenCount = existingTokenCount + activatedTokens;
|
|
8433
|
+
const existingPending = Number(doc.pendingMessageTokens || 0);
|
|
8434
|
+
const newPending = Math.max(0, existingPending - activatedMessageTokens);
|
|
8435
|
+
if ((await withRunFence(this.#connector, this.#runFenceCheck(void 0, "swapBufferedToActive"), (session) => collection.updateOne({
|
|
8436
|
+
id: input.id,
|
|
8437
|
+
supersededBy: null,
|
|
8438
|
+
...matchStoredFields(doc, [
|
|
8439
|
+
"bufferedObservationChunks",
|
|
8440
|
+
"activeObservations",
|
|
8441
|
+
"observationTokenCount",
|
|
8442
|
+
"pendingMessageTokens",
|
|
8443
|
+
"lastObservedAt"
|
|
8444
|
+
])
|
|
8445
|
+
}, { $set: {
|
|
8446
|
+
activeObservations: newActive,
|
|
8447
|
+
observationTokenCount: newTokenCount,
|
|
8448
|
+
pendingMessageTokens: newPending,
|
|
8449
|
+
bufferedObservationChunks: remainingChunks,
|
|
8450
|
+
lastObservedAt: maxObservationCursor(doc.lastObservedAt, lastObservedAt),
|
|
8451
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
8452
|
+
} }, { session }))).matchedCount === 0) continue;
|
|
8453
|
+
const latestChunkHints = activatedChunks[activatedChunks.length - 1];
|
|
8454
|
+
return {
|
|
8455
|
+
chunksActivated: activatedChunks.length,
|
|
8456
|
+
messageTokensActivated: activatedMessageTokens,
|
|
8457
|
+
observationTokensActivated: activatedTokens,
|
|
8458
|
+
messagesActivated: activatedMessageCount,
|
|
8459
|
+
activatedCycleIds,
|
|
8460
|
+
activatedMessageIds,
|
|
8461
|
+
observations: activatedContent,
|
|
8462
|
+
perChunk: activatedChunks.map((c) => ({
|
|
8463
|
+
cycleId: c.cycleId ?? "",
|
|
8464
|
+
messageTokens: c.messageTokens ?? 0,
|
|
8465
|
+
observationTokens: c.tokenCount,
|
|
8466
|
+
messageCount: c.messageIds.length,
|
|
8467
|
+
observations: c.observations
|
|
8468
|
+
})),
|
|
8469
|
+
suggestedContinuation: latestChunkHints?.suggestedContinuation ?? void 0,
|
|
8470
|
+
currentTask: latestChunkHints?.currentTask ?? void 0
|
|
8471
|
+
};
|
|
8090
8472
|
}
|
|
8091
|
-
|
|
8092
|
-
const overshoot = bestOverTokens - targetMessageTokens;
|
|
8093
|
-
const remainingAfterOver = input.currentPendingTokens - bestOverTokens;
|
|
8094
|
-
const remainingAfterUnder = input.currentPendingTokens - bestUnderTokens;
|
|
8095
|
-
const minRemaining = Math.min(1e3, retentionFloor);
|
|
8096
|
-
let chunksToActivate;
|
|
8097
|
-
if (input.forceMaxActivation && bestOverBoundary > 0 && remainingAfterOver >= minRemaining) chunksToActivate = bestOverBoundary;
|
|
8098
|
-
else if (bestOverBoundary > 0 && overshoot <= maxOvershoot && remainingAfterOver >= minRemaining) chunksToActivate = bestOverBoundary;
|
|
8099
|
-
else if (bestUnderBoundary > 0 && remainingAfterUnder >= minRemaining) chunksToActivate = bestUnderBoundary;
|
|
8100
|
-
else if (bestOverBoundary > 0) chunksToActivate = bestOverBoundary;
|
|
8101
|
-
else chunksToActivate = 1;
|
|
8102
|
-
const activatedChunks = chunks.slice(0, chunksToActivate);
|
|
8103
|
-
const remainingChunks = chunks.slice(chunksToActivate);
|
|
8104
|
-
const activatedContent = activatedChunks.map((c) => c.observations).join("\n\n");
|
|
8105
|
-
const activatedTokens = activatedChunks.reduce((sum, c) => sum + c.tokenCount, 0);
|
|
8106
|
-
const activatedMessageTokens = activatedChunks.reduce((sum, c) => sum + (c.messageTokens ?? 0), 0);
|
|
8107
|
-
const activatedMessageCount = activatedChunks.reduce((sum, c) => sum + c.messageIds.length, 0);
|
|
8108
|
-
const activatedCycleIds = activatedChunks.map((c) => c.cycleId).filter((id) => !!id);
|
|
8109
|
-
const activatedMessageIds = activatedChunks.flatMap((c) => c.messageIds ?? []);
|
|
8110
|
-
const latestChunk = activatedChunks[activatedChunks.length - 1];
|
|
8111
|
-
const lastObservedAt = input.lastObservedAt ?? (latestChunk?.lastObservedAt ? new Date(latestChunk.lastObservedAt) : /* @__PURE__ */ new Date());
|
|
8112
|
-
const existingActive = doc.activeObservations || "";
|
|
8113
|
-
const existingTokenCount = Number(doc.observationTokenCount || 0);
|
|
8114
|
-
const boundary = `\n\n--- message boundary (${lastObservedAt.toISOString()}) ---\n\n`;
|
|
8115
|
-
const newActive = existingActive ? `${existingActive}${boundary}${activatedContent}` : activatedContent;
|
|
8116
|
-
const newTokenCount = existingTokenCount + activatedTokens;
|
|
8117
|
-
const existingPending = Number(doc.pendingMessageTokens || 0);
|
|
8118
|
-
const newPending = Math.max(0, existingPending - activatedMessageTokens);
|
|
8119
|
-
if ((await collection.updateOne({
|
|
8120
|
-
id: input.id,
|
|
8121
|
-
bufferedObservationChunks: {
|
|
8122
|
-
$exists: true,
|
|
8123
|
-
$ne: null,
|
|
8124
|
-
$not: { $size: 0 }
|
|
8125
|
-
}
|
|
8126
|
-
}, { $set: {
|
|
8127
|
-
activeObservations: newActive,
|
|
8128
|
-
observationTokenCount: newTokenCount,
|
|
8129
|
-
pendingMessageTokens: newPending,
|
|
8130
|
-
bufferedObservationChunks: remainingChunks,
|
|
8131
|
-
lastObservedAt,
|
|
8132
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
8133
|
-
} })).modifiedCount === 0) return {
|
|
8134
|
-
chunksActivated: 0,
|
|
8135
|
-
messageTokensActivated: 0,
|
|
8136
|
-
observationTokensActivated: 0,
|
|
8137
|
-
messagesActivated: 0,
|
|
8138
|
-
activatedCycleIds: [],
|
|
8139
|
-
activatedMessageIds: []
|
|
8140
|
-
};
|
|
8141
|
-
const latestChunkHints = activatedChunks[activatedChunks.length - 1];
|
|
8142
|
-
return {
|
|
8143
|
-
chunksActivated: activatedChunks.length,
|
|
8144
|
-
messageTokensActivated: activatedMessageTokens,
|
|
8145
|
-
observationTokensActivated: activatedTokens,
|
|
8146
|
-
messagesActivated: activatedMessageCount,
|
|
8147
|
-
activatedCycleIds,
|
|
8148
|
-
activatedMessageIds,
|
|
8149
|
-
observations: activatedContent,
|
|
8150
|
-
perChunk: activatedChunks.map((c) => ({
|
|
8151
|
-
cycleId: c.cycleId ?? "",
|
|
8152
|
-
messageTokens: c.messageTokens ?? 0,
|
|
8153
|
-
observationTokens: c.tokenCount,
|
|
8154
|
-
messageCount: c.messageIds.length,
|
|
8155
|
-
observations: c.observations
|
|
8156
|
-
})),
|
|
8157
|
-
suggestedContinuation: latestChunkHints?.suggestedContinuation ?? void 0,
|
|
8158
|
-
currentTask: latestChunkHints?.currentTask ?? void 0
|
|
8159
|
-
};
|
|
8473
|
+
throw omConflict("SWAP_BUFFERED_TO_ACTIVE", input.id);
|
|
8160
8474
|
} catch (error) {
|
|
8161
8475
|
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
8162
8476
|
throw new _mastra_core_error.MastraError({
|
|
@@ -8184,13 +8498,13 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8184
8498
|
const newContent = existingContent ? `${existingContent}\n\n${input.reflection}` : input.reflection;
|
|
8185
8499
|
const newTokens = existingTokens + input.tokenCount;
|
|
8186
8500
|
const newInputTokens = existingInputTokens + input.inputTokenCount;
|
|
8187
|
-
if ((await collection.updateOne({ id: input.id }, { $set: {
|
|
8501
|
+
if ((await withRunFence(this.#connector, this.#runFenceCheck(void 0, "updateBufferedReflection"), (session) => collection.updateOne({ id: input.id }, { $set: {
|
|
8188
8502
|
bufferedReflection: newContent,
|
|
8189
8503
|
bufferedReflectionTokens: newTokens,
|
|
8190
8504
|
bufferedReflectionInputTokens: newInputTokens,
|
|
8191
8505
|
reflectedObservationLineCount: input.reflectedObservationLineCount,
|
|
8192
8506
|
updatedAt: /* @__PURE__ */ new Date()
|
|
8193
|
-
} })).matchedCount === 0) throw new _mastra_core_error.MastraError({
|
|
8507
|
+
} }, { session }))).matchedCount === 0) throw new _mastra_core_error.MastraError({
|
|
8194
8508
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "UPDATE_BUFFERED_REFLECTION", "NOT_FOUND"),
|
|
8195
8509
|
text: `Observational memory record not found: ${input.id}`,
|
|
8196
8510
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -8209,39 +8523,33 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8209
8523
|
}
|
|
8210
8524
|
async swapBufferedReflectionToActive(input) {
|
|
8211
8525
|
try {
|
|
8212
|
-
const
|
|
8213
|
-
|
|
8214
|
-
|
|
8215
|
-
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
|
|
8230
|
-
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
|
|
8526
|
+
const { currentRecord } = input;
|
|
8527
|
+
return await this.#rollOver(currentRecord, "swapBufferedReflectionToActive", (doc) => {
|
|
8528
|
+
const stored = this.parseOMDocument(doc);
|
|
8529
|
+
const bufferedReflection = stored.bufferedReflection || "";
|
|
8530
|
+
if (!bufferedReflection) throw new _mastra_core_error.MastraError({
|
|
8531
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "SWAP_BUFFERED_REFLECTION_TO_ACTIVE", "NO_CONTENT"),
|
|
8532
|
+
text: "No buffered reflection to swap",
|
|
8533
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
8534
|
+
category: _mastra_core_error.ErrorCategory.USER,
|
|
8535
|
+
details: { id: currentRecord.id }
|
|
8536
|
+
});
|
|
8537
|
+
if (!isAppendOnlySince(stored.activeObservations, currentRecord.activeObservations)) return null;
|
|
8538
|
+
const reflectedLineCount = stored.reflectedObservationLineCount ?? 0;
|
|
8539
|
+
const unreflectedContent = (stored.activeObservations || "").split("\n").slice(reflectedLineCount).join("\n").trim();
|
|
8540
|
+
const newObservations = unreflectedContent ? `${bufferedReflection}\n\n${unreflectedContent}` : bufferedReflection;
|
|
8541
|
+
const tokenCount = input.tokenCount + Math.max(0, (stored.observationTokenCount ?? 0) - (currentRecord.observationTokenCount ?? 0));
|
|
8542
|
+
return {
|
|
8543
|
+
newId: input.newRecordId ?? globalThis.crypto.randomUUID(),
|
|
8544
|
+
mode: "equal",
|
|
8545
|
+
reflection: newObservations,
|
|
8546
|
+
tokenCount,
|
|
8547
|
+
snapTextLength: (stored.activeObservations ?? "").length,
|
|
8548
|
+
snapObservationTokenCount: stored.observationTokenCount ?? 0,
|
|
8549
|
+
clearBufferedReflection: true,
|
|
8550
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
8551
|
+
};
|
|
8236
8552
|
});
|
|
8237
|
-
await collection.updateOne({ id: input.currentRecord.id }, { $set: {
|
|
8238
|
-
bufferedReflection: null,
|
|
8239
|
-
bufferedReflectionTokens: null,
|
|
8240
|
-
bufferedReflectionInputTokens: null,
|
|
8241
|
-
reflectedObservationLineCount: null,
|
|
8242
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
8243
|
-
} });
|
|
8244
|
-
return newRecord;
|
|
8245
8553
|
} catch (error) {
|
|
8246
8554
|
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
8247
8555
|
throw new _mastra_core_error.MastraError({
|
|
@@ -8252,6 +8560,171 @@ var MemoryStorageMongoDB = class MemoryStorageMongoDB extends _mastra_core_stora
|
|
|
8252
8560
|
}, error);
|
|
8253
8561
|
}
|
|
8254
8562
|
}
|
|
8563
|
+
/**
|
|
8564
|
+
* The head of a lookup key by the canonical order (`generationCount DESC, createdAt ASC, id ASC`).
|
|
8565
|
+
* A head that was fenced for rollover but whose successor insert never ran (crash, or still in
|
|
8566
|
+
* flight in another process) is rolled forward here, so every head read reaches the successor.
|
|
8567
|
+
*/
|
|
8568
|
+
async #getHeadDoc(collection, lookupKey) {
|
|
8569
|
+
for (let hop = 0; hop <= OM_MAX_HEAD_HOPS; hop++) {
|
|
8570
|
+
const head = await collection.findOne({ lookupKey }, { sort: OM_HEAD_SORT });
|
|
8571
|
+
if (!head || !head.supersededBy || !head.pendingSuccessor) return head;
|
|
8572
|
+
await this.#completeRollover(collection, head, head.pendingSuccessor);
|
|
8573
|
+
}
|
|
8574
|
+
throw omNoLiveHead(lookupKey);
|
|
8575
|
+
}
|
|
8576
|
+
/**
|
|
8577
|
+
* A single-document update aimed at a live record. A retired (or concurrently fenced) id is
|
|
8578
|
+
* redirected to the head, at most `OM_MAX_HEAD_HOPS` times.
|
|
8579
|
+
*/
|
|
8580
|
+
async #updateLiveDoc(id, operation, update) {
|
|
8581
|
+
const collection = await this.getCollection(OM_TABLE);
|
|
8582
|
+
let targetId = id;
|
|
8583
|
+
for (let hop = 0; hop <= OM_MAX_HEAD_HOPS; hop++) {
|
|
8584
|
+
if ((await collection.updateOne({
|
|
8585
|
+
id: targetId,
|
|
8586
|
+
supersededBy: null
|
|
8587
|
+
}, update)).matchedCount === 1) return targetId;
|
|
8588
|
+
const doc = await collection.findOne({ id: targetId }, { projection: {
|
|
8589
|
+
lookupKey: 1,
|
|
8590
|
+
supersededBy: 1
|
|
8591
|
+
} });
|
|
8592
|
+
if (!doc) throw omNotFound(operation, targetId);
|
|
8593
|
+
if (!doc.supersededBy) continue;
|
|
8594
|
+
const head = await this.#getHeadDoc(collection, doc.lookupKey);
|
|
8595
|
+
if (!head || head.supersededBy || head.id === targetId) throw omNoLiveHead(id);
|
|
8596
|
+
targetId = head.id;
|
|
8597
|
+
}
|
|
8598
|
+
throw omNoLiveHead(id);
|
|
8599
|
+
}
|
|
8600
|
+
/**
|
|
8601
|
+
* Roll the live record `currentRecord.id` over to a new generation.
|
|
8602
|
+
*
|
|
8603
|
+
* 1. Read the stored document and decide (`decide` returns the successor inputs, or `null`
|
|
8604
|
+
* when the snapshot is stale).
|
|
8605
|
+
* 2. Fence: one conditional update sets `supersededBy` and the small `pendingSuccessor`
|
|
8606
|
+
* payload, matching only if the fields the decision read are unchanged. From here the old
|
|
8607
|
+
* document is frozen — no lifecycle write matches it — so its pre-image is its final state.
|
|
8608
|
+
* 3. Insert the successor built purely from that pre-image, then clear the old document's
|
|
8609
|
+
* chunks (they moved) and `pendingSuccessor`.
|
|
8610
|
+
*
|
|
8611
|
+
* A crash between 2 and 3 is finished by the next head read (`#getHeadDoc`) or startup.
|
|
8612
|
+
*/
|
|
8613
|
+
async #rollOver(currentRecord, operation, decide) {
|
|
8614
|
+
const collection = await this.getCollection(OM_TABLE);
|
|
8615
|
+
for (let attempt = 1; attempt <= OM_MAX_CONDITIONAL_ATTEMPTS; attempt++) {
|
|
8616
|
+
const doc = await collection.findOne({ id: currentRecord.id });
|
|
8617
|
+
if (!doc) return currentRecord;
|
|
8618
|
+
if (doc.supersededBy) {
|
|
8619
|
+
const head = await this.#getHeadDoc(collection, doc.lookupKey);
|
|
8620
|
+
return head ? this.parseOMDocument(head) : currentRecord;
|
|
8621
|
+
}
|
|
8622
|
+
const pending = decide(doc);
|
|
8623
|
+
if (!pending) return this.parseOMDocument(doc);
|
|
8624
|
+
const frozen = await withRunFence(this.#connector, this.#runFenceCheck(void 0, operation), (session) => collection.findOneAndUpdate({
|
|
8625
|
+
id: doc.id,
|
|
8626
|
+
supersededBy: null,
|
|
8627
|
+
...matchStoredFields(doc, [
|
|
8628
|
+
"activeObservations",
|
|
8629
|
+
"observationTokenCount",
|
|
8630
|
+
"bufferedReflection",
|
|
8631
|
+
"reflectedObservationLineCount"
|
|
8632
|
+
])
|
|
8633
|
+
}, { $set: {
|
|
8634
|
+
supersededBy: pending.newId,
|
|
8635
|
+
pendingSuccessor: pending
|
|
8636
|
+
} }, {
|
|
8637
|
+
returnDocument: "before",
|
|
8638
|
+
session
|
|
8639
|
+
}));
|
|
8640
|
+
if (!frozen) continue;
|
|
8641
|
+
return this.parseOMDocument(await this.#completeRollover(collection, frozen, pending));
|
|
8642
|
+
}
|
|
8643
|
+
throw omConflict("CREATE_REFLECTION_GENERATION", currentRecord.id);
|
|
8644
|
+
}
|
|
8645
|
+
/** Insert the successor of a fenced document (idempotent) and clean up the old document. */
|
|
8646
|
+
async #completeRollover(collection, frozen, pending) {
|
|
8647
|
+
try {
|
|
8648
|
+
await collection.insertOne(buildSuccessorDocument(frozen, pending));
|
|
8649
|
+
} catch (error) {
|
|
8650
|
+
if (!isDuplicateKeyError(error)) throw error;
|
|
8651
|
+
}
|
|
8652
|
+
await collection.updateOne({
|
|
8653
|
+
id: frozen.id,
|
|
8654
|
+
supersededBy: pending.newId
|
|
8655
|
+
}, {
|
|
8656
|
+
$set: {
|
|
8657
|
+
bufferedObservationChunks: [],
|
|
8658
|
+
...pending.clearBufferedReflection ? {
|
|
8659
|
+
bufferedReflection: null,
|
|
8660
|
+
bufferedReflectionTokens: null,
|
|
8661
|
+
bufferedReflectionInputTokens: null,
|
|
8662
|
+
reflectedObservationLineCount: null
|
|
8663
|
+
} : {},
|
|
8664
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
8665
|
+
},
|
|
8666
|
+
$unset: { pendingSuccessor: "" }
|
|
8667
|
+
});
|
|
8668
|
+
const successor = await collection.findOne({ id: pending.newId });
|
|
8669
|
+
if (!successor) throw omNotFound("CREATE_REFLECTION_GENERATION", pending.newId);
|
|
8670
|
+
return successor;
|
|
8671
|
+
}
|
|
8672
|
+
/**
|
|
8673
|
+
* Startup maintenance for the `supersededBy` marker:
|
|
8674
|
+
* - finish rollovers interrupted after the fence (insert the successor if missing, clean up);
|
|
8675
|
+
* - for keys with more than one live document (left by older adapter versions, which never set
|
|
8676
|
+
* `supersededBy`), retire every live document that sorts after the canonical head. The head's
|
|
8677
|
+
* ordering key is embedded in the filter, so a document created by a concurrent rollover
|
|
8678
|
+
* (a newer generation) never matches.
|
|
8679
|
+
*/
|
|
8680
|
+
async #maintainSupersededBy() {
|
|
8681
|
+
const collection = await this.getCollection(OM_TABLE);
|
|
8682
|
+
const interrupted = await collection.find({
|
|
8683
|
+
supersededBy: { $nin: [null] },
|
|
8684
|
+
pendingSuccessor: { $exists: true }
|
|
8685
|
+
}).toArray();
|
|
8686
|
+
for (const doc of interrupted) await this.#completeRollover(collection, doc, doc.pendingSuccessor);
|
|
8687
|
+
const keys = await collection.aggregate([
|
|
8688
|
+
{ $match: { supersededBy: null } },
|
|
8689
|
+
{ $group: {
|
|
8690
|
+
_id: "$lookupKey",
|
|
8691
|
+
live: { $sum: 1 }
|
|
8692
|
+
} },
|
|
8693
|
+
{ $match: { live: { $gt: 1 } } }
|
|
8694
|
+
]).toArray();
|
|
8695
|
+
for (const { _id: lookupKey } of keys) {
|
|
8696
|
+
const head = await this.#getHeadDoc(collection, lookupKey);
|
|
8697
|
+
if (!head || head.supersededBy) continue;
|
|
8698
|
+
await collection.updateMany({
|
|
8699
|
+
lookupKey,
|
|
8700
|
+
supersededBy: null,
|
|
8701
|
+
$or: [
|
|
8702
|
+
{ generationCount: { $lt: head.generationCount } },
|
|
8703
|
+
{
|
|
8704
|
+
generationCount: head.generationCount,
|
|
8705
|
+
createdAt: { $gt: head.createdAt }
|
|
8706
|
+
},
|
|
8707
|
+
{
|
|
8708
|
+
generationCount: head.generationCount,
|
|
8709
|
+
createdAt: head.createdAt,
|
|
8710
|
+
id: { $gt: head.id }
|
|
8711
|
+
}
|
|
8712
|
+
]
|
|
8713
|
+
}, { $set: { supersededBy: head.id } });
|
|
8714
|
+
}
|
|
8715
|
+
}
|
|
8716
|
+
/**
|
|
8717
|
+
* Cross-process rollover and initialization rely on the unique `id` index (a duplicate insert
|
|
8718
|
+
* of the same successor or generation-0 id must fail). Warn once if it is missing, e.g. under
|
|
8719
|
+
* `skipDefaultIndexes`.
|
|
8720
|
+
*/
|
|
8721
|
+
async #warnIfOMIdIndexMissing() {
|
|
8722
|
+
try {
|
|
8723
|
+
if (!(await (await this.getCollection(OM_TABLE)).listIndexes().toArray().catch((error) => error?.code === 26 ? [] : Promise.reject(error))).some((index) => index.unique && Object.keys(index.key ?? {}).length === 1 && index.key.id === 1)) this.logger?.warn?.(`MongoDB collection "${OM_TABLE}" has no unique index on { id: 1 }. Observational memory needs it to stay consistent when several processes write the same thread or resource. Create it with db.${OM_TABLE}.createIndex({ id: 1 }, { unique: true }).`);
|
|
8724
|
+
} catch (error) {
|
|
8725
|
+
this.logger?.warn?.(`Could not list indexes on MongoDB collection "${OM_TABLE}":`, error);
|
|
8726
|
+
}
|
|
8727
|
+
}
|
|
8255
8728
|
};
|
|
8256
8729
|
//#endregion
|
|
8257
8730
|
//#region src/storage/domains/notifications/index.ts
|
|
@@ -11478,33 +11951,58 @@ var MongoDBWorkflowDefinitionsStore = class MongoDBWorkflowDefinitionsStore exte
|
|
|
11478
11951
|
};
|
|
11479
11952
|
//#endregion
|
|
11480
11953
|
//#region src/storage/domains/workflows/index.ts
|
|
11954
|
+
const RUN_OWNER_PROJECTION = {
|
|
11955
|
+
generation: 1,
|
|
11956
|
+
ownerId: 1,
|
|
11957
|
+
leaseExpiresAt: 1,
|
|
11958
|
+
live: { $gt: ["$leaseExpiresAt", "$$NOW"] }
|
|
11959
|
+
};
|
|
11960
|
+
const NOT_LIVE = { $or: [{ leaseExpiresAt: null }, { $expr: { $lte: ["$leaseExpiresAt", "$$NOW"] } }] };
|
|
11961
|
+
function toRunOwnershipRecord(doc) {
|
|
11962
|
+
return {
|
|
11963
|
+
runId: doc._id,
|
|
11964
|
+
generation: Number(doc.generation),
|
|
11965
|
+
ownerId: doc.ownerId,
|
|
11966
|
+
leaseExpiresAt: doc.leaseExpiresAt ?? null,
|
|
11967
|
+
live: Boolean(doc.live)
|
|
11968
|
+
};
|
|
11969
|
+
}
|
|
11481
11970
|
var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core_storage.WorkflowsStorage {
|
|
11482
11971
|
#connector;
|
|
11483
11972
|
#skipDefaultIndexes;
|
|
11484
11973
|
#indexes;
|
|
11485
11974
|
/** Collections managed by this domain */
|
|
11486
|
-
static MANAGED_COLLECTIONS = [_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT];
|
|
11975
|
+
static MANAGED_COLLECTIONS = [_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT, _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS];
|
|
11487
11976
|
/**
|
|
11488
|
-
*
|
|
11489
|
-
* a run is pruned only after its snapshot has not been touched
|
|
11977
|
+
* Both anchors are `updatedAt` (BSON date), so the policies read as
|
|
11978
|
+
* inactivity: a run is pruned only after its snapshot has not been touched
|
|
11979
|
+
* for `maxAge`, and an ownership document only after no claim, renewal or
|
|
11980
|
+
* release has touched it for `maxAge`.
|
|
11490
11981
|
*/
|
|
11491
|
-
static retentionTables = {
|
|
11492
|
-
|
|
11493
|
-
|
|
11494
|
-
|
|
11495
|
-
|
|
11982
|
+
static retentionTables = {
|
|
11983
|
+
workflowSnapshot: {
|
|
11984
|
+
table: _mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
11985
|
+
column: "updatedAt",
|
|
11986
|
+
indexed: true
|
|
11987
|
+
},
|
|
11988
|
+
runOwnership: {
|
|
11989
|
+
table: _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS,
|
|
11990
|
+
column: "updatedAt",
|
|
11991
|
+
indexed: true
|
|
11992
|
+
}
|
|
11993
|
+
};
|
|
11496
11994
|
constructor(config) {
|
|
11497
11995
|
super();
|
|
11498
11996
|
this.#connector = resolveMongoDBConfig(config);
|
|
11499
11997
|
this.#skipDefaultIndexes = config.skipDefaultIndexes;
|
|
11500
11998
|
this.#indexes = config.indexes?.filter((idx) => WorkflowsStorageMongoDB.MANAGED_COLLECTIONS.includes(idx.collection));
|
|
11501
11999
|
}
|
|
11502
|
-
/** Delete workflow snapshots idle for longer than
|
|
12000
|
+
/** Delete workflow snapshots and ownership documents idle for longer than each policy's `maxAge`, batched. */
|
|
11503
12001
|
async prune(policies, options) {
|
|
11504
12002
|
const targets = resolveTargets({
|
|
11505
12003
|
policies,
|
|
11506
12004
|
descriptor: WorkflowsStorageMongoDB.retentionTables,
|
|
11507
|
-
order: ["workflowSnapshot"]
|
|
12005
|
+
order: ["workflowSnapshot", "runOwnership"]
|
|
11508
12006
|
});
|
|
11509
12007
|
return runPrune({
|
|
11510
12008
|
connector: this.#connector,
|
|
@@ -11517,6 +12015,13 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11517
12015
|
supportsConcurrentUpdates() {
|
|
11518
12016
|
return true;
|
|
11519
12017
|
}
|
|
12018
|
+
/**
|
|
12019
|
+
* Fenced writes need multi-document transactions, so only replica sets and
|
|
12020
|
+
* sharded clusters fence. Rejects while the deployment can't be probed.
|
|
12021
|
+
*/
|
|
12022
|
+
supportsRunFencing() {
|
|
12023
|
+
return this.#connector.probeTransactions();
|
|
12024
|
+
}
|
|
11520
12025
|
async getCollection(name) {
|
|
11521
12026
|
return this.#connector.getCollection(name);
|
|
11522
12027
|
}
|
|
@@ -11524,6 +12029,124 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11524
12029
|
await this.createDefaultIndexes();
|
|
11525
12030
|
await this.createCustomIndexes();
|
|
11526
12031
|
}
|
|
12032
|
+
#runFenceCheck(fence, runId, operation) {
|
|
12033
|
+
const resolved = (0, _mastra_core_storage.resolveRunFence)(this, fence, runId);
|
|
12034
|
+
return resolved && {
|
|
12035
|
+
claims: _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS,
|
|
12036
|
+
fence: resolved,
|
|
12037
|
+
operation
|
|
12038
|
+
};
|
|
12039
|
+
}
|
|
12040
|
+
async #readRunOwner(runId) {
|
|
12041
|
+
const doc = await (await getRunClaims(this.#connector, _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS)).findOne({ _id: runId }, { projection: RUN_OWNER_PROJECTION });
|
|
12042
|
+
return doc ? toRunOwnershipRecord(doc) : null;
|
|
12043
|
+
}
|
|
12044
|
+
#ownershipError(operation, runId, error) {
|
|
12045
|
+
return new _mastra_core_error.MastraError({
|
|
12046
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", operation, "FAILED"),
|
|
12047
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
12048
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
12049
|
+
details: { runId }
|
|
12050
|
+
}, error);
|
|
12051
|
+
}
|
|
12052
|
+
async claimRunOwnership({ runId, ownerId, leaseMs, force, expectedGeneration }) {
|
|
12053
|
+
try {
|
|
12054
|
+
const owners = await getRunClaims(this.#connector, _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS);
|
|
12055
|
+
const claim = (generation) => [{ $set: {
|
|
12056
|
+
generation,
|
|
12057
|
+
ownerId: { $literal: ownerId },
|
|
12058
|
+
leaseExpiresAt: { $add: ["$$NOW", leaseMs] },
|
|
12059
|
+
updatedAt: "$$NOW"
|
|
12060
|
+
} }];
|
|
12061
|
+
if (!expectedGeneration) {
|
|
12062
|
+
try {
|
|
12063
|
+
const created = await owners.findOneAndUpdate({
|
|
12064
|
+
_id: runId,
|
|
12065
|
+
generation: { $exists: false }
|
|
12066
|
+
}, claim({ $max: [1, { $toLong: "$$NOW" }] }), {
|
|
12067
|
+
upsert: true,
|
|
12068
|
+
returnDocument: "after",
|
|
12069
|
+
projection: RUN_OWNER_PROJECTION
|
|
12070
|
+
});
|
|
12071
|
+
if (created) return {
|
|
12072
|
+
acquired: true,
|
|
12073
|
+
record: toRunOwnershipRecord(created)
|
|
12074
|
+
};
|
|
12075
|
+
} catch (error) {
|
|
12076
|
+
if (!isDuplicateKeyError(error)) throw error;
|
|
12077
|
+
}
|
|
12078
|
+
if (expectedGeneration === 0) return {
|
|
12079
|
+
acquired: false,
|
|
12080
|
+
record: await this.#readRunOwner(runId)
|
|
12081
|
+
};
|
|
12082
|
+
}
|
|
12083
|
+
const advanced = await owners.findOneAndUpdate({
|
|
12084
|
+
_id: runId,
|
|
12085
|
+
...expectedGeneration !== void 0 ? { generation: expectedGeneration } : {},
|
|
12086
|
+
...force ? {} : NOT_LIVE
|
|
12087
|
+
}, claim({ $add: ["$generation", 1] }), {
|
|
12088
|
+
returnDocument: "after",
|
|
12089
|
+
projection: RUN_OWNER_PROJECTION
|
|
12090
|
+
});
|
|
12091
|
+
if (advanced) return {
|
|
12092
|
+
acquired: true,
|
|
12093
|
+
record: toRunOwnershipRecord(advanced)
|
|
12094
|
+
};
|
|
12095
|
+
return {
|
|
12096
|
+
acquired: false,
|
|
12097
|
+
record: await this.#readRunOwner(runId)
|
|
12098
|
+
};
|
|
12099
|
+
} catch (error) {
|
|
12100
|
+
throw this.#ownershipError("CLAIM_RUN_OWNERSHIP", runId, error);
|
|
12101
|
+
}
|
|
12102
|
+
}
|
|
12103
|
+
async renewRunOwnership({ leaseMs, ...fence }) {
|
|
12104
|
+
try {
|
|
12105
|
+
const renewed = await (await getRunClaims(this.#connector, _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS)).findOneAndUpdate({
|
|
12106
|
+
_id: fence.runId,
|
|
12107
|
+
generation: fence.generation,
|
|
12108
|
+
ownerId: fence.ownerId,
|
|
12109
|
+
leaseExpiresAt: { $ne: null }
|
|
12110
|
+
}, [{ $set: {
|
|
12111
|
+
leaseExpiresAt: { $add: ["$$NOW", leaseMs] },
|
|
12112
|
+
updatedAt: "$$NOW"
|
|
12113
|
+
} }], {
|
|
12114
|
+
returnDocument: "after",
|
|
12115
|
+
projection: RUN_OWNER_PROJECTION
|
|
12116
|
+
});
|
|
12117
|
+
if (renewed) return {
|
|
12118
|
+
renewed: true,
|
|
12119
|
+
record: toRunOwnershipRecord(renewed)
|
|
12120
|
+
};
|
|
12121
|
+
return {
|
|
12122
|
+
renewed: false,
|
|
12123
|
+
record: await this.#readRunOwner(fence.runId)
|
|
12124
|
+
};
|
|
12125
|
+
} catch (error) {
|
|
12126
|
+
throw this.#ownershipError("RENEW_RUN_OWNERSHIP", fence.runId, error);
|
|
12127
|
+
}
|
|
12128
|
+
}
|
|
12129
|
+
async releaseRunOwnership(fence) {
|
|
12130
|
+
try {
|
|
12131
|
+
return (await (await getRunClaims(this.#connector, _mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS)).updateOne({
|
|
12132
|
+
_id: fence.runId,
|
|
12133
|
+
generation: fence.generation,
|
|
12134
|
+
ownerId: fence.ownerId
|
|
12135
|
+
}, [{ $set: {
|
|
12136
|
+
leaseExpiresAt: null,
|
|
12137
|
+
updatedAt: "$$NOW"
|
|
12138
|
+
} }])).matchedCount > 0;
|
|
12139
|
+
} catch (error) {
|
|
12140
|
+
throw this.#ownershipError("RELEASE_RUN_OWNERSHIP", fence.runId, error);
|
|
12141
|
+
}
|
|
12142
|
+
}
|
|
12143
|
+
async getRunOwnership({ runId }) {
|
|
12144
|
+
try {
|
|
12145
|
+
return await this.#readRunOwner(runId);
|
|
12146
|
+
} catch (error) {
|
|
12147
|
+
throw this.#ownershipError("GET_RUN_OWNERSHIP", runId, error);
|
|
12148
|
+
}
|
|
12149
|
+
}
|
|
11527
12150
|
/**
|
|
11528
12151
|
* Returns default index definitions for the workflows domain collections.
|
|
11529
12152
|
*/
|
|
@@ -11583,8 +12206,10 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11583
12206
|
}
|
|
11584
12207
|
async dangerouslyClearAll() {
|
|
11585
12208
|
await (await this.getCollection(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT)).deleteMany({});
|
|
12209
|
+
await (await this.getCollection(_mastra_core_storage.TABLE_WORKFLOW_RUN_OWNERS)).deleteMany({});
|
|
11586
12210
|
}
|
|
11587
|
-
async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext, state }) {
|
|
12211
|
+
async updateWorkflowResults({ workflowName, runId, stepId, result, requestContext, state, fence }) {
|
|
12212
|
+
const check = this.#runFenceCheck(fence, runId, "updateWorkflowResults");
|
|
11588
12213
|
try {
|
|
11589
12214
|
const collection = await this.getCollection(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
11590
12215
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -11604,7 +12229,7 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11604
12229
|
runId,
|
|
11605
12230
|
requestContext: {}
|
|
11606
12231
|
};
|
|
11607
|
-
const updatedDoc = await collection.findOneAndUpdate({
|
|
12232
|
+
const updatedDoc = await withRunFence(this.#connector, check, (session) => collection.findOneAndUpdate({
|
|
11608
12233
|
workflow_name: workflowName,
|
|
11609
12234
|
run_id: runId
|
|
11610
12235
|
}, [{ $set: {
|
|
@@ -11619,10 +12244,12 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11619
12244
|
createdAt: { $ifNull: ["$createdAt", now] }
|
|
11620
12245
|
} }], {
|
|
11621
12246
|
upsert: true,
|
|
11622
|
-
returnDocument: "after"
|
|
11623
|
-
|
|
12247
|
+
returnDocument: "after",
|
|
12248
|
+
session
|
|
12249
|
+
}));
|
|
11624
12250
|
return (typeof updatedDoc?.snapshot === "string" ? JSON.parse(updatedDoc.snapshot) : updatedDoc?.snapshot)?.context || {};
|
|
11625
12251
|
} catch (error) {
|
|
12252
|
+
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
11626
12253
|
throw new _mastra_core_error.MastraError({
|
|
11627
12254
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "UPDATE_WORKFLOW_RESULTS", "FAILED"),
|
|
11628
12255
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -11635,7 +12262,8 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11635
12262
|
}, error);
|
|
11636
12263
|
}
|
|
11637
12264
|
}
|
|
11638
|
-
async updateWorkflowState({ workflowName, runId, opts }) {
|
|
12265
|
+
async updateWorkflowState({ workflowName, runId, opts, fence }) {
|
|
12266
|
+
const check = this.#runFenceCheck(fence, runId, "updateWorkflowState");
|
|
11639
12267
|
try {
|
|
11640
12268
|
const collection = await this.getCollection(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
11641
12269
|
const { expectedStatus, ...state } = opts;
|
|
@@ -11644,10 +12272,13 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11644
12272
|
run_id: runId
|
|
11645
12273
|
};
|
|
11646
12274
|
if (expectedStatus !== void 0) filter["snapshot.status"] = { $in: Array.isArray(expectedStatus) ? expectedStatus : [expectedStatus] };
|
|
11647
|
-
const updatedDoc = await collection.findOneAndUpdate(filter, [{ $set: {
|
|
12275
|
+
const updatedDoc = await withRunFence(this.#connector, check, (session) => collection.findOneAndUpdate(filter, [{ $set: {
|
|
11648
12276
|
snapshot: { $mergeObjects: ["$snapshot", state] },
|
|
11649
12277
|
updatedAt: /* @__PURE__ */ new Date()
|
|
11650
|
-
} }], {
|
|
12278
|
+
} }], {
|
|
12279
|
+
returnDocument: "after",
|
|
12280
|
+
session
|
|
12281
|
+
}));
|
|
11651
12282
|
if (!updatedDoc) return;
|
|
11652
12283
|
const snapshot = typeof updatedDoc.snapshot === "string" ? JSON.parse(updatedDoc.snapshot) : updatedDoc.snapshot;
|
|
11653
12284
|
if (!snapshot?.context) throw new _mastra_core_error.MastraError({
|
|
@@ -11662,7 +12293,7 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11662
12293
|
});
|
|
11663
12294
|
return snapshot;
|
|
11664
12295
|
} catch (error) {
|
|
11665
|
-
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
12296
|
+
if (error instanceof _mastra_core_error.MastraError || (0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
11666
12297
|
throw new _mastra_core_error.MastraError({
|
|
11667
12298
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "UPDATE_WORKFLOW_STATE", "FAILED"),
|
|
11668
12299
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -11674,10 +12305,12 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11674
12305
|
}, error);
|
|
11675
12306
|
}
|
|
11676
12307
|
}
|
|
11677
|
-
async persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot, createdAt, updatedAt }) {
|
|
12308
|
+
async persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot, createdAt, updatedAt, fence }) {
|
|
12309
|
+
const check = this.#runFenceCheck(fence, runId, "persistWorkflowSnapshot");
|
|
11678
12310
|
try {
|
|
11679
12311
|
const now = /* @__PURE__ */ new Date();
|
|
11680
|
-
|
|
12312
|
+
const collection = await this.getCollection(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
12313
|
+
await withRunFence(this.#connector, check, (session) => collection.updateOne({
|
|
11681
12314
|
workflow_name: workflowName,
|
|
11682
12315
|
run_id: runId
|
|
11683
12316
|
}, {
|
|
@@ -11689,8 +12322,12 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11689
12322
|
updatedAt: updatedAt ?? now
|
|
11690
12323
|
},
|
|
11691
12324
|
$setOnInsert: { createdAt: createdAt ?? now }
|
|
11692
|
-
}, {
|
|
12325
|
+
}, {
|
|
12326
|
+
upsert: true,
|
|
12327
|
+
session
|
|
12328
|
+
}));
|
|
11693
12329
|
} catch (error) {
|
|
12330
|
+
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
11694
12331
|
throw new _mastra_core_error.MastraError({
|
|
11695
12332
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
|
|
11696
12333
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
@@ -11783,13 +12420,16 @@ var WorkflowsStorageMongoDB = class WorkflowsStorageMongoDB extends _mastra_core
|
|
|
11783
12420
|
}, error);
|
|
11784
12421
|
}
|
|
11785
12422
|
}
|
|
11786
|
-
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
12423
|
+
async deleteWorkflowRunById({ runId, workflowName, fence }) {
|
|
12424
|
+
const check = this.#runFenceCheck(fence, runId, "deleteWorkflowRunById");
|
|
11787
12425
|
try {
|
|
11788
|
-
|
|
12426
|
+
const collection = await this.getCollection(_mastra_core_storage.TABLE_WORKFLOW_SNAPSHOT);
|
|
12427
|
+
await withRunFence(this.#connector, check, (session) => collection.deleteOne({
|
|
11789
12428
|
workflow_name: workflowName,
|
|
11790
12429
|
run_id: runId
|
|
11791
|
-
});
|
|
12430
|
+
}, { session }));
|
|
11792
12431
|
} catch (error) {
|
|
12432
|
+
if ((0, _mastra_core_storage.isRunFenceConflictError)(error)) throw error;
|
|
11793
12433
|
throw new _mastra_core_error.MastraError({
|
|
11794
12434
|
id: (0, _mastra_core_storage.createStorageErrorId)("MONGODB", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
11795
12435
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|