@mastra/memory 0.1.0-alpha.70 → 0.1.0-alpha.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # @mastra/memory
2
2
 
3
+ ## 0.1.0-alpha.73
4
+
5
+ ### Minor Changes
6
+
7
+ - d7d465a: Breaking change for Memory: embeddings: {} has been replaced with embedder: new OpenAIEmbedder() (or whichever embedder you want - check the docs)
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [d7d465a]
12
+ - Updated dependencies [d7d465a]
13
+ - Updated dependencies [2017553]
14
+ - Updated dependencies [a10b7a3]
15
+ - Updated dependencies [16e5b04]
16
+ - @mastra/core@0.2.0-alpha.91
17
+
18
+ ## 0.1.0-alpha.72
19
+
20
+ ### Patch Changes
21
+
22
+ - Updated dependencies [8151f44]
23
+ - Updated dependencies [e897f1c]
24
+ - Updated dependencies [3700be1]
25
+ - @mastra/core@0.2.0-alpha.90
26
+
27
+ ## 0.1.0-alpha.71
28
+
29
+ ### Minor Changes
30
+
31
+ - 27275c9: Added new short term "working" memory for agents. Also added a "maskStreamTags" helper to assist in hiding working memory xml blocks in streamed responses
32
+
33
+ ### Patch Changes
34
+
35
+ - Updated dependencies [27275c9]
36
+ - @mastra/core@0.2.0-alpha.89
37
+
3
38
  ## 0.1.0-alpha.70
4
39
 
5
40
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -8,7 +8,9 @@ import { Message } from 'ai';
8
8
  * and message injection.
9
9
  */
