@mastra/memory 0.11.2 → 0.11.3-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.
@@ -1,9 +1,9 @@
1
1
 
2
- > @mastra/memory@0.11.2-alpha.1 build /home/runner/work/mastra/mastra/packages/memory
2
+ > @mastra/memory@0.11.3-alpha.1 build /home/runner/work/mastra/mastra/packages/memory
3
3
  > pnpm run check && tsup --silent src/index.ts src/processors/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting
4
4
 
5
5
 
6
- > @mastra/memory@0.11.2-alpha.1 check /home/runner/work/mastra/mastra/packages/memory
6
+ > @mastra/memory@0.11.3-alpha.1 check /home/runner/work/mastra/mastra/packages/memory
7
7
  > tsc --noEmit
8
8
 
9
9
  Analysis will use the bundled TypeScript version 5.8.3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @mastra/memory
2
2
 
3
+ ## 0.11.3-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 2ba5b76: Allow passing jsonSchema into workingMemory schema
8
+ - c3a30de: added new experimental vnext working memory
9
+ - Updated dependencies [0b56518]
10
+ - Updated dependencies [2ba5b76]
11
+ - Updated dependencies [c3a30de]
12
+ - Updated dependencies [cf3a184]
13
+ - Updated dependencies [d6bfd60]
14
+ - @mastra/core@0.10.15-alpha.1
15
+
16
+ ## 0.11.3-alpha.0
17
+
18
+ ### Patch Changes
19
+
20
+ - 4b20131: Fixed an issue where per-resource semantic recall wouldn't always be enabled properly in agent tool calls
21
+ - 626b0f4: [Cloud-126] Working Memory Playground - Added working memory to playground to allow users to view/edit working memory
22
+ - Updated dependencies [db5cc15]
23
+ - Updated dependencies [5237998]
24
+ - Updated dependencies [37c1acd]
25
+ - Updated dependencies [1aa60b1]
26
+ - Updated dependencies [89ec9d4]
27
+ - Updated dependencies [626b0f4]
28
+ - Updated dependencies [c22a91f]
29
+ - Updated dependencies [f7403ab]
30
+ - Updated dependencies [6c89d7f]
31
+ - @mastra/core@0.10.15-alpha.0
32
+
3
33
  ## 0.11.2
4
34
 
5
35
  ### Patch Changes
@@ -6,6 +6,7 @@ import { MastraMemory } from '@mastra/core/memory';
6
6
  import type { MastraMessageV1 } from '@mastra/core';
7
7
  import type { MastraMessageV2 } from '@mastra/core/agent';
8
8
  import type { MemoryConfig } from '@mastra/core/memory';
9
+ import type { MemoryConfig as MemoryConfig_2 } from '@mastra/core';
9
10
  import { MemoryProcessor } from '@mastra/core/memory';
10
11
  import { MemoryProcessor as MemoryProcessor_2 } from '@mastra/core';
11
12
  import type { MemoryProcessorOpts } from '@mastra/core';
@@ -14,9 +15,10 @@ import type { StorageGetMessagesArg } from '@mastra/core/storage';
14
15
  import type { StorageThreadType } from '@mastra/core/memory';
15
16
  import type { TiktokenBPE } from 'js-tiktoken/lite';
16
17
  import type { UIMessage } from 'ai';
17
- import type { WorkingMemoryFormat } from '@mastra/core/memory';
18
18
  import type { WorkingMemoryTemplate } from '@mastra/core/memory';
19
19
 
