@mastra/memory 1.18.3-alpha.0 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/dist/{chunk-BK3AYI7X.cjs → chunk-5IJQOXJM.cjs} +117 -24
  3. package/dist/chunk-5IJQOXJM.cjs.map +1 -0
  4. package/dist/{chunk-KLETR4RS.js → chunk-NZXH5WER.js} +117 -24
  5. package/dist/chunk-NZXH5WER.js.map +1 -0
  6. package/dist/docs/SKILL.md +3 -1
  7. package/dist/docs/assets/SOURCE_MAP.json +47 -47
  8. package/dist/docs/references/docs-agents-agent-approval.md +2 -0
  9. package/dist/docs/references/docs-agents-background-tasks.md +9 -6
  10. package/dist/docs/references/docs-evals-evals-with-memory.md +146 -0
  11. package/dist/docs/references/docs-memory-multi-user-threads.md +206 -0
  12. package/dist/docs/references/docs-memory-observational-memory.md +53 -17
  13. package/dist/docs/references/docs-memory-overview.md +1 -0
  14. package/dist/docs/references/docs-memory-working-memory.md +1 -1
  15. package/dist/docs/references/reference-memory-observational-memory.md +5 -3
  16. package/dist/index.cjs +13 -13
  17. package/dist/index.js +4 -4
  18. package/dist/{observational-memory-K5ES5KKQ.js → observational-memory-KFKHBTCB.js} +3 -3
  19. package/dist/{observational-memory-K5ES5KKQ.js.map → observational-memory-KFKHBTCB.js.map} +1 -1
  20. package/dist/{observational-memory-SRGNHILF.cjs → observational-memory-V2APY3TO.cjs} +26 -26
  21. package/dist/{observational-memory-SRGNHILF.cjs.map → observational-memory-V2APY3TO.cjs.map} +1 -1
  22. package/dist/processors/index.cjs +24 -24
  23. package/dist/processors/index.js +1 -1
  24. package/dist/processors/observational-memory/activation-ttl.d.ts +4 -0
  25. package/dist/processors/observational-memory/activation-ttl.d.ts.map +1 -0
  26. package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
  27. package/dist/processors/observational-memory/observer-agent.d.ts +13 -0
  28. package/dist/processors/observational-memory/observer-agent.d.ts.map +1 -1
  29. package/dist/processors/observational-memory/observer-runner.d.ts.map +1 -1
  30. package/dist/processors/observational-memory/processor.d.ts.map +1 -1
  31. package/dist/processors/observational-memory/reflector-runner.d.ts.map +1 -1
  32. package/dist/processors/observational-memory/tracing.d.ts.map +1 -1
  33. package/dist/processors/observational-memory/types.d.ts +30 -6
  34. package/dist/processors/observational-memory/types.d.ts.map +1 -1
  35. package/package.json +7 -7
  36. package/dist/chunk-BK3AYI7X.cjs.map +0 -1
  37. package/dist/chunk-KLETR4RS.js.map +0 -1
@@ -14,6 +14,47 @@ import { inspect } from 'util';
14
14
  import { AsyncLocalStorage } from 'async_hooks';
15
15
  import imageSize from 'image-size';
16
16
 
