@mastra/memory 0.2.10-alpha.5 → 0.2.11-alpha.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.
@@ -1,29 +1,29 @@
1
1
 
2
- > @mastra/memory@0.2.10-alpha.5 build /home/runner/work/mastra/mastra/packages/memory
2
+ > @mastra/memory@0.2.11-alpha.1 build /home/runner/work/mastra/mastra/packages/memory
3
3
  > pnpm run check && tsup src/index.ts src/processors/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting
4
4
 
5
5
 
6
- > @mastra/memory@0.2.10-alpha.5 check /home/runner/work/mastra/mastra/packages/memory
6
+ > @mastra/memory@0.2.11-alpha.1 check /home/runner/work/mastra/mastra/packages/memory
7
7
  > tsc --noEmit
8
8
 
9
9
  CLI Building entry: src/index.ts, src/processors/index.ts
10
10
  CLI Using tsconfig: tsconfig.json
11
11
  CLI tsup v8.4.0
12
12
  TSC Build start
13
- TSC ⚡️ Build success in 9128ms
13
+ TSC ⚡️ Build success in 9818ms
14
14
  DTS Build start
15
15
  CLI Target: es2022
16
16
  Analysis will use the bundled TypeScript version 5.8.2
17
17
  Writing package typings: /home/runner/work/mastra/mastra/packages/memory/dist/_tsup-dts-rollup.d.ts
18
18
  Analysis will use the bundled TypeScript version 5.8.2
19
19
  Writing package typings: /home/runner/work/mastra/mastra/packages/memory/dist/_tsup-dts-rollup.d.cts
20
- DTS ⚡️ Build success in 12528ms
20
+ DTS ⚡️ Build success in 11869ms
21
21
  CLI Cleaning output folder
22
22
  ESM Build start
23
23
  CJS Build start
24
- CJS dist/index.cjs 15.71 KB
25
- CJS dist/processors/index.cjs 5.54 KB
26
- CJS ⚡️ Build success in 882ms
27
- ESM dist/index.js 15.44 KB
24
+ ESM dist/index.js 17.39 KB
28
25
  ESM dist/processors/index.js 5.33 KB
29
- ESM ⚡️ Build success in 882ms
26
+ ESM ⚡️ Build success in 1099ms
27
+ CJS dist/index.cjs 17.66 KB
28
+ CJS dist/processors/index.cjs 5.54 KB
29
+ CJS ⚡️ Build success in 1103ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # @mastra/memory
2
2
 
3
+ ## 0.2.11-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 6f92295: Fixed an issue where some user messages and llm messages would have the exact same createdAt date, leading to incorrect message ordering. Added a fix for new messages as well as any that were saved before the fix in the wrong order
8
+ - Updated dependencies [8a8a73b]
9
+ - Updated dependencies [6f92295]
10
+ - @mastra/core@0.8.4-alpha.1
11
+
12
+ ## 0.2.11-alpha.0
13
+
14
+ ### Patch Changes
15
+
16
+ - Updated dependencies [03f3cd0]
17
+ - @mastra/core@0.8.4-alpha.0
18
+
19
+ ## 0.2.10
20
+
21
+ ### Patch Changes
22
+
23
+ - f6f7345: Added missing createdAt field to UI messages in memory
24
+ - 359b089: Allowed explicitly disabling vector/embedder in Memory by passing vector: false or options.semanticRecall: false
25
+ - 37bb612: Add Elastic-2.0 licensing for packages
26
+ - Updated dependencies [d72318f]
27
+ - Updated dependencies [0bcc862]
28
+ - Updated dependencies [10a8caf]
29
+ - Updated dependencies [359b089]
30
+ - Updated dependencies [32e7b71]
31
+ - Updated dependencies [37bb612]
32
+ - Updated dependencies [7f1b291]
33
+ - @mastra/core@0.8.3
34
+
3
35
  ## 0.2.10-alpha.5
4
36
 
5
37
  ### Patch Changes
@@ -76,6 +76,12 @@ export declare class Memory extends MastraMemory {
76
76
  getTools(config?: MemoryConfig): Record<string, CoreTool>;
77
77
  }
78
78
 