20
+ export declare const __experimental_updateWorkingMemoryToolVNext: (config: MemoryConfig_2) => CoreTool;
21
+
20
22
  /**
21
23
  * Concrete implementation of MastraMemory that adds support for thread configuration
22
24
  * and message injection.
@@ -47,7 +49,7 @@ export declare class Memory extends MastraMemory {
47
49
  getThreadsByResourceId({ resourceId }: {
48
50
  resourceId: string;
49
51
  }): Promise<StorageThreadType[]>;
50
- saveThread({ thread, memoryConfig, }: {
52
+ saveThread({ thread }: {
51
53
  thread: StorageThreadType;
52
54
  memoryConfig?: MemoryConfig;
53
55
  }): Promise<StorageThreadType>;
@@ -63,6 +65,20 @@ export declare class Memory extends MastraMemory {
63
65
  workingMemory: string;
64
66
  memoryConfig?: MemoryConfig;
65
67
  }): Promise<void>;
68
+ private updateWorkingMemoryMutexes;
69
+ /**
70
+ * @warning experimental! can be removed or changed at any time
71
+ */
72
+ __experimental_updateWorkingMemoryVNext({ threadId, resourceId, workingMemory, searchString, memoryConfig, }: {
73
+ threadId: string;
74
+ resourceId?: string;
75
+ workingMemory: string;
76
+ searchString?: string;
77
+ memoryConfig?: MemoryConfig;
78
+ }): Promise<{
79
+ success: boolean;
80
+ reason: string;
81
+ }>;
66
82
  protected chunkText(text: string, tokenSize?: number): string[];
67
83
  private hasher;
68
84
  private embeddingCache;
@@ -90,7 +106,16 @@ export declare class Memory extends MastraMemory {
90
106
  resourceId?: string;
91
107
  memoryConfig?: MemoryConfig;
92
108
  }): Promise<string | null>;
93
- getWorkingMemoryTemplate(): Promise<WorkingMemoryTemplate | null>;
109
+ /**
110
+ * Gets the working memory template for the current memory configuration.
111
+ * Supports both ZodObject and JSONSchema7 schemas.
112
+ *
113
+ * @param memoryConfig - The memory configuration containing the working memory settings
114
+ * @returns The working memory template with format and content, or null if working memory is disabled
115
+ */
116
+ getWorkingMemoryTemplate({ memoryConfig, }: {
117
+ memoryConfig?: MemoryConfig;
118
+ }): Promise<WorkingMemoryTemplate | null>;
94
119
  getSystemMessage({ threadId, resourceId, memoryConfig, }: {
95
120
  threadId: string;
96
121
  resourceId?: string;
@@ -101,6 +126,11 @@ export declare class Memory extends MastraMemory {
101
126
  template: WorkingMemoryTemplate;
102
127
  data: string | null;
103
128
  }): string;
129
+ protected __experimental_getWorkingMemoryToolInstructionVNext({ template, data, }: {
130
+ template: WorkingMemoryTemplate;
131
+ data: string | null;
132
+ }): string;
133
+ private isVNextWorkingMemoryConfig;
104
134
  getTools(config?: MemoryConfig): Record<string, CoreTool>;
105
135
  /**
106
136
  * Updates the metadata of a list of messages
@@ -164,8 +194,6 @@ declare class ToolCallFilter extends MemoryProcessor_2 {
164
194
  export { ToolCallFilter }
165
195
  export { ToolCallFilter as ToolCallFilter_alias_1 }
166
196
 
167
- export declare const updateWorkingMemoryTool: ({ format }: {
168
- format: WorkingMemoryFormat;
169
- }) => CoreTool;
197
+ export declare const updateWorkingMemoryTool: (memoryConfig?: MemoryConfig_2) => CoreTool;
170
198
 
171
199
  export { }
@@ -6,6 +6,7 @@ import { MastraMemory } from '@mastra/core/memory';
6
6
  import type { MastraMessageV1 } from '@mastra/core';
7
7
  import type { MastraMessageV2 } from '@mastra/core/agent';
8
8
  import type { MemoryConfig } from '@mastra/core/memory';
9
+ import type { MemoryConfig as MemoryConfig_2 } from '@mastra/core';
9
10
  import { MemoryProcessor } from '@mastra/core/memory';
10
11
  import { MemoryProcessor as MemoryProcessor_2 } from '@mastra/core';
11
12
  import type { MemoryProcessorOpts } from '@mastra/core';
@@ -14,9 +15,10 @@ import type { StorageGetMessagesArg } from '@mastra/core/storage';
14
15
  import type { StorageThreadType } from '@mastra/core/memory';
15
16
  import type { TiktokenBPE } from 'js-tiktoken/lite';
16
17
  import type { UIMessage } from 'ai';
17
- import type { WorkingMemoryFormat } from '@mastra/core/memory';
18
18
  import type { WorkingMemoryTemplate } from '@mastra/core/memory';
19
19
 
20
+ export declare const __experimental_updateWorkingMemoryToolVNext: (config: MemoryConfig_2) => CoreTool;
21
+
20
22
  /**
21
23
  * Concrete implementation of MastraMemory that adds support for thread configuration
22
24
  * and message injection.
@@ -47,7 +49,7 @@ export declare class Memory extends MastraMemory {
47
49
  getThreadsByResourceId({ resourceId }: {
48
50
  resourceId: string;
49
51
  }): Promise<StorageThreadType[]>;
50
- saveThread({ thread, memoryConfig, }: {
52
+ saveThread({ thread }: {
51
53
  thread: StorageThreadType;
52
54
  memoryConfig?: MemoryConfig;
53
55
  }): Promise<StorageThreadType>;
@@ -63,6 +65,20 @@ export declare class Memory extends MastraMemory {
63
65
  workingMemory: string;
64
66
  memoryConfig?: MemoryConfig;
65
67
  }): Promise<void>;
68
+ private updateWorkingMemoryMutexes;
69
+ /**
70
+ * @warning experimental! can be removed or changed at any time
71
+ */
72
+ __experimental_updateWorkingMemoryVNext({ threadId, resourceId, workingMemory, searchString, memoryConfig, }: {
73
+ threadId: string;
74
+ resourceId?: string;
75
+ workingMemory: string;
76
+ searchString?: string;
77
+ memoryConfig?: MemoryConfig;
78
+ }): Promise<{
79
+ success: boolean;
80
+ reason: string;
81
+ }>;
66
82
  protected chunkText(text: string, tokenSize?: number): string[];
67
83
  private hasher;
68
84
  private embeddingCache;
@@ -90,7 +106,16 @@ export declare class Memory extends MastraMemory {
90
106
  resourceId?: string;
91
107
  memoryConfig?: MemoryConfig;
92
108
  }): Promise<string | null>;
