@mastra/memory 0.2.6-alpha.2 → 0.2.6-alpha.4

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.
@@ -1,27 +1,27 @@
1
1
 
2
- > @mastra/memory@0.2.6-alpha.2 build /home/runner/work/mastra/mastra/packages/memory
2
+ > @mastra/memory@0.2.6-alpha.4 build /home/runner/work/mastra/mastra/packages/memory
3
3
  > pnpm run check && tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting
4
4
 
5
5
 
6
- > @mastra/memory@0.2.6-alpha.2 check /home/runner/work/mastra/mastra/packages/memory
6
+ > @mastra/memory@0.2.6-alpha.4 check /home/runner/work/mastra/mastra/packages/memory
7
7
  > tsc --noEmit
8
8
 
9
9
  CLI Building entry: src/index.ts
10
10
  CLI Using tsconfig: tsconfig.json
11
11
  CLI tsup v8.4.0
12
12
  TSC Build start
13
- TSC ⚡️ Build success in 10016ms
13
+ TSC ⚡️ Build success in 13659ms
14
14
  DTS Build start
15
15
  CLI Target: es2022
16
16
  Analysis will use the bundled TypeScript version 5.8.2
17
17
  Writing package typings: /home/runner/work/mastra/mastra/packages/memory/dist/_tsup-dts-rollup.d.ts
18
18
  Analysis will use the bundled TypeScript version 5.8.2
19
19
  Writing package typings: /home/runner/work/mastra/mastra/packages/memory/dist/_tsup-dts-rollup.d.cts
20
- DTS ⚡️ Build success in 11685ms
20
+ DTS ⚡️ Build success in 5635ms
21
21
  CLI Cleaning output folder
22
22
  ESM Build start
23
23
  CJS Build start
24
- ESM dist/index.js 12.85 KB
25
- ESM ⚡️ Build success in 605ms
26
- CJS dist/index.cjs 12.88 KB
27
- CJS ⚡️ Build success in 605ms
24
+ ESM dist/index.js 13.53 KB
25
+ ESM ⚡️ Build success in 315ms
26
+ CJS dist/index.cjs 13.56 KB
27
+ CJS ⚡️ Build success in 316ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @mastra/memory
2
2
 
3
+ ## 0.2.6-alpha.4
4
+
5
+ ### Patch Changes
6
+
7
+ - 394dfad: Removed working memory tool calls from thread history after the working memory has been updated. This is to prevent updates from polluting the context history and confusing agents. They should only see the most recent copy of working memory.
8
+ Also made memory.getWorkingMemory() public since it's useful for testing, debugging, and building UIs.
9
+
10
+ ## 0.2.6-alpha.3
11
+
12
+ ### Patch Changes
13
+
14
+ - 05095e9: Fixed an issue where very long messages would cause Memory semantic recall to throw errors
15
+ - Updated dependencies [b3b34f5]
16
+ - Updated dependencies [a4686e8]
17
+ - @mastra/core@0.7.0-alpha.3
18
+ - @mastra/rag@0.1.14-alpha.3
19
+
3
20
  ## 0.2.6-alpha.2
4
21
 
5
22
  ### Patch Changes
@@ -45,13 +45,14 @@ export declare class Memory extends MastraMemory {
45
45
  metadata: Record<string, unknown>;
46
46
  }): Promise<StorageThreadType>;
47
47
  deleteThread(threadId: string): Promise<void>;
48
+ private embedMessageContent;
48
49
  saveMessages({ messages, memoryConfig, }: {
49
50
  messages: MessageType[];
50
51
  memoryConfig?: MemoryConfig;
51
52
  }): Promise<MessageType[]>;
52
53
  protected mutateMessagesToHideWorkingMemory(messages: MessageType[]): void;
53
54
  protected parseWorkingMemory(text: string): string | null;