79
+ /**
80
+ * Self-heals message ordering to ensure tool calls are directly before their matching tool results.
81
+ * This is needed due to a bug where messages were saved in the wrong order. That bug is fixed, but this code ensures any tool calls saved in the wrong order in the past will still be usable now.
82
+ */
83
+ export declare function reorderToolCallsAndResults(messages: MessageType[]): MessageType[];
84
+
79
85
  /**
80
86
  * Limits the total number of tokens in the messages.
81
87
  * Uses js-tiktoken with o200k_base encoding by default for accurate token counting with modern models.
@@ -76,6 +76,12 @@ export declare class Memory extends MastraMemory {
76
76
  getTools(config?: MemoryConfig): Record<string, CoreTool>;
77
77
  }
78
78
 
79
+ /**
80
+ * Self-heals message ordering to ensure tool calls are directly before their matching tool results.
81
+ * This is needed due to a bug where messages were saved in the wrong order. That bug is fixed, but this code ensures any tool calls saved in the wrong order in the past will still be usable now.
82
+ */
83
+ export declare function reorderToolCallsAndResults(messages: MessageType[]): MessageType[];
84
+
79
85
  /**
80
86
  * Limits the total number of tokens in the messages.
81
87
  * Uses js-tiktoken with o200k_base encoding by default for accurate token counting with modern models.
package/dist/index.cjs CHANGED
@@ -41,6 +41,48 @@ var updateWorkingMemoryTool = {
41
41
  }
42
42
  };
43
43
 
44
+ // src/utils/index.ts
45
+ var isToolCallWithId = (message, targetToolCallId) => {
46
+ if (!message || !Array.isArray(message.content)) return false;
47
+ return message.content.some(
48
+ (part) => part && typeof part === "object" && "type" in part && part.type === "tool-call" && "toolCallId" in part && part.toolCallId === targetToolCallId
49
+ );
50
+ };
51
+ var getToolResultIndexById = (id, results) => results.findIndex((message) => {
52
+ if (!Array.isArray(message?.content)) return false;
53
+ return message.content.some(
54
+ (part) => part && typeof part === "object" && "type" in part && part.type === "tool-result" && "toolCallId" in part && part.toolCallId === id
55
+ );
56
+ });
57
+ function reorderToolCallsAndResults(messages) {
58
+ if (!messages.length) return messages;
59
+ const results = [...messages];
60
+ const toolCallIds = /* @__PURE__ */ new Set();
61
+ for (const message of results) {
62
+ if (!Array.isArray(message.content)) continue;
63
+ for (const part of message.content) {
64
+ if (part && typeof part === "object" && "type" in part && part.type === "tool-result" && "toolCallId" in part && part.toolCallId) {
65
+ toolCallIds.add(part.toolCallId);
66
+ }
67
+ }
68
+ }
69
+ for (const toolCallId of toolCallIds) {
70
+ const resultIndex = getToolResultIndexById(toolCallId, results);
71
+ const oneMessagePrev = results[resultIndex - 1];
72
+ if (isToolCallWithId(oneMessagePrev, toolCallId)) {
73
+ continue;
74
+ }
75
+ const toolCallIndex = results.findIndex((message) => isToolCallWithId(message, toolCallId));
76
+ if (toolCallIndex !== -1 && toolCallIndex !== resultIndex - 1) {
77
+ const toolCall = results[toolCallIndex];
78
+ if (!toolCall) continue;
79
+ results.splice(toolCallIndex, 1);
80
+ results.splice(getToolResultIndexById(toolCallId, results), 0, toolCall);
81
+ }
82
+ }
83
+ return results;
84
+ }
85
+
44
86
  // src/index.ts
45
87
  var encoder = new lite.Tiktoken(o200k_base__default.default);
46
88
  var Memory = class extends memory.MastraMemory {
@@ -123,8 +165,10 @@ var Memory = class extends memory.MastraMemory {
123
165
  },
124
166
  threadConfig: config
125
167
  });
126
- const messages = this.parseMessages(rawMessages);
127
- const uiMessages = this.convertToUIMessages(rawMessages);
168
+ const orderedByDate = rawMessages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
169
+ const reorderedToolCalls = reorderToolCallsAndResults(orderedByDate);
170
+ const messages = this.parseMessages(reorderedToolCalls);
171
+ const uiMessages = this.convertToUIMessages(reorderedToolCalls);
128
172
  return { messages, uiMessages };
129
173
  }
