@mastra/memory 1.17.5 → 1.17.6-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 (27) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/{chunk-BPJLUC2F.js → chunk-QZGJY67D.js} +85 -6
  3. package/dist/chunk-QZGJY67D.js.map +1 -0
  4. package/dist/{chunk-UZDSNIGD.cjs → chunk-WNLFJKTX.cjs} +85 -6
  5. package/dist/chunk-WNLFJKTX.cjs.map +1 -0
  6. package/dist/docs/SKILL.md +1 -1
  7. package/dist/docs/assets/SOURCE_MAP.json +39 -39
  8. package/dist/docs/references/docs-agents-background-tasks.md +62 -2
  9. package/dist/docs/references/docs-memory-observational-memory.md +7 -2
  10. package/dist/docs/references/docs-memory-overview.md +2 -1
  11. package/dist/index.cjs +298 -172
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +289 -163
  15. package/dist/index.js.map +1 -1
  16. package/dist/{observational-memory-KWFKMLG6.cjs → observational-memory-BJF72NKJ.cjs} +26 -26
  17. package/dist/{observational-memory-KWFKMLG6.cjs.map → observational-memory-BJF72NKJ.cjs.map} +1 -1
  18. package/dist/{observational-memory-FBBKXNO5.js → observational-memory-HAJ3K5JJ.js} +3 -3
  19. package/dist/{observational-memory-FBBKXNO5.js.map → observational-memory-HAJ3K5JJ.js.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/observation-strategies/resource-scoped.d.ts.map +1 -1
  23. package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
  24. package/dist/processors/observational-memory/observer-agent.d.ts.map +1 -1
  25. package/package.json +8 -8
  26. package/dist/chunk-BPJLUC2F.js.map +0 -1
  27. package/dist/chunk-UZDSNIGD.cjs.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @mastra/memory
2
2
 
3
+ ## 1.17.6-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Added extra defensive checks to prevent edge cases where system messages may have already been stored in message history. ([#15787](https://github.com/mastra-ai/mastra/pull/15787))
8
+
9
+ - Updated dependencies [[`b560d6f`](https://github.com/mastra-ai/mastra/commit/b560d6f88b9b904b15c10f75c949eb145bc27684), [`36b3bbf`](https://github.com/mastra-ai/mastra/commit/36b3bbf5a8d59f7e23d47e29340e76c681b4929c), [`b275631`](https://github.com/mastra-ai/mastra/commit/b275631dc10541a482b2e2d4a3e3cfa843bd5fa1)]:
10
+ - @mastra/core@1.33.0-alpha.6
11
+
12
+ ## 1.17.6-alpha.0
13
+
14
+ ### Patch Changes
15
+
16
+ - Fixed an issue where tool results containing AI SDK v5 `image-data` content blocks (returned via `toModelOutput`) were stringified into the observational memory prompt as raw base64 text. The base64 data overflowed the observer's context, causing token-limit errors and degenerate output. ([#16117](https://github.com/mastra-ai/mastra/pull/16117))
17
+
18
+ Image and file blocks (`image-data`, `image-url`, `file-data`, `file-url`, and `media`) inside tool results are now hoisted into the observer's input as proper attachments, the same way image and file message parts already are. The text body shows a placeholder like `[Image #1: image/png]` so the observer keeps positional context without seeing the bytes.
19
+
3
20
  ## 1.17.5
4
21
 
5
22
  ### Patch Changes
@@ -1689,8 +1689,9 @@ var ResourceScopedObservationStrategy = class extends ObservationStrategy {
1689
1689
  orderBy: { field: "createdAt", direction: "ASC" },
1690
1690
  filter: startDate ? { dateRange: { start: startDate } } : void 0
1691
1691
  });
1692
- if (result.messages.length > 0) {
1693
- this.messagesByThread.set(thread.id, result.messages);
1692
+ const messages = result.messages.filter((msg) => msg.role !== "system");
1693
+ if (messages.length > 0) {
1694
+ this.messagesByThread.set(thread.id, messages);
1694
1695
  }
1695
1696
  }
1696
1697
  if (currentThreadMessages.length > 0) {
@@ -3158,6 +3159,71 @@ function formatObserverAttachmentPlaceholder(part, counter) {
3158
3159
  const label = resolveObserverAttachmentLabel(part);
3159
3160
  return label ? `[${attachmentType} #${attachmentId}: ${label}]` : `[${attachmentType} #${attachmentId}]`;
3160
3161
  }
3162
+ function isRecord(value) {
3163
+ return !!value && typeof value === "object";
3164
+ }
3165
+ function mapToolResultBlockToAttachment(block) {
3166
+ if (!isRecord(block) || typeof block.type !== "string") {
3167
+ return void 0;
3168
+ }
3169
+ const mediaType = typeof block.mediaType === "string" ? block.mediaType : void 0;
3170
+ const filename = typeof block.filename === "string" ? block.filename : void 0;
3171
+ switch (block.type) {
3172
+ case "image-data": {
3173
+ const data = block.data;
3174
+ if (typeof data !== "string") return void 0;
3175
+ const image = mediaType ? `data:${mediaType};base64,${data}` : data;
3176
+ return { type: "image", image, mimeType: mediaType };
3177
+ }
3178
+ case "image-url": {
3179
+ const url = block.url;
3180
+ if (typeof url !== "string") return void 0;
3181
+ return { type: "image", image: url, mimeType: mediaType };
3182
+ }
3183
+ case "media": {
3184
+ const data = block.data;
3185
+ if (typeof data !== "string" || !mediaType) return void 0;
3186
+ const dataUri = `data:${mediaType};base64,${data}`;
3187
+ if (mediaType.toLowerCase().startsWith("image/")) {
3188
+ return { type: "image", image: dataUri, mimeType: mediaType };
3189
+ }
3190
+ return { type: "file", data: dataUri, mimeType: mediaType };
3191
+ }
3192
+ case "file-data": {
3193
+ const data = block.data;
3194
+ if (typeof data !== "string") return void 0;
3195
+ const dataUri = mediaType ? `data:${mediaType};base64,${data}` : data;
3196
+ return { type: "file", data: dataUri, mimeType: mediaType, filename };
3197
+ }
3198
+ case "file-url": {
3199
+ const url = block.url;
3200
+ if (typeof url !== "string") return void 0;
3201
+ return { type: "file", data: url, mimeType: mediaType, filename };
3202
+ }
3203
+ default:
3204
+ return void 0;
3205
+ }
3206
+ }
3207
+ function extractToolResultAttachments(result, counter) {
3208
+ if (!isRecord(result) || result.type !== "content" || !Array.isArray(result.value)) {
3209
+ return { resultWithoutAttachments: result, attachments: [] };
3210
+ }
3211
+ const record = result;
3212
+ const attachments = [];
3213
+ const newValue = record.value.map((block) => {
3214
+ const attachment = mapToolResultBlockToAttachment(block);
3215
+ if (!attachment) {
3216
+ return block;
3217
+ }
3218
+ attachments.push(toObserverInputAttachmentPart(attachment));
3219
+ const placeholder = formatObserverAttachmentPlaceholder(attachment, counter);
3220
+ return { type: isRecord(block) ? block.type : void 0, placeholder };
3221
+ });
3222
+ if (attachments.length === 0) {
3223
+ return { resultWithoutAttachments: result, attachments };
3224
+ }
3225
+ return { resultWithoutAttachments: { ...record, value: newValue }, attachments };
3226
+ }
3161
3227
  function formatObserverPartLine(title, body, time, previousTime) {
3162
3228
  const timeLabel = time && time !== previousTime ? `(${time})` : "";
3163
3229
  if (!title) {
@@ -3247,9 +3313,19 @@ function formatObserverMessage(msg, counter, options) {
3247
3313
  part,
3248
3314
  inv.result
3249
3315
  );
3316
+ const { resultWithoutAttachments, attachments: extractedAttachments } = extractToolResultAttachments(
3317
+ resultForObserver,
3318
+ counter
3319
+ );
3320
+ if (extractedAttachments.length > 0) {
3321
+ attachments.push(...extractedAttachments);
3322
+ }
3250
3323
  pushLine(
3251
3324
  `Tool Result ${inv.toolName}`,
3252
- maybeTruncate(formatToolResultForObserver(resultForObserver, { maxTokens: maxToolResultTokens }), maxLen),
3325
+ maybeTruncate(
3326
+ formatToolResultForObserver(resultWithoutAttachments, { maxTokens: maxToolResultTokens }),
3327
+ maxLen
3328
+ ),
3253
3329
  partCreatedAt
3254
3330
  );
3255
3331
  return;
@@ -7344,6 +7420,9 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
7344
7420
  }
7345
7421
  const result = [];
7346
7422
  for (const msg of allMessages) {
7423
+ if (msg.role === "system") {
7424
+ continue;
7425
+ }
7347
7426
  if (observedMessageIds?.has(msg.id)) {
7348
7427
  continue;
7349
7428
  }
@@ -7654,7 +7733,7 @@ ${suggestedResponse}
7654
7733
  } : void 0
7655
7734
  });
7656
7735
  }
7657
- return result.messages;
7736
+ return result.messages.filter((msg) => msg.role !== "system");
7658
7737
  }
7659
7738
  /**
7660
7739
  * Format unobserved messages from other threads as <unobserved-context> blocks.
@@ -9366,5 +9445,5 @@ function getObservationsAsOf(activeObservations, asOf) {
9366
9445
  }
9367
9446
 
9368
9447
  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 };
9369
- //# sourceMappingURL=chunk-BPJLUC2F.js.map
9370
- //# sourceMappingURL=chunk-BPJLUC2F.js.map
9448
+ //# sourceMappingURL=chunk-QZGJY67D.js.map
9449
+ //# sourceMappingURL=chunk-QZGJY67D.js.map