54
- protected getWorkingMemory({ threadId }: {
55
+ getWorkingMemory({ threadId }: {
55
56
  threadId: string;
56
57
  }): Promise<string | null>;
57
58
  private saveWorkingMemory;
@@ -45,13 +45,14 @@ export declare class Memory extends MastraMemory {
45
45
  metadata: Record<string, unknown>;
46
46
  }): Promise<StorageThreadType>;
47
47
  deleteThread(threadId: string): Promise<void>;
48
+ private embedMessageContent;
48
49
  saveMessages({ messages, memoryConfig, }: {
49
50
  messages: MessageType[];
50
51
  memoryConfig?: MemoryConfig;
51
52
  }): Promise<MessageType[]>;
52
53
  protected mutateMessagesToHideWorkingMemory(messages: MessageType[]): void;
53
54
  protected parseWorkingMemory(text: string): string | null;
54
- protected getWorkingMemory({ threadId }: {
55
+ getWorkingMemory({ threadId }: {
55
56
  threadId: string;
56
57
  }): Promise<string | null>;
57
58
  private saveWorkingMemory;
package/dist/index.cjs CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  var core = require('@mastra/core');
4
4
  var memory = require('@mastra/core/memory');
5
+ var rag = require('@mastra/rag');
5
6
  var ai = require('ai');
6
7
  var zod = require('zod');
7
8
 
@@ -63,7 +64,7 @@ var Memory = class extends memory.MastraMemory {
63
64
  threadConfig
64
65
  }) {
65
66
  if (resourceId) await this.validateThreadIsOwnedByResource(threadId, resourceId);
66
- let vectorResults = null;
67
+ const vectorResults = [];
67
68
  this.logger.debug(`Memory query() with:`, {
68
69
  threadId,
69
70
  selectBy,
@@ -78,19 +79,22 @@ var Memory = class extends memory.MastraMemory {
78
79
  messageRange: config?.semanticRecall?.messageRange ?? { before: 2, after: 2 }
79
80
  };
80
81
  if (config?.semanticRecall && selectBy?.vectorSearchString && this.vector && !!selectBy.vectorSearchString) {
81
- const { embedding } = await ai.embed({
82
- value: selectBy.vectorSearchString,
83
- model: this.embedder
84
- });
85
82
  const { indexName } = await this.createEmbeddingIndex();
86
- vectorResults = await this.vector.query({
87
- indexName,
88
- queryVector: embedding,
89
- topK: vectorConfig.topK,
90
- filter: {
91
- thread_id: threadId
92
- }
93
- });
83
+ const { embeddings } = await this.embedMessageContent(selectBy.vectorSearchString);
84
+ await Promise.all(
85
+ embeddings.map(async (embedding) => {
86
+ vectorResults.push(
87
+ ...await this.vector.query({
88
+ indexName,
89
+ queryVector: embedding,
90
+ topK: vectorConfig.topK,
91
+ filter: {
92
+ thread_id: threadId
93
+ }
94
+ })
95
+ );
96
+ })
97
+ );
94
98
  }
95
99
  const rawMessages = await this.storage.__getMessages({
96
100
  threadId,
@@ -176,6 +180,23 @@ var Memory = class extends memory.MastraMemory {
176
180
  async deleteThread(threadId) {
177
181
  await this.storage.__deleteThread({ threadId });
178
182
  }
183
+ async embedMessageContent(content) {
184
+ const doc = rag.MDocument.fromText(content);
185
+ const chunks = await doc.chunk({
186
+ strategy: "token",
187
+ size: 4096,
188
+ overlap: 20
189
+ });
190
+ const { embeddings } = await ai.embedMany({
191
+ values: chunks.map((chunk) => chunk.text),
192
+ model: this.embedder,
193
+ maxRetries: 3
194
+ });
195
+ return {
196
+ embeddings,
197
+ chunks
198
+ };
199
+ }
179
200
  async saveMessages({
180
201
  messages,
181
202
  memoryConfig
@@ -187,17 +208,14 @@ var Memory = class extends memory.MastraMemory {
187
208
  const { indexName } = await this.createEmbeddingIndex();
188
209
  for (const message of messages) {
189
210
  if (typeof message.content !== `string` || message.content === "") continue;
190
- const { embedding } = await ai.embed({ value: message.content, model: this.embedder, maxRetries: 3 });
211
+ const { embeddings, chunks } = await this.embedMessageContent(message.content);
191
212
  await this.vector.upsert({
192
213
  indexName,
193
- vectors: [embedding],
194
- metadata: [
195
- {
196
- text: message.content,
197
- message_id: message.id,
198
- thread_id: message.threadId
199
- }
200
- ]
214
+ vectors: embeddings,
215
+ metadata: chunks.map(() => ({
216
+ message_id: message.id,
217
+ thread_id: message.threadId
218
+ }))
201
219
  });
202
220
  }
203
221
  }
@@ -205,7 +223,7 @@ var Memory = class extends memory.MastraMemory {
205
223
  }
206
224
  mutateMessagesToHideWorkingMemory(messages) {
207
225
  const workingMemoryRegex = /<working_memory>([^]*?)<\/working_memory>/g;
208
- for (const message of messages) {
226
+ for (const [index, message] of messages.entries()) {
209
227
  if (typeof message?.content === `string`) {
210
228
  message.content = message.content.replace(workingMemoryRegex, ``).trim();
211
229
  } else if (Array.isArray(message?.content)) {
@@ -213,6 +231,9 @@ var Memory = class extends memory.MastraMemory {
213
231
  if (content.type === `text`) {
214
232
  content.text = content.text.replace(workingMemoryRegex, ``).trim();
215
233
  }
234
+ if ((content.type === `tool-call` || content.type === `tool-result`) && content.toolName === `updateWorkingMemory`) {
235
+ delete messages[index];
236
+ }
216
237
  }
217
238
  }
218
239
  }
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { deepMerge } from '@mastra/core';
2
2
  import { MastraMemory } from '@mastra/core/memory';
3
- import { embed } from 'ai';
3
+ import { MDocument } from '@mastra/rag';
4
+ import { embedMany } from 'ai';
4
5
  import { z } from 'zod';
5
6
 
6
7
  // src/index.ts
@@ -61,7 +62,7 @@ var Memory = class extends MastraMemory {
61
62
  threadConfig
62
63
  }) {
63
64
  if (resourceId) await this.validateThreadIsOwnedByResource(threadId, resourceId);
64
- let vectorResults = null;
65
+ const vectorResults = [];
65
66
  this.logger.debug(`Memory query() with:`, {
66
67
  threadId,
67
68
  selectBy,
@@ -76,19 +77,22 @@ var Memory = class extends MastraMemory {
76
77
  messageRange: config?.semanticRecall?.messageRange ?? { before: 2, after: 2 }
77
78
  };
78
79
  if (config?.semanticRecall && selectBy?.vectorSearchString && this.vector && !!selectBy.vectorSearchString) {
79
- const { embedding } = await embed({
80
- value: selectBy.vectorSearchString,
81
- model: this.embedder
82
- });
83
80
  const { indexName } = await this.createEmbeddingIndex();
84
- vectorResults = await this.vector.query({
85
- indexName,
86
- queryVector: embedding,
87
- topK: vectorConfig.topK,
88
- filter: {
89
- thread_id: threadId
90
- }
91
- });
81
+ const { embeddings } = await this.embedMessageContent(selectBy.vectorSearchString);
82
+ await Promise.all(
83
+ embeddings.map(async (embedding) => {
84
+ vectorResults.push(
85
+ ...await this.vector.query({
86
+ indexName,
87
+ queryVector: embedding,
88
+ topK: vectorConfig.topK,
89
+ filter: {
90
+ thread_id: threadId
91
+ }
92
+ })
93
+ );
94
+ })
95
+ );
92
96
  }
93
97
  const rawMessages = await this.storage.__getMessages({
94
98
  threadId,
@@ -174,6 +178,23 @@ var Memory = class extends MastraMemory {
174
178
  async deleteThread(threadId) {
175
179
  await this.storage.__deleteThread({ threadId });
176
180
  }
181
+ async embedMessageContent(content) {
182
+ const doc = MDocument.fromText(content);
183
+ const chunks = await doc.chunk({
184
+ strategy: "token",
185
+ size: 4096,
186
+ overlap: 20
187
+ });
188
+ const { embeddings } = await embedMany({
189
+ values: chunks.map((chunk) => chunk.text),
190
+ model: this.embedder,
191
+ maxRetries: 3
192
+ });
193
+ return {
194
+ embeddings,
195
+ chunks
196
+ };
197
+ }
177
198
  async saveMessages({
178
199
  messages,
179
200
  memoryConfig
@@ -185,17 +206,14 @@ var Memory = class extends MastraMemory {
185
206
  const { indexName } = await this.createEmbeddingIndex();
186
207
  for (const message of messages) {
187
208
  if (typeof message.content !== `string` || message.content === "") continue;
188
- const { embedding } = await embed({ value: message.content, model: this.embedder, maxRetries: 3 });
209
+ const { embeddings, chunks } = await this.embedMessageContent(message.content);
189
210
  await this.vector.upsert({
190
211
  indexName,
191
- vectors: [embedding],
192
- metadata: [
193
- {
194
- text: message.content,
195
- message_id: message.id,
196
- thread_id: message.threadId
197
- }
198
- ]
212
+ vectors: embeddings,
213
+ metadata: chunks.map(() => ({
214
+ message_id: message.id,
215
+ thread_id: message.threadId
216
+ }))
199
217
  });
200
218
  }
201
219
  }
@@ -203,7 +221,7 @@ var Memory = class extends MastraMemory {
203
221
  }
204
222
  mutateMessagesToHideWorkingMemory(messages) {
205
223
  const workingMemoryRegex = /<working_memory>([^]*?)<\/working_memory>/g;
206
- for (const message of messages) {
224
+ for (const [index, message] of messages.entries()) {
207
225
  if (typeof message?.content === `string`) {
208
226
  message.content = message.content.replace(workingMemoryRegex, ``).trim();
209
227
  } else if (Array.isArray(message?.content)) {
@@ -211,6 +229,9 @@ var Memory = class extends MastraMemory {
211
229
  if (content.type === `text`) {
212
230
  content.text = content.text.replace(workingMemoryRegex, ``).trim();
213
231
  }
232
+ if ((content.type === `tool-call` || content.type === `tool-result`) && content.toolName === `updateWorkingMemory`) {
233
+ delete messages[index];
234
+ }
214
235
  }
215
236
  }
216
237
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/memory",
3
- "version": "0.2.6-alpha.2",
3
+ "version": "0.2.6-alpha.4",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -49,7 +49,8 @@
49
49
  "postgres": "^3.4.5",
50
50
  "redis": "^4.7.0",
51
51
  "zod": "^3.24.2",
52
- "@mastra/core": "^0.7.0-alpha.2"
52
+ "@mastra/core": "^0.7.0-alpha.3",
53
+ "@mastra/rag": "^0.1.14-alpha.3"
53
54
  },
54
55
  "devDependencies": {
55
56
  "@microsoft/api-extractor": "^7.52.1",
package/src/index.ts CHANGED
@@ -3,7 +3,8 @@ import type { AiMessageType, CoreMessage, CoreTool } from '@mastra/core';
3
3
  import { MastraMemory } from '@mastra/core/memory';
4
4
  import type { MessageType, MemoryConfig, SharedMemoryConfig, StorageThreadType } from '@mastra/core/memory';
5
5
  import type { StorageGetMessagesArg } from '@mastra/core/storage';
6
- import { embed } from 'ai';
6
+ import { MDocument } from '@mastra/rag';
7
+ import { embedMany } from 'ai';
7
8
  import { updateWorkingMemoryTool } from './tools/working-memory';
8
9
 
9
10
  /**
@@ -43,14 +44,12 @@ export class Memory extends MastraMemory {
43
44
  }: StorageGetMessagesArg): Promise<{ messages: CoreMessage[]; uiMessages: AiMessageType[] }> {
44
45
  if (resourceId) await this.validateThreadIsOwnedByResource(threadId, resourceId);
45
46
 
46
- let vectorResults:
47
- | null
48
- | {
49
- id: string;
50
- score: number;
51
- metadata?: Record<string, any>;
52
- vector?: number[];
53
- }[] = null;
47
+ const vectorResults: {
48
+ id: string;
49
+ score: number;
50
+ metadata?: Record<string, any>;
51
+ vector?: number[];
52
+ }[] = [];
54
53
 
55
54
  this.logger.debug(`Memory query() with:`, {
56
55
  threadId,
@@ -72,21 +71,23 @@ export class Memory extends MastraMemory {
72
71
  };
73
72
 
74
73
  if (config?.semanticRecall && selectBy?.vectorSearchString && this.vector && !!selectBy.vectorSearchString) {
75
- const { embedding } = await embed({
76
- value: selectBy.vectorSearchString,
77
- model: this.embedder,
78
- });
79
-
80
74
  const { indexName } = await this.createEmbeddingIndex();
81
-
82
- vectorResults = await this.vector.query({
83
- indexName,
84
- queryVector: embedding,
85
- topK: vectorConfig.topK,
86
- filter: {
87
- thread_id: threadId,
88
- },
89
- });
75
+ const { embeddings } = await this.embedMessageContent(selectBy.vectorSearchString);
76
+
77
+ await Promise.all(
78
+ embeddings.map(async embedding => {
79
+ vectorResults.push(
80
+ ...(await this.vector.query({
81
+ indexName,
82
+ queryVector: embedding,
83
+ topK: vectorConfig.topK,
84
+ filter: {
85
+ thread_id: threadId,
86
+ },
87
+ })),
88
+ );
89
+ }),
90
+ );
90
91
  }
91
92
 
92
93
  // Get raw messages from storage
@@ -220,6 +221,27 @@ export class Memory extends MastraMemory {
220
221
  // }
221
222
  }
222
223
 
224
+ private async embedMessageContent(content: string) {
225
+ const doc = MDocument.fromText(content);
226
+
227
+ const chunks = await doc.chunk({
228
+ strategy: 'token',
229
+ size: 4096,
230
+ overlap: 20,
231
+ });
232
+
233
+ const { embeddings } = await embedMany({
234
+ values: chunks.map(chunk => chunk.text),
235
+ model: this.embedder,
236
+ maxRetries: 3,
237
+ });
238
+
239
+ return {
240
+ embeddings,
241
+ chunks,
242
+ };
243
+ }
244
+
223
245
  async saveMessages({
224
246
  messages,
225
247
  memoryConfig,
@@ -240,17 +262,16 @@ export class Memory extends MastraMemory {
240
262
 
241
263
  for (const message of messages) {
242
264
  if (typeof message.content !== `string` || message.content === '') continue;
243
- const { embedding } = await embed({ value: message.content, model: this.embedder, maxRetries: 3 });
265
+
266
+ const { embeddings, chunks } = await this.embedMessageContent(message.content);
267
+
244
268
  await this.vector.upsert({
245
269
  indexName,
246
- vectors: [embedding],
247
- metadata: [
248
- {
249
- text: message.content,
250
- message_id: message.id,
251
- thread_id: message.threadId,
252
- },
253
- ],
270
+ vectors: embeddings,
271
+ metadata: chunks.map(() => ({
272
+ message_id: message.id,
273
+ thread_id: message.threadId,
274
+ })),
254
275
  });
255
276
  }
256
277
  }
@@ -260,7 +281,8 @@ export class Memory extends MastraMemory {
260
281
 
261
282
  protected mutateMessagesToHideWorkingMemory(messages: MessageType[]) {
262
283
  const workingMemoryRegex = /<working_memory>([^]*?)<\/working_memory>/g;
263
- for (const message of messages) {
284
+
285
+ for (const [index, message] of messages.entries()) {
264
286
  if (typeof message?.content === `string`) {
265
287
  message.content = message.content.replace(workingMemoryRegex, ``).trim();
266
288
  } else if (Array.isArray(message?.content)) {
@@ -268,6 +290,13 @@ export class Memory extends MastraMemory {
268
290
  if (content.type === `text`) {
269
291
  content.text = content.text.replace(workingMemoryRegex, ``).trim();
270
292
  }
293
+
294
+ if (
295
+ (content.type === `tool-call` || content.type === `tool-result`) &&
296
+ content.toolName === `updateWorkingMemory`
297
+ ) {
298
+ delete messages[index];
299
+ }
271
300
  }
272
301
  }
273
302
  }
@@ -287,7 +316,7 @@ export class Memory extends MastraMemory {
287
316
  return null;
288
317
  }
289
318
 
290
- protected async getWorkingMemory({ threadId }: { threadId: string }): Promise<string | null> {
319
+ public async getWorkingMemory({ threadId }: { threadId: string }): Promise<string | null> {
291
320
  if (!this.threadConfig.workingMemory?.enabled) return null;
292
321
 
293
322
  // Get thread from storage