130
174
  async rememberMessages({
package/dist/index.js CHANGED
@@ -34,6 +34,48 @@ var updateWorkingMemoryTool = {
34
34
  }
35
35
  };
36
36
 
37
+ // src/utils/index.ts
38
+ var isToolCallWithId = (message, targetToolCallId) => {
39
+ if (!message || !Array.isArray(message.content)) return false;
40
+ return message.content.some(
41
+ (part) => part && typeof part === "object" && "type" in part && part.type === "tool-call" && "toolCallId" in part && part.toolCallId === targetToolCallId
42
+ );
43
+ };
44
+ var getToolResultIndexById = (id, results) => results.findIndex((message) => {
45
+ if (!Array.isArray(message?.content)) return false;
46
+ return message.content.some(
47
+ (part) => part && typeof part === "object" && "type" in part && part.type === "tool-result" && "toolCallId" in part && part.toolCallId === id
48
+ );
49
+ });
50
+ function reorderToolCallsAndResults(messages) {
51
+ if (!messages.length) return messages;
52
+ const results = [...messages];
53
+ const toolCallIds = /* @__PURE__ */ new Set();
54
+ for (const message of results) {
55
+ if (!Array.isArray(message.content)) continue;
56
+ for (const part of message.content) {
57
+ if (part && typeof part === "object" && "type" in part && part.type === "tool-result" && "toolCallId" in part && part.toolCallId) {
58
+ toolCallIds.add(part.toolCallId);
59
+ }
60
+ }
61
+ }
62
+ for (const toolCallId of toolCallIds) {
63
+ const resultIndex = getToolResultIndexById(toolCallId, results);
64
+ const oneMessagePrev = results[resultIndex - 1];
65
+ if (isToolCallWithId(oneMessagePrev, toolCallId)) {
66
+ continue;
67
+ }
68
+ const toolCallIndex = results.findIndex((message) => isToolCallWithId(message, toolCallId));
69
+ if (toolCallIndex !== -1 && toolCallIndex !== resultIndex - 1) {
70
+ const toolCall = results[toolCallIndex];
71
+ if (!toolCall) continue;
72
+ results.splice(toolCallIndex, 1);
73
+ results.splice(getToolResultIndexById(toolCallId, results), 0, toolCall);
74
+ }
75
+ }
76
+ return results;
77
+ }
78
+
37
79
  // src/index.ts
38
80
  var encoder = new Tiktoken(o200k_base);
39
81
  var Memory = class extends MastraMemory {
@@ -116,8 +158,10 @@ var Memory = class extends MastraMemory {
116
158
  },
117
159
  threadConfig: config
118
160
  });
119
- const messages = this.parseMessages(rawMessages);
120
- const uiMessages = this.convertToUIMessages(rawMessages);
161
+ const orderedByDate = rawMessages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
162
+ const reorderedToolCalls = reorderToolCallsAndResults(orderedByDate);
163
+ const messages = this.parseMessages(reorderedToolCalls);
164
+ const uiMessages = this.convertToUIMessages(reorderedToolCalls);
121
165
  return { messages, uiMessages };
122
166
  }
123
167
  async rememberMessages({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/memory",
3
- "version": "0.2.10-alpha.5",
3
+ "version": "0.2.11-alpha.1",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -41,7 +41,7 @@
41
41
  "redis": "^4.7.0",
42
42
  "xxhash-wasm": "^1.1.0",
43
43
  "zod": "^3.24.2",
44
- "@mastra/core": "^0.8.3-alpha.5"
44
+ "@mastra/core": "^0.8.4-alpha.1"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@ai-sdk/openai": "^1.3.3",
@@ -53,7 +53,7 @@
53
53
  "typescript": "^5.8.2",
54
54
  "typescript-eslint": "^8.26.1",
55
55
  "vitest": "^3.0.9",
56
- "@internal/lint": "0.0.2-alpha.0"
56
+ "@internal/lint": "0.0.2"
57
57
  },
58
58
  "scripts": {
59
59
  "check": "tsc --noEmit",
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@ import { Tiktoken } from 'js-tiktoken/lite';
8
8
  import o200k_base from 'js-tiktoken/ranks/o200k_base';
9
9
  import xxhash from 'xxhash-wasm';
10
10
  import { updateWorkingMemoryTool } from './tools/working-memory';
11
+ import { reorderToolCallsAndResults } from './utils';
11
12
 
12
13
  const encoder = new Tiktoken(o200k_base);
13
14
 
@@ -126,9 +127,14 @@ export class Memory extends MastraMemory {
126
127
  threadConfig: config,
127
128
  });
128
129
 
130
+ // First sort messages by date
131
+ const orderedByDate = rawMessages.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());
132
+ // Then reorder tool calls to be directly before their results
133
+ const reorderedToolCalls = reorderToolCallsAndResults(orderedByDate);
134
+
129
135
  // Parse and convert messages
