@mastra/memory 0.15.11 → 1.0.0-beta.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.
- package/CHANGELOG.md +307 -26
- package/dist/index.cjs +90 -160
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +16 -43
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +90 -160
- package/dist/index.js.map +1 -1
- package/dist/tools/working-memory.d.ts +2 -14
- package/dist/tools/working-memory.d.ts.map +1 -1
- package/package.json +13 -22
package/dist/index.cjs
CHANGED
|
@@ -33,8 +33,10 @@ var updateWorkingMemoryTool = (memoryConfig) => {
|
|
|
33
33
|
id: "update-working-memory",
|
|
34
34
|
description: `Update the working memory with new information. Any data not included will be overwritten.${schema ? " Always pass data as string to the memory field. Never pass an object." : ""}`,
|
|
35
35
|
inputSchema,
|
|
36
|
-
execute: async (
|
|
37
|
-
const
|
|
36
|
+
execute: async (inputData, context) => {
|
|
37
|
+
const threadId = context?.agent?.threadId;
|
|
38
|
+
const resourceId = context?.agent?.resourceId;
|
|
39
|
+
const memory = context?.memory;
|
|
38
40
|
if (!threadId || !memory || !resourceId) {
|
|
39
41
|
throw new Error("Thread ID, Memory instance, and resourceId are required for working memory updates");
|
|
40
42
|
}
|
|
@@ -49,7 +51,7 @@ var updateWorkingMemoryTool = (memoryConfig) => {
|
|
|
49
51
|
if (thread.resourceId && thread.resourceId !== resourceId) {
|
|
50
52
|
throw new Error(`Thread with id ${threadId} resourceId does not match the current resourceId ${resourceId}`);
|
|
51
53
|
}
|
|
52
|
-
const workingMemory = typeof
|
|
54
|
+
const workingMemory = typeof inputData.memory === "string" ? inputData.memory : JSON.stringify(inputData.memory);
|
|
53
55
|
await memory.updateWorkingMemory({
|
|
54
56
|
threadId,
|
|
55
57
|
resourceId,
|
|
@@ -75,8 +77,10 @@ var __experimental_updateWorkingMemoryToolVNext = (config) => {
|
|
|
75
77
|
"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"
|
|
76
78
|
)
|
|
77
79
|
}),
|
|
78
|
-
execute: async (
|
|
79
|
-
const
|
|
80
|
+
execute: async (inputData, context) => {
|
|
81
|
+
const threadId = context?.agent?.threadId;
|
|
82
|
+
const resourceId = context?.agent?.resourceId;
|
|
83
|
+
const memory = context?.memory;
|
|
80
84
|
if (!threadId || !memory || !resourceId) {
|
|
81
85
|
throw new Error("Thread ID, Memory instance, and resourceId are required for working memory updates");
|
|
82
86
|
}
|
|
@@ -91,25 +95,25 @@ var __experimental_updateWorkingMemoryToolVNext = (config) => {
|
|
|
91
95
|
if (thread.resourceId && thread.resourceId !== resourceId) {
|
|
92
96
|
throw new Error(`Thread with id ${threadId} resourceId does not match the current resourceId ${resourceId}`);
|
|
93
97
|
}
|
|
94
|
-
const workingMemory =
|
|
95
|
-
if (!
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
+
const workingMemory = inputData.newMemory || "";
|
|
99
|
+
if (!inputData.updateReason) inputData.updateReason = `append-new-memory`;
|
|
100
|
+
if (inputData.searchString && config.workingMemory?.scope === `resource` && inputData.updateReason === `replace-irrelevant-memory`) {
|
|
101
|
+
inputData.searchString = void 0;
|
|
98
102
|
}
|
|
99
|
-
if (
|
|
100
|
-
|
|
103
|
+
if (inputData.updateReason === `append-new-memory` && inputData.searchString) {
|
|
104
|
+
inputData.searchString = void 0;
|
|
101
105
|
}
|
|
102
|
-
if (
|
|
106
|
+
if (inputData.updateReason !== `append-new-memory` && !inputData.searchString) {
|
|
103
107
|
return {
|
|
104
108
|
success: false,
|
|
105
|
-
reason: `updateReason was ${
|
|
109
|
+
reason: `updateReason was ${inputData.updateReason} but no searchString was provided. Unable to replace undefined with "${inputData.newMemory}"`
|
|
106
110
|
};
|
|
107
111
|
}
|
|
108
112
|
const result = await memory.__experimental_updateWorkingMemoryVNext({
|
|
109
113
|
threadId,
|
|
110
114
|
resourceId,
|
|
111
115
|
workingMemory,
|
|
112
|
-
searchString:
|
|
116
|
+
searchString: inputData.searchString,
|
|
113
117
|
memoryConfig: config
|
|
114
118
|
});
|
|
115
119
|
if (result) {
|
|
@@ -122,8 +126,8 @@ var __experimental_updateWorkingMemoryToolVNext = (config) => {
|
|
|
122
126
|
|
|
123
127
|
// src/index.ts
|
|
124
128
|
var CHARS_PER_TOKEN = 4;
|
|
125
|
-
var DEFAULT_MESSAGE_RANGE = { before:
|
|
126
|
-
var DEFAULT_TOP_K =
|
|
129
|
+
var DEFAULT_MESSAGE_RANGE = { before: 1, after: 1 };
|
|
130
|
+
var DEFAULT_TOP_K = 4;
|
|
127
131
|
var isZodObject = (v) => v instanceof zod.ZodObject;
|
|
128
132
|
var Memory = class extends memory.MastraMemory {
|
|
129
133
|
constructor(config = {}) {
|
|
@@ -140,7 +144,7 @@ var Memory = class extends memory.MastraMemory {
|
|
|
140
144
|
this.threadConfig = mergedConfig;
|
|
141
145
|
}
|
|
142
146
|
async validateThreadIsOwnedByResource(threadId, resourceId, config) {
|
|
143
|
-
const resourceScope = typeof config?.semanticRecall === "object" && config?.semanticRecall?.scope ===
|
|
147
|
+
const resourceScope = typeof config?.semanticRecall === "object" && config?.semanticRecall?.scope !== `thread` || config.semanticRecall === true;
|
|
144
148
|
const thread = await this.storage.getThreadById({ threadId });
|
|
145
149
|
if (!thread && !resourceScope) {
|
|
146
150
|
throw new Error(`No thread found with id ${threadId}`);
|
|
@@ -152,7 +156,9 @@ var Memory = class extends memory.MastraMemory {
|
|
|
152
156
|
}
|
|
153
157
|
}
|
|
154
158
|
checkStorageFeatureSupport(config) {
|
|
155
|
-
|
|
159
|
+
const resourceScope = typeof config.semanticRecall === "object" && config.semanticRecall.scope !== "thread" || // resource scope is now default
|
|
160
|
+
config.semanticRecall === true;
|
|
161
|
+
if (resourceScope && !this.storage.supports.selectByIncludeResourceScope) {
|
|
156
162
|
throw new Error(
|
|
157
163
|
`Memory error: Attached storage adapter "${this.storage.name || "unknown"}" doesn't support semanticRecall: { scope: "resource" } yet and currently only supports per-thread semantic recall.`
|
|
158
164
|
);
|
|
@@ -163,18 +169,17 @@ var Memory = class extends memory.MastraMemory {
|
|
|
163
169
|
);
|
|
164
170
|
}
|
|
165
171
|
}
|
|
166
|
-
async
|
|
167
|
-
threadId,
|
|
168
|
-
resourceId,
|
|
169
|
-
selectBy,
|
|
170
|
-
threadConfig
|
|
171
|
-
}) {
|
|
172
|
+
async recall(args) {
|
|
173
|
+
const { threadId, resourceId, perPage: perPageArg, page, orderBy, threadConfig, vectorSearchString, filter } = args;
|
|
172
174
|
const config = this.getMergedThreadConfig(threadConfig || {});
|
|
173
175
|
if (resourceId) await this.validateThreadIsOwnedByResource(threadId, resourceId, config);
|
|
176
|
+
const perPage = perPageArg !== void 0 ? perPageArg : config.lastMessages;
|
|
174
177
|
const vectorResults = [];
|
|
175
|
-
this.logger.debug(`Memory
|
|
178
|
+
this.logger.debug(`Memory recall() with:`, {
|
|
176
179
|
threadId,
|
|
177
|
-
|
|
180
|
+
perPage,
|
|
181
|
+
page,
|
|
182
|
+
orderBy,
|
|
178
183
|
threadConfig
|
|
179
184
|
});
|
|
180
185
|
this.checkStorageFeatureSupport(config);
|
|
@@ -187,9 +192,14 @@ var Memory = class extends memory.MastraMemory {
|
|
|
187
192
|
topK: config?.semanticRecall?.topK ?? defaultTopK,
|
|
188
193
|
messageRange: config?.semanticRecall?.messageRange ?? defaultRange
|
|
189
194
|
};
|
|
190
|
-
const resourceScope = typeof config?.semanticRecall === "object" && config?.semanticRecall?.scope ===
|
|
191
|
-
if (config?.semanticRecall &&
|
|
192
|
-
|
|
195
|
+
const resourceScope = typeof config?.semanticRecall === "object" && config?.semanticRecall?.scope !== `thread` || config.semanticRecall === true;
|
|
196
|
+
if (resourceScope && !resourceId && config?.semanticRecall && vectorSearchString) {
|
|
197
|
+
throw new Error(
|
|
198
|
+
`Memory error: Resource-scoped semantic recall is enabled but no resourceId was provided. Either provide a resourceId or explicitly set semanticRecall.scope to 'thread'.`
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
if (config?.semanticRecall && vectorSearchString && this.vector) {
|
|
202
|
+
const { embeddings, dimension } = await this.embedMessageContent(vectorSearchString);
|
|
193
203
|
const { indexName } = await this.createEmbeddingIndex(dimension, config);
|
|
194
204
|
await Promise.all(
|
|
195
205
|
embeddings.map(async (embedding) => {
|
|
@@ -213,114 +223,32 @@ var Memory = class extends memory.MastraMemory {
|
|
|
213
223
|
})
|
|
214
224
|
);
|
|
215
225
|
}
|
|
216
|
-
|
|
217
|
-
if (selectBy?.pagination) {
|
|
218
|
-
const paginatedResult = await this.storage.getMessagesPaginated({
|
|
219
|
-
threadId,
|
|
220
|
-
resourceId,
|
|
221
|
-
format: "v2",
|
|
222
|
-
selectBy: {
|
|
223
|
-
...selectBy,
|
|
224
|
-
...vectorResults?.length ? {
|
|
225
|
-
include: vectorResults.map((r) => ({
|
|
226
|
-
id: r.metadata?.message_id,
|
|
227
|
-
threadId: r.metadata?.thread_id,
|
|
228
|
-
withNextMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.after,
|
|
229
|
-
withPreviousMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.before
|
|
230
|
-
}))
|
|
231
|
-
} : {}
|
|
232
|
-
},
|
|
233
|
-
threadConfig: config
|
|
234
|
-
});
|
|
235
|
-
rawMessages = paginatedResult.messages;
|
|
236
|
-
} else {
|
|
237
|
-
rawMessages = await this.storage.getMessages({
|
|
238
|
-
threadId,
|
|
239
|
-
resourceId,
|
|
240
|
-
format: "v2",
|
|
241
|
-
selectBy: {
|
|
242
|
-
...selectBy,
|
|
243
|
-
...vectorResults?.length ? {
|
|
244
|
-
include: vectorResults.map((r) => ({
|
|
245
|
-
id: r.metadata?.message_id,
|
|
246
|
-
threadId: r.metadata?.thread_id,
|
|
247
|
-
withNextMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.after,
|
|
248
|
-
withPreviousMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.before
|
|
249
|
-
}))
|
|
250
|
-
} : {}
|
|
251
|
-
},
|
|
252
|
-
threadConfig: config
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
const list = new agent.MessageList({ threadId, resourceId }).add(rawMessages, "memory");
|
|
256
|
-
return {
|
|
257
|
-
get messages() {
|
|
258
|
-
const v1Messages = list.get.all.v1();
|
|
259
|
-
if (selectBy?.last && v1Messages.length > selectBy.last) {
|
|
260
|
-
return v1Messages.slice(v1Messages.length - selectBy.last);
|
|
261
|
-
}
|
|
262
|
-
return v1Messages;
|
|
263
|
-
},
|
|
264
|
-
get uiMessages() {
|
|
265
|
-
return list.get.all.ui();
|
|
266
|
-
},
|
|
267
|
-
get messagesV2() {
|
|
268
|
-
return list.get.all.v2();
|
|
269
|
-
}
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
async rememberMessages({
|
|
273
|
-
threadId,
|
|
274
|
-
resourceId,
|
|
275
|
-
vectorMessageSearch,
|
|
276
|
-
config
|
|
277
|
-
}) {
|
|
278
|
-
const threadConfig = this.getMergedThreadConfig(config || {});
|
|
279
|
-
if (resourceId) await this.validateThreadIsOwnedByResource(threadId, resourceId, threadConfig);
|
|
280
|
-
if (!threadConfig.lastMessages && !threadConfig.semanticRecall) {
|
|
281
|
-
return {
|
|
282
|
-
messages: [],
|
|
283
|
-
messagesV2: []
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
const messagesResult = await this.query({
|
|
287
|
-
resourceId,
|
|
226
|
+
const paginatedResult = await this.storage.listMessages({
|
|
288
227
|
threadId,
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
228
|
+
resourceId,
|
|
229
|
+
perPage,
|
|
230
|
+
page,
|
|
231
|
+
orderBy,
|
|
232
|
+
filter,
|
|
233
|
+
...vectorResults?.length ? {
|
|
234
|
+
include: vectorResults.map((r) => ({
|
|
235
|
+
id: r.metadata?.message_id,
|
|
236
|
+
threadId: r.metadata?.thread_id,
|
|
237
|
+
withNextMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.after,
|
|
238
|
+
withPreviousMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.before
|
|
239
|
+
}))
|
|
240
|
+
} : {}
|
|
295
241
|
});
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
242
|
+
const rawMessages = paginatedResult.messages;
|
|
243
|
+
const list = new agent.MessageList({ threadId, resourceId }).add(rawMessages, "memory");
|
|
244
|
+
const messages = list.get.all.db();
|
|
245
|
+
return { messages };
|
|
299
246
|
}
|
|
300
247
|
async getThreadById({ threadId }) {
|
|
301
248
|
return this.storage.getThreadById({ threadId });
|
|
302
249
|
}
|
|
303
|
-
async
|
|
304
|
-
|
|
305
|
-
orderBy,
|
|
306
|
-
sortDirection
|
|
307
|
-
}) {
|
|
308
|
-
return this.storage.getThreadsByResourceId({ resourceId, orderBy, sortDirection });
|
|
309
|
-
}
|
|
310
|
-
async getThreadsByResourceIdPaginated({
|
|
311
|
-
resourceId,
|
|
312
|
-
page,
|
|
313
|
-
perPage,
|
|
314
|
-
orderBy,
|
|
315
|
-
sortDirection
|
|
316
|
-
}) {
|
|
317
|
-
return this.storage.getThreadsByResourceIdPaginated({
|
|
318
|
-
resourceId,
|
|
319
|
-
page,
|
|
320
|
-
perPage,
|
|
321
|
-
orderBy,
|
|
322
|
-
sortDirection
|
|
323
|
-
});
|
|
250
|
+
async listThreadsByResourceId(args) {
|
|
251
|
+
return this.storage.listThreadsByResourceId(args);
|
|
324
252
|
}
|
|
325
253
|
async handleWorkingMemoryFromMetadata({
|
|
326
254
|
workingMemory,
|
|
@@ -330,7 +258,7 @@ var Memory = class extends memory.MastraMemory {
|
|
|
330
258
|
const config = this.getMergedThreadConfig(memoryConfig || {});
|
|
331
259
|
if (config.workingMemory?.enabled) {
|
|
332
260
|
this.checkStorageFeatureSupport(config);
|
|
333
|
-
const scope = config.workingMemory.scope || "
|
|
261
|
+
const scope = config.workingMemory.scope || "resource";
|
|
334
262
|
if (scope === "resource" && resourceId) {
|
|
335
263
|
await this.storage.updateResource({
|
|
336
264
|
resourceId,
|
|
@@ -387,7 +315,12 @@ var Memory = class extends memory.MastraMemory {
|
|
|
387
315
|
throw new Error("Working memory is not enabled for this memory instance");
|
|
388
316
|
}
|
|
389
317
|
this.checkStorageFeatureSupport(config);
|
|
390
|
-
const scope = config.workingMemory.scope || "
|
|
318
|
+
const scope = config.workingMemory.scope || "resource";
|
|
319
|
+
if (scope === "resource" && !resourceId) {
|
|
320
|
+
throw new Error(
|
|
321
|
+
`Memory error: Resource-scoped working memory is enabled but no resourceId was provided. Either provide a resourceId or explicitly set workingMemory.scope to 'thread'.`
|
|
322
|
+
);
|
|
323
|
+
}
|
|
391
324
|
if (scope === "resource" && resourceId) {
|
|
392
325
|
await this.storage.updateResource({
|
|
393
326
|
resourceId,
|
|
@@ -459,7 +392,12 @@ ${workingMemory}`;
|
|
|
459
392
|
reason = `started new working memory`;
|
|
460
393
|
}
|
|
461
394
|
workingMemory = template?.content ? workingMemory.replaceAll(template?.content, "") : workingMemory;
|
|
462
|
-
const scope = config.workingMemory.scope || "
|
|
395
|
+
const scope = config.workingMemory.scope || "resource";
|
|
396
|
+
if (scope === "resource" && !resourceId) {
|
|
397
|
+
throw new Error(
|
|
398
|
+
`Memory error: Resource-scoped working memory is enabled but no resourceId was provided. Either provide a resourceId or explicitly set workingMemory.scope to 'thread'.`
|
|
399
|
+
);
|
|
400
|
+
}
|
|
463
401
|
if (scope === "resource" && resourceId) {
|
|
464
402
|
await this.storage.updateResource({
|
|
465
403
|
resourceId,
|
|
@@ -543,40 +481,28 @@ ${workingMemory}`;
|
|
|
543
481
|
}
|
|
544
482
|
async saveMessages({
|
|
545
483
|
messages,
|
|
546
|
-
memoryConfig
|
|
547
|
-
format = `v1`
|
|
484
|
+
memoryConfig
|
|
548
485
|
}) {
|
|
549
486
|
const updatedMessages = messages.map((m) => {
|
|
550
|
-
if (agent.MessageList.isMastraMessageV1(m)) {
|
|
551
|
-
return this.updateMessageToHideWorkingMemory(m);
|
|
552
|
-
}
|
|
553
|
-
if (!m.type) m.type = `v2`;
|
|
554
487
|
return this.updateMessageToHideWorkingMemoryV2(m);
|
|
555
488
|
}).filter((m) => Boolean(m));
|
|
556
489
|
const config = this.getMergedThreadConfig(memoryConfig);
|
|
557
|
-
const
|
|
558
|
-
|
|
559
|
-
|
|
490
|
+
const dbMessages = new agent.MessageList({
|
|
491
|
+
generateMessageId: () => this.generateId()
|
|
492
|
+
}).add(updatedMessages, "memory").get.all.db();
|
|
493
|
+
const result = await this.storage.saveMessages({
|
|
494
|
+
messages: dbMessages
|
|
560
495
|
});
|
|
561
496
|
if (this.vector && config.semanticRecall) {
|
|
562
497
|
let indexName;
|
|
563
498
|
await Promise.all(
|
|
564
499
|
updatedMessages.map(async (message) => {
|
|
565
500
|
let textForEmbedding = null;
|
|
566
|
-
if (
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
if (joined) textForEmbedding = joined;
|
|
572
|
-
}
|
|
573
|
-
} else if (agent.MessageList.isMastraMessageV1(message)) {
|
|
574
|
-
if (message.content && typeof message.content === "string" && message.content.trim() !== "") {
|
|
575
|
-
textForEmbedding = message.content;
|
|
576
|
-
} else if (message.content && Array.isArray(message.content) && message.content.length > 0) {
|
|
577
|
-
const joined = message.content.filter((part) => part.type === "text").map((part) => part.text).join(" ").trim();
|
|
578
|
-
if (joined) textForEmbedding = joined;
|
|
579
|
-
}
|
|
501
|
+
if (message.content.content && typeof message.content.content === "string" && message.content.content.trim() !== "") {
|
|
502
|
+
textForEmbedding = message.content.content;
|
|
503
|
+
} else if (message.content.parts && message.content.parts.length > 0) {
|
|
504
|
+
const joined = message.content.parts.filter((part) => part.type === "text").map((part) => part.text).join(" ").trim();
|
|
505
|
+
if (joined) textForEmbedding = joined;
|
|
580
506
|
}
|
|
581
507
|
if (!textForEmbedding) return;
|
|
582
508
|
const { embeddings, chunks, dimension } = await this.embedMessageContent(textForEmbedding);
|
|
@@ -600,7 +526,6 @@ ${workingMemory}`;
|
|
|
600
526
|
})
|
|
601
527
|
);
|
|
602
528
|
}
|
|
603
|
-
if (format === `v1`) return new agent.MessageList().add(await result, "memory").get.all.v1();
|
|
604
529
|
return result;
|
|
605
530
|
}
|
|
606
531
|
updateMessageToHideWorkingMemory(message) {
|
|
@@ -676,8 +601,13 @@ ${workingMemory}`;
|
|
|
676
601
|
return null;
|
|
677
602
|
}
|
|
678
603
|
this.checkStorageFeatureSupport(config);
|
|
679
|
-
const scope = config.workingMemory.scope || "
|
|
604
|
+
const scope = config.workingMemory.scope || "resource";
|
|
680
605
|
let workingMemoryData = null;
|
|
606
|
+
if (scope === "resource" && !resourceId) {
|
|
607
|
+
throw new Error(
|
|
608
|
+
`Memory error: Resource-scoped working memory is enabled but no resourceId was provided. Either provide a resourceId or explicitly set workingMemory.scope to 'thread'.`
|
|
609
|
+
);
|
|
610
|
+
}
|
|
681
611
|
if (scope === "resource" && resourceId) {
|
|
682
612
|
const resource = await this.storage.getResourceById({ resourceId });
|
|
683
613
|
workingMemoryData = resource?.workingMemory || null;
|
|
@@ -833,7 +763,7 @@ ${template.content !== this.defaultWorkingMemoryTemplate ? `- Only store informa
|
|
|
833
763
|
const isMDWorkingMemory = !(`schema` in config.workingMemory) && (typeof config.workingMemory.template === `string` || config.workingMemory.template) && config.workingMemory;
|
|
834
764
|
return Boolean(isMDWorkingMemory && isMDWorkingMemory.version === `vnext`);
|
|
835
765
|
}
|
|
836
|
-
|
|
766
|
+
listTools(config) {
|
|
837
767
|
const mergedConfig = this.getMergedThreadConfig(config);
|
|
838
768
|
if (mergedConfig.workingMemory?.enabled) {
|
|
839
769
|
return {
|