10
10
  declare class Memory extends MastraMemory {
11
- constructor(config: SharedMemoryConfig);
11
+ constructor(config: SharedMemoryConfig & {
12
+ embeddings?: any;
13
+ });
12
14
  query({ threadId, selectBy, threadConfig, }: StorageGetMessagesArg): Promise<{
13
15
  messages: CoreMessage[];
14
16
  uiMessages: Message[];
@@ -27,18 +29,31 @@ declare class Memory extends MastraMemory {
27
29
  getThreadsByResourceId({ resourceId }: {
28
30
  resourceId: string;
29
31
  }): Promise<StorageThreadType[]>;
30
- saveThread({ thread }: {
32
+ saveThread({ thread, memoryConfig, }: {
31
33
  thread: StorageThreadType;
34
+ memoryConfig?: MemoryConfig;
32
35
  }): Promise<StorageThreadType>;
33
36
  updateThread({ id, title, metadata, }: {
34
37
  id: string;
35
38
  title: string;
36
39
  metadata: Record<string, unknown>;
37
40
  }): Promise<StorageThreadType>;
41
+ deleteThread(threadId: string): Promise<void>;
38
42
  saveMessages({ messages }: {
39
43
  messages: MessageType[];
40
44
  }): Promise<MessageType[]>;
41
- deleteThread(threadId: string): Promise<void>;
45
+ protected mutateMessagesToHideWorkingMemory(messages: MessageType[]): void;
46
+ protected parseWorkingMemory(text: string): string | null;
47
+ protected getWorkingMemory({ threadId }: {
48
+ threadId: string;
49
+ }): Promise<string | null>;
50
+ private saveWorkingMemory;
51
+ getSystemMessage({ threadId, memoryConfig, }: {
52
+ threadId: string;
53
+ memoryConfig?: MemoryConfig;
54
+ }): Promise<string | null>;
55
+ defaultWorkingMemoryTemplate: string;
56
+ private getWorkingMemoryWithInstruction;
42
57
  }
43
58
 
44
59
  export { Memory };
package/dist/index.js CHANGED
@@ -1,9 +1,35 @@
1
+ import { deepMerge } from '@mastra/core';
1
2
  import { MastraMemory } from '@mastra/core/memory';
2
3
 
3
4
  // src/index.ts
4
5
  var Memory = class extends MastraMemory {
5
6
  constructor(config) {
7
+ if (config.embeddings) {
8
+ throw new Error(
9
+ 'The `embeddings` option is deprecated. Please use `embedder` instead. Example: new Memory({ embedder: new OpenAIEmbedder({ model: "text-embedding-3-small" }) })'
10
+ );
11
+ }
6
12
  super({ name: "Memory", ...config });
13
+ this.defaultWorkingMemoryTemplate = `
14
+ <user>
15
+ <first_name></first_name>
16
+ <last_name></last_name>
17
+ <location></location>
18
+ <occupation></occupation>
19
+ <interests></interests>
20
+ <goals></goals>
21
+ <events></events>
22
+ <facts></facts>
23
+ <projects></projects>
24
+ </user>
25
+ `;
26
+ const mergedConfig = this.getMergedThreadConfig({
27
+ workingMemory: config.options?.workingMemory || {
28
+ enabled: false,
29
+ template: this.defaultWorkingMemoryTemplate
30
+ }
31
+ });
32
+ this.threadConfig = mergedConfig;
7
33
  }
8
34
  async query({
9
35
  threadId,
@@ -25,9 +51,10 @@ var Memory = class extends MastraMemory {
25
51
  messageRange: config?.semanticRecall?.messageRange || { before: 2, after: 2 }
26
52
  };
27
53
  if (selectBy?.vectorSearchString && this.vector) {
28
- const { embeddings } = await this.vector.embed(selectBy.vectorSearchString, this.parseEmbeddingOptions());
54
+ const embedder = this.getEmbedder();
55
+ const { embedding } = await embedder.embed(selectBy.vectorSearchString);
29
56
  await this.vector.createIndex("memory_messages", 1536);
30
- vectorResults = await this.vector.query("memory_messages", embeddings[0], vectorConfig.topK, {
57
+ vectorResults = await this.vector.query("memory_messages", embedding, vectorConfig.topK, {
31
58
  thread_id: threadId
32
59
  });
33
60
  }
@@ -78,7 +105,20 @@ var Memory = class extends MastraMemory {
78
105
  async getThreadsByResourceId({ resourceId }) {
79
106
  return this.storage.__getThreadsByResourceId({ resourceId });
80
107
  }
81
- async saveThread({ thread }) {
108
+ async saveThread({
109
+ thread,
110
+ memoryConfig
111
+ }) {
112
+ const config = this.getMergedThreadConfig(memoryConfig || {});
113
+ if (config.workingMemory?.enabled && !thread?.metadata?.workingMemory) {
114
+ return this.storage.__saveThread({
115
+ thread: deepMerge(thread, {
116
+ metadata: {
117
+ workingMemory: config.workingMemory.template || this.defaultWorkingMemoryTemplate
118
+ }
119
+ })
120
+ });
121
+ }
82
122
  return this.storage.__saveThread({ thread });
83
123
  }
84
124
  async updateThread({
@@ -92,25 +132,126 @@ var Memory = class extends MastraMemory {
92
132
  metadata
93
133
  });
94
134
  }
135
+ async deleteThread(threadId) {
136
+ await this.storage.__deleteThread({ threadId });
137
+ }
95
138
  async saveMessages({ messages }) {
139
+ await this.saveWorkingMemory(messages);
140
+ this.mutateMessagesToHideWorkingMemory(messages);
96
141
  if (this.vector) {
97
142
  await this.vector.createIndex("memory_messages", 1536);
98
143
  for (const message of messages) {
99
144
  if (typeof message.content !== `string`) continue;
100
- const { embeddings } = await this.vector.embed(message.content, this.parseEmbeddingOptions());
101
- await this.vector.upsert("memory_messages", embeddings, [
102
- {
103
- text: message.content,
104
- message_id: message.id,
105
- thread_id: message.threadId
106
- }
107
- ]);
145
+ const embedder = this.getEmbedder();
146
+ const { embedding } = await embedder.embed(message.content);
147
+ await this.vector.upsert(
148
+ "memory_messages",
149
+ [embedding],
150
+ [
151
+ {
152
+ text: message.content,
153
+ message_id: message.id,
154
+ thread_id: message.threadId
155
+ }
156
+ ]
157
+ );
108
158
  }
109
159
  }
110
160
  return this.storage.__saveMessages({ messages });
111
161
  }
112
- async deleteThread(threadId) {
113
- await this.storage.__deleteThread({ threadId });
162
+ mutateMessagesToHideWorkingMemory(messages) {
163
+ const workingMemoryRegex = /<working_memory>([^]*?)<\/working_memory>/g;
164
+ for (const message of messages) {
165
+ if (typeof message?.content === `string`) {
166
+ message.content = message.content.replace(workingMemoryRegex, ``).trim();
167
+ } else if (Array.isArray(message?.content)) {
168
+ for (const content of message.content) {
169
+ if (content.type === `text`) {
170
+ content.text = content.text.replace(workingMemoryRegex, ``).trim();
171
+ }
172
+ }
173
+ }
174
+ }
175
+ }
176
+ parseWorkingMemory(text) {
177
+ if (!this.threadConfig.workingMemory?.enabled) return null;
178
+ const workingMemoryRegex = /<working_memory>([^]*?)<\/working_memory>/g;
179
+ const matches = text.match(workingMemoryRegex);
180
+ const match = matches?.[0];
181
+ if (match) {
182
+ return match.replace(/<\/?working_memory>/g, "").trim();
183
+ }
184
+ return null;
185
+ }
186
+ async getWorkingMemory({ threadId }) {
187
+ if (!this.threadConfig.workingMemory?.enabled) return null;
188
+ const thread = await this.storage.__getThreadById({ threadId });
189
+ if (!thread) return this.threadConfig?.workingMemory?.template || this.defaultWorkingMemoryTemplate;
190
+ const memory = thread.metadata?.workingMemory || this.threadConfig.workingMemory.template || this.defaultWorkingMemoryTemplate;
191
+ return memory.split(`>
192
+ `).map((c) => c.trim()).join(`>`);
193
+ }
194
+ async saveWorkingMemory(messages) {
195
+ const latestMessage = messages[messages.length - 1];
196
+ if (!latestMessage || !this.threadConfig.workingMemory?.enabled) {
197
+ return;
198
+ }
199
+ const latestContent = !latestMessage?.content ? null : typeof latestMessage.content === "string" ? latestMessage.content : latestMessage.content.filter((c) => c.type === "text").map((c) => c.text).join("\n");
200
+ const threadId = latestMessage?.threadId;
201
+ if (!latestContent || !threadId) {
202
+ return;
203
+ }
204
+ const newMemory = this.parseWorkingMemory(latestContent);
205
+ if (!newMemory) {
206
+ return;
207
+ }
208
+ const thread = await this.storage.__getThreadById({ threadId });
209
+ if (!thread) return;
210
+ await this.storage.__updateThread({
211
+ id: thread.id,
212
+ title: thread.title || "",
213
+ metadata: deepMerge(thread.metadata || {}, {
214
+ workingMemory: newMemory
215
+ })
216
+ });
217
+ return newMemory;
218
+ }
219
+ async getSystemMessage({
220
+ threadId,
221
+ memoryConfig
222
+ }) {
223
+ const config = this.getMergedThreadConfig(memoryConfig);
224
+ if (!config.workingMemory?.enabled) {
225
+ return null;
226
+ }
227
+ const workingMemory = await this.getWorkingMemory({ threadId });
228
+ if (!workingMemory) {
229
+ return null;
230
+ }
231
+ return this.getWorkingMemoryWithInstruction(workingMemory);
232
+ }
233
+ getWorkingMemoryWithInstruction(workingMemoryBlock) {
234
+ return `WORKING_MEMORY_SYSTEM_INSTRUCTION:
235
+ Store and update any conversation-relevant information by including "<working_memory>text</working_memory>" in your responses. Updates replace existing memory while maintaining this structure. If information might be referenced again - store it!
236
+
237
+ Guidelines:
238
+ 1. Store anything that could be useful later in the conversation
239
+ 2. Update proactively when information changes, no matter how small
240
+ 3. Use nested tags for all data
241
+ 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"
242
+
243
+ Memory Structure:
244
+ <working_memory>
245
+ ${workingMemoryBlock}
246
+ </working_memory>
247
+
248
+ Notes:
249
+ - Update memory whenever referenced information changes
250
+ - If you're unsure whether to store something, store it (eg if the user tells you their name or the value of another empty section in your working memory, output the <working_memory> block immediately to update it)
251
+ - 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
252
+ - Do not remove empty sections - you must output the empty sections along with the ones you're filling in
253
+ - REMEMBER: the way you update your working memory is by outputting the entire "<working_memory>text</working_memory>" block in your response. The system will pick this up and store it for you. The user will not see it.
254
+ - IMPORTANT: You MUST output the <working_memory> block in every response to a prompt where you received relevant information. `;
114
255
  }
115
256
  };
116
257
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/memory",
3
- "version": "0.1.0-alpha.70",
3
+ "version": "0.1.0-alpha.73",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -36,7 +36,7 @@
36
36
  "pg-pool": "^3.7.0",
37
37
  "postgres": "^3.4.5",
38
38
  "redis": "^4.7.0",
39
- "@mastra/core": "^0.2.0-alpha.88"
39
+ "@mastra/core": "^0.2.0-alpha.91"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@babel/preset-env": "^7.26.0",
@@ -48,7 +48,8 @@
48
48
  "vitest": "^3.0.4"
49
49
  },
50
50
  "scripts": {
51
- "build": "tsup src/index.ts --format esm --dts --clean --treeshake",
51
+ "check": "tsc --noEmit",
52
+ "build": "pnpm run check && tsup src/index.ts --format esm --dts --clean --treeshake",
52
53
  "dev": "tsup src/index.ts --format esm --dts --clean --watch",
53
54
  "test:integration": "cd integration-tests && pnpm run test",
54
55
  "test": "pnpm test:integration"
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CoreMessage } from '@mastra/core';
1
+ import { CoreMessage, deepMerge } from '@mastra/core';
2
2
  import { MastraMemory, MessageType, MemoryConfig, SharedMemoryConfig, StorageThreadType } from '@mastra/core/memory';
3
3
  import { StorageGetMessagesArg } from '@mastra/core/storage';
4
4
  import { Message as AiMessage } from 'ai';
@@ -8,8 +8,28 @@ import { Message as AiMessage } from 'ai';
8
8
  * and message injection.
9
9
  */
10
10
  export class Memory extends MastraMemory {
11
- constructor(config: SharedMemoryConfig) {
11
+ constructor(
12
+ config: SharedMemoryConfig & {
13
+ /* @deprecated use embedder instead */
14
+ embeddings?: any;
15
+ },
16
+ ) {
17
+ // Check for deprecated embeddings object
18
+ if (config.embeddings) {
19
+ throw new Error(
20
+ 'The `embeddings` option is deprecated. Please use `embedder` instead. Example: new Memory({ embedder: new OpenAIEmbedder({ model: "text-embedding-3-small" }) })',
21
+ );
22
+ }
23
+
12
24
  super({ name: 'Memory', ...config });
25
+
26
+ const mergedConfig = this.getMergedThreadConfig({
27
+ workingMemory: config.options?.workingMemory || {
28
+ enabled: false,
29
+ template: this.defaultWorkingMemoryTemplate,
30
+ },
31
+ });
32
+ this.threadConfig = mergedConfig;
13
33
  }
14
34
 
15
35
  async query({
@@ -46,10 +66,11 @@ export class Memory extends MastraMemory {
46
66
  };
47
67
 
48
68
  if (selectBy?.vectorSearchString && this.vector) {
49
- const { embeddings } = await this.vector.embed(selectBy.vectorSearchString, this.parseEmbeddingOptions());
69
+ const embedder = this.getEmbedder();
70
+ const { embedding } = await embedder.embed(selectBy.vectorSearchString);
50
71
 
51
72
  await this.vector.createIndex('memory_messages', 1536);
52
- vectorResults = await this.vector.query('memory_messages', embeddings[0]!, vectorConfig.topK, {
73
+ vectorResults = await this.vector.query('memory_messages', embedding, vectorConfig.topK, {
53
74
  thread_id: threadId,
54
75
  });
55
76
  }
@@ -124,7 +145,26 @@ export class Memory extends MastraMemory {
124
145
  return this.storage.__getThreadsByResourceId({ resourceId });
125
146
  }
126
147
 
127
- async saveThread({ thread }: { thread: StorageThreadType }): Promise<StorageThreadType> {
148
+ async saveThread({
149
+ thread,
150
+ memoryConfig,
151
+ }: {
152
+ thread: StorageThreadType;
153
+ memoryConfig?: MemoryConfig;
154
+ }): Promise<StorageThreadType> {
155
+ const config = this.getMergedThreadConfig(memoryConfig || {});
156
+
157
+ if (config.workingMemory?.enabled && !thread?.metadata?.workingMemory) {
158
+ // if working memory is enabled but the thread doesn't have it, we need to set it
159
+ return this.storage.__saveThread({
160
+ thread: deepMerge(thread, {
161
+ metadata: {
162
+ workingMemory: config.workingMemory.template || this.defaultWorkingMemoryTemplate,
163
+ },
164
+ }),
165
+ });
166
+ }
167
+
128
168
  return this.storage.__saveThread({ thread });
129
169
  }
130
170
 
@@ -144,30 +184,189 @@ export class Memory extends MastraMemory {
144
184
  });
145
185
  }
146
186
 
187
+ async deleteThread(threadId: string): Promise<void> {
188
+ await this.storage.__deleteThread({ threadId });
189
+
190
+ // TODO: Also clean up vector storage if it exists
191
+ // if (this.vector) {
192
+ // await this.vector.deleteThread(threadId); ?? filter by thread attributes and delete all returned messages?
193
+ // }
194
+ }
195
+
147
196
  async saveMessages({ messages }: { messages: MessageType[] }): Promise<MessageType[]> {
197
+ // First save working memory from any messages
198
+ await this.saveWorkingMemory(messages);
199
+
200
+ // Then strip working memory tags from all messages
201
+ this.mutateMessagesToHideWorkingMemory(messages);
202
+
148
203
  if (this.vector) {
149
204
  await this.vector.createIndex('memory_messages', 1536);
150
205
  for (const message of messages) {
151
206
  if (typeof message.content !== `string`) continue;
152
- const { embeddings } = await this.vector.embed(message.content, this.parseEmbeddingOptions());
153
- await this.vector.upsert('memory_messages', embeddings, [
154
- {
155
- text: message.content,
156
- message_id: message.id,
157
- thread_id: message.threadId,
158
- },
159
- ]);
207
+ const embedder = this.getEmbedder();
208
+ const { embedding } = await embedder.embed(message.content);
209
+ await this.vector.upsert(
210
+ 'memory_messages',
211
+ [embedding],
212
+ [
213
+ {
214
+ text: message.content,
215
+ message_id: message.id,
216
+ thread_id: message.threadId,
217
+ },
218
+ ],
219
+ );
160
220
  }
161
221
  }
222
+
162
223
  return this.storage.__saveMessages({ messages });
163
224
  }
164
225
 
165
- async deleteThread(threadId: string): Promise<void> {
166
- await this.storage.__deleteThread({ threadId });
226
+ protected mutateMessagesToHideWorkingMemory(messages: MessageType[]) {
227
+ const workingMemoryRegex = /<working_memory>([^]*?)<\/working_memory>/g;
228
+ for (const message of messages) {
229
+ if (typeof message?.content === `string`) {
230
+ message.content = message.content.replace(workingMemoryRegex, ``).trim();
231
+ } else if (Array.isArray(message?.content)) {
232
+ for (const content of message.content) {
233
+ if (content.type === `text`) {
234
+ content.text = content.text.replace(workingMemoryRegex, ``).trim();
235
+ }
236
+ }
237
+ }
238
+ }
239
+ }
167
240
 
168
- // TODO: Also clean up vector storage if it exists
169
- // if (this.vector) {
170
- // await this.vector.deleteThread(threadId); ?? filter by thread attributes and delete all returned messages?
171
- // }
241
+ protected parseWorkingMemory(text: string): string | null {
242
+ if (!this.threadConfig.workingMemory?.enabled) return null;
243
+
244
+ const workingMemoryRegex = /<working_memory>([^]*?)<\/working_memory>/g;
245
+ const matches = text.match(workingMemoryRegex);
246
+ const match = matches?.[0];
247
+
248
+ if (match) {
249
+ return match.replace(/<\/?working_memory>/g, '').trim();
250
+ }
251
+
252
+ return null;
253
+ }
254
+
255
+ protected async getWorkingMemory({ threadId }: { threadId: string }): Promise<string | null> {
256
+ if (!this.threadConfig.workingMemory?.enabled) return null;
257
+
258
+ // Get thread from storage
259
+ const thread = await this.storage.__getThreadById({ threadId });
260
+ if (!thread) return this.threadConfig?.workingMemory?.template || this.defaultWorkingMemoryTemplate;
261
+
262
+ // Return working memory from metadata
263
+ const memory =
264
+ (thread.metadata?.workingMemory as string) ||
265
+ this.threadConfig.workingMemory.template ||
266
+ this.defaultWorkingMemoryTemplate;
267
+
268
+ // compress working memory because LLMs will generate faster without the spaces and line breaks
269
+ return memory
270
+ .split(`>\n`)
271
+ .map(c => c.trim()) // remove extra whitespace
272
+ .join(`>`); // and linebreaks
273
+ }
274
+
275
+ private async saveWorkingMemory(messages: MessageType[]) {
276
+ const latestMessage = messages[messages.length - 1];
277
+
278
+ if (!latestMessage || !this.threadConfig.workingMemory?.enabled) {
279
+ return;
280
+ }
281
+
282
+ const latestContent = !latestMessage?.content
283
+ ? null
284
+ : typeof latestMessage.content === 'string'
285
+ ? latestMessage.content
286
+ : latestMessage.content
287
+ .filter(c => c.type === 'text')
288
+ .map(c => c.text)
289
+ .join('\n');
290
+
291
+ const threadId = latestMessage?.threadId;
292
+ if (!latestContent || !threadId) {
293
+ return;
294
+ }
295
+
296
+ const newMemory = this.parseWorkingMemory(latestContent);
297
+ if (!newMemory) {
298
+ return;
299
+ }
300
+
301
+ const thread = await this.storage.__getThreadById({ threadId });
302
+ if (!thread) return;
303
+
304
+ // Update thread metadata with new working memory
305
+ await this.storage.__updateThread({
306
+ id: thread.id,
307
+ title: thread.title || '',
308
+ metadata: deepMerge(thread.metadata || {}, {
309
+ workingMemory: newMemory,
310
+ }),
311
+ });
312
+ return newMemory;
313
+ }
314
+
315
+ public async getSystemMessage({
316
+ threadId,
317
+ memoryConfig,
318
+ }: {
319
+ threadId: string;
320
+ memoryConfig?: MemoryConfig;
321
+ }): Promise<string | null> {
322
+ const config = this.getMergedThreadConfig(memoryConfig);
323
+ if (!config.workingMemory?.enabled) {
324
+ return null;
325
+ }
326
+
327
+ const workingMemory = await this.getWorkingMemory({ threadId });
328
+ if (!workingMemory) {
329
+ return null;
330
+ }
331
+
332
+ return this.getWorkingMemoryWithInstruction(workingMemory);
333
+ }
334
+
335
+ public defaultWorkingMemoryTemplate = `
336
+ <user>
337
+ <first_name></first_name>
338
+ <last_name></last_name>
339
+ <location></location>
340
+ <occupation></occupation>
341
+ <interests></interests>
342
+ <goals></goals>
343
+ <events></events>
344
+ <facts></facts>
345
+ <projects></projects>
346
+ </user>
347
+ `;
348
+
349
+ private getWorkingMemoryWithInstruction(workingMemoryBlock: string) {
350
+ return `WORKING_MEMORY_SYSTEM_INSTRUCTION:
351
+ Store and update any conversation-relevant information by including "<working_memory>text</working_memory>" in your responses. Updates replace existing memory while maintaining this structure. If information might be referenced again - store it!
352
+
353
+ Guidelines:
354
+ 1. Store anything that could be useful later in the conversation
355
+ 2. Update proactively when information changes, no matter how small
356
+ 3. Use nested tags for all data
357
+ 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"
358
+
359
+ Memory Structure:
360
+ <working_memory>
361
+ ${workingMemoryBlock}
362
+ </working_memory>
363
+
364
+ Notes:
365
+ - Update memory whenever referenced information changes
366
+ - If you're unsure whether to store something, store it (eg if the user tells you their name or the value of another empty section in your working memory, output the <working_memory> block immediately to update it)
367
+ - 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
368
+ - Do not remove empty sections - you must output the empty sections along with the ones you're filling in
369
+ - REMEMBER: the way you update your working memory is by outputting the entire "<working_memory>text</working_memory>" block in your response. The system will pick this up and store it for you. The user will not see it.
370
+ - IMPORTANT: You MUST output the <working_memory> block in every response to a prompt where you received relevant information. `;
172
371
  }
173
372
  }