@mastra/memory 1.15.1 → 1.16.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/{chunk-3TU4GGH3.cjs → chunk-3NECGYWZ.cjs} +117 -16
  3. package/dist/chunk-3NECGYWZ.cjs.map +1 -0
  4. package/dist/{chunk-7NCBGOHT.js → chunk-HB6AYAFD.js} +117 -16
  5. package/dist/chunk-HB6AYAFD.js.map +1 -0
  6. package/dist/docs/SKILL.md +1 -1
  7. package/dist/docs/assets/SOURCE_MAP.json +47 -47
  8. package/dist/docs/references/docs-memory-observational-memory.md +23 -7
  9. package/dist/docs/references/reference-memory-observational-memory.md +2 -0
  10. package/dist/index.cjs +14 -13
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +5 -4
  15. package/dist/index.js.map +1 -1
  16. package/dist/{observational-memory-4TDIBXK6.js → observational-memory-WWAB2MMI.js} +3 -3
  17. package/dist/{observational-memory-4TDIBXK6.js.map → observational-memory-WWAB2MMI.js.map} +1 -1
  18. package/dist/{observational-memory-GH6IRH6E.cjs → observational-memory-X4N2R4CA.cjs} +26 -26
  19. package/dist/{observational-memory-GH6IRH6E.cjs.map → observational-memory-X4N2R4CA.cjs.map} +1 -1
  20. package/dist/processors/index.cjs +24 -24
  21. package/dist/processors/index.js +1 -1
  22. package/dist/processors/observational-memory/markers.d.ts +3 -0
  23. package/dist/processors/observational-memory/markers.d.ts.map +1 -1
  24. package/dist/processors/observational-memory/observation-turn/step.d.ts.map +1 -1
  25. package/dist/processors/observational-memory/observational-memory.d.ts +6 -0
  26. package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
  27. package/dist/processors/observational-memory/processor.d.ts.map +1 -1
  28. package/dist/processors/observational-memory/reflector-runner.d.ts +1 -0
  29. package/dist/processors/observational-memory/reflector-runner.d.ts.map +1 -1
  30. package/dist/processors/observational-memory/types.d.ts +19 -0
  31. package/dist/processors/observational-memory/types.d.ts.map +1 -1
  32. package/package.json +5 -5
  33. package/dist/chunk-3TU4GGH3.cjs.map +0 -1
  34. package/dist/chunk-7NCBGOHT.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @mastra/memory
2
2
 
