@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.js
CHANGED
|
@@ -27,8 +27,10 @@ var updateWorkingMemoryTool = (memoryConfig) => {
|
|
|
27
27
|
id: "update-working-memory",
|
|
28
28
|
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." : ""}`,
|
|
29
29
|
inputSchema,
|
|
30
|
-
execute: async (
|
|
31
|
-
const
|
|
30
|
+
execute: async (inputData, context) => {
|
|
31
|
+
const threadId = context?.agent?.threadId;
|
|
32
|
+
const resourceId = context?.agent?.resourceId;
|
|
33
|
+
const memory = context?.memory;
|
|
32
34
|
if (!threadId || !memory || !resourceId) {
|
|
33
35
|
throw new Error("Thread ID, Memory instance, and resourceId are required for working memory updates");
|
|
34
36
|
}
|
|
@@ -43,7 +45,7 @@ var updateWorkingMemoryTool = (memoryConfig) => {
|
|
|
43
45
|
if (thread.resourceId && thread.resourceId !== resourceId) {
|
|
44
46
|
throw new Error(`Thread with id ${threadId} resourceId does not match the current resourceId ${resourceId}`);
|
|
45
47
|
}
|
|
46
|
-
const workingMemory = typeof
|
|
48
|
+
const workingMemory = typeof inputData.memory === "string" ? inputData.memory : JSON.stringify(inputData.memory);
|
|
47
49
|
await memory.updateWorkingMemory({
|
|
48
50
|
threadId,
|
|
49
51
|
resourceId,
|
|
@@ -69,8 +71,10 @@ var __experimental_updateWorkingMemoryToolVNext = (config) => {
|
|
|
69
71
|
"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"
|
|
70
72
|
)
|
|
71
73
|
}),
|
|
72
|
-
execute: async (
|
|
73
|
-
const
|
|
74
|
+
execute: async (inputData, context) => {
|
|
75
|
+
const threadId = context?.agent?.threadId;
|
|
76
|
+
const resourceId = context?.agent?.resourceId;
|
|
77
|
+
const memory = context?.memory;
|
|
74
78
|
if (!threadId || !memory || !resourceId) {
|
|
75
79
|
throw new Error("Thread ID, Memory instance, and resourceId are required for working memory updates");
|
|
76
80
|
}
|
|
@@ -85,25 +89,25 @@ var __experimental_updateWorkingMemoryToolVNext = (config) => {
|
|
|
85
89
|
if (thread.resourceId && thread.resourceId !== resourceId) {
|
|
86
90
|
throw new Error(`Thread with id ${threadId} resourceId does not match the current resourceId ${resourceId}`);
|
|
87
91
|
}
|
|
88
|
-
const workingMemory =
|
|
89
|
-
if (!
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
+
const workingMemory = inputData.newMemory || "";
|
|
93
|
+
if (!inputData.updateReason) inputData.updateReason = `append-new-memory`;
|
|
94
|
+
if (inputData.searchString && config.workingMemory?.scope === `resource` && inputData.updateReason === `replace-irrelevant-memory`) {
|
|
95
|
+
inputData.searchString = void 0;
|
|
92
96
|
}
|
|
93
|
-
if (
|
|
94
|
-
|
|
97
|
+
if (inputData.updateReason === `append-new-memory` && inputData.searchString) {
|
|
98
|
+
inputData.searchString = void 0;
|
|
95
99
|
}
|
|
96
|
-
if (
|
|
100
|
+
if (inputData.updateReason !== `append-new-memory` && !inputData.searchString) {
|
|
97
101
|
return {
|
|
98
102
|
success: false,
|
|
99
|
-
reason: `updateReason was ${
|
|
103
|
+
reason: `updateReason was ${inputData.updateReason} but no searchString was provided. Unable to replace undefined with "${inputData.newMemory}"`
|
|
100
104
|
};
|
|
101
105
|
}
|
|
102
106
|
const result = await memory.__experimental_updateWorkingMemoryVNext({
|
|
103
107
|
threadId,
|
|
104
108
|
resourceId,
|
|
105
109
|
workingMemory,
|
|
106
|
-
searchString:
|
|
110
|
+
searchString: inputData.searchString,
|
|
107
111
|
memoryConfig: config
|
|
108
112
|
});
|
|
109
113
|
if (result) {
|
|
@@ -116,8 +120,8 @@ var __experimental_updateWorkingMemoryToolVNext = (config) => {
|
|
|
116
120
|
|
|
117
121
|
// src/index.ts
|
|
118
122
|
var CHARS_PER_TOKEN = 4;
|
|
119
|
-
var DEFAULT_MESSAGE_RANGE = { before:
|
|
120
|
-
var DEFAULT_TOP_K =
|
|
123
|
+
var DEFAULT_MESSAGE_RANGE = { before: 1, after: 1 };
|
|
124
|
+
var DEFAULT_TOP_K = 4;
|
|
121
125
|
var isZodObject = (v) => v instanceof ZodObject;
|
|
122
126
|
var Memory = class extends MastraMemory {
|
|
123
127
|
constructor(config = {}) {
|
|
@@ -134,7 +138,7 @@ var Memory = class extends MastraMemory {
|
|
|
134
138
|
this.threadConfig = mergedConfig;
|
|
135
139
|
}
|
|
136
140
|
async validateThreadIsOwnedByResource(threadId, resourceId, config) {
|
|
137
|
-
const resourceScope = typeof config?.semanticRecall === "object" && config?.semanticRecall?.scope ===
|
|
141
|
+
const resourceScope = typeof config?.semanticRecall === "object" && config?.semanticRecall?.scope !== `thread` || config.semanticRecall === true;
|
|
138
142
|
const thread = await this.storage.getThreadById({ threadId });
|
|
139
143
|
if (!thread && !resourceScope) {
|
|
140
144
|
throw new Error(`No thread found with id ${threadId}`);
|
|
@@ -146,7 +150,9 @@ var Memory = class extends MastraMemory {
|
|
|
146
150
|
}
|
|
147
151
|
}
|
|
148
152
|
checkStorageFeatureSupport(config) {
|
|
149
|
-
|
|
153
|
+
const resourceScope = typeof config.semanticRecall === "object" && config.semanticRecall.scope !== "thread" || // resource scope is now default
|
|
154
|
+
config.semanticRecall === true;
|
|
155
|
+
if (resourceScope && !this.storage.supports.selectByIncludeResourceScope) {
|
|
150
156
|
throw new Error(
|
|
151
157
|
`Memory error: Attached storage adapter "${this.storage.name || "unknown"}" doesn't support semanticRecall: { scope: "resource" } yet and currently only supports per-thread semantic recall.`
|
|
152
158
|
);
|
|
@@ -157,18 +163,17 @@ var Memory = class extends MastraMemory {
|
|
|
157
163
|
);
|
|
158
164
|
}
|
|
159
165
|
}
|
|
160
|
-
async
|
|
161
|
-
threadId,
|
|
162
|
-
resourceId,
|
|
163
|
-
selectBy,
|
|
164
|
-
threadConfig
|
|
165
|
-
}) {
|
|
166
|
+
async recall(args) {
|
|
167
|
+
const { threadId, resourceId, perPage: perPageArg, page, orderBy, threadConfig, vectorSearchString, filter } = args;
|
|
166
168
|
const config = this.getMergedThreadConfig(threadConfig || {});
|
|
167
169
|
if (resourceId) await this.validateThreadIsOwnedByResource(threadId, resourceId, config);
|
|
170
|
+
const perPage = perPageArg !== void 0 ? perPageArg : config.lastMessages;
|
|
168
171
|
const vectorResults = [];
|
|
169
|
-
this.logger.debug(`Memory
|
|
172
|
+
this.logger.debug(`Memory recall() with:`, {
|
|
170
173
|
threadId,
|
|
171
|
-
|
|
174
|
+
perPage,
|
|
175
|
+
page,
|
|
176
|
+
orderBy,
|
|
172
177
|
threadConfig
|
|
173
178
|
});
|
|
174
179
|
this.checkStorageFeatureSupport(config);
|
|
@@ -181,9 +186,14 @@ var Memory = class extends MastraMemory {
|
|
|
181
186
|
topK: config?.semanticRecall?.topK ?? defaultTopK,
|
|
182
187
|
messageRange: config?.semanticRecall?.messageRange ?? defaultRange
|
|
183
188
|
};
|
|
184
|
-
const resourceScope = typeof config?.semanticRecall === "object" && config?.semanticRecall?.scope ===
|
|
185
|
-
if (config?.semanticRecall &&
|
|
186
|
-
|
|
189
|
+
const resourceScope = typeof config?.semanticRecall === "object" && config?.semanticRecall?.scope !== `thread` || config.semanticRecall === true;
|
|
190
|
+
if (resourceScope && !resourceId && config?.semanticRecall && vectorSearchString) {
|
|
191
|
+
throw new Error(
|
|
192
|
+
`Memory error: Resource-scoped semantic recall is enabled but no resourceId was provided. Either provide a resourceId or explicitly set semanticRecall.scope to 'thread'.`
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
if (config?.semanticRecall && vectorSearchString && this.vector) {
|
|
196
|
+
const { embeddings, dimension } = await this.embedMessageContent(vectorSearchString);
|
|
187
197
|
const { indexName } = await this.createEmbeddingIndex(dimension, config);
|
|
188
198
|
await Promise.all(
|
|
189
199
|
embeddings.map(async (embedding) => {
|
|
@@ -207,114 +217,32 @@ var Memory = class extends MastraMemory {
|
|
|
207
217
|
})
|
|
208
218
|
);
|
|
209
219
|
}
|
|
210
|
-
|
|
211
|
-
if (selectBy?.pagination) {
|
|
212
|
-
const paginatedResult = await this.storage.getMessagesPaginated({
|
|
213
|
-
threadId,
|
|
214
|
-
resourceId,
|
|
215
|
-
format: "v2",
|
|
216
|
-
selectBy: {
|
|
217
|
-
...selectBy,
|
|
218
|
-
...vectorResults?.length ? {
|
|
219
|
-
include: vectorResults.map((r) => ({
|
|
220
|
-
id: r.metadata?.message_id,
|
|
221
|
-
threadId: r.metadata?.thread_id,
|
|
222
|
-
withNextMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.after,
|
|
223
|
-
withPreviousMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.before
|
|
224
|
-
}))
|
|
225
|
-
} : {}
|
|
226
|
-
},
|
|
227
|
-
threadConfig: config
|
|
228
|
-
});
|
|
229
|
-
rawMessages = paginatedResult.messages;
|
|
230
|
-
} else {
|
|
231
|
-
rawMessages = await this.storage.getMessages({
|
|
232
|
-
threadId,
|
|
233
|
-
resourceId,
|
|
234
|
-
format: "v2",
|
|
235
|
-
selectBy: {
|
|
236
|
-
...selectBy,
|
|
237
|
-
...vectorResults?.length ? {
|
|
238
|
-
include: vectorResults.map((r) => ({
|
|
239
|
-
id: r.metadata?.message_id,
|
|
240
|
-
threadId: r.metadata?.thread_id,
|
|
241
|
-
withNextMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.after,
|
|
242
|
-
withPreviousMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.before
|
|
243
|
-
}))
|
|
244
|
-
} : {}
|
|
245
|
-
},
|
|
246
|
-
threadConfig: config
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
const list = new MessageList({ threadId, resourceId }).add(rawMessages, "memory");
|
|
250
|
-
return {
|
|
251
|
-
get messages() {
|
|
252
|
-
const v1Messages = list.get.all.v1();
|
|
253
|
-
if (selectBy?.last && v1Messages.length > selectBy.last) {
|
|
254
|
-
return v1Messages.slice(v1Messages.length - selectBy.last);
|
|
255
|
-
}
|
|
256
|
-
return v1Messages;
|
|
257
|
-
},
|
|
258
|
-
get uiMessages() {
|
|
259
|
-
return list.get.all.ui();
|
|
260
|
-
},
|
|
261
|
-
get messagesV2() {
|
|
262
|
-
return list.get.all.v2();
|
|
263
|
-
}
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
async rememberMessages({
|
|
267
|
-
threadId,
|
|
268
|
-
resourceId,
|
|
269
|
-
vectorMessageSearch,
|
|
270
|
-
config
|
|
271
|
-
}) {
|
|
272
|
-
const threadConfig = this.getMergedThreadConfig(config || {});
|
|
273
|
-
if (resourceId) await this.validateThreadIsOwnedByResource(threadId, resourceId, threadConfig);
|
|
274
|
-
if (!threadConfig.lastMessages && !threadConfig.semanticRecall) {
|
|
275
|
-
return {
|
|
276
|
-
messages: [],
|
|
277
|
-
messagesV2: []
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
const messagesResult = await this.query({
|
|
281
|
-
resourceId,
|
|
220
|
+
const paginatedResult = await this.storage.listMessages({
|
|
282
221
|
threadId,
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
222
|
+
resourceId,
|
|
223
|
+
perPage,
|
|
224
|
+
page,
|
|
225
|
+
orderBy,
|
|
226
|
+
filter,
|
|
227
|
+
...vectorResults?.length ? {
|
|
228
|
+
include: vectorResults.map((r) => ({
|
|
229
|
+
id: r.metadata?.message_id,
|
|
230
|
+
threadId: r.metadata?.thread_id,
|
|
231
|
+
withNextMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.after,
|
|
232
|
+
withPreviousMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.before
|
|
233
|
+
}))
|
|
234
|
+
} : {}
|
|
289
235
|
});
|
|
290
|
-
const
|
|
291
|
-
|
|
292
|
-
|
|
236
|
+
const rawMessages = paginatedResult.messages;
|
|
237
|
+
const list = new MessageList({ threadId, resourceId }).add(rawMessages, "memory");
|
|
238
|
+
const messages = list.get.all.db();
|
|
239
|
+
return { messages };
|
|
293
240
|
}
|
|
294
241
|
async getThreadById({ threadId }) {
|
|
295
242
|
return this.storage.getThreadById({ threadId });
|
|
296
243
|
}
|
|
297
|
-
async
|
|
298
|
-
|
|
299
|
-
orderBy,
|
|
300
|
-
sortDirection
|
|
301
|
-
}) {
|
|
302
|
-
return this.storage.getThreadsByResourceId({ resourceId, orderBy, sortDirection });
|
|
303
|
-
}
|
|
304
|
-
async getThreadsByResourceIdPaginated({
|
|
305
|
-
resourceId,
|
|
306
|
-
page,
|
|
307
|
-
perPage,
|
|
308
|
-
orderBy,
|
|
309
|
-
sortDirection
|
|
310
|
-
}) {
|
|
311
|
-
return this.storage.getThreadsByResourceIdPaginated({
|
|
312
|
-
resourceId,
|
|
313
|
-
page,
|
|
314
|
-
perPage,
|
|
315
|
-
orderBy,
|
|
316
|
-
sortDirection
|
|
317
|
-
});
|
|
244
|
+
async listThreadsByResourceId(args) {
|
|
245
|
+
return this.storage.listThreadsByResourceId(args);
|
|
318
246
|
}
|
|
319
247
|
async handleWorkingMemoryFromMetadata({
|
|
320
248
|
workingMemory,
|
|
@@ -324,7 +252,7 @@ var Memory = class extends MastraMemory {
|
|
|
324
252
|
const config = this.getMergedThreadConfig(memoryConfig || {});
|
|
325
253
|
if (config.workingMemory?.enabled) {
|
|
326
254
|
this.checkStorageFeatureSupport(config);
|
|
327
|
-
const scope = config.workingMemory.scope || "
|
|
255
|
+
const scope = config.workingMemory.scope || "resource";
|
|
328
256
|
if (scope === "resource" && resourceId) {
|
|
329
257
|
await this.storage.updateResource({
|
|
330
258
|
resourceId,
|
|
@@ -381,7 +309,12 @@ var Memory = class extends MastraMemory {
|
|
|
381
309
|
throw new Error("Working memory is not enabled for this memory instance");
|
|
382
310
|
}
|
|
383
311
|
this.checkStorageFeatureSupport(config);
|
|
384
|
-
const scope = config.workingMemory.scope || "
|
|
312
|
+
const scope = config.workingMemory.scope || "resource";
|
|
313
|
+
if (scope === "resource" && !resourceId) {
|
|
314
|
+
throw new Error(
|
|
315
|
+
`Memory error: Resource-scoped working memory is enabled but no resourceId was provided. Either provide a resourceId or explicitly set workingMemory.scope to 'thread'.`
|
|
316
|
+
);
|
|
317
|
+
}
|
|
385
318
|
if (scope === "resource" && resourceId) {
|
|
386
319
|
await this.storage.updateResource({
|
|
387
320
|
resourceId,
|
|
@@ -453,7 +386,12 @@ ${workingMemory}`;
|
|
|
453
386
|
reason = `started new working memory`;
|
|
454
387
|
}
|
|
455
388
|
workingMemory = template?.content ? workingMemory.replaceAll(template?.content, "") : workingMemory;
|
|
456
|
-
const scope = config.workingMemory.scope || "
|
|
389
|
+
const scope = config.workingMemory.scope || "resource";
|
|
390
|
+
if (scope === "resource" && !resourceId) {
|
|
391
|
+
throw new Error(
|
|
392
|
+
`Memory error: Resource-scoped working memory is enabled but no resourceId was provided. Either provide a resourceId or explicitly set workingMemory.scope to 'thread'.`
|
|
393
|
+
);
|
|
394
|
+
}
|
|
457
395
|
if (scope === "resource" && resourceId) {
|
|
458
396
|
await this.storage.updateResource({
|
|
459
397
|
resourceId,
|
|
@@ -537,40 +475,28 @@ ${workingMemory}`;
|
|
|
537
475
|
}
|
|
538
476
|
async saveMessages({
|
|
539
477
|
messages,
|
|
540
|
-
memoryConfig
|
|
541
|
-
format = `v1`
|
|
478
|
+
memoryConfig
|
|
542
479
|
}) {
|
|
543
480
|
const updatedMessages = messages.map((m) => {
|
|
544
|
-
if (MessageList.isMastraMessageV1(m)) {
|
|
545
|
-
return this.updateMessageToHideWorkingMemory(m);
|
|
546
|
-
}
|
|
547
|
-
if (!m.type) m.type = `v2`;
|
|
548
481
|
return this.updateMessageToHideWorkingMemoryV2(m);
|
|
549
482
|
}).filter((m) => Boolean(m));
|
|
550
483
|
const config = this.getMergedThreadConfig(memoryConfig);
|
|
551
|
-
const
|
|
552
|
-
|
|
553
|
-
|
|
484
|
+
const dbMessages = new MessageList({
|
|
485
|
+
generateMessageId: () => this.generateId()
|
|
486
|
+
}).add(updatedMessages, "memory").get.all.db();
|
|
487
|
+
const result = await this.storage.saveMessages({
|
|
488
|
+
messages: dbMessages
|
|
554
489
|
});
|
|
555
490
|
if (this.vector && config.semanticRecall) {
|
|
556
491
|
let indexName;
|
|
557
492
|
await Promise.all(
|
|
558
493
|
updatedMessages.map(async (message) => {
|
|
559
494
|
let textForEmbedding = null;
|
|
560
|
-
if (
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
if (joined) textForEmbedding = joined;
|
|
566
|
-
}
|
|
567
|
-
} else if (MessageList.isMastraMessageV1(message)) {
|
|
568
|
-
if (message.content && typeof message.content === "string" && message.content.trim() !== "") {
|
|
569
|
-
textForEmbedding = message.content;
|
|
570
|
-
} else if (message.content && Array.isArray(message.content) && message.content.length > 0) {
|
|
571
|
-
const joined = message.content.filter((part) => part.type === "text").map((part) => part.text).join(" ").trim();
|
|
572
|
-
if (joined) textForEmbedding = joined;
|
|
573
|
-
}
|
|
495
|
+
if (message.content.content && typeof message.content.content === "string" && message.content.content.trim() !== "") {
|
|
496
|
+
textForEmbedding = message.content.content;
|
|
497
|
+
} else if (message.content.parts && message.content.parts.length > 0) {
|
|
498
|
+
const joined = message.content.parts.filter((part) => part.type === "text").map((part) => part.text).join(" ").trim();
|
|
499
|
+
if (joined) textForEmbedding = joined;
|
|
574
500
|
}
|
|
575
501
|
if (!textForEmbedding) return;
|
|
576
502
|
const { embeddings, chunks, dimension } = await this.embedMessageContent(textForEmbedding);
|
|
@@ -594,7 +520,6 @@ ${workingMemory}`;
|
|
|
594
520
|
})
|
|
595
521
|
);
|
|
596
522
|
}
|
|
597
|
-
if (format === `v1`) return new MessageList().add(await result, "memory").get.all.v1();
|
|
598
523
|
return result;
|
|
599
524
|
}
|
|
600
525
|
updateMessageToHideWorkingMemory(message) {
|
|
@@ -670,8 +595,13 @@ ${workingMemory}`;
|
|
|
670
595
|
return null;
|
|
671
596
|
}
|
|
672
597
|
this.checkStorageFeatureSupport(config);
|
|
673
|
-
const scope = config.workingMemory.scope || "
|
|
598
|
+
const scope = config.workingMemory.scope || "resource";
|
|
674
599
|
let workingMemoryData = null;
|
|
600
|
+
if (scope === "resource" && !resourceId) {
|
|
601
|
+
throw new Error(
|
|
602
|
+
`Memory error: Resource-scoped working memory is enabled but no resourceId was provided. Either provide a resourceId or explicitly set workingMemory.scope to 'thread'.`
|
|
603
|
+
);
|
|
604
|
+
}
|
|
675
605
|
if (scope === "resource" && resourceId) {
|
|
676
606
|
const resource = await this.storage.getResourceById({ resourceId });
|
|
677
607
|
workingMemoryData = resource?.workingMemory || null;
|
|
@@ -827,7 +757,7 @@ ${template.content !== this.defaultWorkingMemoryTemplate ? `- Only store informa
|
|
|
827
757
|
const isMDWorkingMemory = !(`schema` in config.workingMemory) && (typeof config.workingMemory.template === `string` || config.workingMemory.template) && config.workingMemory;
|
|
828
758
|
return Boolean(isMDWorkingMemory && isMDWorkingMemory.version === `vnext`);
|
|
829
759
|
}
|
|
830
|
-
|
|
760
|
+
listTools(config) {
|
|
831
761
|
const mergedConfig = this.getMergedThreadConfig(config);
|
|
832
762
|
if (mergedConfig.workingMemory?.enabled) {
|
|
833
763
|
return {
|