@mastra/memory 1.27.0-alpha.1 → 1.27.0-alpha.2

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.
@@ -22295,7 +22295,7 @@ var ObservationStep = class {
22295
22295
  messageList.removeByIds(candidates.map((msg) => msg.id));
22296
22296
  for (const msg of candidates) messageList.add(msg, "memory");
22297
22297
  }
22298
- om.buffer({
22298
+ om.trackBackgroundWork(om.buffer({
22299
22299
  threadId,
22300
22300
  resourceId,
22301
22301
  messages: unobservedMessages,
@@ -22306,7 +22306,7 @@ var ObservationStep = class {
22306
22306
  observabilityContext: this.turn.observabilityContext
22307
22307
  }).catch((err) => {
22308
22308
  omDebug(`[OM:buffer] fire-and-forget buffer failed: ${err?.message}`);
22309
- });
22309
+ }));
22310
22310
  buffered = true;
22311
22311
  }
22312
22312
  const willObserveNow = statusSnapshot.shouldObserve && !hasIncompleteToolCalls;
@@ -22674,7 +22674,7 @@ var ObservationTurn = class {
22674
22674
  const allMessages = getObservableMessages(this.messageList);
22675
22675
  const record = this._record;
22676
22676
  const unobservedMessages = this.om.getUnobservedMessages(allMessages, record);
22677
- if (unobservedMessages.length > 0) this.om.buffer({
22677
+ if (unobservedMessages.length > 0) this.om.trackBackgroundWork(this.om.buffer({
22678
22678
  threadId: this.threadId,
22679
22679
  resourceId: this.resourceId,
22680
22680
  messages: unobservedMessages,
@@ -22688,7 +22688,7 @@ var ObservationTurn = class {
22688
22688
  skipMinimumTokenCheck: true
22689
22689
  }).catch((err) => {
22690
22690
  omDebug(`[OM:turn.end] idle buffer failed: ${err?.message}`);
22691
- });
22691
+ }));
22692
22692
  }
22693
22693
  return { record: this._record };
22694
22694
  }
@@ -23172,6 +23172,8 @@ var ReflectorRunner = class {
23172
23172
  };
23173
23173
  let reflectedTokens = 0;
23174
23174
  let attemptNumber = 0;
