@mastra/memory 0.0.0-a2a-20250421213654
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 +1842 -0
- package/LICENSE.md +46 -0
- package/README.md +7 -0
- package/dist/_tsup-dts-rollup.d.cts +138 -0
- package/dist/_tsup-dts-rollup.d.ts +138 -0
- package/dist/index.cjs +482 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +476 -0
- package/dist/processors/index.cjs +161 -0
- package/dist/processors/index.d.cts +2 -0
- package/dist/processors/index.d.ts +2 -0
- package/dist/processors/index.js +154 -0
- package/eslint.config.js +12 -0
- package/package.json +67 -0
- package/src/index.ts +565 -0
- package/src/processors/index.test.ts +238 -0
- package/src/processors/index.ts +2 -0
- package/src/processors/token-limiter.ts +150 -0
- package/src/processors/tool-call-filter.ts +77 -0
- package/src/tools/working-memory.ts +33 -0
- package/src/utils/index.ts +88 -0
- package/tsconfig.json +5 -0
- package/vitest.config.ts +8 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@mastra/core');
|
|
4
|
+
var memory = require('@mastra/core/memory');
|
|
5
|
+
var ai = require('ai');
|
|
6
|
+
var xxhash = require('xxhash-wasm');
|
|
7
|
+
var zod = require('zod');
|
|
8
|
+
|
|
9
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
|
|
11
|
+
var xxhash__default = /*#__PURE__*/_interopDefault(xxhash);
|
|
12
|
+
|
|
13
|
+
// src/index.ts
|
|
14
|
+
var updateWorkingMemoryTool = {
|
|
15
|
+
description: "Update the working memory with new information",
|
|
16
|
+
parameters: zod.z.object({
|
|
17
|
+
memory: zod.z.string().describe("The Markdown-formatted working memory content to store")
|
|
18
|
+
}),
|
|
19
|
+
execute: async (params) => {
|
|
20
|
+
const { context, threadId, memory } = params;
|
|
21
|
+
if (!threadId || !memory) {
|
|
22
|
+
throw new Error("Thread ID and Memory instance are required for working memory updates");
|
|
23
|
+
}
|
|
24
|
+
const thread = await memory.getThreadById({ threadId });
|
|
25
|
+
if (!thread) {
|
|
26
|
+
throw new Error(`Thread ${threadId} not found`);
|
|
27
|
+
}
|
|
28
|
+
await memory.saveThread({
|
|
29
|
+
thread: {
|
|
30
|
+
...thread,
|
|
31
|
+
metadata: {
|
|
32
|
+
...thread.metadata,
|
|
33
|
+
workingMemory: context.memory
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
return { success: true };
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// src/utils/index.ts
|
|
42
|
+
var isToolCallWithId = (message, targetToolCallId) => {
|
|
43
|
+
if (!message || !Array.isArray(message.content)) return false;
|
|
44
|
+
return message.content.some(
|
|
45
|
+
(part) => part && typeof part === "object" && "type" in part && part.type === "tool-call" && "toolCallId" in part && part.toolCallId === targetToolCallId
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
var getToolResultIndexById = (id, results) => results.findIndex((message) => {
|
|
49
|
+
if (!Array.isArray(message?.content)) return false;
|
|
50
|
+
return message.content.some(
|
|
51
|
+
(part) => part && typeof part === "object" && "type" in part && part.type === "tool-result" && "toolCallId" in part && part.toolCallId === id
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
function reorderToolCallsAndResults(messages) {
|
|
55
|
+
if (!messages.length) return messages;
|
|
56
|
+
const results = [...messages];
|
|
57
|
+
const toolCallIds = /* @__PURE__ */ new Set();
|
|
58
|
+
for (const message of results) {
|
|
59
|
+
if (!Array.isArray(message.content)) continue;
|
|
60
|
+
for (const part of message.content) {
|
|
61
|
+
if (part && typeof part === "object" && "type" in part && part.type === "tool-result" && "toolCallId" in part && part.toolCallId) {
|
|
62
|
+
toolCallIds.add(part.toolCallId);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
for (const toolCallId of toolCallIds) {
|
|
67
|
+
const resultIndex = getToolResultIndexById(toolCallId, results);
|
|
68
|
+
const oneMessagePrev = results[resultIndex - 1];
|
|
69
|
+
if (isToolCallWithId(oneMessagePrev, toolCallId)) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const toolCallIndex = results.findIndex((message) => isToolCallWithId(message, toolCallId));
|
|
73
|
+
if (toolCallIndex !== -1 && toolCallIndex !== resultIndex - 1) {
|
|
74
|
+
const toolCall = results[toolCallIndex];
|
|
75
|
+
if (!toolCall) continue;
|
|
76
|
+
results.splice(toolCallIndex, 1);
|
|
77
|
+
results.splice(getToolResultIndexById(toolCallId, results), 0, toolCall);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return results;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/index.ts
|
|
84
|
+
var CHARS_PER_TOKEN = 4;
|
|
85
|
+
var Memory = class extends memory.MastraMemory {
|
|
86
|
+
constructor(config = {}) {
|
|
87
|
+
super({ name: "Memory", ...config });
|
|
88
|
+
const mergedConfig = this.getMergedThreadConfig({
|
|
89
|
+
workingMemory: config.options?.workingMemory || {
|
|
90
|
+
enabled: false,
|
|
91
|
+
template: this.defaultWorkingMemoryTemplate
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
this.threadConfig = mergedConfig;
|
|
95
|
+
}
|
|
96
|
+
async validateThreadIsOwnedByResource(threadId, resourceId) {
|
|
97
|
+
const thread = await this.storage.getThreadById({ threadId });
|
|
98
|
+
if (!thread) {
|
|
99
|
+
throw new Error(`No thread found with id ${threadId}`);
|
|
100
|
+
}
|
|
101
|
+
if (thread.resourceId !== resourceId) {
|
|
102
|
+
throw new Error(
|
|
103
|
+
`Thread with id ${threadId} is for resource with id ${thread.resourceId} but resource ${resourceId} was queried.`
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async query({
|
|
108
|
+
threadId,
|
|
109
|
+
resourceId,
|
|
110
|
+
selectBy,
|
|
111
|
+
threadConfig
|
|
112
|
+
}) {
|
|
113
|
+
if (resourceId) await this.validateThreadIsOwnedByResource(threadId, resourceId);
|
|
114
|
+
const vectorResults = [];
|
|
115
|
+
this.logger.debug(`Memory query() with:`, {
|
|
116
|
+
threadId,
|
|
117
|
+
selectBy,
|
|
118
|
+
threadConfig
|
|
119
|
+
});
|
|
120
|
+
const config = this.getMergedThreadConfig(threadConfig || {});
|
|
121
|
+
const vectorConfig = typeof config?.semanticRecall === `boolean` ? {
|
|
122
|
+
topK: 2,
|
|
123
|
+
messageRange: { before: 2, after: 2 }
|
|
124
|
+
} : {
|
|
125
|
+
topK: config?.semanticRecall?.topK ?? 2,
|
|
126
|
+
messageRange: config?.semanticRecall?.messageRange ?? { before: 2, after: 2 }
|
|
127
|
+
};
|
|
128
|
+
if (config?.semanticRecall && selectBy?.vectorSearchString && this.vector && !!selectBy.vectorSearchString) {
|
|
129
|
+
const { embeddings, dimension } = await this.embedMessageContent(selectBy.vectorSearchString);
|
|
130
|
+
const { indexName } = await this.createEmbeddingIndex(dimension);
|
|
131
|
+
await Promise.all(
|
|
132
|
+
embeddings.map(async (embedding) => {
|
|
133
|
+
if (typeof this.vector === `undefined`) {
|
|
134
|
+
throw new Error(
|
|
135
|
+
`Tried to query vector index ${indexName} but this Memory instance doesn't have an attached vector db.`
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
vectorResults.push(
|
|
139
|
+
...await this.vector.query({
|
|
140
|
+
indexName,
|
|
141
|
+
queryVector: embedding,
|
|
142
|
+
topK: vectorConfig.topK,
|
|
143
|
+
filter: {
|
|
144
|
+
thread_id: threadId
|
|
145
|
+
}
|
|
146
|
+
})
|
|
147
|
+
);
|
|
148
|
+
})
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
const rawMessages = await this.storage.getMessages({
|
|
152
|
+
threadId,
|
|
153
|
+
selectBy: {
|
|
154
|
+
...selectBy,
|
|
155
|
+
...vectorResults?.length ? {
|
|
156
|
+
include: vectorResults.map((r) => ({
|
|
157
|
+
id: r.metadata?.message_id,
|
|
158
|
+
withNextMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.after,
|
|
159
|
+
withPreviousMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.before
|
|
160
|
+
}))
|
|
161
|
+
} : {}
|
|
162
|
+
},
|
|
163
|
+
threadConfig: config
|
|
164
|
+
});
|
|
165
|
+
const orderedByDate = rawMessages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
|
|
166
|
+
const reorderedToolCalls = reorderToolCallsAndResults(orderedByDate);
|
|
167
|
+
const messages = this.parseMessages(reorderedToolCalls);
|
|
168
|
+
const uiMessages = this.convertToUIMessages(reorderedToolCalls);
|
|
169
|
+
return { messages, uiMessages };
|
|
170
|
+
}
|
|
171
|
+
async rememberMessages({
|
|
172
|
+
threadId,
|
|
173
|
+
resourceId,
|
|
174
|
+
vectorMessageSearch,
|
|
175
|
+
config
|
|
176
|
+
}) {
|
|
177
|
+
if (resourceId) await this.validateThreadIsOwnedByResource(threadId, resourceId);
|
|
178
|
+
const threadConfig = this.getMergedThreadConfig(config || {});
|
|
179
|
+
if (!threadConfig.lastMessages && !threadConfig.semanticRecall) {
|
|
180
|
+
return {
|
|
181
|
+
messages: [],
|
|
182
|
+
uiMessages: [],
|
|
183
|
+
threadId
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const messagesResult = await this.query({
|
|
187
|
+
threadId,
|
|
188
|
+
selectBy: {
|
|
189
|
+
last: threadConfig.lastMessages,
|
|
190
|
+
vectorSearchString: threadConfig.semanticRecall && vectorMessageSearch ? vectorMessageSearch : void 0
|
|
191
|
+
},
|
|
192
|
+
threadConfig: config
|
|
193
|
+
});
|
|
194
|
+
this.logger.debug(`Remembered message history includes ${messagesResult.messages.length} messages.`);
|
|
195
|
+
return {
|
|
196
|
+
threadId,
|
|
197
|
+
messages: messagesResult.messages,
|
|
198
|
+
uiMessages: messagesResult.uiMessages
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
async getThreadById({ threadId }) {
|
|
202
|
+
return this.storage.getThreadById({ threadId });
|
|
203
|
+
}
|
|
204
|
+
async getThreadsByResourceId({ resourceId }) {
|
|
205
|
+
return this.storage.getThreadsByResourceId({ resourceId });
|
|
206
|
+
}
|
|
207
|
+
async saveThread({
|
|
208
|
+
thread,
|
|
209
|
+
memoryConfig
|
|
210
|
+
}) {
|
|
211
|
+
const config = this.getMergedThreadConfig(memoryConfig || {});
|
|
212
|
+
if (config.workingMemory?.enabled && !thread?.metadata?.workingMemory) {
|
|
213
|
+
return this.storage.saveThread({
|
|
214
|
+
thread: core.deepMerge(thread, {
|
|
215
|
+
metadata: {
|
|
216
|
+
workingMemory: config.workingMemory.template || this.defaultWorkingMemoryTemplate
|
|
217
|
+
}
|
|
218
|
+
})
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
return this.storage.saveThread({ thread });
|
|
222
|
+
}
|
|
223
|
+
async updateThread({
|
|
224
|
+
id,
|
|
225
|
+
title,
|
|
226
|
+
metadata
|
|
227
|
+
}) {
|
|
228
|
+
return this.storage.updateThread({
|
|
229
|
+
id,
|
|
230
|
+
title,
|
|
231
|
+
metadata
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
async deleteThread(threadId) {
|
|
235
|
+
await this.storage.deleteThread({ threadId });
|
|
236
|
+
}
|
|
237
|
+
chunkText(text, tokenSize = 4096) {
|
|
238
|
+
const charSize = tokenSize * CHARS_PER_TOKEN;
|
|
239
|
+
const chunks = [];
|
|
240
|
+
let currentChunk = "";
|
|
241
|
+
const words = text.split(/\s+/);
|
|
242
|
+
for (const word of words) {
|
|
243
|
+
const wordWithSpace = currentChunk ? " " + word : word;
|
|
244
|
+
if (currentChunk.length + wordWithSpace.length > charSize) {
|
|
245
|
+
chunks.push(currentChunk);
|
|
246
|
+
currentChunk = word;
|
|
247
|
+
} else {
|
|
248
|
+
currentChunk += wordWithSpace;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (currentChunk) {
|
|
252
|
+
chunks.push(currentChunk);
|
|
253
|
+
}
|
|
254
|
+
return chunks;
|
|
255
|
+
}
|
|
256
|
+
hasher = xxhash__default.default();
|
|
257
|
+
// embedding is computationally expensive so cache content -> embeddings/chunks
|
|
258
|
+
embeddingCache = /* @__PURE__ */ new Map();
|
|
259
|
+
firstEmbed;
|
|
260
|
+
async embedMessageContent(content) {
|
|
261
|
+
const key = (await this.hasher).h32(content);
|
|
262
|
+
const cached = this.embeddingCache.get(key);
|
|
263
|
+
if (cached) return cached;
|
|
264
|
+
const chunks = this.chunkText(content);
|
|
265
|
+
if (typeof this.embedder === `undefined`) {
|
|
266
|
+
throw new Error(`Tried to embed message content but this Memory instance doesn't have an attached embedder.`);
|
|
267
|
+
}
|
|
268
|
+
const isFastEmbed = this.embedder.provider === `fastembed`;
|
|
269
|
+
if (isFastEmbed && this.firstEmbed instanceof Promise) {
|
|
270
|
+
await this.firstEmbed;
|
|
271
|
+
}
|
|
272
|
+
const promise = ai.embedMany({
|
|
273
|
+
values: chunks,
|
|
274
|
+
model: this.embedder,
|
|
275
|
+
maxRetries: 3
|
|
276
|
+
});
|
|
277
|
+
if (isFastEmbed && !this.firstEmbed) this.firstEmbed = promise;
|
|
278
|
+
const { embeddings } = await promise;
|
|
279
|
+
const result = {
|
|
280
|
+
embeddings,
|
|
281
|
+
chunks,
|
|
282
|
+
dimension: embeddings[0]?.length
|
|
283
|
+
};
|
|
284
|
+
this.embeddingCache.set(key, result);
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
async saveMessages({
|
|
288
|
+
messages,
|
|
289
|
+
memoryConfig
|
|
290
|
+
}) {
|
|
291
|
+
await this.saveWorkingMemory(messages);
|
|
292
|
+
const updatedMessages = this.updateMessagesToHideWorkingMemory(messages);
|
|
293
|
+
const config = this.getMergedThreadConfig(memoryConfig);
|
|
294
|
+
const result = this.storage.saveMessages({ messages: updatedMessages });
|
|
295
|
+
if (this.vector && config.semanticRecall) {
|
|
296
|
+
let indexName;
|
|
297
|
+
await Promise.all(
|
|
298
|
+
updatedMessages.map(async (message) => {
|
|
299
|
+
if (typeof message.content !== `string` || message.content === "") return;
|
|
300
|
+
const { embeddings, chunks, dimension } = await this.embedMessageContent(message.content);
|
|
301
|
+
if (typeof indexName === `undefined`) {
|
|
302
|
+
indexName = this.createEmbeddingIndex(dimension).then((result2) => result2.indexName);
|
|
303
|
+
}
|
|
304
|
+
if (typeof this.vector === `undefined`) {
|
|
305
|
+
throw new Error(
|
|
306
|
+
`Tried to upsert embeddings to index ${indexName} but this Memory instance doesn't have an attached vector db.`
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
await this.vector.upsert({
|
|
310
|
+
indexName: await indexName,
|
|
311
|
+
vectors: embeddings,
|
|
312
|
+
metadata: chunks.map(() => ({
|
|
313
|
+
message_id: message.id,
|
|
314
|
+
thread_id: message.threadId,
|
|
315
|
+
resource_id: message.resourceId
|
|
316
|
+
}))
|
|
317
|
+
});
|
|
318
|
+
})
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
return result;
|
|
322
|
+
}
|
|
323
|
+
updateMessagesToHideWorkingMemory(messages) {
|
|
324
|
+
const workingMemoryRegex = /<working_memory>([^]*?)<\/working_memory>/g;
|
|
325
|
+
const updatedMessages = [];
|
|
326
|
+
for (const message of messages) {
|
|
327
|
+
if (typeof message?.content === `string`) {
|
|
328
|
+
updatedMessages.push({
|
|
329
|
+
...message,
|
|
330
|
+
content: message.content.replace(workingMemoryRegex, ``).trim()
|
|
331
|
+
});
|
|
332
|
+
} else if (Array.isArray(message?.content)) {
|
|
333
|
+
const contentIsWorkingMemory = message.content.some(
|
|
334
|
+
(content) => (content.type === `tool-call` || content.type === `tool-result`) && content.toolName === `updateWorkingMemory`
|
|
335
|
+
);
|
|
336
|
+
if (contentIsWorkingMemory) {
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
const newContent = message.content.map((content) => {
|
|
340
|
+
if (content.type === "text") {
|
|
341
|
+
return {
|
|
342
|
+
...content,
|
|
343
|
+
text: content.text.replace(workingMemoryRegex, "").trim()
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
return { ...content };
|
|
347
|
+
});
|
|
348
|
+
updatedMessages.push({ ...message, content: newContent });
|
|
349
|
+
} else {
|
|
350
|
+
updatedMessages.push({ ...message });
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
return updatedMessages;
|
|
354
|
+
}
|
|
355
|
+
parseWorkingMemory(text) {
|
|
356
|
+
if (!this.threadConfig.workingMemory?.enabled) return null;
|
|
357
|
+
const workingMemoryRegex = /<working_memory>([^]*?)<\/working_memory>/g;
|
|
358
|
+
const matches = text.match(workingMemoryRegex);
|
|
359
|
+
const match = matches?.[0];
|
|
360
|
+
if (match) {
|
|
361
|
+
return match.replace(/<\/?working_memory>/g, "").trim();
|
|
362
|
+
}
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
async getWorkingMemory({ threadId }) {
|
|
366
|
+
if (!this.threadConfig.workingMemory?.enabled) return null;
|
|
367
|
+
const thread = await this.storage.getThreadById({ threadId });
|
|
368
|
+
if (!thread) return this.threadConfig?.workingMemory?.template || this.defaultWorkingMemoryTemplate;
|
|
369
|
+
const memory = thread.metadata?.workingMemory || this.threadConfig.workingMemory.template || this.defaultWorkingMemoryTemplate;
|
|
370
|
+
return memory.trim();
|
|
371
|
+
}
|
|
372
|
+
async saveWorkingMemory(messages) {
|
|
373
|
+
const latestMessage = messages[messages.length - 1];
|
|
374
|
+
if (!latestMessage || !this.threadConfig.workingMemory?.enabled) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
const latestContent = !latestMessage?.content ? null : typeof latestMessage.content === "string" ? latestMessage.content : latestMessage.content.filter((c) => c.type === "text").map((c) => c.text).join("\n");
|
|
378
|
+
const threadId = latestMessage?.threadId;
|
|
379
|
+
if (!latestContent || !threadId) {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
const newMemory = this.parseWorkingMemory(latestContent);
|
|
383
|
+
if (!newMemory) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
const thread = await this.storage.getThreadById({ threadId });
|
|
387
|
+
if (!thread) return;
|
|
388
|
+
await this.storage.updateThread({
|
|
389
|
+
id: thread.id,
|
|
390
|
+
title: thread.title || "",
|
|
391
|
+
metadata: core.deepMerge(thread.metadata || {}, {
|
|
392
|
+
workingMemory: newMemory
|
|
393
|
+
})
|
|
394
|
+
});
|
|
395
|
+
return newMemory;
|
|
396
|
+
}
|
|
397
|
+
async getSystemMessage({
|
|
398
|
+
threadId,
|
|
399
|
+
memoryConfig
|
|
400
|
+
}) {
|
|
401
|
+
const config = this.getMergedThreadConfig(memoryConfig);
|
|
402
|
+
if (!config.workingMemory?.enabled) {
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
const workingMemory = await this.getWorkingMemory({ threadId });
|
|
406
|
+
if (!workingMemory) {
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
if (config.workingMemory.use === "tool-call") {
|
|
410
|
+
return this.getWorkingMemoryToolInstruction(workingMemory);
|
|
411
|
+
}
|
|
412
|
+
return this.getWorkingMemoryWithInstruction(workingMemory);
|
|
413
|
+
}
|
|
414
|
+
defaultWorkingMemoryTemplate = `
|
|
415
|
+
# User Information
|
|
416
|
+
- **First Name**:
|
|
417
|
+
- **Last Name**:
|
|
418
|
+
- **Location**:
|
|
419
|
+
- **Occupation**:
|
|
420
|
+
- **Interests**:
|
|
421
|
+
- **Goals**:
|
|
422
|
+
- **Events**:
|
|
423
|
+
- **Facts**:
|
|
424
|
+
- **Projects**:
|
|
425
|
+
`;
|
|
426
|
+
getWorkingMemoryWithInstruction(workingMemoryBlock) {
|
|
427
|
+
return `WORKING_MEMORY_SYSTEM_INSTRUCTION:
|
|
428
|
+
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!
|
|
429
|
+
|
|
430
|
+
Guidelines:
|
|
431
|
+
1. Store anything that could be useful later in the conversation
|
|
432
|
+
2. Update proactively when information changes, no matter how small
|
|
433
|
+
3. Use Markdown for all data
|
|
434
|
+
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"
|
|
435
|
+
|
|
436
|
+
Memory Structure:
|
|
437
|
+
<working_memory>
|
|
438
|
+
${workingMemoryBlock}
|
|
439
|
+
</working_memory>
|
|
440
|
+
|
|
441
|
+
Notes:
|
|
442
|
+
- Update memory whenever referenced information changes
|
|
443
|
+
- If you're unsure whether to store something, store it (eg if the user tells you their name or other information, output the <working_memory> block immediately to update it)
|
|
444
|
+
- 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
|
|
445
|
+
- 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.
|
|
446
|
+
- IMPORTANT: You MUST output the <working_memory> block in every response to a prompt where you received relevant information.
|
|
447
|
+
- IMPORTANT: Preserve the Markdown formatting structure above while updating the content.`;
|
|
448
|
+
}
|
|
449
|
+
getWorkingMemoryToolInstruction(workingMemoryBlock) {
|
|
450
|
+
return `WORKING_MEMORY_SYSTEM_INSTRUCTION:
|
|
451
|
+
Store and update any conversation-relevant information by calling the updateWorkingMemory tool. If information might be referenced again - store it!
|
|
452
|
+
|
|
453
|
+
Guidelines:
|
|
454
|
+
1. Store anything that could be useful later in the conversation
|
|
455
|
+
2. Update proactively when information changes, no matter how small
|
|
456
|
+
3. Use Markdown format for all data
|
|
457
|
+
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"
|
|
458
|
+
|
|
459
|
+
Memory Structure:
|
|
460
|
+
${workingMemoryBlock}
|
|
461
|
+
|
|
462
|
+
Notes:
|
|
463
|
+
- Update memory whenever referenced information changes
|
|
464
|
+
- 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)
|
|
465
|
+
- 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
|
|
466
|
+
- Do not remove empty sections - you must include the empty sections along with the ones you're filling in
|
|
467
|
+
- REMEMBER: the way you update your working memory is by calling the updateWorkingMemory tool with the entire Markdown content. The system will store it for you. The user will not see it.
|
|
468
|
+
- IMPORTANT: You MUST call updateWorkingMemory in every response to a prompt where you received relevant information.
|
|
469
|
+
- IMPORTANT: Preserve the Markdown formatting structure above while updating the content.`;
|
|
470
|
+
}
|
|
471
|
+
getTools(config) {
|
|
472
|
+
const mergedConfig = this.getMergedThreadConfig(config);
|
|
473
|
+
if (mergedConfig.workingMemory?.enabled && mergedConfig.workingMemory.use === "tool-call") {
|
|
474
|
+
return {
|
|
475
|
+
updateWorkingMemory: updateWorkingMemoryTool
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
return {};
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
exports.Memory = Memory;
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Memory } from './_tsup-dts-rollup.cjs';
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Memory } from './_tsup-dts-rollup.js';
|