@mastra/memory 1.5.2 → 1.6.0-alpha.0

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.
Files changed (30) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/LICENSE.md +15 -0
  3. package/dist/{chunk-PVFLHAZX.cjs → chunk-5UYAHJVJ.cjs} +77 -73
  4. package/dist/chunk-5UYAHJVJ.cjs.map +1 -0
  5. package/dist/{chunk-HNPAIFCZ.js → chunk-A62BQK35.js} +77 -73
  6. package/dist/chunk-A62BQK35.js.map +1 -0
  7. package/dist/docs/SKILL.md +1 -1
  8. package/dist/docs/assets/SOURCE_MAP.json +16 -16
  9. package/dist/docs/references/docs-memory-observational-memory.md +3 -5
  10. package/dist/docs/references/reference-memory-cloneThread.md +13 -1
  11. package/dist/docs/references/reference-memory-observational-memory.md +4 -2
  12. package/dist/index.cjs +106 -7
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.ts +15 -0
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +106 -7
  17. package/dist/index.js.map +1 -1
  18. package/dist/{observational-memory-Q47HN5YL.cjs → observational-memory-MXI54VC7.cjs} +17 -17
  19. package/dist/{observational-memory-Q47HN5YL.cjs.map → observational-memory-MXI54VC7.cjs.map} +1 -1
  20. package/dist/{observational-memory-KAFD4QZK.js → observational-memory-SR6G4HN5.js} +3 -3
  21. package/dist/{observational-memory-KAFD4QZK.js.map → observational-memory-SR6G4HN5.js.map} +1 -1
  22. package/dist/processors/index.cjs +15 -15
  23. package/dist/processors/index.js +1 -1
  24. package/dist/processors/observational-memory/observational-memory.d.ts +3 -4
  25. package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
  26. package/dist/processors/observational-memory/types.d.ts +8 -2
  27. package/dist/processors/observational-memory/types.d.ts.map +1 -1
  28. package/package.json +6 -6
  29. package/dist/chunk-HNPAIFCZ.js.map +0 -1
  30. package/dist/chunk-PVFLHAZX.cjs.map +0 -1
@@ -3,7 +3,7 @@ name: mastra-memory
3
3
  description: Documentation for @mastra/memory. Use when working with @mastra/memory APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/memory"