17
+ // src/processors/observational-memory/activation-ttl.ts
18
+ var MINUTE = 6e4;
19
+ var HOUR = 60 * MINUTE;
20
+ var SHORT_TTL = 5 * MINUTE;
21
+ var OPENAI_EXTENDED_TTL = HOUR;
22
+ var GEMINI_TTL = 24 * HOUR;
23
+ var DEEPSEEK_TTL = HOUR;
24
+ var GROQ_TTL = 2 * HOUR;
25
+ function normalize(value) {
26
+ return value?.toLowerCase() ?? "";
27
+ }
28
+ function isOpenAIShortTtlModel(modelId) {
29
+ return /^gpt-4/.test(modelId) || /^gpt-5(?:$|-|\.([1-4])(?:$|-))/.test(modelId);
30
+ }
31
+ function getOpenAIPromptCacheRetention(providerOptions) {
32
+ const openaiOptions = providerOptions?.openai;
33
+ return typeof openaiOptions?.promptCacheRetention === "string" ? openaiOptions.promptCacheRetention.toLowerCase() : void 0;
34
+ }
35
+ function resolveActivationTTL(activateAfterIdle, modelContext) {
36
+ if (activateAfterIdle !== "auto") {
37
+ return activateAfterIdle;
38
+ }
39
+ return resolveAutoActivationTTL(modelContext);
40
+ }
41
+ function resolveAutoActivationTTL(modelContext) {
42
+ const provider = normalize(modelContext?.provider);
43
+ const modelId = normalize(modelContext?.modelId);
44
+ if (provider.includes("openai")) {
45
+ const promptCacheRetention = getOpenAIPromptCacheRetention(modelContext?.providerOptions);
46
+ if (promptCacheRetention === "24h") return OPENAI_EXTENDED_TTL;
47
+ if (promptCacheRetention === "in_memory") return SHORT_TTL;
48
+ return isOpenAIShortTtlModel(modelId) ? SHORT_TTL : OPENAI_EXTENDED_TTL;
49
+ }
50
+ if (provider.includes("google") || provider.includes("gemini")) return GEMINI_TTL;
51
+ if (provider.includes("deepseek")) return DEEPSEEK_TTL;
52
+ if (provider.includes("groq")) return GROQ_TTL;
53
+ if (provider.includes("anthropic")) return SHORT_TTL;
54
+ if (provider.includes("xai") || provider.includes("grok")) return SHORT_TTL;
55
+ if (provider.includes("openrouter")) return SHORT_TTL;
56
+ return SHORT_TTL;
57
+ }
17
58
  var OM_DEBUG_LOG = process.env.OM_DEBUG ? join(process.cwd(), "om-debug.log") : null;
18
59
  function omDebug(msg) {
19
60
  if (!OM_DEBUG_LOG) return;
@@ -3145,6 +3186,35 @@ function isImageLikeObserverFilePart(part) {
3145
3186
  }
3146
3187
  return hasObserverImageFilenameExtension(part.filename);
3147
3188
  }