3
+ ## 1.16.0-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`fdd54cf`](https://github.com/mastra-ai/mastra/commit/fdd54cf612a9af876e9fdd85e534454f6e7dd518), [`7db42a9`](https://github.com/mastra-ai/mastra/commit/7db42a9cccd3b29c44fb0731f792c51575e8421c), [`30456b6`](https://github.com/mastra-ai/mastra/commit/30456b6b08c8fd17e109dd093b73d93b65e83bc5), [`9d11a8c`](https://github.com/mastra-ai/mastra/commit/9d11a8c1c8924eb975a245a5884d40ca1b7e0491), [`d246696`](https://github.com/mastra-ai/mastra/commit/d246696139a3144a5b21b042d41c532688e957e1), [`354f9ce`](https://github.com/mastra-ai/mastra/commit/354f9ce1ca6af2074b6a196a23f8ec30012dccca), [`e9837b5`](https://github.com/mastra-ai/mastra/commit/e9837b53699e18711b09e0ca010a4106376f2653)]:
8
+ - @mastra/core@1.26.0-alpha.3
9
+ - @mastra/schema-compat@1.2.9-alpha.1
10
+
11
+ ## 1.16.0-alpha.0
12
+
13
+ ### Minor Changes
14
+
15
+ - Added activateAfterIdle setting for observational memory so buffered observations can activate after idle time before the next prompt. ([#15365](https://github.com/mastra-ai/mastra/pull/15365))
16
+
17
+ **Example**
18
+
19
+ Set `activateAfterIdle: 300_000` (or `"5m"`) on the `observationalMemory` config to activate buffered context after 5 minutes of inactivity.
20
+
21
+ This helps long-running threads reuse compressed context after prompt cache TTLs expire instead of sending a larger raw message window on the next request.
22
+
23
+ ### Patch Changes
24
+
25
+ - Updated dependencies [[`3d83d06`](https://github.com/mastra-ai/mastra/commit/3d83d06f776f00fb5f4163dddd32a030c5c20844), [`7e0e63e`](https://github.com/mastra-ai/mastra/commit/7e0e63e2e485e84442351f4c7a79a424c83539dc), [`9467ea8`](https://github.com/mastra-ai/mastra/commit/9467ea87695749a53dfc041576410ebf9ee7bb67), [`7338d94`](https://github.com/mastra-ai/mastra/commit/7338d949380cf68b095342e8e42610dc51d557c1), [`c65aec3`](https://github.com/mastra-ai/mastra/commit/c65aec356cc037ee7c4b30ccea946807d4c4f443)]:
26
+ - @mastra/core@1.26.0-alpha.2
27
+ - @mastra/schema-compat@1.2.9-alpha.0
28
+
3
29
  ## 1.15.1
4
30
 
5
31
  ### Patch Changes
@@ -491,7 +491,10 @@ function createActivationMarker(params) {
491
491
  threadId: params.threadId,
492
492
  generationCount: params.generationCount,
493
493
  config: params.config,
494
- observations: params.observations
494
+ observations: params.observations,
495
+ triggeredBy: params.triggeredBy,
496
+ lastActivityAt: params.lastActivityAt,
497
+ ttlExpiredMs: params.ttlExpiredMs
495
498
  }
496
499
  };
497
500
  }
@@ -2010,7 +2013,8 @@ var ObservationStep = class {
2010
2013
  threadId,
2011
2014
  writer: this.turn.writer,
2012
2015
  requestContext: this.turn.requestContext,
2013
- observabilityContext: this.turn.observabilityContext
2016
+ observabilityContext: this.turn.observabilityContext,
2017
+ lastActivityAt: getLastActivityFromMessages(messageList.get.all.db())
2014
2018
  });
2015
2019
  await this.turn.refreshRecord();
2016
2020
  if (this.turn.record.generationCount > preReflectGeneration) {
@@ -2186,7 +2190,8 @@ var ObservationStep = class {
2186
2190
  writer: this.turn.writer,
2187
2191
  messageList,
2188
2192
  requestContext: this.turn.requestContext,
2189
- observabilityContext: this.turn.observabilityContext
2193
+ observabilityContext: this.turn.observabilityContext,
2194
+ lastActivityAt: getLastActivityFromMessages(messageList.get.all.db())
2190
2195
  });
2191
2196
  return {
2192
2197
  succeeded: true,
@@ -4141,7 +4146,8 @@ var ReflectorRunner = class {
4141
4146
  observationTokens: getMaxThreshold(
4142
4147
  record ? this.getEffectiveReflectionTokens(record) : this.reflectionConfig.observationTokens
4143
4148
  ),
4144
- scope: this.scope
4149
+ scope: this.scope,
4150
+ activateAfterIdle: this.reflectionConfig.activateAfterIdle
4145
4151
  };
4146
4152
  }
4147
4153
  /**
@@ -4427,7 +4433,7 @@ var ReflectorRunner = class {
4427
4433
  * Try to activate buffered reflection when threshold is reached.
4428
4434
  * Returns true if activation succeeded.
4429
4435
  */
4430
- async tryActivateBufferedReflection(record, lockKey, writer, messageList) {
4436
+ async tryActivateBufferedReflection(record, lockKey, writer, messageList, activationMetadata) {
4431
4437
  const bufferKey = this.buffering.getReflectionBufferKey(lockKey);
4432
4438
  const asyncOp = BufferingCoordinator.asyncBufferingOps.get(bufferKey);
4433
4439
  if (asyncOp) {
@@ -4487,6 +4493,9 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
4487
4493
  threadId: freshRecord.threadId ?? "",
4488
4494
  generationCount: afterRecord?.generationCount ?? freshRecord.generationCount ?? 0,
4489
4495
  observations: afterRecord?.activeObservations,
4496
+ triggeredBy: activationMetadata?.triggeredBy,
4497
+ lastActivityAt: activationMetadata?.lastActivityAt,
4498
+ ttlExpiredMs: activationMetadata?.ttlExpiredMs,
4490
4499
  config: this.getObservationMarkerConfig(freshRecord)
4491
4500
  });
4492
4501
  void writer.custom(activationMarker).catch(() => {
@@ -4515,7 +4524,9 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
4515
4524
  messageList,
4516
4525
  reflectionHooks,
4517
4526
  requestContext,
4518
- observabilityContext
4527
+ observabilityContext,
4528
+ lastActivityAt,
4529
+ threadId: requestedThreadId
4519
4530
  } = opts;
4520
4531
  const lockKey = this.buffering.getLockKey(record.threadId, record.resourceId);
4521
4532
  const reflectThreshold = getMaxThreshold(this.getEffectiveReflectionTokens(record));
@@ -4547,9 +4558,17 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
4547
4558
  );
4548
4559
  }
4549
4560
  }