93
- getWorkingMemoryTemplate(): Promise<WorkingMemoryTemplate | null>;
109
+ /**
110
+ * Gets the working memory template for the current memory configuration.
111
+ * Supports both ZodObject and JSONSchema7 schemas.
112
+ *
113
+ * @param memoryConfig - The memory configuration containing the working memory settings
114
+ * @returns The working memory template with format and content, or null if working memory is disabled
115
+ */
116
+ getWorkingMemoryTemplate({ memoryConfig, }: {
117
+ memoryConfig?: MemoryConfig;
118
+ }): Promise<WorkingMemoryTemplate | null>;
94
119
  getSystemMessage({ threadId, resourceId, memoryConfig, }: {
95
120
  threadId: string;
96
121
  resourceId?: string;
@@ -101,6 +126,11 @@ export declare class Memory extends MastraMemory {
101
126
  template: WorkingMemoryTemplate;
102
127
  data: string | null;
103
128
  }): string;
129
+ protected __experimental_getWorkingMemoryToolInstructionVNext({ template, data, }: {
130
+ template: WorkingMemoryTemplate;
131
+ data: string | null;
132
+ }): string;
133
+ private isVNextWorkingMemoryConfig;
104
134
  getTools(config?: MemoryConfig): Record<string, CoreTool>;
105
135
  /**
106
136
  * Updates the metadata of a list of messages
@@ -164,8 +194,6 @@ declare class ToolCallFilter extends MemoryProcessor_2 {
164
194
  export { ToolCallFilter }
165
195
  export { ToolCallFilter as ToolCallFilter_alias_1 }
166
196
 
167
- export declare const updateWorkingMemoryTool: ({ format }: {
168
- format: WorkingMemoryFormat;
169
- }) => CoreTool;
197
+ export declare const updateWorkingMemoryTool: (memoryConfig?: MemoryConfig_2) => CoreTool;
170
198
 
171
199
  export { }
package/dist/index.cjs CHANGED
@@ -4,9 +4,10 @@ var core = require('@mastra/core');
4
4
  var agent = require('@mastra/core/agent');
5
5
  var memory = require('@mastra/core/memory');
6
6
  var ai = require('ai');
7
+ var asyncMutex = require('async-mutex');
7
8
  var xxhash = require('xxhash-wasm');
8
- var zodToJsonSchema = require('zod-to-json-schema');
9
9
  var zod = require('zod');
10
+ var zodToJsonSchema = require('zod-to-json-schema');
10
11
 
11
12
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
12
13
 
@@ -14,10 +15,12 @@ var xxhash__default = /*#__PURE__*/_interopDefault(xxhash);
14
15
  var zodToJsonSchema__default = /*#__PURE__*/_interopDefault(zodToJsonSchema);
15
16
 
16
17
  // src/index.ts
17
- var updateWorkingMemoryTool = ({ format }) => ({
18
- description: "Update the working memory with new information",
18
+ var updateWorkingMemoryTool = (memoryConfig) => ({
19
+ description: "Update the working memory with new information. Always pass data as string to the memory field. Never pass an object.",
19
20
  parameters: zod.z.object({
20
- memory: zod.z.string().describe(`The ${format === "json" ? "JSON" : "Markdown"} formatted working memory content to store`)
21
+ memory: zod.z.string().describe(
22
+ `The ${!!memoryConfig?.workingMemory?.schema ? "JSON" : "Markdown"} formatted working memory content to store. This MUST be a string. Never pass an object.`
23
+ )
21
24
  }),
22
25
  execute: async (params) => {
23
26
  const { context, threadId, memory, resourceId } = params;
@@ -35,8 +38,59 @@ var updateWorkingMemoryTool = ({ format }) => ({
35
38
  await memory.updateWorkingMemory({
36
39
  threadId,
37
40
  resourceId: resourceId || thread.resourceId,
38
- workingMemory
41
+ workingMemory,
42
+ memoryConfig
43
+ });
44
+ return { success: true };
45
+ }
46
+ });
47
+ var __experimental_updateWorkingMemoryToolVNext = (config) => ({
48
+ description: "Update the working memory with new information.",
49
+ parameters: zod.z.object({
50
+ newMemory: zod.z.string().optional().nullable().describe(`The ${config.workingMemory?.schema ? "JSON" : "Markdown"} formatted working memory content to store`),
51
+ searchString: zod.z.string().optional().nullable().describe(
52
+ "The working memory string to find. Will be replaced with the newMemory string. If this is omitted or doesn't exist, the newMemory string will be appended to the end of your working memory. Replacing single lines at a time is encouraged for greater accuracy. If updateReason is not 'append-new-memory', this search string must be provided or the tool call will be rejected."
53
+ ),
54
+ updateReason: zod.z.enum(["append-new-memory", "clarify-existing-memory", "replace-irrelevant-memory"]).optional().nullable().describe(
55
+ "The reason you're updating working memory. Passing any value other than 'append-new-memory' requires a searchString to be provided. Defaults to append-new-memory"
56
+ )
57
+ }),
58
+ execute: async (params) => {
59
+ const { context, threadId, memory, resourceId } = params;
60
+ if (!threadId || !memory) {
61
+ throw new Error("Thread ID and Memory instance are required for working memory updates");
62
+ }
63
+ const thread = await memory.getThreadById({ threadId });
64
+ if (!thread) {
65
+ throw new Error(`Thread ${threadId} not found`);
66
+ }
67
+ if (thread.resourceId && thread.resourceId !== resourceId) {
68
+ throw new Error(`Thread with id ${threadId} resourceId does not match the current resourceId ${resourceId}`);
69
+ }
70
+ const workingMemory = context.newMemory || "";
71
+ if (!context.updateReason) context.updateReason = `append-new-memory`;
72
+ if (context.searchString && config.workingMemory?.scope === `resource` && context.updateReason === `replace-irrelevant-memory`) {
73
+ context.searchString = void 0;
74
+ }
75
+ if (context.updateReason === `append-new-memory` && context.searchString) {
76
+ context.searchString = void 0;
77
+ }
78
+ if (context.updateReason !== `append-new-memory` && !context.searchString) {
79
+ return {
80
+ success: false,
81
+ reason: `updateReason was ${context.updateReason} but no searchString was provided. Unable to replace undefined with "${context.newMemory}"`
82
+ };
83
+ }
84
+ const result = await memory.__experimental_updateWorkingMemoryVNext({
85
+ threadId,
86
+ resourceId: resourceId || thread.resourceId,
87
+ workingMemory,
88
+ searchString: context.searchString,
89
+ memoryConfig: config
39
90
  });
91
+ if (result) {
92
+ return result;
93
+ }
40
94
  return { success: true };
41
95
  }
42
96
  });
@@ -45,6 +99,7 @@ var updateWorkingMemoryTool = ({ format }) => ({
45
99
  var CHARS_PER_TOKEN = 4;
46
100
  var DEFAULT_MESSAGE_RANGE = { before: 2, after: 2 };
47
101
  var DEFAULT_TOP_K = 2;
102
+ var isZodObject = (v) => v instanceof zod.ZodObject;
48
103
  var Memory = class extends memory.MastraMemory {
49
104
  constructor(config = {}) {
50
105
  super({ name: "Memory", ...config });
@@ -201,39 +256,7 @@ var Memory = class extends memory.MastraMemory {
201
256
  async getThreadsByResourceId({ resourceId }) {
202
257
  return this.storage.getThreadsByResourceId({ resourceId });
203
258
  }
204
- async saveThread({
205
- thread,
206
- memoryConfig
207
- }) {
208
- const config = this.getMergedThreadConfig(memoryConfig || {});
209
- if (config.workingMemory?.enabled) {
210
- const scope = config.workingMemory.scope || "thread";
211
- if (scope === "resource" && thread.resourceId) {
212
- const existingResource = await this.storage.getResourceById({ resourceId: thread.resourceId });
213
- if (!existingResource?.workingMemory) {
214
- let workingMemory = config.workingMemory.template || this.defaultWorkingMemoryTemplate;
215
- if (config.workingMemory.schema) {
216
- workingMemory = JSON.stringify(zodToJsonSchema__default.default(config.workingMemory.schema));
217
- }
218
- await this.storage.updateResource({
219
- resourceId: thread.resourceId,
220
- workingMemory
221
- });
222
- }
223
- } else if (scope === "thread" && !thread?.metadata?.workingMemory) {
224
- let workingMemory = config.workingMemory.template || this.defaultWorkingMemoryTemplate;
225
- if (config.workingMemory.schema) {
226
- workingMemory = JSON.stringify(zodToJsonSchema__default.default(config.workingMemory.schema));
227
- }
228
- return this.storage.saveThread({
229
- thread: core.deepMerge(thread, {
230
- metadata: {
231
- workingMemory
232
- }
233
- })
234
- });
235
- }
236
- }
259
+ async saveThread({ thread }) {
237
260
  return this.storage.saveThread({ thread });
238
261
  }
239
262
  async updateThread({
@@ -281,6 +304,87 @@ var Memory = class extends memory.MastraMemory {
281
304
  });
282
305
  }
283
306
  }
307
+ updateWorkingMemoryMutexes = /* @__PURE__ */ new Map();
308
+ /**
309
+ * @warning experimental! can be removed or changed at any time
310
+ */
311
+ async __experimental_updateWorkingMemoryVNext({
312
+ threadId,
313
+ resourceId,
314
+ workingMemory,
315
+ searchString,
316
+ memoryConfig
317
+ }) {
318
+ const config = this.getMergedThreadConfig(memoryConfig || {});
319
+ if (!config.workingMemory?.enabled) {
320
+ throw new Error("Working memory is not enabled for this memory instance");
321
+ }
322
+ const mutexKey = memoryConfig?.workingMemory?.scope === `resource` ? `resource-${resourceId}` : `thread-${threadId}`;
323
+ const mutex = this.updateWorkingMemoryMutexes.has(mutexKey) ? this.updateWorkingMemoryMutexes.get(mutexKey) : new asyncMutex.Mutex();
324
+ this.updateWorkingMemoryMutexes.set(mutexKey, mutex);
325
+ const release = await mutex.acquire();
326
+ try {
327
+ const existingWorkingMemory = await this.getWorkingMemory({ threadId, resourceId, memoryConfig }) || "";
328
+ const template = await this.getWorkingMemoryTemplate({ memoryConfig });
329
+ let reason = "";
330
+ if (existingWorkingMemory) {
331
+ if (searchString && existingWorkingMemory?.includes(searchString)) {
332
+ workingMemory = existingWorkingMemory.replace(searchString, workingMemory);
333
+ reason = `found and replaced searchString with newMemory`;
334
+ } else if (existingWorkingMemory.includes(workingMemory) || template?.content?.trim() === workingMemory.trim()) {
335
+ return {
336
+ success: false,
337
+ reason: `attempted to insert duplicate data into working memory. this entry was skipped`
338
+ };
339
+ } else {
340
+ if (searchString) {
341
+ reason = `attempted to replace working memory string that doesn't exist. Appending to working memory instead.`;
342
+ } else {
343
+ reason = `appended newMemory to end of working memory`;
344
+ }
345
+ workingMemory = existingWorkingMemory + `
346
+ ${workingMemory}`;
347
+ }
348
+ } else if (workingMemory === template?.content) {
349
+ return {
350
+ success: false,
351
+ reason: `try again when you have data to add. newMemory was equal to the working memory template`
352
+ };
353
+ } else {
354
+ reason = `started new working memory`;
355
+ }
356
+ workingMemory = template?.content ? workingMemory.replaceAll(template?.content, "") : workingMemory;
357
+ const scope = config.workingMemory.scope || "thread";
358
+ if (scope === "resource" && resourceId) {
359
+ await this.storage.updateResource({
360
+ resourceId,
361
+ workingMemory
362
+ });
363
+ if (reason) {
364
+ return { success: true, reason };
365
+ }
366
+ } else {
367
+ const thread = await this.storage.getThreadById({ threadId });
368
+ if (!thread) {
369
+ throw new Error(`Thread ${threadId} not found`);
370
+ }
371
+ await this.storage.updateThread({
372
+ id: threadId,
373
+ title: thread.title || "Untitled Thread",
374
+ metadata: {
375
+ ...thread.metadata,
376
+ workingMemory
377
+ }
378
+ });
379
+ }
380
+ return { success: true, reason };
381
+ } catch (e) {
382
+ this.logger.error(e instanceof Error ? e.stack || e.message : JSON.stringify(e));
383
+ return { success: false, reason: "Tool error." };
384
+ } finally {
385
+ release();
386
+ }
387
+ }
284
388
  chunkText(text, tokenSize = 4096) {
285
389
  const charSize = tokenSize * CHARS_PER_TOKEN;
286
390
  const chunks = [];
@@ -479,23 +583,38 @@ var Memory = class extends memory.MastraMemory {
479
583
  }
480
584
  return workingMemoryData;
481
585
  }
482
- async getWorkingMemoryTemplate() {
483
- if (!this.threadConfig.workingMemory?.enabled) {
586
+ /**
587
+ * Gets the working memory template for the current memory configuration.
588
+ * Supports both ZodObject and JSONSchema7 schemas.
589
+ *
590
+ * @param memoryConfig - The memory configuration containing the working memory settings
591
+ * @returns The working memory template with format and content, or null if working memory is disabled
592
+ */
593
+ async getWorkingMemoryTemplate({
594
+ memoryConfig
595
+ }) {
596
+ const config = this.getMergedThreadConfig(memoryConfig || {});
597
+ if (!config.workingMemory?.enabled) {
484
598
  return null;
485
599
  }
486
- if (this.threadConfig?.workingMemory?.schema) {
600
+ if (config.workingMemory?.schema) {
487
601
  try {
488
- const schema = this.threadConfig.workingMemory.schema;
489
- const convertedSchema = zodToJsonSchema__default.default(schema, {
490
- $refStrategy: "none"
491
- });
602
+ const schema = config.workingMemory.schema;
603
+ let convertedSchema;
604
+ if (isZodObject(schema)) {
605
+ convertedSchema = zodToJsonSchema__default.default(schema, {
606
+ $refStrategy: "none"
607
+ });
608
+ } else {
609
+ convertedSchema = schema;
610
+ }
492
611
  return { format: "json", content: JSON.stringify(convertedSchema) };
493
612
  } catch (error) {
494
613
  this.logger.error("Error converting schema", error);
495
614
  throw error;
496
615
  }
497
616
  }
498
- const memory = this.threadConfig.workingMemory.template || this.defaultWorkingMemoryTemplate;
617
+ const memory = config.workingMemory.template || this.defaultWorkingMemoryTemplate;
499
618
  return { format: "markdown", content: memory.trim() };
500
619
  }
501
620
  async getSystemMessage({
@@ -507,12 +626,15 @@ var Memory = class extends memory.MastraMemory {
507
626
  if (!config.workingMemory?.enabled) {
508
627
  return null;
509
628
  }
510
- const workingMemoryTemplate = await this.getWorkingMemoryTemplate();
629
+ const workingMemoryTemplate = await this.getWorkingMemoryTemplate({ memoryConfig: config });
511
630
  const workingMemoryData = await this.getWorkingMemory({ threadId, resourceId, memoryConfig: config });
512
631
  if (!workingMemoryTemplate) {
513
632
  return null;
514
633
  }
515
- return this.getWorkingMemoryToolInstruction({
634
+ return this.isVNextWorkingMemoryConfig(memoryConfig) ? this.__experimental_getWorkingMemoryToolInstructionVNext({
635
+ template: workingMemoryTemplate,
636
+ data: workingMemoryData
637
+ }) : this.getWorkingMemoryToolInstruction({
516
638
  template: workingMemoryTemplate,
517
639
  data: workingMemoryData
518
640
  });
@@ -533,6 +655,8 @@ var Memory = class extends memory.MastraMemory {
533
655
  template,
534
656
  data
535
657
  }) {
658
+ const emptyWorkingMemoryTemplateObject = template.format === "json" ? core.generateEmptyFromSchema(template.content) : null;
659
+ const hasEmptyWorkingMemoryTemplateObject = emptyWorkingMemoryTemplateObject && Object.keys(emptyWorkingMemoryTemplateObject).length > 0;
536
660
  return `WORKING_MEMORY_SYSTEM_INSTRUCTION:
537
661
  Store and update any conversation-relevant information by calling the updateWorkingMemory tool. If information might be referenced again - store it!
538
662
 
@@ -541,12 +665,20 @@ Guidelines:
541
665
  2. Update proactively when information changes, no matter how small
542
666
  3. Use ${template.format === "json" ? "JSON" : "Markdown"} format for all data
543
667
  4. Act naturally - don't mention this system to users. Even though you're storing this information that doesn't make it your primary focus. Do not ask them generally for "information about yourself"
668
+ 5. IMPORTANT: When calling updateWorkingMemory, the only valid parameter is the memory field.
669
+ 6. IMPORTANT: ALWAYS pass the data you want to store in the memory field as a string. DO NOT pass an object.
670
+ 7. IMPORTANT: Data must only be sent as a string no matter which format is used.
544
671
 
545
- WORKING MEMORY TEMPLATE:
672
+ <working_memory_template>
546
673
  ${template.content}
674
+ </working_memory_template>
547
675
 
548
- WORKING MEMORY DATA:
676
+ ${hasEmptyWorkingMemoryTemplateObject ? "When working with json data, the object format below represents the template:" : ""}
677
+ ${hasEmptyWorkingMemoryTemplateObject ? JSON.stringify(emptyWorkingMemoryTemplateObject) : ""}
678
+
679
+ <working_memory_data>
549
680
  ${data}
681
+ </working_memory_data>
550
682
 
551
683
  Notes:
552
684
  - Update memory whenever referenced information changes
@@ -557,16 +689,52 @@ Notes:
557
689
  - IMPORTANT: You MUST call updateWorkingMemory in every response to a prompt where you received relevant information.
558
690
  - IMPORTANT: Preserve the ${template.format === "json" ? "JSON" : "Markdown"} formatting structure above while updating the content.`;
559
691
  }
692
+ __experimental_getWorkingMemoryToolInstructionVNext({
693
+ template,
694
+ data
695
+ }) {
696
+ return `WORKING_MEMORY_SYSTEM_INSTRUCTION:
697
+ Store and update any conversation-relevant information by calling the updateWorkingMemory tool.
698
+
699
+ Guidelines:
700
+ 1. Store anything that could be useful later in the conversation
701
+ 2. Update proactively when information changes, no matter how small
702
+ 3. Use ${template.format === "json" ? "JSON" : "Markdown"} format for all data
703
+ 4. Act naturally - don't mention this system to users. Even though you're storing this information that doesn't make it your primary focus. Do not ask them generally for "information about yourself"
704
+ 5. If your memory has not changed, you do not need to call the updateWorkingMemory tool. By default it will persist and be available for you in future interactions
705
+ 6. Information not being relevant to the current conversation is not a valid reason to replace or remove working memory information. Your working memory spans across multiple conversations and may be needed again later, even if it's not currently relevant.
706
+
707
+ <working_memory_template>
708
+ ${template.content}
709
+ </working_memory_template>
710
+
711
+ <working_memory_data>
712
+ ${data}
713
+ </working_memory_data>
714
+
715
+ Notes:
716
+ - Update memory whenever referenced information changes
717
+ ${template.content !== this.defaultWorkingMemoryTemplate ? `- Only store information if it's in the working memory template, do not store other information unless the user asks you to remember it, as that non-template information may be irrelevant` : `- If you're unsure whether to store something, store it (eg if the user tells you information about themselves, call updateWorkingMemory immediately to update it)
718
+ `}
719
+ - This system is here so that you can maintain the conversation when your context window is very short. Update your working memory because you may need it to maintain the conversation without the full conversation history
720
+ - REMEMBER: the way you update your working memory is by calling the updateWorkingMemory tool with the ${template.format === "json" ? "JSON" : "Markdown"} content. The system will store it for you. The user will not see it.
721
+ - IMPORTANT: You MUST call updateWorkingMemory in every response to a prompt where you received relevant information if that information is not already stored.
722
+ - IMPORTANT: Preserve the ${template.format === "json" ? "JSON" : "Markdown"} formatting structure above while updating the content.
723
+ `;
724
+ }
725
+ isVNextWorkingMemoryConfig(config) {
726
+ if (!config?.workingMemory) return false;
727
+ const isMDWorkingMemory = !(`schema` in config.workingMemory) && (typeof config.workingMemory.template === `string` || config.workingMemory.template) && config.workingMemory;
728
+ return Boolean(isMDWorkingMemory && isMDWorkingMemory.version === `vnext`);
729
+ }
560
730
  getTools(config) {
561
731
  const mergedConfig = this.getMergedThreadConfig(config);
562
732
  if (mergedConfig.workingMemory?.enabled) {
563
- if (mergedConfig.workingMemory.schema) {
564
- return {
565
- updateWorkingMemory: updateWorkingMemoryTool({ format: "json" })
566
- };
567
- }
568
733
  return {
569
- updateWorkingMemory: updateWorkingMemoryTool({ format: "markdown" })
734
+ updateWorkingMemory: this.isVNextWorkingMemoryConfig(mergedConfig) ? (
735
+ // use the new experimental tool
736
+ __experimental_updateWorkingMemoryToolVNext(mergedConfig)
737
+ ) : updateWorkingMemoryTool(mergedConfig)
570
738
  };
571
739
  }
572
740
  return {};