130
- const messages = this.parseMessages(rawMessages);
131
- const uiMessages = this.convertToUIMessages(rawMessages);
136
+ const messages = this.parseMessages(reorderedToolCalls);
137
+ const uiMessages = this.convertToUIMessages(reorderedToolCalls);
132
138
 
133
139
  return { messages, uiMessages };
134
140
  }
@@ -0,0 +1,88 @@
1
+ import type { MessageType } from '@mastra/core/memory';
2
+
3
+ const isToolCallWithId = (message: MessageType | undefined, targetToolCallId: string): boolean => {
4
+ if (!message || !Array.isArray(message.content)) return false;
5
+ return message.content.some(
6
+ part =>
7
+ part &&
8
+ typeof part === 'object' &&
9
+ 'type' in part &&
10
+ part.type === 'tool-call' &&
11
+ 'toolCallId' in part &&
12
+ part.toolCallId === targetToolCallId,
13
+ );
14
+ };
15
+
16
+ const getToolResultIndexById = (id: string, results: MessageType[]) =>
17
+ results.findIndex(message => {
18
+ if (!Array.isArray(message?.content)) return false;
19
+ return message.content.some(
20
+ part =>
21
+ part &&
22
+ typeof part === 'object' &&
23
+ 'type' in part &&
24
+ part.type === 'tool-result' &&
25
+ 'toolCallId' in part &&
26
+ part.toolCallId === id,
27
+ );
28
+ });
29
+
30
+ /**
31
+ * Self-heals message ordering to ensure tool calls are directly before their matching tool results.
32
+ * This is needed due to a bug where messages were saved in the wrong order. That bug is fixed, but this code ensures any tool calls saved in the wrong order in the past will still be usable now.
33
+ */
34
+ export function reorderToolCallsAndResults(messages: MessageType[]): MessageType[] {
35
+ if (!messages.length) return messages;
36
+
37
+ // Create a copy of messages to avoid modifying the original
38
+ const results = [...messages];
39
+
40
+ const toolCallIds = new Set<string>();
41
+
42
+ // First loop: collect all tool result IDs in a set
43
+ for (const message of results) {
44
+ if (!Array.isArray(message.content)) continue;
45
+
46
+ for (const part of message.content) {
47
+ if (
48
+ part &&
49
+ typeof part === 'object' &&
50
+ 'type' in part &&
51
+ part.type === 'tool-result' &&
52
+ 'toolCallId' in part &&
53
+ part.toolCallId
54
+ ) {
55
+ toolCallIds.add(part.toolCallId);
56
+ }
57
+ }
58
+ }
59
+
60
+ // Second loop: for each tool ID, ensure tool calls come before tool results
61
+ for (const toolCallId of toolCallIds) {
62
+ // Find tool result index
63
+ const resultIndex = getToolResultIndexById(toolCallId, results);
64
+
65
+ // Check if tool call is at resultIndex - 1
66
+ const oneMessagePrev = results[resultIndex - 1];
67
+ if (isToolCallWithId(oneMessagePrev, toolCallId)) {
68
+ continue; // Tool call is already in the correct position
69
+ }
70
+
71
+ // Find the tool call anywhere in the array
72
+ const toolCallIndex = results.findIndex(message => isToolCallWithId(message, toolCallId));
73
+
74
+ if (toolCallIndex !== -1 && toolCallIndex !== resultIndex - 1) {
75
+ // Store the tool call message
76
+ const toolCall = results[toolCallIndex];
77
+ if (!toolCall) continue;
78
+
79
+ // Remove the tool call from its current position
80
+ results.splice(toolCallIndex, 1);
81
+
82
+ // Insert right before the tool result
83
+ results.splice(getToolResultIndexById(toolCallId, results), 0, toolCall);
84
+ }
85
+ }
86
+
87
+ return results;
88
+ }