@mastra/memory 1.17.6-alpha.1 → 1.18.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.
@@ -3,7 +3,7 @@ name: mastra-memory
3
3
  description: Documentation for @mastra/memory. Use when working with @mastra/memory APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/memory"
6
- version: "1.17.6-alpha.1"
6
+ version: "1.18.0-alpha.2"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,119 +1,119 @@
1
1
  {
2
- "version": "1.17.6-alpha.1",
2
+ "version": "1.18.0-alpha.2",
3
3
  "package": "@mastra/memory",
4
4
  "exports": {
5
5
  "ModelByInputTokens": {
6
6
  "types": "dist/processors/index.d.ts",
7
- "implementation": "dist/chunk-QZGJY67D.js",
7
+ "implementation": "dist/chunk-PBZHHKPE.js",
8
8
  "line": 745
9
9
  },
10
10
  "OBSERVER_SYSTEM_PROMPT": {
11
11
  "types": "dist/processors/index.d.ts",
12
- "implementation": "dist/chunk-QZGJY67D.js"
12
+ "implementation": "dist/chunk-PBZHHKPE.js"
13
13
  },
14
14
  "ObservationalMemory": {
15
15
  "types": "dist/processors/index.d.ts",
16
- "implementation": "dist/chunk-QZGJY67D.js",
17
- "line": 6674
16
+ "implementation": "dist/chunk-PBZHHKPE.js",
17
+ "line": 6690
18
18
  },
19
19
  "ObservationalMemoryProcessor": {
20
20
  "types": "dist/processors/index.d.ts",
21
- "implementation": "dist/chunk-QZGJY67D.js",
22
- "line": 9219
21
+ "implementation": "dist/chunk-PBZHHKPE.js",
22
+ "line": 9262
23
23
  },
24
24
  "TokenCounter": {
25
25
  "types": "dist/processors/index.d.ts",
26
- "implementation": "dist/chunk-QZGJY67D.js",
27
- "line": 6144
26
+ "implementation": "dist/chunk-PBZHHKPE.js",
27
+ "line": 6160
28
28
  },
29
29
  "buildObserverPrompt": {
30
30
  "types": "dist/processors/index.d.ts",
31
- "implementation": "dist/chunk-QZGJY67D.js",
32
- "line": 3643
31
+ "implementation": "dist/chunk-PBZHHKPE.js",
32
+ "line": 3659
33
33
  },
34
34
  "buildObserverSystemPrompt": {
35
35
  "types": "dist/processors/index.d.ts",
36
- "implementation": "dist/chunk-QZGJY67D.js",
37
- "line": 2951
36
+ "implementation": "dist/chunk-PBZHHKPE.js",
37
+ "line": 2967
38
38
  },
39
39
  "combineObservationGroupRanges": {
40
40
  "types": "dist/processors/index.d.ts",
41
- "implementation": "dist/chunk-QZGJY67D.js",
41
+ "implementation": "dist/chunk-PBZHHKPE.js",
42
42
  "line": 837
43
43
  },
44
44
  "deriveObservationGroupProvenance": {
45
45
  "types": "dist/processors/index.d.ts",
46
- "implementation": "dist/chunk-QZGJY67D.js",
46
+ "implementation": "dist/chunk-PBZHHKPE.js",
47
47
  "line": 871
48
48
  },
49
49
  "extractCurrentTask": {
50
50
  "types": "dist/processors/index.d.ts",
51
- "implementation": "dist/chunk-QZGJY67D.js",
52
- "line": 3757
51
+ "implementation": "dist/chunk-PBZHHKPE.js",
52
+ "line": 3773
53
53
  },
54
54
  "formatMessagesForObserver": {
55
55
  "types": "dist/processors/index.d.ts",
56
- "implementation": "dist/chunk-QZGJY67D.js",
57
- "line": 3369
56
+ "implementation": "dist/chunk-PBZHHKPE.js",
57
+ "line": 3385
58
58
  },
59
59
  "getObservationsAsOf": {
60
60
  "types": "dist/processors/index.d.ts",
61
- "implementation": "dist/chunk-QZGJY67D.js",
62
- "line": 9425
61
+ "implementation": "dist/chunk-PBZHHKPE.js",
62
+ "line": 9474
63
63
  },
64
64
  "hasCurrentTaskSection": {
65
65
  "types": "dist/processors/index.d.ts",
66
- "implementation": "dist/chunk-QZGJY67D.js",
67
- "line": 3745
66
+ "implementation": "dist/chunk-PBZHHKPE.js",
67
+ "line": 3761
68
68
  },
69
69
  "injectAnchorIds": {
70
70
  "types": "dist/processors/index.d.ts",
71
- "implementation": "dist/chunk-QZGJY67D.js",
72
- "line": 2499
71
+ "implementation": "dist/chunk-PBZHHKPE.js",
72
+ "line": 2515
73
73
  },
74
74
  "optimizeObservationsForContext": {
75
75
  "types": "dist/processors/index.d.ts",
76
- "implementation": "dist/chunk-QZGJY67D.js",
77
- "line": 3768
76
+ "implementation": "dist/chunk-PBZHHKPE.js",
77
+ "line": 3784
78
78
  },
79
79
  "parseAnchorId": {
80
80
  "types": "dist/processors/index.d.ts",
81
- "implementation": "dist/chunk-QZGJY67D.js",
82
- "line": 2472
81
+ "implementation": "dist/chunk-PBZHHKPE.js",
82
+ "line": 2488
83
83
  },
84
84
  "parseObservationGroups": {
85
85
  "types": "dist/processors/index.d.ts",
86
- "implementation": "dist/chunk-QZGJY67D.js",
86
+ "implementation": "dist/chunk-PBZHHKPE.js",
87
87
  "line": 806
88
88
  },
89
89
  "parseObserverOutput": {
90
90
  "types": "dist/processors/index.d.ts",
91
- "implementation": "dist/chunk-QZGJY67D.js",
92
- "line": 3653
91
+ "implementation": "dist/chunk-PBZHHKPE.js",
92
+ "line": 3669
93
93
  },
94
94
  "reconcileObservationGroupsFromReflection": {
95
95
  "types": "dist/processors/index.d.ts",
96
- "implementation": "dist/chunk-QZGJY67D.js",
96
+ "implementation": "dist/chunk-PBZHHKPE.js",
97
97
  "line": 895
98
98
  },
99
99
  "renderObservationGroupsForReflection": {
100
100
  "types": "dist/processors/index.d.ts",
101
- "implementation": "dist/chunk-QZGJY67D.js",
101
+ "implementation": "dist/chunk-PBZHHKPE.js",
102
102
  "line": 851
103
103
  },
104
104
  "stripEphemeralAnchorIds": {
105
105
  "types": "dist/processors/index.d.ts",
106
- "implementation": "dist/chunk-QZGJY67D.js",
107
- "line": 2529
106
+ "implementation": "dist/chunk-PBZHHKPE.js",
107
+ "line": 2545
108
108
  },
109
109
  "stripObservationGroups": {
110
110
  "types": "dist/processors/index.d.ts",
111
- "implementation": "dist/chunk-QZGJY67D.js",
111
+ "implementation": "dist/chunk-PBZHHKPE.js",
112
112
  "line": 828
113
113
  },
114
114
  "wrapInObservationGroup": {
115
115
  "types": "dist/processors/index.d.ts",
116
- "implementation": "dist/chunk-QZGJY67D.js",
116
+ "implementation": "dist/chunk-PBZHHKPE.js",
117
117
  "line": 799
118
118
  },
119
119
  "OBSERVATIONAL_MEMORY_DEFAULTS": {
@@ -149,7 +149,7 @@
149
149
  "processors": {
150
150
  "index": "dist/processors/index.js",
151
151
  "chunks": [
152
- "chunk-QZGJY67D.js",
152
+ "chunk-PBZHHKPE.js",
153
153
  "chunk-LSJJAJAF.js"
154
154
  ]
155
155
  }
@@ -121,26 +121,88 @@ Each vector store page below includes installation instructions, configuration p
121
121
 
122
122
  ## Recall configuration
123
123
 
124
- The three main parameters that control semantic recall behavior are:
124
+ The following options control semantic recall behavior:
125
125
 
126
- 1. **topK**: How many semantically similar messages to retrieve
127
- 2. **messageRange**: How much surrounding context to include with each match
128
- 3. **scope**: Whether to search within the current thread or across all threads owned by a resource (the default is resource scope).
126
+ 1. **topK**: The number of similar messages to retrieve
127
+ 2. **messageRange**: The surrounding messages to include with each match
128
+ 3. **scope**: Whether to search the current thread or all threads for a resource
129
+ 4. **filter**: Metadata criteria that restrict search results
129
130
 
130
131
  ```typescript
131
132
  const agent = new Agent({
132
133
  memory: new Memory({
133
134
  options: {
134
135
  semanticRecall: {
135
- topK: 3, // Retrieve 3 most similar messages
136
+ topK: 3, // Retrieve 3 similar messages
136
137
  messageRange: 2, // Include 2 messages before and after each match
137
- scope: 'resource', // Search across all threads for this user (default setting if omitted)
138
+ scope: 'resource', // Search all threads for this resource
139
+ filter: { projectId: { $eq: 'project-a' } },
138
140
  },
139
141
  },
140
142
  }),
141
143
  })
142
144
  ```
143
145
 
146
+ > **Note:** `scope: 'resource'` is supported by the LibSQL, PostgreSQL, and Upstash storage adapters.
147
+
148
+ ### Metadata filtering
149
+
150
+ The `filter` option restricts semantic recall results to messages with matching thread metadata.
151
+
152
+ ```typescript
153
+ const agent = new Agent({
154
+ memory: new Memory({
155
+ options: {
156
+ semanticRecall: {
157
+ scope: 'resource',
158
+ filter: {
159
+ projectId: { $eq: 'project-a' },
160
+ category: { $in: ['work', 'personal'] },
161
+ },
162
+ },
163
+ },
164
+ }),
165
+ })
166
+ ```
167
+
168
+ Filters match metadata stored on message embeddings when messages are saved. If thread metadata changes later, existing embeddings keep their previous metadata until those messages are saved or indexed again.
169
+
170
+ Supported filter operators:
171
+
172
+ - `$and`: Logical AND
173
+ - `$eq`: Equal to
174
+ - `$gt`: Greater than
175
+ - `$gte`: Greater than or equal
176
+ - `$in`: In array
177
+ - `$lt`: Less than
178
+ - `$lte`: Less than or equal
179
+ - `$ne`: Not equal to
180
+ - `$nin`: Not in array
181
+ - `$or`: Logical OR
182
+
183
+ The following example demonstrates metadata filters for common use cases:
184
+
185
+ ```typescript
186
+ // Filter by project
187
+ const options = {
188
+ semanticRecall: { filter: { projectId: { $eq: 'my-project' } } },
189
+ }
190
+
191
+ // Filter by multiple categories
192
+ const options = {
193
+ semanticRecall: { filter: { category: { $in: ['work', 'research'] } } },
194
+ }
195
+
196
+ // Filter by project and priority
197
+ const options = {
198
+ semanticRecall: {
199
+ filter: {
200
+ $and: [{ projectId: { $eq: 'project-a' } }, { priority: { $gte: 3 } }],
201
+ },
202
+ },
203
+ }
204
+ ```
205
+
144
206
  ## Embedder configuration
145
207
 
146
208
  Semantic recall relies on an [embedding model](https://mastra.ai/reference/memory/memory-class) to convert messages into embeddings. Mastra supports embedding models through the model router using `provider/model` strings, or you can use any [embedding model](https://sdk.vercel.ai/docs/ai-sdk-core/embeddings) compatible with the AI SDK.
package/dist/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkWNLFJKTX_cjs = require('./chunk-WNLFJKTX.cjs');
3
+ var chunkMJNTQ6GP_cjs = require('./chunk-MJNTQ6GP.cjs');
4
4
  var v3 = require('zod/v3');
5
5
  var zod = require('zod');
6
6
  var z4 = require('zod/v4');
@@ -16110,7 +16110,7 @@ function formatTimestamp(date) {
16110
16110
  }
16111
16111
  function truncateByTokens(text4, maxTokens, hint) {
16112
16112
  if (tokenx.estimateTokenCount(text4) <= maxTokens) return { text: text4, wasTruncated: false };
16113
- const truncated = chunkWNLFJKTX_cjs.truncateStringByTokens(text4, maxTokens);
16113
+ const truncated = chunkMJNTQ6GP_cjs.truncateStringByTokens(text4, maxTokens);
16114
16114
  const suffix = hint ? ` [${hint} for more]` : "";
16115
16115
  return { text: truncated + suffix, wasTruncated: true };
16116
16116
  }
@@ -16162,11 +16162,11 @@ ${JSON.stringify(inv.args, null, 2)}`;
16162
16162
  });
16163
16163
  }
16164
16164
  if (inv.state === "result") {
16165
- const { value: resultValue } = chunkWNLFJKTX_cjs.resolveToolResultValue(
16165
+ const { value: resultValue } = chunkMJNTQ6GP_cjs.resolveToolResultValue(
16166
16166
  part,
16167
16167
  inv.result
16168
16168
  );
16169
- const resultStr = chunkWNLFJKTX_cjs.formatToolResultForObserver(resultValue, { maxTokens: HIGH_DETAIL_TOOL_RESULT_TOKENS });
16169
+ const resultStr = chunkMJNTQ6GP_cjs.formatToolResultForObserver(resultValue, { maxTokens: HIGH_DETAIL_TOOL_RESULT_TOKENS });
16170
16170
  const fullText = `[Tool Result: ${inv.toolName}]
16171
16171
  ${resultStr}`;
16172
16172
  parts.push(makePart(msg, i, "tool-result", fullText, detail, inv.toolName));
@@ -16193,7 +16193,7 @@ ${typeof rawArgs === "string" ? rawArgs : JSON.stringify(rawArgs, null, 2)}`;
16193
16193
  const toolName = part.toolName;
16194
16194
  if (toolName) {
16195
16195
  const rawResult = part.output ?? part.result;
16196
- const resultStr = chunkWNLFJKTX_cjs.formatToolResultForObserver(rawResult, { maxTokens: HIGH_DETAIL_TOOL_RESULT_TOKENS });
16196
+ const resultStr = chunkMJNTQ6GP_cjs.formatToolResultForObserver(rawResult, { maxTokens: HIGH_DETAIL_TOOL_RESULT_TOKENS });
16197
16197
  const fullText = `[Tool Result: ${toolName}]
16198
16198
  ${resultStr}`;
16199
16199
  parts.push(makePart(msg, i, "tool-result", fullText, detail, toolName));
@@ -16272,7 +16272,7 @@ function renderFormattedParts(parts, timestamps, options) {
16272
16272
  const text4 = buildRenderedText(parts, timestamps);
16273
16273
  let totalTokens = tokenx.estimateTokenCount(text4);
16274
16274
  if (totalTokens > options.maxTokens) {
16275
- const truncated = chunkWNLFJKTX_cjs.truncateStringByTokens(text4, options.maxTokens);
16275
+ const truncated = chunkMJNTQ6GP_cjs.truncateStringByTokens(text4, options.maxTokens);
16276
16276
  return { text: truncated, truncated: true, tokenOffset: totalTokens - options.maxTokens };
16277
16277
  }
16278
16278
  const truncatedIndices = parts.map((p, i) => ({ part: p, index: i })).filter(({ part }) => part.text !== part.fullText).sort((a, b) => expandPriority(a.part) - expandPriority(b.part));
@@ -16305,7 +16305,7 @@ function renderFormattedParts(parts, timestamps, options) {
16305
16305
  if (expandedTokens <= options.maxTokens) {
16306
16306
  return { text: expanded, truncated: false, tokenOffset: 0 };
16307
16307
  }
16308
- const hardTruncated = chunkWNLFJKTX_cjs.truncateStringByTokens(expanded, options.maxTokens);
16308
+ const hardTruncated = chunkMJNTQ6GP_cjs.truncateStringByTokens(expanded, options.maxTokens);
16309
16309
  return { text: hardTruncated, truncated: true, tokenOffset: expandedTokens - options.maxTokens };
16310
16310
  }
16311
16311
  async function recallPart({
@@ -16356,7 +16356,7 @@ async function recallPart({
16356
16356
 
16357
16357
  `;
16358
16358
  const fallbackText = `${fallbackNote}${firstNextPart.text}`;
16359
- const truncatedText2 = chunkWNLFJKTX_cjs.truncateStringByTokens(fallbackText, maxTokens);
16359
+ const truncatedText2 = chunkMJNTQ6GP_cjs.truncateStringByTokens(fallbackText, maxTokens);
16360
16360
  const wasTruncated2 = truncatedText2 !== fallbackText;
16361
16361
  return {
16362
16362
  text: truncatedText2,
@@ -16371,7 +16371,7 @@ async function recallPart({
16371
16371
  }
16372
16372
  throw new Error(`Part index ${partIndex} not found in message ${cursor}. Available indices: ${availableIndices}`);
16373
16373
  }
16374
- const truncatedText = chunkWNLFJKTX_cjs.truncateStringByTokens(target.text, maxTokens);
16374
+ const truncatedText = chunkMJNTQ6GP_cjs.truncateStringByTokens(target.text, maxTokens);
16375
16375
  const wasTruncated = truncatedText !== target.text;
16376
16376
  return {
16377
16377
  text: truncatedText,
@@ -17351,16 +17351,15 @@ var Memory = class extends memory.MastraMemory {
17351
17351
  `Tried to query vector index ${indexName} but this Memory instance doesn't have an attached vector db.`
17352
17352
  );
17353
17353
  }
17354
+ const scopeFilter = resourceScope ? { resource_id: resourceId } : { thread_id: threadId };
17355
+ const userFilter = typeof config.semanticRecall === "object" ? config.semanticRecall.filter : void 0;
17356
+ const combinedFilter = userFilter ? { $and: [scopeFilter, userFilter] } : scopeFilter;
17354
17357
  vectorResults.push(
17355
17358
  ...await this.vector.query({
17356
17359
  indexName,
17357
17360
  queryVector: embedding,
17358
17361
  topK: vectorConfig.topK,
17359
- filter: resourceScope ? {
17360
- resource_id: resourceId
17361
- } : {
17362
- thread_id: threadId
17363
- }
17362
+ filter: combinedFilter
17364
17363
  })
17365
17364
  );
17366
17365
  })
@@ -17762,6 +17761,31 @@ ${workingMemory}`;
17762
17761
  });
17763
17762
  let totalTokens = 0;
17764
17763
  if (this.vector && config.semanticRecall) {
17764
+ const messagesByThread = /* @__PURE__ */ new Map();
17765
+ updatedMessages.forEach((message) => {
17766
+ if (message.threadId) {
17767
+ if (!messagesByThread.has(message.threadId)) {
17768
+ messagesByThread.set(message.threadId, []);
17769
+ }
17770
+ messagesByThread.get(message.threadId).push(message);
17771
+ }
17772
+ });
17773
+ const threadMetadataMap = /* @__PURE__ */ new Map();
17774
+ await Promise.all(
17775
+ Array.from(messagesByThread.keys()).map(async (threadId) => {
17776
+ try {
17777
+ const thread = await memoryStore.getThreadById({ threadId });
17778
+ if (thread?.metadata) {
17779
+ threadMetadataMap.set(threadId, thread.metadata);
17780
+ }
17781
+ } catch (error) {
17782
+ const message = error instanceof Error ? error.message : String(error);
17783
+ throw new Error(
17784
+ `Could not fetch metadata for thread ${threadId} while saving semantic recall embeddings: ${message}`
17785
+ );
17786
+ }
17787
+ })
17788
+ );
17765
17789
  const embeddingData = [];
17766
17790
  let dimension;
17767
17791
  await Promise.all(
@@ -17779,9 +17803,11 @@ ${workingMemory}`;
17779
17803
  if (result2.usage?.tokens) {
17780
17804
  totalTokens += result2.usage.tokens;
17781
17805
  }
17806
+ const threadMetadata = message.threadId ? threadMetadataMap.get(message.threadId) || {} : {};
17782
17807
  embeddingData.push({
17783
17808
  embeddings: result2.embeddings,
17784
17809
  metadata: result2.chunks.map(() => ({
17810
+ ...threadMetadata,
17785
17811
  message_id: message.id,
17786
17812
  thread_id: message.threadId,
17787
17813
  resource_id: message.resourceId
@@ -18094,7 +18120,7 @@ ${workingMemory}`;
18094
18120
  "Observational memory requires @mastra/core support for request-response-id-rotation. Please bump @mastra/core to a newer version."
18095
18121
  );
18096
18122
  }
18097
- const { ObservationalMemory: OMClass } = await import('./observational-memory-BJF72NKJ.cjs');
18123
+ const { ObservationalMemory: OMClass } = await import('./observational-memory-TASIB4PH.cjs');
18098
18124
  const onIndexObservations = this.hasRetrievalSearch(omConfig.retrieval) ? async (observation) => {
18099
18125
  await this.indexObservation(observation);
18100
18126
  } : void 0;
@@ -19020,7 +19046,7 @@ Notes:
19020
19046
  if (!effectiveConfig) return null;
19021
19047
  const engine = await this.omEngine;
19022
19048
  if (!engine) return null;
19023
- const { ObservationalMemoryProcessor } = await import('./observational-memory-BJF72NKJ.cjs');
19049
+ const { ObservationalMemoryProcessor } = await import('./observational-memory-TASIB4PH.cjs');
19024
19050
  return new ObservationalMemoryProcessor(engine, this, {
19025
19051
  temporalMarkers: effectiveConfig.temporalMarkers
19026
19052
  });
@@ -19029,11 +19055,11 @@ Notes:
19029
19055
 
19030
19056
  Object.defineProperty(exports, "ModelByInputTokens", {
19031
19057
  enumerable: true,
19032
- get: function () { return chunkWNLFJKTX_cjs.ModelByInputTokens; }
19058
+ get: function () { return chunkMJNTQ6GP_cjs.ModelByInputTokens; }
19033
19059
  });
19034
19060
  Object.defineProperty(exports, "getObservationsAsOf", {
19035
19061
  enumerable: true,
19036
- get: function () { return chunkWNLFJKTX_cjs.getObservationsAsOf; }
19062
+ get: function () { return chunkMJNTQ6GP_cjs.getObservationsAsOf; }
19037
19063
  });
19038
19064
  Object.defineProperty(exports, "MessageHistory", {
19039
19065
  enumerable: true,