6
- version: "1.5.2"
6
+ version: "1.6.0-alpha.0"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,70 +1,70 @@
1
1
  {
2
- "version": "1.5.2",
2
+ "version": "1.6.0-alpha.0",
3
3
  "package": "@mastra/memory",
4
4
  "exports": {
5
5
  "OBSERVATIONAL_MEMORY_DEFAULTS": {
6
6
  "types": "dist/processors/index.d.ts",
7
- "implementation": "dist/chunk-HNPAIFCZ.js"
7
+ "implementation": "dist/chunk-A62BQK35.js"
8
8
  },
9
9
  "OBSERVATION_CONTEXT_INSTRUCTIONS": {
10
10
  "types": "dist/processors/index.d.ts",
11
- "implementation": "dist/chunk-HNPAIFCZ.js"
11
+ "implementation": "dist/chunk-A62BQK35.js"
12
12
  },
13
13
  "OBSERVATION_CONTEXT_PROMPT": {
14
14
  "types": "dist/processors/index.d.ts",
15
- "implementation": "dist/chunk-HNPAIFCZ.js"
15
+ "implementation": "dist/chunk-A62BQK35.js"
16
16
  },
17
17
  "OBSERVATION_CONTINUATION_HINT": {
18
18
  "types": "dist/processors/index.d.ts",
19
- "implementation": "dist/chunk-HNPAIFCZ.js"
19
+ "implementation": "dist/chunk-A62BQK35.js"
20
20
  },
21
21
  "OBSERVER_SYSTEM_PROMPT": {
22
22
  "types": "dist/processors/index.d.ts",
23
- "implementation": "dist/chunk-HNPAIFCZ.js"
23
+ "implementation": "dist/chunk-A62BQK35.js"
24
24
  },
25
25
  "ObservationalMemory": {
26
26
  "types": "dist/processors/index.d.ts",
27
- "implementation": "dist/chunk-HNPAIFCZ.js",
27
+ "implementation": "dist/chunk-A62BQK35.js",
28
28
  "line": 1258
29
29
  },
30
30
  "TokenCounter": {
31
31
  "types": "dist/processors/index.d.ts",
32
- "implementation": "dist/chunk-HNPAIFCZ.js",
32
+ "implementation": "dist/chunk-A62BQK35.js",
33
33
  "line": 919
34
34
  },
35
35
  "buildObserverPrompt": {
36
36
  "types": "dist/processors/index.d.ts",
37
- "implementation": "dist/chunk-HNPAIFCZ.js",
37
+ "implementation": "dist/chunk-A62BQK35.js",
38
38
  "line": 533
39
39
  },
40
40
  "buildObserverSystemPrompt": {
41
41
  "types": "dist/processors/index.d.ts",
42
- "implementation": "dist/chunk-HNPAIFCZ.js",
42
+ "implementation": "dist/chunk-A62BQK35.js",
43
43
  "line": 281
44
44
  },
45
45
  "extractCurrentTask": {
46
46
  "types": "dist/processors/index.d.ts",
47
- "implementation": "dist/chunk-HNPAIFCZ.js",
47
+ "implementation": "dist/chunk-A62BQK35.js",
48
48
  "line": 662
49
49
  },
50
50
  "formatMessagesForObserver": {
51
51
  "types": "dist/processors/index.d.ts",
52
- "implementation": "dist/chunk-HNPAIFCZ.js",
52
+ "implementation": "dist/chunk-A62BQK35.js",
53
53
  "line": 376
54
54
  },
55
55
  "hasCurrentTaskSection": {
56
56
  "types": "dist/processors/index.d.ts",
57
- "implementation": "dist/chunk-HNPAIFCZ.js",
57
+ "implementation": "dist/chunk-A62BQK35.js",
58
58
  "line": 650
59
59
  },
60
60
  "optimizeObservationsForContext": {
61
61
  "types": "dist/processors/index.d.ts",
62
- "implementation": "dist/chunk-HNPAIFCZ.js",
62
+ "implementation": "dist/chunk-A62BQK35.js",
63
63
  "line": 673
64
64
  },
65
65
  "parseObserverOutput": {
66
66
  "types": "dist/processors/index.d.ts",
67
- "implementation": "dist/chunk-HNPAIFCZ.js",
67
+ "implementation": "dist/chunk-A62BQK35.js",
68
68
  "line": 564
69
69
  },
70
70
  "extractWorkingMemoryContent": {
@@ -96,7 +96,7 @@
96
96
  "processors": {
97
97
  "index": "dist/processors/index.js",
98
98
  "chunks": [
99
- "chunk-HNPAIFCZ.js"
99
+ "chunk-A62BQK35.js"
100
100
  ]
101
101
  }
102
102
  }
@@ -85,13 +85,11 @@ The result is a three-tier system:
85
85
 
86
86
  ## Models
87
87
 
88
- The Observer and Reflector run in the background. Any model that works with Mastra's model routing (e.g. `openai/...`, `google/...`, `deepseek/...`) can be used.
88
+ The Observer and Reflector run in the background. Any model that works with Mastra's [model routing](https://mastra.ai/models) (`provider/model`) can be used. When using `observationalMemory: true`, the default model is `google/gemini-2.5-flash`. When passing a config object, a `model` must be explicitly set.
89
89
 
90
- When using `observationalMemory: true`, the default model is `google/gemini-2.5-flash`. When passing a config object, a `model` must be explicitly set.
90
+ Generally speaking, we recommend using a model that has a large context window (128K+ tokens) and is fast enough to run in the background without slowing down your actions.
91
91
 
92
- We recommend `google/gemini-2.5-flash` it works well for both observation and reflection, and its 1M token context window gives the Reflector headroom.
93
-
94
- We've also tested `deepseek`, `qwen3`, and `glm-4.7` for the Observer. For the Reflector, make sure the model's context window can fit all observations. Note that Claude 4.5 models currently don't work well as observer or reflector.
92
+ If you're unsure which model to use, start with the default `google/gemini-2.5-flash`. We've also successfully tested `openai/gpt-5-mini`, `anthropic/claude-haiku-4-5`, `deepseek/deepseek-reasoner`, `qwen3`, and `glm-4.7`.
95
93
 
96
94
  ```typescript
97
95
  const memory = new Memory({
@@ -44,6 +44,8 @@ const { thread, clonedMessages } = await memory.cloneThread({
44
44
 
45
45
  **clonedMessages:** (`MastraDBMessage[]`): Array of the cloned messages with new IDs assigned to the new thread.
46
46
 
47
+ **messageIdMap?:** (`Record<string, string>`): A mapping from source message IDs to their corresponding cloned message IDs.
48
+
47
49
  ### Clone Metadata
48
50
 
49
51
  The cloned thread's metadata includes a `clone` property with:
@@ -127,4 +129,14 @@ const results = await memory.recall({
127
129
  threadId: thread.id,
128
130
  vectorSearchString: 'search query',
129
131
  })
130
- ```
132
+ ```
133
+
134
+ ## Observational Memory
135
+
136
+ When [Observational Memory](https://mastra.ai/docs/memory/observational-memory) is enabled, `cloneThread()` automatically clones the OM records associated with the source thread. The behavior depends on the OM scope:
137
+
138
+ - **Thread-scoped OM**: The OM record is cloned to the new thread. All internal message ID references are remapped to point to the cloned messages.
139
+ - **Resource-scoped OM (same `resourceId`)**: The OM record is shared between the source and cloned threads since they belong to the same resource. No duplication occurs.
140
+ - **Resource-scoped OM (different `resourceId`)**: The OM record is cloned to the new resource. Message IDs are remapped and any thread-identifying tags within observations are updated to reference the cloned thread.
141
+
142
+ Only the current (most recent) OM generation is cloned — older history generations are not copied. Transient processing state (observation/reflection in-progress flags) is reset on the cloned record.
@@ -107,6 +107,8 @@ export const agent = new Agent({
107
107
 
108
108
  ### Shared token budget
109
109
 
110
+ When `shareTokenBudget` is enabled, the total budget is `observation.messageTokens + reflection.observationTokens` (100k in this example). If observations only use 30k tokens, messages can expand to use up to 70k. If messages are short, observations have more room before triggering reflection.
111
+
110
112
  ```typescript
111
113
  import { Memory } from '@mastra/memory'
112
114
  import { Agent } from '@mastra/core/agent'
@@ -132,10 +134,10 @@ export const agent = new Agent({
132
134
  })
133
135
  ```
134
136
 
135
- When `shareTokenBudget` is enabled, the total budget is `observation.messageTokens + reflection.observationTokens` (100k in this example). If observations only use 30k tokens, messages can expand to use up to 70k. If messages are short, observations have more room before triggering reflection.
136
-
137
137
  ### Custom model
138
138
 
139
+ By passing a `model` in the config, you can use any model from Mastra's model router.
140
+
139
141
  ```typescript
140
142
  import { Memory } from '@mastra/memory'
141
143
  import { Agent } from '@mastra/core/agent'
package/dist/index.cjs CHANGED
@@ -15364,7 +15364,8 @@ var Memory = class extends memory.MastraMemory {
15364
15364
  const rawMessages = shouldGetNewestAndReverse ? paginatedResult.messages.reverse() : paginatedResult.messages;
15365
15365
  const list = new agent.MessageList({ threadId, resourceId }).add(rawMessages, "memory");
15366
15366
  const messages = list.get.all.db();
15367
- return { messages, usage };
15367
+ const { total, page: resultPage, perPage: resultPerPage, hasMore } = paginatedResult;
15368
+ return { messages, usage, total, page: resultPage, perPage: resultPerPage, hasMore };
15368
15369
  }
15369
15370
  async getThreadById({ threadId }) {
15370
15371
  const memoryStore = await this.getMemoryStore();
@@ -16119,13 +16120,10 @@ Notes:
16119
16120
  const memoryStore = await this.getMemoryStore();
16120
16121
  const result = await memoryStore.cloneThread(args);
16121
16122
  const config = this.getMergedThreadConfig(memoryConfig);
16122
- if (this.vector && config.semanticRecall && result.clonedMessages.length > 0) {
16123
- await this.embedClonedMessages(result.clonedMessages, config);
16124
- }
16123
+ const sourceThread = await this.getThreadById({ threadId: args.sourceThreadId });
16124
+ const sourceResourceId = sourceThread?.resourceId;
16125
16125
  if (config.workingMemory?.enabled) {
16126
16126
  const scope = config.workingMemory.scope || "resource";
16127
- const sourceThread = await this.getThreadById({ threadId: args.sourceThreadId });
16128
- const sourceResourceId = sourceThread?.resourceId;
16129
16127
  const shouldCopy = scope === "thread" || scope === "resource" && args.resourceId && args.resourceId !== sourceResourceId;
16130
16128
  if (shouldCopy) {
16131
16129
  const sourceWm = await this.getWorkingMemory({
@@ -16143,8 +16141,109 @@ Notes:
16143
16141
  }
16144
16142
  }
16145
16143
  }
16144
+ if (memoryStore.supportsObservationalMemory && sourceResourceId) {
16145
+ try {
16146
+ await this.cloneObservationalMemory(memoryStore, args.sourceThreadId, sourceResourceId, result);
16147
+ } catch (error) {
16148
+ try {
16149
+ await memoryStore.deleteThread({ threadId: result.thread.id });
16150
+ } catch (rollbackError) {
16151
+ this.logger.error("Failed to rollback cloned thread after OM clone failure", rollbackError);
16152
+ }
16153
+ throw error;
16154
+ }
16155
+ }
16156
+ if (this.vector && config.semanticRecall && result.clonedMessages.length > 0) {
16157
+ await this.embedClonedMessages(result.clonedMessages, config);
16158
+ }
16146
16159
  return result;
16147
16160
  }
16161
+ /**
16162
+ * Clone observational memory records when cloning a thread.
16163
+ * Thread-scoped: always cloned to the new thread.
16164
+ * Resource-scoped: cloned only when the resourceId changes (same resourceId shares OM naturally).
16165
+ * All stored message/thread IDs are remapped to the cloned IDs.
16166
+ */
16167
+ async cloneObservationalMemory(memoryStore, sourceThreadId, sourceResourceId, result) {
16168
+ let sourceOM = await memoryStore.getObservationalMemory(sourceThreadId, sourceResourceId);
16169
+ if (!sourceOM) {
16170
+ sourceOM = await memoryStore.getObservationalMemory(null, sourceResourceId);
16171
+ }
16172
+ if (!sourceOM) return;
16173
+ const clonedThreadId = result.thread.id;
16174
+ const clonedResourceId = result.thread.resourceId;
16175
+ const resourceChanged = clonedResourceId !== sourceResourceId;
16176
+ if (sourceOM.scope === "resource" && !resourceChanged) return;
16177
+ const messageIdMap = result.messageIdMap ?? {};
16178
+ const hasher = await this.hasher;
16179
+ const cloned = this.remapObservationalMemoryRecord(sourceOM, {
16180
+ newThreadId: sourceOM.scope === "thread" ? clonedThreadId : null,
16181
+ newResourceId: clonedResourceId,
16182
+ messageIdMap,
16183
+ sourceThreadId: resourceChanged ? sourceThreadId : void 0,
16184
+ clonedThreadId: resourceChanged ? clonedThreadId : void 0,
16185
+ hasher: resourceChanged ? hasher : void 0
16186
+ });
16187
+ const now = /* @__PURE__ */ new Date();
16188
+ cloned.id = crypto.randomUUID();
16189
+ cloned.createdAt = now;
16190
+ cloned.updatedAt = now;
16191
+ await memoryStore.insertObservationalMemoryRecord(cloned);
16192
+ }
16193
+ /**
16194
+ * Create a remapped copy of an OM record with new thread/message IDs.
16195
+ */
16196
+ remapObservationalMemoryRecord(record, opts) {
16197
+ const { newThreadId, newResourceId, messageIdMap, sourceThreadId, clonedThreadId, hasher } = opts;
16198
+ const cloned = { ...record };
16199
+ cloned.threadId = newThreadId;
16200
+ cloned.resourceId = newResourceId;
16201
+ if (Array.isArray(cloned.observedMessageIds)) {
16202
+ cloned.observedMessageIds = cloned.observedMessageIds.map((id) => messageIdMap[id]).filter((id) => Boolean(id));
16203
+ } else {
16204
+ cloned.observedMessageIds = void 0;
16205
+ }
16206
+ if (Array.isArray(cloned.bufferedMessageIds)) {
16207
+ cloned.bufferedMessageIds = cloned.bufferedMessageIds.map((id) => messageIdMap[id]).filter((id) => Boolean(id));
16208
+ } else {
16209
+ cloned.bufferedMessageIds = void 0;
16210
+ }
16211
+ if (Array.isArray(cloned.bufferedObservationChunks)) {
16212
+ cloned.bufferedObservationChunks = cloned.bufferedObservationChunks.map(
16213
+ (chunk) => ({
16214
+ ...chunk,
16215
+ messageIds: Array.isArray(chunk.messageIds) ? chunk.messageIds.map((id) => messageIdMap[id]).filter((id) => Boolean(id)) : []
16216
+ })
16217
+ );
16218
+ } else {
16219
+ cloned.bufferedObservationChunks = void 0;
16220
+ }
16221
+ if (sourceThreadId && clonedThreadId && hasher) {
16222
+ const sourceObscured = hasher.h32ToString(sourceThreadId);
16223
+ const clonedObscured = hasher.h32ToString(clonedThreadId);
16224
+ if (sourceObscured !== clonedObscured) {
16225
+ const replaceThreadTags = (text4) => {
16226
+ if (!text4) return text4;
16227
+ return text4.replaceAll(`<thread id="${sourceObscured}">`, `<thread id="${clonedObscured}">`);
16228
+ };
16229
+ cloned.activeObservations = replaceThreadTags(cloned.activeObservations) ?? "";
16230
+ cloned.bufferedReflection = replaceThreadTags(cloned.bufferedReflection);
16231
+ if (cloned.bufferedObservationChunks) {
16232
+ cloned.bufferedObservationChunks = cloned.bufferedObservationChunks.map(
16233
+ (chunk) => ({
16234
+ ...chunk,
16235
+ observations: replaceThreadTags(chunk.observations) ?? chunk.observations
16236
+ })
16237
+ );
16238
+ }
16239
+ }
16240
+ }
16241
+ cloned.isObserving = false;
16242
+ cloned.isReflecting = false;
16243
+ cloned.isBufferingObservation = false;
16244
+ cloned.isBufferingReflection = false;
16245
+ return cloned;
16246
+ }
16148
16247
  /**
16149
16248
  * Embed cloned messages for semantic recall.
16150
16249
  * This is similar to the embedding logic in saveMessages but operates on already-saved messages.
@@ -16377,7 +16476,7 @@ Notes:
16377
16476
  "Observational memory async buffering is enabled by default but the installed version of @mastra/core does not support it. Either upgrade @mastra/core, @mastra/memory, and your storage adapter (@mastra/libsql, @mastra/pg, or @mastra/mongodb) to the latest version, or explicitly disable async buffering by setting `observation: { bufferTokens: false }` in your observationalMemory config."
16378
16477
  );
16379
16478
  }
16380
- const { ObservationalMemory } = await import('./observational-memory-Q47HN5YL.cjs');
16479
+ const { ObservationalMemory } = await import('./observational-memory-MXI54VC7.cjs');
16381
16480
  return new ObservationalMemory({
16382
16481
  storage: memoryStore,
16383
16482
  scope: omConfig.scope,