@mastra/memory 1.18.0 → 1.18.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/CHANGELOG.md CHANGED
@@ -1,5 +1,51 @@
1
1
  # @mastra/memory
2
2
 
3
+ ## 1.18.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Added a public escape hatch so callers can supply an authoritative token estimate for file parts whose binary payload has been stripped before persistence (for example, files uploaded to cloud storage with a hidden reference token left in `data` and re-hydrated by LLM middleware before inference). ([#16565](https://github.com/mastra-ai/mastra/pull/16565))
8
+
9
+ For those pipelines TokenCounter has no on-device file size to measure, so Observational Memory thresholds and context budgets undercount large attachments. Callers can now stamp an estimate directly on the part:
10
+
11
+ ```ts
12
+ part.providerMetadata = {
13
+ mastra: {
14
+ tokenEstimate: { v: 0, source: 'client', key: 'client', tokens: 25_000 },
15
+ },
16
+ };
17
+ ```
18
+
19
+ When present, TokenCounter returns those tokens from both the sync and async paths and skips provider fetches. Invalid entries (NaN, negative, non-numeric) fall through to the default estimator. Parts without a client estimate are unaffected.
20
+
21
+ Related to https://github.com/mastra-ai/mastra/issues/16522
22
+
23
+ - Updated dependencies [[`20787de`](https://github.com/mastra-ai/mastra/commit/20787de5965234a1af28fe35f49437c537dbfa0d), [`784ad98`](https://github.com/mastra-ai/mastra/commit/784ad989549de91dc5d33ab8ef36caa6f7dcd34e), [`fceae1f`](https://github.com/mastra-ai/mastra/commit/fceae1f5f5db4722cb078a663c6eb4bd22944123), [`090a647`](https://github.com/mastra-ai/mastra/commit/090a647ba5a66d36f203f9f49457e03a1ff4e6fb), [`bf02acb`](https://github.com/mastra-ai/mastra/commit/bf02acbb8a6110f638ac844e89f1ebf04cb7fe74), [`090a647`](https://github.com/mastra-ai/mastra/commit/090a647ba5a66d36f203f9f49457e03a1ff4e6fb), [`bdb4cbf`](https://github.com/mastra-ai/mastra/commit/bdb4cbf8ba4b685d7481f28bb9dc3de6c79c9ed2), [`0fd3fbe`](https://github.com/mastra-ai/mastra/commit/0fd3fbe40fb63657aedd72f6e7b38c8e8ee6940d), [`f84447d`](https://github.com/mastra-ai/mastra/commit/f84447d6c80f3471836a9b300d246b331fb47e0d), [`a1a5b3e`](https://github.com/mastra-ai/mastra/commit/a1a5b3e42ab2ca5161ea21db59ebf28442680fa7), [`af84f57`](https://github.com/mastra-ai/mastra/commit/af84f571ed762e92e8e61c5f9a72363520914274), [`8b3c6f9`](https://github.com/mastra-ai/mastra/commit/8b3c6f90f7879833ba7d1bc70937e1d8f69d0804), [`fed0475`](https://github.com/mastra-ai/mastra/commit/fed0475ccfea31e4fc251469ac05640d0742c1f0), [`0d53730`](https://github.com/mastra-ai/mastra/commit/0d53730c1ed87ef80c87caa5701c4170ea8028e6), [`522f44d`](https://github.com/mastra-ai/mastra/commit/522f44d947214bfc06cff50599bae1ef3494880d)]:
24
+ - @mastra/core@1.34.0
25
+
26
+ ## 1.18.1-alpha.0
27
+
28
+ ### Patch Changes
29
+
30
+ - Added a public escape hatch so callers can supply an authoritative token estimate for file parts whose binary payload has been stripped before persistence (for example, files uploaded to cloud storage with a hidden reference token left in `data` and re-hydrated by LLM middleware before inference). ([#16565](https://github.com/mastra-ai/mastra/pull/16565))
31
+
32
+ For those pipelines TokenCounter has no on-device file size to measure, so Observational Memory thresholds and context budgets undercount large attachments. Callers can now stamp an estimate directly on the part:
33
+
34
+ ```ts
35
+ part.providerMetadata = {
36
+ mastra: {
37
+ tokenEstimate: { v: 0, source: 'client', key: 'client', tokens: 25_000 },
38
+ },
39
+ };
40
+ ```
41
+
42
+ When present, TokenCounter returns those tokens from both the sync and async paths and skips provider fetches. Invalid entries (NaN, negative, non-numeric) fall through to the default estimator. Parts without a client estimate are unaffected.
43
+
44
+ Related to https://github.com/mastra-ai/mastra/issues/16522
45
+
46
+ - Updated dependencies [[`fceae1f`](https://github.com/mastra-ai/mastra/commit/fceae1f5f5db4722cb078a663c6eb4bd22944123), [`bf02acb`](https://github.com/mastra-ai/mastra/commit/bf02acbb8a6110f638ac844e89f1ebf04cb7fe74), [`0fd3fbe`](https://github.com/mastra-ai/mastra/commit/0fd3fbe40fb63657aedd72f6e7b38c8e8ee6940d), [`fed0475`](https://github.com/mastra-ai/mastra/commit/fed0475ccfea31e4fc251469ac05640d0742c1f0), [`522f44d`](https://github.com/mastra-ai/mastra/commit/522f44d947214bfc06cff50599bae1ef3494880d)]:
47
+ - @mastra/core@1.34.0-alpha.1
48
+
3
49
  ## 1.18.0
4
50
 
5
51
  ### Minor Changes
package/README.md CHANGED
@@ -1,3 +1,28 @@
1
1
  # Mastra Memory
2
2
 
3
3
  Memory management for Mastra agents. Visit [the docs](https://mastra.ai/docs/memory/overview) for more information.
4
+
5
+ ## Token counting for file parts
6
+
7
+ Observational Memory uses a built-in Token Counter to decide when to observe and reflect. You can attach an explicit estimate to an `image` or `file` part using `providerMetadata.mastra.tokenEstimate`:
8
+
9
+ ```typescript
10
+ const filePart = {
11
+ type: 'file',
12
+ data: 'storage://bucket/large-report.pdf',
13
+ mimeType: 'application/pdf',
14
+ filename: 'large-report.pdf',
15
+ providerMetadata: {
16
+ mastra: {
17
+ tokenEstimate: {
18
+ v: 0,
19
+ source: 'client',
20
+ key: 'client',
21
+ tokens: 100_000,
22
+ },
23
+ },
24
+ },
25
+ };
26
+ ```
27
+
28
+ The Token Counter honors caller-supplied estimates verbatim on `image` and `file` parts. See [Caller-supplied token estimates for file parts](https://mastra.ai/docs/memory/observational-memory#caller-supplied-token-estimates-for-file-parts) for details.
@@ -1013,6 +1013,8 @@ var ObservationStrategy = class _ObservationStrategy {
1013
1013
  this.scope = deps.scope;
1014
1014
  this.retrieval = deps.retrieval;
1015
1015
  }
1016
+ deps;
1017
+ opts;
1016
1018
  storage;
1017
1019
  messageHistory;
1018
1020
  tokenCounter;
@@ -2041,6 +2043,8 @@ var ObservationStep = class {
2041
2043
  this.turn = turn;
2042
2044
  this.stepNumber = stepNumber;
2043
2045
  }
2046
+ turn;
2047
+ stepNumber;
2044
2048
  _prepared = false;
2045
2049
  _context;
2046
2050
  /** Whether this step has been prepared. */
@@ -5529,6 +5533,7 @@ var IMAGE_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
5529
5533
  "avif"
5530
5534
  ]);
5531
5535
  var TOKEN_ESTIMATE_CACHE_VERSION = 6;
5536
+ var CLIENT_TOKEN_ESTIMATE_SOURCE = "client";
5532
5537
  var DEFAULT_IMAGE_ESTIMATOR = {
5533
5538
  baseTokens: 85,
5534
5539
  tileTokens: 170,
@@ -5636,6 +5641,16 @@ function setPartCacheEntry(part, key, entry) {
5636
5641
  const mastraMetadata = ensurePartMastraMetadata(part);
5637
5642
  mastraMetadata.tokenEstimate = mergeCacheEntry(mastraMetadata.tokenEstimate, key, entry);
5638
5643
  }
5644
+ function getClientPartTokenEstimate(part) {
5645
+ const cache = getPartMastraMetadata(part)?.tokenEstimate;
5646
+ if (!cache || typeof cache !== "object") return void 0;
5647
+ const matches = (entry) => isTokenEstimateEntry(entry) && entry.source === CLIENT_TOKEN_ESTIMATE_SOURCE && Number.isFinite(entry.tokens) && entry.tokens >= 0;
5648
+ if (matches(cache)) return cache;
5649
+ for (const value of Object.values(cache)) {
5650
+ if (matches(value)) return value;
5651
+ }
5652
+ return void 0;
5653
+ }
5639
5654
  function getMessageCacheEntry(message, key) {
5640
5655
  const contentLevelEntry = getCacheEntry(getContentMastraMetadata(message.content)?.tokenEstimate, key);
5641
5656
  if (contentLevelEntry) return contentLevelEntry;
@@ -6440,6 +6455,12 @@ var TokenCounter = class _TokenCounter {
6440
6455
  return this.estimateImageAssetTokens(part, part.data, "file");
6441
6456
  }
6442
6457
  countAttachmentPartSync(part) {
6458
+ if (part.type === "image" || part.type === "file") {
6459
+ const clientEstimate = getClientPartTokenEstimate(part);
6460
+ if (clientEstimate) {
6461
+ return clientEstimate.tokens;
6462
+ }
6463
+ }
6443
6464
  if (part.type === "image") {
6444
6465
  const estimate = this.estimateImageTokens(part);
6445
6466
  return this.readOrPersistFixedPartEstimate(part, "image", estimate.cachePayload, estimate.tokens);
@@ -6504,6 +6525,12 @@ var TokenCounter = class _TokenCounter {
6504
6525
  return void 0;
6505
6526
  }
6506
6527
  async countAttachmentPartAsync(part) {
6528
+ if (part.type === "image" || part.type === "file") {
6529
+ const clientEstimate = getClientPartTokenEstimate(part);
6530
+ if (clientEstimate) {
6531
+ return clientEstimate.tokens;
6532
+ }
6533
+ }
6507
6534
  const isImageAttachment = part.type === "image" || part.type === "file" && isImageLikeFilePart(part);
6508
6535
  const remotePayload = this.buildRemoteAttachmentCachePayload(part);
6509
6536
  if (remotePayload) {
@@ -9633,5 +9660,5 @@ function getObservationsAsOf(activeObservations, asOf) {
9633
9660
  }
9634
9661
 
9635
9662
  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 };
9636
- //# sourceMappingURL=chunk-LPMZNXSF.js.map
9637
- //# sourceMappingURL=chunk-LPMZNXSF.js.map
9663
+ //# sourceMappingURL=chunk-KGYJHNI6.js.map
9664
+ //# sourceMappingURL=chunk-KGYJHNI6.js.map