@mastra/memory 0.11.2 → 0.11.3-alpha.0

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.0 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.0 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,22 @@
1
1
  # @mastra/memory
2
2
 
3
+ ## 0.11.3-alpha.0
4
+
5
+ ### Patch Changes
6
+
7
+ - 4b20131: Fixed an issue where per-resource semantic recall wouldn't always be enabled properly in agent tool calls
8
+ - 626b0f4: [Cloud-126] Working Memory Playground - Added working memory to playground to allow users to view/edit working memory
9
+ - Updated dependencies [db5cc15]
10
+ - Updated dependencies [5237998]
11
+ - Updated dependencies [37c1acd]
12
+ - Updated dependencies [1aa60b1]
13
+ - Updated dependencies [89ec9d4]
14
+ - Updated dependencies [626b0f4]
15
+ - Updated dependencies [c22a91f]
16
+ - Updated dependencies [f7403ab]
17
+ - Updated dependencies [6c89d7f]
18
+ - @mastra/core@0.10.15-alpha.0
19
+
3
20
  ## 0.11.2
4
21
 
5
22
  ### 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,7 +15,6 @@ 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
20
  /**
@@ -90,7 +90,16 @@ export declare class Memory extends MastraMemory {
90
90
  resourceId?: string;
91
91
  memoryConfig?: MemoryConfig;
92
92
  }): Promise<string | null>;
93
- getWorkingMemoryTemplate(): Promise<WorkingMemoryTemplate | null>;
93
+ /**
94
+ * Gets the working memory template for the current memory configuration.
95
+ * Supports both ZodObject and JSONSchema7 schemas.
96
+ *
97
+ * @param memoryConfig - The memory configuration containing the working memory settings
98
+ * @returns The working memory template with format and content, or null if working memory is disabled
99
+ */
100
+ getWorkingMemoryTemplate({ memoryConfig, }: {
101
+ memoryConfig?: MemoryConfig;
102
+ }): Promise<WorkingMemoryTemplate | null>;
94
103
  getSystemMessage({ threadId, resourceId, memoryConfig, }: {
95
104
  threadId: string;
96
105
  resourceId?: string;
@@ -164,8 +173,6 @@ declare class ToolCallFilter extends MemoryProcessor_2 {
164
173
  export { ToolCallFilter }
165
174
  export { ToolCallFilter as ToolCallFilter_alias_1 }
166
175
 
167
- export declare const updateWorkingMemoryTool: ({ format }: {
168
- format: WorkingMemoryFormat;
169
- }) => CoreTool;
176
+ export declare const updateWorkingMemoryTool: (memoryConfig?: MemoryConfig_2) => CoreTool;
170
177
 
171
178
  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,7 +15,6 @@ 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
20
  /**
@@ -90,7 +90,16 @@ export declare class Memory extends MastraMemory {
90
90
  resourceId?: string;
91
91
  memoryConfig?: MemoryConfig;
92
92
  }): Promise<string | null>;
93
- getWorkingMemoryTemplate(): Promise<WorkingMemoryTemplate | null>;
93
+ /**
94
+ * Gets the working memory template for the current memory configuration.
95
+ * Supports both ZodObject and JSONSchema7 schemas.
96
+ *
97
+ * @param memoryConfig - The memory configuration containing the working memory settings
98
+ * @returns The working memory template with format and content, or null if working memory is disabled
99
+ */
100
+ getWorkingMemoryTemplate({ memoryConfig, }: {
101
+ memoryConfig?: MemoryConfig;
102
+ }): Promise<WorkingMemoryTemplate | null>;
94
103
  getSystemMessage({ threadId, resourceId, memoryConfig, }: {
95
104
  threadId: string;
96
105
  resourceId?: string;
@@ -164,8 +173,6 @@ declare class ToolCallFilter extends MemoryProcessor_2 {
164
173
  export { ToolCallFilter }
165
174
  export { ToolCallFilter as ToolCallFilter_alias_1 }
166
175
 
167
- export declare const updateWorkingMemoryTool: ({ format }: {
168
- format: WorkingMemoryFormat;
169
- }) => CoreTool;
176
+ export declare const updateWorkingMemoryTool: (memoryConfig?: MemoryConfig_2) => CoreTool;
170
177
 
171
178
  export { }
package/dist/index.cjs CHANGED
@@ -5,8 +5,8 @@ var agent = require('@mastra/core/agent');
5
5
  var memory = require('@mastra/core/memory');
6
6
  var ai = require('ai');
7
7
  var xxhash = require('xxhash-wasm');
8
- var zodToJsonSchema = require('zod-to-json-schema');
9
8
  var zod = require('zod');
9
+ var zodToJsonSchema = require('zod-to-json-schema');
10
10
 
11
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
12
12
 
@@ -14,10 +14,12 @@ var xxhash__default = /*#__PURE__*/_interopDefault(xxhash);
14
14
  var zodToJsonSchema__default = /*#__PURE__*/_interopDefault(zodToJsonSchema);
15
15
 
16
16
  // src/index.ts
17
- var updateWorkingMemoryTool = ({ format }) => ({
18
- description: "Update the working memory with new information",
17
+ var updateWorkingMemoryTool = (memoryConfig) => ({
18
+ description: "Update the working memory with new information. Always pass data as string to the memory field. Never pass an object.",
19
19
  parameters: zod.z.object({
20
- memory: zod.z.string().describe(`The ${format === "json" ? "JSON" : "Markdown"} formatted working memory content to store`)
20
+ memory: zod.z.string().describe(
21
+ `The ${!!memoryConfig?.workingMemory?.schema ? "JSON" : "Markdown"} formatted working memory content to store. This MUST be a string. Never pass an object.`
22
+ )
21
23
  }),
22
24
  execute: async (params) => {
23
25
  const { context, threadId, memory, resourceId } = params;
@@ -35,7 +37,8 @@ var updateWorkingMemoryTool = ({ format }) => ({
35
37
  await memory.updateWorkingMemory({
36
38
  threadId,
37
39
  resourceId: resourceId || thread.resourceId,
38
- workingMemory
40
+ workingMemory,
41
+ memoryConfig
39
42
  });
40
43
  return { success: true };
41
44
  }
@@ -45,6 +48,7 @@ var updateWorkingMemoryTool = ({ format }) => ({
45
48
  var CHARS_PER_TOKEN = 4;
46
49
  var DEFAULT_MESSAGE_RANGE = { before: 2, after: 2 };
47
50
  var DEFAULT_TOP_K = 2;
51
+ var isZodObject = (v) => v instanceof zod.ZodObject;
48
52
  var Memory = class extends memory.MastraMemory {
49
53
  constructor(config = {}) {
50
54
  super({ name: "Memory", ...config });
@@ -208,27 +212,20 @@ var Memory = class extends memory.MastraMemory {
208
212
  const config = this.getMergedThreadConfig(memoryConfig || {});
209
213
  if (config.workingMemory?.enabled) {
210
214
  const scope = config.workingMemory.scope || "thread";
215
+ const workingMemory = await this.getWorkingMemoryTemplate({ memoryConfig: config });
211
216
  if (scope === "resource" && thread.resourceId) {
212
217
  const existingResource = await this.storage.getResourceById({ resourceId: thread.resourceId });
213
218
  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
219
  await this.storage.updateResource({
219
220
  resourceId: thread.resourceId,
220
- workingMemory
221
+ workingMemory: workingMemory?.content
221
222
  });
222
223
  }
223
224
  } 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
225
  return this.storage.saveThread({
229
226
  thread: core.deepMerge(thread, {
230
227
  metadata: {
231
- workingMemory
228
+ workingMemory: workingMemory?.content
232
229
  }
233
230
  })
234
231
  });
@@ -479,23 +476,38 @@ var Memory = class extends memory.MastraMemory {
479
476
  }
480
477
  return workingMemoryData;
481
478
  }
482
- async getWorkingMemoryTemplate() {
483
- if (!this.threadConfig.workingMemory?.enabled) {
479
+ /**
480
+ * Gets the working memory template for the current memory configuration.
481
+ * Supports both ZodObject and JSONSchema7 schemas.
482
+ *
483
+ * @param memoryConfig - The memory configuration containing the working memory settings
484
+ * @returns The working memory template with format and content, or null if working memory is disabled
485
+ */
486
+ async getWorkingMemoryTemplate({
487
+ memoryConfig
488
+ }) {
489
+ const config = this.getMergedThreadConfig(memoryConfig || {});
490
+ if (!config.workingMemory?.enabled) {
484
491
  return null;
485
492
  }
486
- if (this.threadConfig?.workingMemory?.schema) {
493
+ if (config.workingMemory?.schema) {
487
494
  try {
488
- const schema = this.threadConfig.workingMemory.schema;
489
- const convertedSchema = zodToJsonSchema__default.default(schema, {
490
- $refStrategy: "none"
491
- });
495
+ const schema = config.workingMemory.schema;
496
+ let convertedSchema;
497
+ if (isZodObject(schema)) {
498
+ convertedSchema = zodToJsonSchema__default.default(schema, {
499
+ $refStrategy: "none"
500
+ });
501
+ } else {
502
+ convertedSchema = schema;
503
+ }
492
504
  return { format: "json", content: JSON.stringify(convertedSchema) };
493
505
  } catch (error) {
494
506
  this.logger.error("Error converting schema", error);
495
507
  throw error;
496
508
  }
497
509
  }
498
- const memory = this.threadConfig.workingMemory.template || this.defaultWorkingMemoryTemplate;
510
+ const memory = config.workingMemory.template || this.defaultWorkingMemoryTemplate;
499
511
  return { format: "markdown", content: memory.trim() };
500
512
  }
501
513
  async getSystemMessage({
@@ -507,7 +519,7 @@ var Memory = class extends memory.MastraMemory {
507
519
  if (!config.workingMemory?.enabled) {
508
520
  return null;
509
521
  }
510
- const workingMemoryTemplate = await this.getWorkingMemoryTemplate();
522
+ const workingMemoryTemplate = await this.getWorkingMemoryTemplate({ memoryConfig: config });
511
523
  const workingMemoryData = await this.getWorkingMemory({ threadId, resourceId, memoryConfig: config });
512
524
  if (!workingMemoryTemplate) {
513
525
  return null;
@@ -533,6 +545,8 @@ var Memory = class extends memory.MastraMemory {
533
545
  template,
534
546
  data
535
547
  }) {
548
+ const emptyWorkingMemoryTemplateObject = template.format === "json" ? core.generateEmptyFromSchema(template.content) : null;
549
+ const hasEmptyWorkingMemoryTemplateObject = emptyWorkingMemoryTemplateObject && Object.keys(emptyWorkingMemoryTemplateObject).length > 0;
536
550
  return `WORKING_MEMORY_SYSTEM_INSTRUCTION:
537
551
  Store and update any conversation-relevant information by calling the updateWorkingMemory tool. If information might be referenced again - store it!
538
552
 
@@ -541,10 +555,16 @@ Guidelines:
541
555
  2. Update proactively when information changes, no matter how small
542
556
  3. Use ${template.format === "json" ? "JSON" : "Markdown"} format for all data
543
557
  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"
558
+ 5. IMPORTANT: When calling updateWorkingMemory, the only valid parameter is the memory field.
559
+ 6. IMPORTANT: ALWAYS pass the data you want to store in the memory field as a string. DO NOT pass an object.
560
+ 7. IMPORTANT: Data must only be sent as a string no matter which format is used.
544
561
 
545
562
  WORKING MEMORY TEMPLATE:
546
563
  ${template.content}
547
564
 
565
+ ${hasEmptyWorkingMemoryTemplateObject ? "When working with json data, the object format below represents the template:" : ""}
566
+ ${hasEmptyWorkingMemoryTemplateObject ? JSON.stringify(emptyWorkingMemoryTemplateObject) : ""}
567
+
548
568
  WORKING MEMORY DATA:
549
569
  ${data}
550
570
 
@@ -560,13 +580,8 @@ Notes:
560
580
  getTools(config) {
561
581
  const mergedConfig = this.getMergedThreadConfig(config);
562
582
  if (mergedConfig.workingMemory?.enabled) {
563
- if (mergedConfig.workingMemory.schema) {
564
- return {
565
- updateWorkingMemory: updateWorkingMemoryTool({ format: "json" })
566
- };
567
- }
568
583
  return {
569
- updateWorkingMemory: updateWorkingMemoryTool({ format: "markdown" })
584
+ updateWorkingMemory: updateWorkingMemoryTool(config)
570
585
  };
571
586
  }
572
587
  return {};
package/dist/index.js CHANGED
@@ -1,16 +1,18 @@
1
- import { deepMerge } from '@mastra/core';
1
+ import { deepMerge, generateEmptyFromSchema } from '@mastra/core';
2
2
  import { MessageList } from '@mastra/core/agent';
3
3
  import { MastraMemory } from '@mastra/core/memory';
4
4
  import { embedMany } from 'ai';
5
5
  import xxhash from 'xxhash-wasm';
6
+ import { z, ZodObject } from 'zod';
6
7
  import zodToJsonSchema from 'zod-to-json-schema';
7
- import { z } from 'zod';
8
8
 
9
9
  // src/index.ts
10
- var updateWorkingMemoryTool = ({ format }) => ({
11
- description: "Update the working memory with new information",
10
+ var updateWorkingMemoryTool = (memoryConfig) => ({
11
+ description: "Update the working memory with new information. Always pass data as string to the memory field. Never pass an object.",
12
12
  parameters: z.object({
13
- memory: z.string().describe(`The ${format === "json" ? "JSON" : "Markdown"} formatted working memory content to store`)
13
+ memory: z.string().describe(
14
+ `The ${!!memoryConfig?.workingMemory?.schema ? "JSON" : "Markdown"} formatted working memory content to store. This MUST be a string. Never pass an object.`
15
+ )
14
16
  }),
15
17
  execute: async (params) => {
16
18
  const { context, threadId, memory, resourceId } = params;
@@ -28,7 +30,8 @@ var updateWorkingMemoryTool = ({ format }) => ({
28
30
  await memory.updateWorkingMemory({
29
31
  threadId,
30
32
  resourceId: resourceId || thread.resourceId,
31
- workingMemory
33
+ workingMemory,
34
+ memoryConfig
32
35
  });
33
36
  return { success: true };
34
37
  }
@@ -38,6 +41,7 @@ var updateWorkingMemoryTool = ({ format }) => ({
38
41
  var CHARS_PER_TOKEN = 4;
39
42
  var DEFAULT_MESSAGE_RANGE = { before: 2, after: 2 };
40
43
  var DEFAULT_TOP_K = 2;
44
+ var isZodObject = (v) => v instanceof ZodObject;
41
45
  var Memory = class extends MastraMemory {
42
46
  constructor(config = {}) {
43
47
  super({ name: "Memory", ...config });
@@ -201,27 +205,20 @@ var Memory = class extends MastraMemory {
201
205
  const config = this.getMergedThreadConfig(memoryConfig || {});
202
206
  if (config.workingMemory?.enabled) {
203
207
  const scope = config.workingMemory.scope || "thread";
208
+ const workingMemory = await this.getWorkingMemoryTemplate({ memoryConfig: config });
204
209
  if (scope === "resource" && thread.resourceId) {
205
210
  const existingResource = await this.storage.getResourceById({ resourceId: thread.resourceId });
206
211
  if (!existingResource?.workingMemory) {
207
- let workingMemory = config.workingMemory.template || this.defaultWorkingMemoryTemplate;
208
- if (config.workingMemory.schema) {
209
- workingMemory = JSON.stringify(zodToJsonSchema(config.workingMemory.schema));
210
- }
211
212
  await this.storage.updateResource({
212
213
  resourceId: thread.resourceId,
213
- workingMemory
214
+ workingMemory: workingMemory?.content
214
215
  });
215
216
  }
216
217
  } else if (scope === "thread" && !thread?.metadata?.workingMemory) {
217
- let workingMemory = config.workingMemory.template || this.defaultWorkingMemoryTemplate;
218
- if (config.workingMemory.schema) {
219
- workingMemory = JSON.stringify(zodToJsonSchema(config.workingMemory.schema));
220
- }
221
218
  return this.storage.saveThread({
222
219
  thread: deepMerge(thread, {
223
220
  metadata: {
224
- workingMemory
221
+ workingMemory: workingMemory?.content
225
222
  }
226
223
  })
227
224
  });
@@ -472,23 +469,38 @@ var Memory = class extends MastraMemory {
472
469
  }
473
470
  return workingMemoryData;
474
471
  }
475
- async getWorkingMemoryTemplate() {
476
- if (!this.threadConfig.workingMemory?.enabled) {
472
+ /**
473
+ * Gets the working memory template for the current memory configuration.
474
+ * Supports both ZodObject and JSONSchema7 schemas.
475
+ *
476
+ * @param memoryConfig - The memory configuration containing the working memory settings
477
+ * @returns The working memory template with format and content, or null if working memory is disabled
478
+ */
479
+ async getWorkingMemoryTemplate({
480
+ memoryConfig
481
+ }) {
482
+ const config = this.getMergedThreadConfig(memoryConfig || {});
483
+ if (!config.workingMemory?.enabled) {
477
484
  return null;
478
485
  }
479
- if (this.threadConfig?.workingMemory?.schema) {
486
+ if (config.workingMemory?.schema) {
480
487
  try {
481
- const schema = this.threadConfig.workingMemory.schema;
482
- const convertedSchema = zodToJsonSchema(schema, {
483
- $refStrategy: "none"
484
- });
488
+ const schema = config.workingMemory.schema;
489
+ let convertedSchema;
490
+ if (isZodObject(schema)) {
491
+ convertedSchema = zodToJsonSchema(schema, {
492
+ $refStrategy: "none"
493
+ });
494
+ } else {
495
+ convertedSchema = schema;
496
+ }
485
497
  return { format: "json", content: JSON.stringify(convertedSchema) };
486
498
  } catch (error) {
487
499
  this.logger.error("Error converting schema", error);
488
500
  throw error;
489
501
  }
490
502
  }
491
- const memory = this.threadConfig.workingMemory.template || this.defaultWorkingMemoryTemplate;
503
+ const memory = config.workingMemory.template || this.defaultWorkingMemoryTemplate;
492
504
  return { format: "markdown", content: memory.trim() };
493
505
  }
494
506
  async getSystemMessage({
@@ -500,7 +512,7 @@ var Memory = class extends MastraMemory {
500
512
  if (!config.workingMemory?.enabled) {
501
513
  return null;
502
514
  }
503
- const workingMemoryTemplate = await this.getWorkingMemoryTemplate();
515
+ const workingMemoryTemplate = await this.getWorkingMemoryTemplate({ memoryConfig: config });
504
516
  const workingMemoryData = await this.getWorkingMemory({ threadId, resourceId, memoryConfig: config });
505
517
  if (!workingMemoryTemplate) {
506
518
  return null;
@@ -526,6 +538,8 @@ var Memory = class extends MastraMemory {
526
538
  template,
527
539
  data
528
540
  }) {
541
+ const emptyWorkingMemoryTemplateObject = template.format === "json" ? generateEmptyFromSchema(template.content) : null;
542
+ const hasEmptyWorkingMemoryTemplateObject = emptyWorkingMemoryTemplateObject && Object.keys(emptyWorkingMemoryTemplateObject).length > 0;
529
543
  return `WORKING_MEMORY_SYSTEM_INSTRUCTION:
530
544
  Store and update any conversation-relevant information by calling the updateWorkingMemory tool. If information might be referenced again - store it!
531
545
 
@@ -534,10 +548,16 @@ Guidelines:
534
548
  2. Update proactively when information changes, no matter how small
535
549
  3. Use ${template.format === "json" ? "JSON" : "Markdown"} format for all data
536
550
  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"
551
+ 5. IMPORTANT: When calling updateWorkingMemory, the only valid parameter is the memory field.
552
+ 6. IMPORTANT: ALWAYS pass the data you want to store in the memory field as a string. DO NOT pass an object.
553
+ 7. IMPORTANT: Data must only be sent as a string no matter which format is used.
537
554
 
538
555
  WORKING MEMORY TEMPLATE:
539
556
  ${template.content}
540
557
 
558
+ ${hasEmptyWorkingMemoryTemplateObject ? "When working with json data, the object format below represents the template:" : ""}
559
+ ${hasEmptyWorkingMemoryTemplateObject ? JSON.stringify(emptyWorkingMemoryTemplateObject) : ""}
560
+
541
561
  WORKING MEMORY DATA:
542
562
  ${data}
543
563
 
@@ -553,13 +573,8 @@ Notes:
553
573
  getTools(config) {
554
574
  const mergedConfig = this.getMergedThreadConfig(config);
555
575
  if (mergedConfig.workingMemory?.enabled) {
556
- if (mergedConfig.workingMemory.schema) {
557
- return {
558
- updateWorkingMemory: updateWorkingMemoryTool({ format: "json" })
559
- };
560
- }
561
576
  return {
562
- updateWorkingMemory: updateWorkingMemoryTool({ format: "markdown" })
577
+ updateWorkingMemory: updateWorkingMemoryTool(config)
563
578
  };
564
579
  }
565
580
  return {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/memory",
3
- "version": "0.11.2",
3
+ "version": "0.11.3-alpha.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -35,6 +35,7 @@
35
35
  "@upstash/redis": "^1.35.0",
36
36
  "ai": "^4.3.16",
37
37
  "js-tiktoken": "^1.0.20",
38
+ "json-schema": "^0.4.0",
38
39
  "pg": "^8.16.3",
39
40
  "pg-pool": "^3.10.1",
40
41
  "postgres": "^3.4.7",
@@ -46,15 +47,16 @@
46
47
  "devDependencies": {
47
48
  "@ai-sdk/openai": "^1.3.22",
48
49
  "@microsoft/api-extractor": "^7.52.8",
50
+ "@types/json-schema": "^7.0.15",
49
51
  "@types/node": "^20.19.0",
50
52
  "@types/pg": "^8.15.4",
51
- "eslint": "^9.29.0",
53
+ "eslint": "^9.30.1",
52
54
  "tsup": "^8.5.0",
53
55
  "typescript": "^5.8.3",
54
56
  "typescript-eslint": "^8.34.0",
55
57
  "vitest": "^3.2.4",
56
- "@mastra/core": "0.10.11",
57
- "@internal/lint": "0.0.18"
58
+ "@mastra/core": "0.10.15-alpha.0",
59
+ "@internal/lint": "0.0.19"
58
60
  },
59
61
  "peerDependencies": {
60
62
  "@mastra/core": ">=0.10.9-0 <0.11.0-0"
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { deepMerge } from '@mastra/core';
1
+ import { deepMerge, generateEmptyFromSchema } from '@mastra/core';
2
2
  import type { CoreTool, MastraMessageV1 } from '@mastra/core';
3
3
  import { MessageList } from '@mastra/core/agent';
4
4
  import type { MastraMessageV2 } from '@mastra/core/agent';
@@ -7,8 +7,11 @@ import type { MemoryConfig, SharedMemoryConfig, StorageThreadType, WorkingMemory
7
7
  import type { StorageGetMessagesArg } from '@mastra/core/storage';
8
8
  import { embedMany } from 'ai';
9
9
  import type { CoreMessage, TextPart, UIMessage } from 'ai';
10
+ import type { JSONSchema7 } from 'json-schema';
10
11
 
11
12
  import xxhash from 'xxhash-wasm';
13
+ import { ZodObject } from 'zod';
14
+ import type { ZodTypeAny } from 'zod';
12
15
  import zodToJsonSchema from 'zod-to-json-schema';
13
16
  import { updateWorkingMemoryTool } from './tools/working-memory';
14
17
 
@@ -18,6 +21,8 @@ const CHARS_PER_TOKEN = 4;
18
21
  const DEFAULT_MESSAGE_RANGE = { before: 2, after: 2 } as const;
19
22
  const DEFAULT_TOP_K = 2;
20
23
 
24
+ const isZodObject = (v: ZodTypeAny): v is ZodObject<any, any, any> => v instanceof ZodObject;
25
+
21
26
  /**
22
27
  * Concrete implementation of MastraMemory that adds support for thread configuration
23
28
  * and message injection.
@@ -258,35 +263,22 @@ export class Memory extends MastraMemory {
258
263
 
259
264
  if (config.workingMemory?.enabled) {
260
265
  const scope = config.workingMemory.scope || 'thread';
261
-
266
+ const workingMemory = await this.getWorkingMemoryTemplate({ memoryConfig: config });
262
267
  if (scope === 'resource' && thread.resourceId) {
263
268
  // For resource scope, initialize working memory in resource table
264
269
  const existingResource = await this.storage.getResourceById({ resourceId: thread.resourceId });
265
-
266
270
  if (!existingResource?.workingMemory) {
267
- let workingMemory = config.workingMemory.template || this.defaultWorkingMemoryTemplate;
268
-
269
- if (config.workingMemory.schema) {
270
- workingMemory = JSON.stringify(zodToJsonSchema(config.workingMemory.schema));
271
- }
272
-
273
271
  await this.storage.updateResource({
274
272
  resourceId: thread.resourceId,
275
- workingMemory,
273
+ workingMemory: workingMemory?.content,
276
274
  });
277
275
  }
278
276
  } else if (scope === 'thread' && !thread?.metadata?.workingMemory) {
279
277
  // For thread scope, initialize working memory in thread metadata (existing behavior)
280
- let workingMemory = config.workingMemory.template || this.defaultWorkingMemoryTemplate;
281
-
282
- if (config.workingMemory.schema) {
283
- workingMemory = JSON.stringify(zodToJsonSchema(config.workingMemory.schema));
284
- }
285
-
286
278
  return this.storage.saveThread({
287
279
  thread: deepMerge(thread, {
288
280
  metadata: {
289
- workingMemory,
281
+ workingMemory: workingMemory?.content,
290
282
  },
291
283
  }),
292
284
  });
@@ -654,18 +646,39 @@ export class Memory extends MastraMemory {
654
646
  return workingMemoryData;
655
647
  }
656
648
 
657
- public async getWorkingMemoryTemplate(): Promise<WorkingMemoryTemplate | null> {
658
- if (!this.threadConfig.workingMemory?.enabled) {
649
+ /**
650
+ * Gets the working memory template for the current memory configuration.
651
+ * Supports both ZodObject and JSONSchema7 schemas.
652
+ *
653
+ * @param memoryConfig - The memory configuration containing the working memory settings
654
+ * @returns The working memory template with format and content, or null if working memory is disabled
655
+ */
656
+ public async getWorkingMemoryTemplate({
657
+ memoryConfig,
658
+ }: {
659
+ memoryConfig?: MemoryConfig;
660
+ }): Promise<WorkingMemoryTemplate | null> {
661
+ const config = this.getMergedThreadConfig(memoryConfig || {});
662
+
663
+ if (!config.workingMemory?.enabled) {
659
664
  return null;
660
665
  }
661
666
 
662
667
  // Get thread from storage
663
- if (this.threadConfig?.workingMemory?.schema) {
668
+ if (config.workingMemory?.schema) {
664
669
  try {
665
- const schema = this.threadConfig.workingMemory.schema;
666
- const convertedSchema = zodToJsonSchema(schema, {
667
- $refStrategy: 'none',
668
- });
670
+ const schema = config.workingMemory.schema;
671
+ let convertedSchema: JSONSchema7;
672
+
673
+ if (isZodObject(schema as ZodTypeAny)) {
674
+ // Convert ZodObject to JSON Schema
675
+ convertedSchema = zodToJsonSchema(schema as ZodTypeAny, {
676
+ $refStrategy: 'none',
677
+ }) as JSONSchema7;
678
+ } else {
679
+ // Already a JSON Schema
680
+ convertedSchema = schema as JSONSchema7;
681
+ }
669
682
 
670
683
  return { format: 'json', content: JSON.stringify(convertedSchema) };
671
684
  } catch (error) {
@@ -675,8 +688,7 @@ export class Memory extends MastraMemory {
675
688
  }
676
689
 
677
690
  // Return working memory from metadata
678
- const memory = this.threadConfig.workingMemory.template || this.defaultWorkingMemoryTemplate;
679
-
691
+ const memory = config.workingMemory.template || this.defaultWorkingMemoryTemplate;
680
692
  return { format: 'markdown', content: memory.trim() };
681
693
  }
682
694
 
@@ -694,7 +706,7 @@ export class Memory extends MastraMemory {
694
706
  return null;
695
707
  }
696
708
 
697
- const workingMemoryTemplate = await this.getWorkingMemoryTemplate();
709
+ const workingMemoryTemplate = await this.getWorkingMemoryTemplate({ memoryConfig: config });
698
710
  const workingMemoryData = await this.getWorkingMemory({ threadId, resourceId, memoryConfig: config });
699
711
 
700
712
  if (!workingMemoryTemplate) {
@@ -727,6 +739,11 @@ export class Memory extends MastraMemory {
727
739
  template: WorkingMemoryTemplate;
728
740
  data: string | null;
729
741
  }) {
742
+ const emptyWorkingMemoryTemplateObject =
743
+ template.format === 'json' ? generateEmptyFromSchema(template.content) : null;
744
+ const hasEmptyWorkingMemoryTemplateObject =
745
+ emptyWorkingMemoryTemplateObject && Object.keys(emptyWorkingMemoryTemplateObject).length > 0;
746
+
730
747
  return `WORKING_MEMORY_SYSTEM_INSTRUCTION:
731
748
  Store and update any conversation-relevant information by calling the updateWorkingMemory tool. If information might be referenced again - store it!
732
749
 
@@ -735,10 +752,16 @@ Guidelines:
735
752
  2. Update proactively when information changes, no matter how small
736
753
  3. Use ${template.format === 'json' ? 'JSON' : 'Markdown'} format for all data
737
754
  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"
755
+ 5. IMPORTANT: When calling updateWorkingMemory, the only valid parameter is the memory field.
756
+ 6. IMPORTANT: ALWAYS pass the data you want to store in the memory field as a string. DO NOT pass an object.
757
+ 7. IMPORTANT: Data must only be sent as a string no matter which format is used.
738
758
 
739
759
  WORKING MEMORY TEMPLATE:
740
760
  ${template.content}
741
761
 
762
+ ${hasEmptyWorkingMemoryTemplateObject ? 'When working with json data, the object format below represents the template:' : ''}
763
+ ${hasEmptyWorkingMemoryTemplateObject ? JSON.stringify(emptyWorkingMemoryTemplateObject) : ''}
764
+
742
765
  WORKING MEMORY DATA:
743
766
  ${data}
744
767
 
@@ -755,14 +778,8 @@ Notes:
755
778
  public getTools(config?: MemoryConfig): Record<string, CoreTool> {
756
779
  const mergedConfig = this.getMergedThreadConfig(config);
757
780
  if (mergedConfig.workingMemory?.enabled) {
758
- if (mergedConfig.workingMemory.schema) {
759
- return {
760
- updateWorkingMemory: updateWorkingMemoryTool({ format: 'json' }),
761
- };
762
- }
763
-
764
781
  return {
765
- updateWorkingMemory: updateWorkingMemoryTool({ format: 'markdown' }),
782
+ updateWorkingMemory: updateWorkingMemoryTool(config),
766
783
  };
767
784
  }
768
785
  return {};
@@ -1,13 +1,15 @@
1
- import type { CoreTool } from '@mastra/core';
2
- import type { WorkingMemoryFormat } from '@mastra/core/memory';
1
+ import type { CoreTool, MemoryConfig } from '@mastra/core';
3
2
  import { z } from 'zod';
4
3
 
5
- export const updateWorkingMemoryTool = ({ format }: { format: WorkingMemoryFormat }): CoreTool => ({
6
- description: 'Update the working memory with new information',
4
+ export const updateWorkingMemoryTool = (memoryConfig?: MemoryConfig): CoreTool => ({
5
+ description:
6
+ 'Update the working memory with new information. Always pass data as string to the memory field. Never pass an object.',
7
7
  parameters: z.object({
8
8
  memory: z
9
9
  .string()
10
- .describe(`The ${format === 'json' ? 'JSON' : 'Markdown'} formatted working memory content to store`),
10
+ .describe(
11
+ `The ${!!memoryConfig?.workingMemory?.schema ? 'JSON' : 'Markdown'} formatted working memory content to store. This MUST be a string. Never pass an object.`,
12
+ ),
11
13
  }),
12
14
  execute: async (params: any) => {
13
15
  const { context, threadId, memory, resourceId } = params;
@@ -32,6 +34,7 @@ export const updateWorkingMemoryTool = ({ format }: { format: WorkingMemoryForma
32
34
  threadId,
33
35
  resourceId: resourceId || thread.resourceId,
34
36
  workingMemory: workingMemory,
37
+ memoryConfig,
35
38
  });
36
39
 
37
40
  return { success: true };