3189
+ function resolveObserverAttachmentMimeType(part) {
3190
+ if (typeof part.mimeType === "string" && part.mimeType.length > 0) {
3191
+ return part.mimeType.toLowerCase();
3192
+ }
3193
+ if (part.type === "image") {
3194
+ return "image/*";
3195
+ }
3196
+ if (isImageLikeObserverFilePart(part)) {
3197
+ return "image/*";
3198
+ }
3199
+ return "application/octet-stream";
3200
+ }
3201
+ function matchObserverMimePattern(mimeType, pattern) {
3202
+ const normalized = pattern.trim().toLowerCase();
3203
+ if (!normalized) return false;
3204
+ if (normalized === "*" || normalized === "*/*") return true;
3205
+ if (normalized.endsWith("/*")) {
3206
+ const prefix = normalized.slice(0, normalized.length - 1);
3207
+ return mimeType.startsWith(prefix);
3208
+ }
3209
+ return mimeType === normalized;
3210
+ }
3211
+ function shouldIncludeObserverAttachment(part, filter) {
3212
+ if (filter === void 0 || filter === true) return true;
3213
+ if (filter === false) return false;
3214
+ if (!Array.isArray(filter) || filter.length === 0) return false;
3215
+ const mimeType = resolveObserverAttachmentMimeType(part);
3216
+ return filter.some((pattern) => matchObserverMimePattern(mimeType, pattern));
3217
+ }
3148
3218
  function toObserverInputAttachmentPart(part) {
3149
3219
  if (part.type === "image") {
3150
3220
  return {
@@ -3243,22 +3313,26 @@ function mapToolResultBlockToAttachment(block) {
3243
3313
  return void 0;
3244
3314
  }
3245
3315
  }
3246
- function extractToolResultAttachments(result, counter) {
3316
+ function extractToolResultAttachments(result, counter, attachmentFilter) {
3247
3317
  if (!isRecord(result) || result.type !== "content" || !Array.isArray(result.value)) {
3248
3318
  return { resultWithoutAttachments: result, attachments: [] };
3249
3319
  }
3250
3320
  const record = result;
3251
3321
  const attachments = [];
3322
+ let hadAttachmentBlocks = false;
3252
3323
  const newValue = record.value.map((block) => {
3253
3324
  const attachment = mapToolResultBlockToAttachment(block);
3254
3325
  if (!attachment) {
3255
3326
  return block;
3256
3327
  }
3257
- attachments.push(toObserverInputAttachmentPart(attachment));
3328
+ hadAttachmentBlocks = true;
3329
+ if (shouldIncludeObserverAttachment(attachment, attachmentFilter)) {
3330
+ attachments.push(toObserverInputAttachmentPart(attachment));
3331
+ }
3258
3332
  const placeholder = formatObserverAttachmentPlaceholder(attachment, counter);
3259
3333
  return { type: isRecord(block) ? block.type : void 0, placeholder };
3260
3334
  });
3261
- if (attachments.length === 0) {
3335
+ if (!hadAttachmentBlocks) {
3262
3336
  return { resultWithoutAttachments: result, attachments };
3263
3337
  }
3264
3338
  return { resultWithoutAttachments: { ...record, value: newValue }, attachments };
@@ -3317,6 +3391,7 @@ function getTemporalGapMarkerText(msg) {
3317
3391
  function formatObserverMessage(msg, counter, options) {
3318
3392
  const maxLen = options?.maxPartLength;
3319
3393
  const maxToolResultTokens = options?.maxToolResultTokens ?? DEFAULT_OBSERVER_TOOL_RESULT_MAX_TOKENS;
3394
+ const attachmentFilter = options?.attachmentFilter;
3320
3395
  const role = msg.role.charAt(0).toUpperCase() + msg.role.slice(1);
3321
3396
  const attachments = [];
3322
3397
  const messageCreatedAt = normalizeObserverCreatedAt(msg.createdAt);
@@ -3354,7 +3429,8 @@ function formatObserverMessage(msg, counter, options) {
3354
3429
  );
3355
3430
  const { resultWithoutAttachments, attachments: extractedAttachments } = extractToolResultAttachments(
3356
3431
  resultForObserver,
3357
- counter
3432
+ counter,
3433
+ attachmentFilter
3358
3434
  );
3359
3435
  if (extractedAttachments.length > 0) {
3360
3436
  attachments.push(...extractedAttachments);
@@ -3383,9 +3459,11 @@ function formatObserverMessage(msg, counter, options) {
3383
3459
  }
3384
3460
  if (partType === "image" || partType === "file") {
3385
3461
  const attachment = part;
3386
- const inputAttachment = toObserverInputAttachmentPart(attachment);
3387
- if (inputAttachment) {
3388
- attachments.push(inputAttachment);
3462
+ if (shouldIncludeObserverAttachment(attachment, attachmentFilter)) {
3463
+ const inputAttachment = toObserverInputAttachmentPart(attachment);
3464
+ if (inputAttachment) {
3465
+ attachments.push(inputAttachment);
3466
+ }
3389
3467
  }
3390
3468
  pushLine(
3391
3469
  partType === "image" ? "Image" : "File",
@@ -3973,13 +4051,11 @@ async function withOmTracingSpan({
3973
4051
  entityType: EntityType.OUTPUT_STEP_PROCESSOR,
3974
4052
  entityName: config.entityName,
3975
4053
  tracingContext: observabilityContext?.tracingContext ?? observabilityContext?.tracing,
3976
- attributes: {
3977
- metadata: {
3978
- omPhase: phase,
3979
- omInputTokens: inputTokens,
3980
- omSelectedModel: typeof model === "string" ? model : "(dynamic-model)",
3981
- ...metadata
3982
- }
4054
+ metadata: {
4055
+ omPhase: phase,
4056
+ omInputTokens: inputTokens,
4057
+ omSelectedModel: typeof model === "string" ? model : "(dynamic-model)",
4058
+ ...metadata
3983
4059
  },
3984
4060
  requestContext
3985
4061
  });
@@ -4050,7 +4126,9 @@ var ObserverRunner = class {
4050
4126
  includeThreadTitle: this.observationConfig.threadTitle
4051
4127
  })
4052
4128
  },
4053
- buildObserverHistoryMessage(messagesToObserve)
4129
+ buildObserverHistoryMessage(messagesToObserve, {
4130
+ attachmentFilter: this.observationConfig.observeAttachments
4131
+ })
4054
4132
  ];
4055
4133
  const doGenerate = async () => {
4056
4134
  return withRetry(
@@ -4147,7 +4225,9 @@ var ObserverRunner = class {
4147
4225
  this.observationConfig.threadTitle
4148
4226
  )
4149
4227
  },
4150
- buildMultiThreadObserverHistoryMessage(messagesByThread, threadOrder)
4228
+ buildMultiThreadObserverHistoryMessage(messagesByThread, threadOrder, {
4229
+ attachmentFilter: this.observationConfig.observeAttachments
4230
+ })
4151
4231
  ];
4152
4232
  for (const msgs of messagesByThread.values()) {
4153
4233
  for (const msg of msgs) {
@@ -4978,7 +5058,10 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
4978
5058
  ttlExpiredMs: activationMetadata?.ttlExpiredMs,
4979
5059
  previousModel: activationMetadata?.previousModel,
4980
5060
  currentModel: activationMetadata?.currentModel,
4981
- config: this.getObservationMarkerConfig(freshRecord)
5061
+ config: {
5062
+ ...this.getObservationMarkerConfig(freshRecord),
5063
+ activateAfterIdle: activationMetadata?.activateAfterIdle ?? this.reflectionConfig.activateAfterIdle
5064
+ }
4982
5065
  });
4983
5066
  void writer.custom({ ...activationMarker, transient: true }).catch(() => {
4984
5067
  });
@@ -5041,7 +5124,7 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
5041
5124
  );
5042
5125
  }
5043
5126
  }
5044
- const activateAfterIdle = this.reflectionConfig.activateAfterIdle;
5127
+ const activateAfterIdle = resolveActivationTTL(this.reflectionConfig.activateAfterIdle, currentModel);
5045
5128
  const ttlExpiredMs = activateAfterIdle !== void 0 && lastActivityAt !== void 0 ? Date.now() - lastActivityAt : void 0;
5046
5129
  const ttlExpired = ttlExpiredMs !== void 0 && activateAfterIdle !== void 0 && ttlExpiredMs >= activateAfterIdle;
5047
5130
  const actorModel = getCurrentModel(currentModel);
@@ -5054,6 +5137,7 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
5054
5137
  const activationMetadata = {
5055
5138
  triggeredBy: activationTriggeredBy,
5056
5139
  lastActivityAt: activationTriggeredBy === "ttl" ? lastActivityAt : void 0,
5140
+ activateAfterIdle: activationTriggeredBy === "ttl" ? activateAfterIdle : void 0,
5057
5141
  ttlExpiredMs: activationTriggeredBy === "ttl" ? ttlExpiredMs : void 0,
5058
5142
  previousModel: activationTriggeredBy === "provider_change" ? lastModel : void 0,
5059
5143
  currentModel: activationTriggeredBy === "provider_change" ? actorModel : void 0
@@ -6894,6 +6978,9 @@ function parseActivationTTL(value, fieldPath) {
6894
6978
  if (value === void 0 || value === false) {
6895
6979
  return void 0;
6896
6980
  }
6981
+ if (value === "auto") {
6982
+ return value;
6983
+ }
6897
6984
  if (typeof value === "number") {
6898
6985
  if (!Number.isFinite(value) || value < 0) {
6899
6986
  throw new Error(`${fieldPath} must be a non-negative number of milliseconds or a duration string like "5m".`);
@@ -7066,7 +7153,8 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
7066
7153
  ),
7067
7154
  previousObserverTokens: config.observation?.previousObserverTokens ?? 2e3,
7068
7155
  instruction: config.observation?.instruction,
7069
- threadTitle: config.observation?.threadTitle ?? false
7156
+ threadTitle: config.observation?.threadTitle ?? false,
7157
+ observeAttachments: config.observation?.observeAttachments ?? true
7070
7158
  };
7071
7159
  this.reflectionConfig = {
7072
7160
  model: reflectionModel,
@@ -8989,6 +9077,7 @@ ${grouped}` : grouped;
8989
9077
  }
8990
9078
  let activationTriggeredBy = "threshold";
8991
9079
  let activationLastActivityAt;
9080
+ let activationActivateAfterIdle;
8992
9081
  let activateAfterIdleExpiredMs;
8993
9082
  let previousModel;
8994
9083
  let currentModel;
@@ -8998,7 +9087,7 @@ ${grouped}` : grouped;
8998
9087
  resourceId,
8999
9088
  record.lastObservedAt ? new Date(record.lastObservedAt) : void 0
9000
9089
  );
9001
- const activateAfterIdle = this.observationConfig.activateAfterIdle;
9090
+ const activateAfterIdle = resolveActivationTTL(this.observationConfig.activateAfterIdle, opts.currentModel);
9002
9091
  const lastActivityAt = getLastActivityFromMessages(thresholdMessages);
9003
9092
  const ttlExpiredMs = activateAfterIdle !== void 0 && lastActivityAt !== void 0 ? Date.now() - lastActivityAt : void 0;
9004
9093
  const ttlExpired = ttlExpiredMs !== void 0 && activateAfterIdle !== void 0 && ttlExpiredMs >= activateAfterIdle;
@@ -9012,6 +9101,7 @@ ${grouped}` : grouped;
9012
9101
  } else if (ttlExpired) {
9013
9102
  activationTriggeredBy = "ttl";
9014
9103
  activationLastActivityAt = lastActivityAt;
9104
+ activationActivateAfterIdle = activateAfterIdle;
9015
9105
  activateAfterIdleExpiredMs = ttlExpiredMs;
9016
9106
  } else {
9017
9107
  const status = await this.getStatus({ threadId, resourceId, messages: thresholdMessages });
@@ -9080,7 +9170,10 @@ ${grouped}` : grouped;
9080
9170
  ttlExpiredMs: activateAfterIdleExpiredMs,
9081
9171
  previousModel,
9082
9172
  currentModel,
9083
- config: this.getObservationMarkerConfig()
9173
+ config: {
9174
+ ...this.getObservationMarkerConfig(),
9175
+ activateAfterIdle: activationActivateAfterIdle ?? this.observationConfig.activateAfterIdle
9176
+ }
9084
9177
  });
9085
9178
  void opts.writer.custom({ ...activationMarker, transient: true }).catch(() => {
9086
9179
  });
@@ -9539,7 +9632,7 @@ var ObservationalMemoryProcessor = class {
9539
9632
  const { threadId, resourceId } = context;
9540
9633
  const memoryContext = parseMemoryRequestContext(requestContext);
9541
9634
  const readOnly = memoryContext?.memoryConfig?.readOnly;
9542
- const actorModelContext = model?.modelId ? { provider: model.provider, modelId: model.modelId } : void 0;
9635
+ const actorModelContext = model?.modelId ? { provider: model.provider, modelId: model.modelId, providerOptions: args.providerOptions } : void 0;
9543
9636
  state.__omActorModelContext = actorModelContext;
9544
9637
  return this.engine.getTokenCounter().runWithModelContext(actorModelContext, async () => {
9545
9638
  const reproCaptureEnabled = isOmReproCaptureEnabled();
@@ -9728,5 +9821,5 @@ function getObservationsAsOf(activeObservations, asOf) {
9728
9821
  }
9729
9822
 
9730
9823
  export { ModelByInputTokens, OBSERVER_SYSTEM_PROMPT, ObservationalMemory, ObservationalMemoryProcessor, TokenCounter, buildObserverPrompt, buildObserverSystemPrompt, combineObservationGroupRanges, deriveObservationGroupProvenance, extractCurrentTask, formatMessagesForObserver, formatToolResultForObserver, getObservationsAsOf, hasCurrentTaskSection, injectAnchorIds, optimizeObservationsForContext, parseAnchorId, parseObservationGroups, parseObserverOutput, reconcileObservationGroupsFromReflection, renderObservationGroupsForReflection, resolveToolResultValue, stripEphemeralAnchorIds, stripObservationGroups, truncateStringByTokens, wrapInObservationGroup };
9731
- //# sourceMappingURL=chunk-KLETR4RS.js.map
9732
- //# sourceMappingURL=chunk-KLETR4RS.js.map
9824
+ //# sourceMappingURL=chunk-NZXH5WER.js.map
9825
+ //# sourceMappingURL=chunk-NZXH5WER.js.map