4550
- if (observationTokens < reflectThreshold) {
4561
+ const activateAfterIdle = this.reflectionConfig.activateAfterIdle;
4562
+ const ttlExpiredMs = activateAfterIdle !== void 0 && lastActivityAt !== void 0 ? Date.now() - lastActivityAt : void 0;
4563
+ const ttlExpired = ttlExpiredMs !== void 0 && activateAfterIdle !== void 0 && ttlExpiredMs >= activateAfterIdle;
4564
+ if (observationTokens < reflectThreshold && !ttlExpired) {
4551
4565
  return;
4552
4566
  }
4567
+ const activationMetadata = {
4568
+ triggeredBy: ttlExpired ? "ttl" : "threshold",
4569
+ lastActivityAt: ttlExpired ? lastActivityAt : void 0,
4570
+ ttlExpiredMs: ttlExpired ? ttlExpiredMs : void 0
4571
+ };
4553
4572
  if (record.isReflecting) {
4554
4573
  if (isOpActiveInProcess(record.id, "reflecting")) {
4555
4574
  omDebug(`[OM:reflect] isReflecting=true and active in this process, skipping`);
@@ -4559,7 +4578,13 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
4559
4578
  await this.storage.setReflectingFlag(record.id, false);
4560
4579
  }
4561
4580
  if (this.buffering.isAsyncReflectionEnabled()) {
4562
- const activationSuccess = await this.tryActivateBufferedReflection(record, lockKey, writer, messageList);
4581
+ const activationSuccess = await this.tryActivateBufferedReflection(
4582
+ record,
4583
+ lockKey,
4584
+ writer,
4585
+ messageList,
4586
+ activationMetadata
4587
+ );
4563
4588
  if (activationSuccess) {
4564
4589
  return;
4565
4590
  }
@@ -4588,7 +4613,7 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
4588
4613
  registerOp(record.id, "reflecting");
4589
4614
  const cycleId = crypto.randomUUID();
4590
4615
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
4591
- const threadId = opts.threadId ?? "unknown";
4616
+ const threadId = requestedThreadId ?? "unknown";
4592
4617
  if (writer) {
4593
4618
  const startMarker = createObservationStartMarker({
4594
4619
  cycleId,
@@ -6238,6 +6263,58 @@ function buildMessageRange(messages) {
6238
6263
  const last = [...messages].reverse().find(messageHasVisibleContent) ?? messages[messages.length - 1];
6239
6264
  return `${first.id}:${last.id}`;
6240
6265
  }
6266
+ function getLastActivityFromMessages(messages) {
6267
+ if (!messages) return void 0;
6268
+ for (let i = messages.length - 1; i >= 0; i--) {
6269
+ const message = messages[i];
6270
+ if (!message || message.role !== "assistant") {
6271
+ continue;
6272
+ }
6273
+ if (!message.content || typeof message.content === "string") {
6274
+ return message.createdAt ? new Date(message.createdAt).getTime() : void 0;
6275
+ }
6276
+ for (let j = message.content.parts.length - 1; j >= 0; j--) {
6277
+ const part = message.content.parts[j];
6278
+ if (!part || part.type?.startsWith("data-")) {
6279
+ continue;
6280
+ }
6281
+ if (part.createdAt !== void 0) {
6282
+ return part.createdAt;
6283
+ }
6284
+ }
6285
+ return message.createdAt ? new Date(message.createdAt).getTime() : void 0;
6286
+ }
6287
+ return void 0;
6288
+ }
6289
+ function parseActivationTTL(value, fieldPath) {
6290
+ if (value === void 0) {
6291
+ return void 0;
6292
+ }
6293
+ if (typeof value === "number") {
6294
+ if (!Number.isFinite(value) || value < 0) {
6295
+ throw new Error(`${fieldPath} must be a non-negative number of milliseconds or a duration string like "5m".`);
6296
+ }
6297
+ return value;
6298
+ }
6299
+ const trimmed = value.trim();
6300
+ const match = trimmed.match(
6301
+ /^(\d+(?:\.\d+)?)\s*(ms|msec|msecs|millisecond|milliseconds|s|sec|secs|second|seconds|m|min|mins|minute|minutes|h|hr|hrs|hour|hours)$/i
6302
+ );
6303
+ if (!match) {
6304
+ throw new Error(
6305
+ `${fieldPath} must be a non-negative number of milliseconds or a duration string like "5m" or "1hr".`
6306
+ );
6307
+ }
6308
+ const rawAmount = match[1];
6309
+ const rawUnit = match[2];
6310
+ const amount = Number(rawAmount);
6311
+ const unit = rawUnit.toLowerCase();
6312
+ if (!Number.isFinite(amount) || amount < 0) {
6313
+ throw new Error(`${fieldPath} must be a non-negative number of milliseconds or a duration string like "5m".`);
6314
+ }
6315
+ const multiplier = unit === "ms" || unit === "msec" || unit === "msecs" || unit === "millisecond" || unit === "milliseconds" ? 1 : unit === "s" || unit === "sec" || unit === "secs" || unit === "second" || unit === "seconds" ? 1e3 : unit === "m" || unit === "min" || unit === "mins" || unit === "minute" || unit === "minutes" ? 6e4 : 36e5;
6316
+ return amount * multiplier;
6317
+ }
6241
6318
  var ObservationalMemory = class _ObservationalMemory {
6242
6319
  storage;
6243
6320
  tokenCounter;
@@ -6384,6 +6461,7 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
6384
6461
  config.observation?.messageTokens ?? chunkD4J4XPGM_cjs.OBSERVATIONAL_MEMORY_DEFAULTS.observation.messageTokens
6385
6462
  ),
6386
6463
  bufferActivation: asyncBufferingDisabled ? void 0 : config.observation?.bufferActivation ?? chunkD4J4XPGM_cjs.OBSERVATIONAL_MEMORY_DEFAULTS.observation.bufferActivation,
6464
+ activateAfterIdle: parseActivationTTL(config.activateAfterIdle, "activateAfterIdle"),
6387
6465
  blockAfter: asyncBufferingDisabled ? void 0 : resolveBlockAfter(
6388
6466
  config.observation?.blockAfter ?? (config.observation?.bufferTokens ?? chunkD4J4XPGM_cjs.OBSERVATIONAL_MEMORY_DEFAULTS.observation.bufferTokens ? 1.2 : void 0),
6389
6467
  config.observation?.messageTokens ?? chunkD4J4XPGM_cjs.OBSERVATIONAL_MEMORY_DEFAULTS.observation.messageTokens
@@ -6402,6 +6480,7 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
6402
6480
  },
6403
6481
  providerOptions: config.reflection?.providerOptions ?? chunkD4J4XPGM_cjs.OBSERVATIONAL_MEMORY_DEFAULTS.reflection.providerOptions,
6404
6482
  bufferActivation: asyncBufferingDisabled ? void 0 : config?.reflection?.bufferActivation ?? chunkD4J4XPGM_cjs.OBSERVATIONAL_MEMORY_DEFAULTS.reflection.bufferActivation,
6483
+ activateAfterIdle: parseActivationTTL(config.activateAfterIdle, "activateAfterIdle"),
6405
6484
  blockAfter: asyncBufferingDisabled ? void 0 : resolveBlockAfter(
6406
6485
  config.reflection?.blockAfter ?? (config.reflection?.bufferActivation ?? chunkD4J4XPGM_cjs.OBSERVATIONAL_MEMORY_DEFAULTS.reflection.bufferActivation ? 1.2 : void 0),
6407
6486
  config.reflection?.observationTokens ?? chunkD4J4XPGM_cjs.OBSERVATIONAL_MEMORY_DEFAULTS.reflection.observationTokens
@@ -6796,7 +6875,8 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
6796
6875
  return {
6797
6876
  messageTokens: getMaxThreshold(this.observationConfig.messageTokens),
6798
6877
  observationTokens: getMaxThreshold(this.reflectionConfig.observationTokens),
6799
- scope: this.scope
6878
+ scope: this.scope,
6879
+ activateAfterIdle: this.observationConfig.activateAfterIdle
6800
6880
  };
6801
6881
  }
6802
6882
  /**
@@ -8034,7 +8114,7 @@ ${grouped}` : grouped;
8034
8114
  await BufferingCoordinator.awaitBuffering(threadId, resourceId ?? null, this.scope);
8035
8115
  const preStatus = await this.getStatus({ threadId, resourceId, messages });
8036
8116
  if (preStatus.canActivate) {
8037
- const actResult = await this.activate({ threadId, resourceId });
8117
+ const actResult = await this.activate({ threadId, resourceId, messages });
8038
8118
  activated = actResult.activated;
8039
8119
  }
8040
8120
  const postStatus = await this.getStatus({ threadId, resourceId, messages });
@@ -8294,10 +8374,28 @@ ${grouped}` : grouped;
8294
8374
  if (!chunks.length) {
8295
8375
  return { activated: false, record };
8296
8376
  }
8377
+ let activationTriggeredBy = "threshold";
8378
+ let activationLastActivityAt;
8379
+ let activateAfterIdleExpiredMs;
8297
8380
  if (opts.checkThreshold) {
8298
- const status = await this.getStatus({ threadId, resourceId, messages: opts.messages });
8299
- if (status.pendingTokens < status.threshold) {
8300
- return { activated: false, record };
8381
+ const thresholdMessages = opts.messages ?? await this.loadMessagesFromStorage(
8382
+ threadId,
8383
+ resourceId,
8384
+ record.lastObservedAt ? new Date(record.lastObservedAt) : void 0
8385
+ );
8386
+ const activateAfterIdle = this.observationConfig.activateAfterIdle;
8387
+ const lastActivityAt = getLastActivityFromMessages(thresholdMessages);
8388
+ const ttlExpiredMs = activateAfterIdle !== void 0 && lastActivityAt !== void 0 ? Date.now() - lastActivityAt : void 0;
8389
+ const ttlExpired = ttlExpiredMs !== void 0 && activateAfterIdle !== void 0 && ttlExpiredMs >= activateAfterIdle;
8390
+ if (ttlExpired) {
8391
+ activationTriggeredBy = "ttl";
8392
+ activationLastActivityAt = lastActivityAt;
8393
+ activateAfterIdleExpiredMs = ttlExpiredMs;
8394
+ } else {
8395
+ const status = await this.getStatus({ threadId, resourceId, messages: thresholdMessages });
8396
+ if (status.pendingTokens < status.threshold) {
8397
+ return { activated: false, record };
8398
+ }
8301
8399
  }
8302
8400
  }
8303
8401
  if (record.isBufferingObservation) {
@@ -8355,6 +8453,9 @@ ${grouped}` : grouped;
8355
8453
  threadId: postSwapRecord.threadId ?? record.threadId ?? "",
8356
8454
  generationCount: postSwapRecord.generationCount ?? 0,
8357
8455
  observations: chunkData?.observations ?? activationResult.observations,
8456
+ triggeredBy: activationTriggeredBy,
8457
+ lastActivityAt: activationLastActivityAt,
8458
+ ttlExpiredMs: activateAfterIdleExpiredMs,
8358
8459
  config: this.getObservationMarkerConfig()
8359
8460
  });
8360
8461
  void opts.writer.custom(activationMarker).catch(() => {
@@ -8870,5 +8971,5 @@ exports.stripEphemeralAnchorIds = stripEphemeralAnchorIds;
8870
8971
  exports.stripObservationGroups = stripObservationGroups;
8871
8972
  exports.truncateStringByTokens = truncateStringByTokens;
8872
8973
  exports.wrapInObservationGroup = wrapInObservationGroup;
8873
- //# sourceMappingURL=chunk-3TU4GGH3.cjs.map
8874
- //# sourceMappingURL=chunk-3TU4GGH3.cjs.map
8974
+ //# sourceMappingURL=chunk-3NECGYWZ.cjs.map
8975
+ //# sourceMappingURL=chunk-3NECGYWZ.cjs.map