23175
+ /** Observations from the previous attempt, used to detect a no-progress ladder. */
23176
+ let previousObservations;
23175
23177
  while (currentLevel <= maxLevel) {
23176
23178
  attemptNumber++;
23177
23179
  const isRetry = attemptNumber > 1;
@@ -23245,6 +23247,11 @@ var ReflectorRunner = class {
23245
23247
  omDebug(`[OM:callReflector] degenerate output persists at maxLevel=${maxLevel}, breaking`);
23246
23248
  break;
23247
23249
  }
23250
+ if (!parsed.degenerate && previousObservations !== void 0 && parsed.observations === previousObservations) {
23251
+ omDebug(`[OM:callReflector] attempt #${attemptNumber} returned output identical to the previous attempt; escalating cannot help, stopping the ladder`);
23252
+ break;
23253
+ }
23254
+ previousObservations = parsed.observations;
23248
23255
  if (streamContext?.writer) {
23249
23256
  const failedMarker = createObservationFailedMarker({
23250
23257
  cycleId: streamContext.cycleId,
@@ -24223,6 +24230,39 @@ var ObservationalMemory = class ObservationalMemory {
24223
24230
  */
24224
24231
  recordInitializations = /* @__PURE__ */ new Map();
24225
24232
  /**
24233
+ * In-flight fire-and-forget background cycles (buffered observation, reflection).
24234
+ * Tracked so callers can join them via `settled()` before closing a storage
24235
+ * connection they own — otherwise a background cycle's tail statements race the close.
24236
+ */
24237
+ pendingBackgroundWork = /* @__PURE__ */ new Set();
24238
+ /**
24239
+ * Register fire-and-forget background work so `settled()` can join it.
24240
+ * Returns the original promise so callers keep their own rejection handling.
24241
+ */
24242
+ trackBackgroundWork(work) {
24243
+ const tracked = work.catch(() => {}).finally(() => {
24244
+ this.pendingBackgroundWork.delete(tracked);
24245
+ });
24246
+ this.pendingBackgroundWork.add(tracked);
24247
+ return work;
24248
+ }
24249
+ /**
24250
+ * Resolve once all background observational-memory work started so far has finished.
24251
+ *
24252
+ * Background cycles enqueue further background work (a buffered observation can
24253
+ * trigger a reflection, which runs nested agent streams), so this drains repeatedly
24254
+ * until nothing is left rather than joining a single snapshot.
24255
+ */
24256
+ async settled() {
24257
+ const maxDrainRounds = 100;
24258
+ for (let round = 0; round < maxDrainRounds; round++) {
24259
+ if (this.pendingBackgroundWork.size === 0) return;
24260
+ await Promise.allSettled([...this.pendingBackgroundWork]);
24261
+ }
24262
+ if (this.pendingBackgroundWork.size === 0) return;
24263
+ omError(`[OM:settled] background work still pending after ${maxDrainRounds} drain rounds; giving up waiting`);
24264
+ }
24265
+ /**
24226
24266
  * Acquire a lock for the given key, execute the callback, then release.
24227
24267
  * If a lock is already held, waits for it to be released before acquiring.
24228
24268
  */
@@ -25223,7 +25263,7 @@ ${formattedMessages}
25223
25263
  if (!this.buffering.isAsyncObservationEnabled()) return false;
25224
25264
  const lockKey = this.buffering.getLockKey(opts.threadId, opts.resourceId);
25225
25265
  const shouldTrigger = this.buffering.shouldTriggerAsyncObservation(opts.pendingTokens, lockKey, opts.record, this.storage, opts.threshold);
25226
- if (shouldTrigger) this.startAsyncBufferedObservation(opts.record, opts.threadId, opts.unobservedMessages, lockKey, opts.writer, opts.unbufferedPendingTokens, opts.requestContext);
25266
+ if (shouldTrigger) this.trackBackgroundWork(this.startAsyncBufferedObservation(opts.record, opts.threadId, opts.unobservedMessages, lockKey, opts.writer, opts.unbufferedPendingTokens, opts.requestContext));
25227
25267
  return shouldTrigger;
25228
25268
  }
25229
25269
  isMessageList(value) {
@@ -27053,6 +27093,25 @@ var Memory = class extends _mastra_core_memory.MastraMemory {
27053
27093
  trackVectorCleanup(cleanup) {
27054
27094
  this.pendingVectorCleanup = Promise.allSettled([this.pendingVectorCleanup, cleanup]).then(() => void 0);
27055
27095
  }
27096
+ /**
27097
+ * Resolve once all background work this Memory started has finished: observational-memory
27098
+ * cycles (buffered observation and reflection, including the nested agent runs they spawn)
27099
+ * and vector cleanup from `deleteThread` / `deleteMessages`.
27100
+ *
27101
+ * Callers that own the storage connection should await this before closing it, otherwise
27102
+ * background statements can race the close.
27103
+ *
27104
+ * ```ts
27105
+ * await agent.generate('hello', { memory: { thread, resource } });
27106
+ * await memory.settled();
27107
+ * await store.close();
27108
+ * ```
27109
+ */
27110
+ async settled() {
27111
+ await this.pendingVectorCleanup;
27112
+ await (this._omEngine ? await this._omEngine : this._omEngineInstance)?.settled();
27113
+ await this.pendingVectorCleanup;
27114
+ }
27056
27115
  /** The shared ObservationalMemory engine. Lazily created on first access. */
27057
27116
  get omEngine() {
27058
27117
  if (!this._omEngine) this._omEngine = this._initOMEngine().then((engine) => {
@@ -29050,4 +29109,4 @@ Object.defineProperty(exports, "wrapInObservationGroup", {
29050
29109
  }
29051
29110
  });
29052
29111
 
29053
- //# sourceMappingURL=src-_7ADtEwc.cjs.map
29112
+ //# sourceMappingURL=src-Drm6l_ZN.cjs.map