@mastra/memory 1.39.0 → 1.39.1-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.
Files changed (55) hide show
  1. package/dist/docs/SKILL.md +2 -1
  2. package/dist/docs/assets/SOURCE_MAP.json +56 -56
  3. package/dist/docs/references/docs-agents-human-in-the-loop.md +18 -5
  4. package/dist/docs/references/docs-agents-networks.md +1 -1
  5. package/dist/docs/references/docs-guides-context-engineering.md +13 -6
  6. package/dist/docs/references/docs-harness-background-tasks.md +3 -3
  7. package/dist/docs/references/docs-harness-goals.md +5 -5
  8. package/dist/docs/references/docs-memory-memory-processors.md +7 -7
  9. package/dist/docs/references/docs-memory-message-history.md +5 -5
  10. package/dist/docs/references/docs-memory-multi-user-threads.md +1 -1
  11. package/dist/docs/references/docs-memory-observational-memory.md +14 -14
  12. package/dist/docs/references/docs-memory-semantic-recall.md +2 -2
  13. package/dist/docs/references/docs-memory-working-memory.md +2 -2
  14. package/dist/docs/references/docs-signals-overview.md +94 -0
  15. package/dist/docs/references/docs-storage.md +1 -1
  16. package/dist/docs/references/docs-subagents.md +6 -6
  17. package/dist/docs/references/integrations-channels-github.md +2 -2
  18. package/dist/docs/references/integrations-databases-aurora-dsql.md +1 -1
  19. package/dist/docs/references/integrations-databases-elasticsearch.md +1 -1
  20. package/dist/docs/references/integrations-databases-mongodb.md +1 -1
  21. package/dist/docs/references/integrations-databases-oracledb.md +1 -1
  22. package/dist/docs/references/integrations-databases-postgresql.md +1 -1
  23. package/dist/docs/references/integrations-databases-redis.md +1 -1
  24. package/dist/docs/references/integrations-databases-upstash.md +1 -1
  25. package/dist/docs/references/reference-memory-memory-class.md +3 -3
  26. package/dist/docs/references/reference-memory-observational-memory.md +16 -16
  27. package/dist/docs/references/reference-memory-summarizeConversation.md +3 -3
  28. package/dist/docs/references/reference-memory-summarizeThread.md +3 -3
  29. package/dist/docs/references/reference-migrations-agentnetwork.md +4 -4
  30. package/dist/docs/references/reference-processors-token-limiter-processor.md +4 -4
  31. package/dist/docs/references/reference-vectors-libsql.md +1 -1
  32. package/dist/docs/references/reference-vectors-mongodb.md +2 -2
  33. package/dist/docs/references/reference-vectors-oracledb.md +2 -2
  34. package/dist/docs/references/reference-vectors-pg.md +1 -1
  35. package/dist/docs/references/reference-vectors-upstash.md +1 -1
  36. package/dist/index.cjs +1 -1
  37. package/dist/index.d.ts +4 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +1 -1
  40. package/dist/persistence-projection.test-utils.d.ts +3 -0
  41. package/dist/persistence-projection.test-utils.d.ts.map +1 -0
  42. package/dist/processors/index.cjs +1 -1
  43. package/dist/processors/index.js +1 -1
  44. package/dist/processors/observational-memory/measure-image-buffer.d.ts.map +1 -1
  45. package/dist/processors/observational-memory/observation-turn/step.d.ts +7 -0
  46. package/dist/processors/observational-memory/observation-turn/step.d.ts.map +1 -1
  47. package/dist/processors/observational-memory/observation-turn/turn.d.ts +0 -6
  48. package/dist/processors/observational-memory/observation-turn/turn.d.ts.map +1 -1
  49. package/dist/processors/observational-memory/processor.d.ts +1 -0
  50. package/dist/processors/observational-memory/processor.d.ts.map +1 -1
  51. package/dist/{src-DxZ7N8nO.js → src-BUWL69LT.js} +129 -31
  52. package/dist/{src-DxZ7N8nO.js.map → src-BUWL69LT.js.map} +1 -1
  53. package/dist/{src-IWcrqO0n.cjs → src-BjH9gT88.cjs} +129 -31
  54. package/dist/{src-IWcrqO0n.cjs.map → src-BjH9gT88.cjs.map} +1 -1
  55. package/package.json +10 -10
@@ -36668,7 +36668,6 @@ var ObservationStep = class {
36668
36668
  let observerExchange;
36669
36669
  const step0Messages = this.stepNumber === 0 ? getObservableMessages(messageList) : [];
36670
36670
  if (this.stepNumber === 0) {
36671
- this.turn.inputMessageIds = messageList.get.input.db().map((msg) => msg.id);
36672
36671
  const activation = await om.activate({
36673
36672
  threadId,
36674
36673
  resourceId,
@@ -36799,7 +36798,7 @@ var ObservationStep = class {
36799
36798
  drainedKeys.set(msg.id, /* @__PURE__ */ new Set([...seen ?? [], ...keys]));
36800
36799
  return !seen || keys.some((key) => !seen.has(key));
36801
36800
  }).map((msg) => msg.id);
36802
- inFlightIds = [.../* @__PURE__ */ new Set([...this.turn.inputMessageIds, ...unreadIds])];
36801
+ inFlightIds = [...new Set(unreadIds)];
36803
36802
  if (messagesToSave.length > 0) {
36804
36803
  for (const msg of messagesToSave) messageList.add(msg, "memory");
36805
36804
  try {
@@ -36876,7 +36875,7 @@ var ObservationStep = class {
36876
36875
  });
36877
36876
  if (!didThresholdCleanup) {
36878
36877
  const fallbackCursor = this.turn.record.threadId ? (0, _mastra_core_memory.getThreadOMMetadata)((await om.getStorage().getThreadById({ threadId: this.turn.record.threadId }))?.metadata)?.lastObservedMessageCursor : void 0;
36879
- const pendingMessageIds = new Set([...messageList.get.input.db(), ...messageList.get.response.db()].map((msg) => msg.id).concat(inFlightIds ?? [], this.turn.inputMessageIds, this.changedSinceDrain(messageList)).filter(Boolean));
36878
+ const pendingMessageIds = new Set([...messageList.get.input.db(), ...messageList.get.response.db()].map((msg) => msg.id).concat(inFlightIds ?? [], this.changedSinceDrain(messageList)).filter(Boolean));
36880
36879
  filterObservedMessages({
36881
36880
  messageList,
36882
36881
  record: this.turn.record,
@@ -37162,12 +37161,6 @@ var ObservationTurn = class {
37162
37161
  /** Generation count at turn start — used to detect if reflection happened during the turn. */
37163
37162
  _generationCountAtStart = -1;
37164
37163
  /**
37165
- * Ids of the messages this turn was started with (the user's request). Mid-turn
37166
- * observation may record them, but they stay in the live prompt until the turn ends.
37167
- * @internal Set by step 0.
37168
- */
37169
- inputMessageIds = [];
37170
- /**
37171
37164
  * Fingerprints of the non-marker parts each message had when a step last drained it. A message
37172
37165
  * is unread step output only if it gained a part the model has not seen — including a tool result
37173
37166
  * merged in place into an existing tool-invocation part — not when it only gained OM markers.
@@ -41937,6 +41930,29 @@ var ObservationalMemoryProcessor = class {
41937
41930
  this.turn.agent = args.agent;
41938
41931
  this.turn.requestContext = requestContext;
41939
41932
  await this.turn.start(this.memory, runState);
41933
+ if (stepNumber > 0) {
41934
+ if (this.memory?.getPersistedMessages) {
41935
+ const responseIds = messageList.getPersisted.response.db().map((message) => message.id);
41936
+ const snapshotMessages = new Map(messageList.get.all.db().map((message) => [message.id, message]));
41937
+ const storedMessages = await this.memory.getPersistedMessages(threadId, responseIds);
41938
+ for (const stored of storedMessages) {
41939
+ const snapshot = snapshotMessages.get(stored.id);
41940
+ if (!snapshot) continue;
41941
+ const snapshotTools = snapshot.content.parts.filter((part) => part.type === "tool-invocation");
41942
+ if (stored.content.parts.some((part) => {
41943
+ if (part.type !== "tool-invocation" || part.toolInvocation.state !== "result") return false;
41944
+ const previous = snapshotTools.find((candidate) => candidate.toolInvocation.toolCallId === part.toolInvocation.toolCallId);
41945
+ if (!previous || previous.toolInvocation.state !== "result") return true;
41946
+ const previousTask = previous.providerMetadata?.mastra?.backgroundTask;
41947
+ const storedTask = part.providerMetadata?.mastra?.backgroundTask;
41948
+ return previousTask?.status === "running" && (storedTask?.status === "completed" || storedTask?.status === "failed");
41949
+ })) {
41950
+ this.turn.drainedPartKeys.set(stored.id, new Set(getPartKeys(snapshot)));
41951
+ messageList.add(stored, "memory");
41952
+ }
41953
+ }
41954
+ }
41955
+ }
41940
41956
  const observedIds = this.turn.record.observedMessageIds;
41941
41957
  const response = messageId ? messageList.get.all.db().find((message) => message.id === messageId) : void 0;
41942
41958
  const responseSealed = (response?.content?.metadata)?.mastra?.sealed === true;
@@ -42081,6 +42097,7 @@ var ObservationalMemoryProcessor = class {
42081
42097
  writer: args.writer,
42082
42098
  observabilityContext: getOmObservabilityContext(args)
42083
42099
  }));
42100
+ if (observed) args.rotateResponseMessageId?.();
42084
42101
  return { retry: activated || observed };
42085
42102
  }
42086
42103
  get config() {
@@ -43166,9 +43183,7 @@ ${workingMemory}`;
43166
43183
  async saveMessages({ messages, memoryConfig, observabilityContext }) {
43167
43184
  const span = this.createMemorySpan("save", observabilityContext, void 0, { messageCount: messages.length });
43168
43185
  try {
43169
- const updatedMessages = messages.filter((m) => m.role !== "system" && !isTransientSignalMessage(m)).map((m) => {
43170
- return this.updateMessageToHideWorkingMemoryV2(m);
43171
- }).filter((m) => Boolean(m));
43186
+ const updatedMessages = this.prepareMessagesForPersistence(messages);
43172
43187
  const config = this.getMergedThreadConfig(memoryConfig);
43173
43188
  const dbMessages = new _mastra_core_agent.MessageList({ generateMessageId: () => this.generateId() }).add(updatedMessages, "memory").get.all.db();
43174
43189
  const memoryStore = await this.getMemoryStore();
@@ -43274,12 +43289,17 @@ ${workingMemory}`;
43274
43289
  throw error;
43275
43290
  }
43276
43291
  }
43292
+ prepareMessagesForPersistence(messages) {
43293
+ return messages.filter((m) => m.role !== "system" && !isTransientSignalMessage(m)).map((m) => this.updateMessageToHideWorkingMemoryV2(m)).filter((m) => m !== null);
43294
+ }
43277
43295
  updateMessageToHideWorkingMemoryV2(message) {
43278
43296
  const newMessage = { ...message };
43279
43297
  if (message.content && typeof message.content === "object" && !Array.isArray(message.content)) newMessage.content = { ...message.content };
43280
43298
  if (typeof newMessage.content?.content === "string" && newMessage.content.content.length > 0) newMessage.content.content = removeWorkingMemoryTags(newMessage.content.content).trim();
43281
43299
  if (Array.isArray(newMessage.content?.parts)) {
43282
43300
  if (Array.isArray(newMessage.content.toolInvocations)) newMessage.content.toolInvocations = removeWorkingMemoryToolInvocations(newMessage.content.toolInvocations);
43301
+ const lastOriginalPart = newMessage.content.parts.at(-1);
43302
+ const sealMetadata = lastOriginalPart && "metadata" in lastOriginalPart ? lastOriginalPart.metadata : void 0;
43283
43303
  newMessage.content.parts = removeWorkingMemoryToolInvocationParts(newMessage.content.parts).map((part) => {
43284
43304
  if (part?.type === "text") {
43285
43305
  const text = typeof part.text === "string" ? part.text : "";
@@ -43290,6 +43310,26 @@ ${workingMemory}`;
43290
43310
  }
43291
43311
  return part;
43292
43312
  });
43313
+ const lastIndex = newMessage.content.parts.length - 1;
43314
+ const lastPart = newMessage.content.parts[lastIndex];
43315
+ if (lastPart && sealMetadata && typeof sealMetadata === "object" && "mastra" in sealMetadata) {
43316
+ const mastra = sealMetadata.mastra;
43317
+ if (mastra && typeof mastra === "object" && "sealedAt" in mastra && typeof mastra.sealedAt === "number") {
43318
+ const existingMetadata = "metadata" in lastPart ? lastPart.metadata : void 0;
43319
+ const metadata = existingMetadata && typeof existingMetadata === "object" ? existingMetadata : {};
43320
+ const existingMastra = "mastra" in metadata && metadata.mastra && typeof metadata.mastra === "object" ? metadata.mastra : {};
43321
+ newMessage.content.parts[lastIndex] = {
43322
+ ...lastPart,
43323
+ metadata: {
43324
+ ...metadata,
43325
+ mastra: {
43326
+ ...existingMastra,
43327
+ sealedAt: mastra.sealedAt
43328
+ }
43329
+ }
43330
+ };
43331
+ }
43332
+ }
43293
43333
  if (newMessage.content.parts.length === 0) {
43294
43334
  if (!(typeof newMessage.content.content === "string" && newMessage.content.content.trim().length > 0)) return null;
43295
43335
  }
@@ -43370,6 +43410,16 @@ ${workingMemory}`;
43370
43410
  data: workingMemoryData
43371
43411
  });
43372
43412
  }
43413
+ /** Fetch current stored copies of messages in a resumed turn, bypassing run-state history caches. */
43414
+ async getPersistedMessages(threadId, ids) {
43415
+ if (!ids.length) return [];
43416
+ return (await (await this.getMemoryStore()).listMessages({
43417
+ threadId,
43418
+ perPage: 0,
43419
+ include: ids.map((id) => ({ id })),
43420
+ includeTotal: false
43421
+ })).messages.filter((message) => ids.includes(message.id));
43422
+ }
43373
43423
  /**
43374
43424
  * Get everything needed for an LLM call in one shot.
43375
43425
  *
@@ -43529,12 +43579,12 @@ ${workingMemory}`;
43529
43579
  };
43530
43580
  }
43531
43581
  /**
43532
- * Raw message upsert — persist messages to storage without embedding or working memory processing.
43582
+ * Raw message upsert — apply the persistence projection without embedding or extracting working memory.
43533
43583
  * Used by the processor to save sealed messages before firing a background buffer operation.
43534
43584
  */
43535
43585
  async persistMessages(messages) {
43536
43586
  if (messages.length === 0) return;
43537
- const persistableMessages = messages.filter((m) => m.role !== "system" && !isTransientSignalMessage(m));
43587
+ const persistableMessages = this.prepareMessagesForPersistence(messages);
43538
43588
  if (persistableMessages.length === 0) return;
43539
43589
  await (await this.getMemoryStore()).saveMessages({ messages: persistableMessages });
43540
43590
  }
@@ -44016,27 +44066,75 @@ Notes:
44016
44066
  if (messages.length === 0) return [];
44017
44067
  const memoryStore = await this.getMemoryStore();
44018
44068
  const config = this.getMergedThreadConfig(memoryConfig);
44069
+ const existing = await memoryStore.listMessagesById({ messageIds: messages.map((m) => m.id) });
44070
+ const existingById = new Map(existing.messages.map((m) => [m.id, m]));
44071
+ const textForEmbeddingById = /* @__PURE__ */ new Map();
44072
+ const textFields = ["content", "parts"];
44073
+ const textOf = (content, fields) => {
44074
+ for (const field of fields) {
44075
+ const text = field === "content" ? content.content?.trim() ? content.content : null : (content.parts ?? []).filter((part) => part?.type === "text").map((part) => part.text).join(" ").trim();
44076
+ if (text) return text;
44077
+ }
44078
+ return null;
44079
+ };
44080
+ messages = messages.flatMap((update) => {
44081
+ const stored = existingById.get(update.id);
44082
+ if (!stored) return [];
44083
+ const effective = {
44084
+ ...stored,
44085
+ ...update,
44086
+ content: update.content === void 0 ? stored.content : {
44087
+ ...stored.content,
44088
+ ...update.content,
44089
+ metadata: {
44090
+ ...stored.content.metadata,
44091
+ ...update.content.metadata
44092
+ }
44093
+ }
44094
+ };
44095
+ const [projected] = this.prepareMessagesForPersistence([effective]);
44096
+ if (!projected) return [];
44097
+ if (update.content === void 0) {
44098
+ existingById.set(update.id, effective);
44099
+ return [update];
44100
+ }
44101
+ const content = {
44102
+ ...update.content,
44103
+ ...update.content.parts !== void 0 ? { parts: projected.content.parts } : {},
44104
+ ...update.content.content !== void 0 ? { content: projected.content.content } : {},
44105
+ ...update.content.toolInvocations !== void 0 ? { toolInvocations: projected.content.toolInvocations } : {}
44106
+ };
44107
+ existingById.set(update.id, {
44108
+ ...effective,
44109
+ content: {
44110
+ ...effective.content,
44111
+ ...content
44112
+ }
44113
+ });
44114
+ const patched = textFields.filter((field) => update.content?.[field] !== void 0);
44115
+ if (patched.length > 0) {
44116
+ const omitted = textFields.filter((field) => !patched.includes(field));
44117
+ const text = textOf(projected.content, patched) ?? (textOf(update.content, patched) ? textOf(projected.content, omitted) : null);
44118
+ textForEmbeddingById.set(update.id, text);
44119
+ }
44120
+ return [{
44121
+ ...update,
44122
+ content
44123
+ }];
44124
+ });
44125
+ if (messages.length === 0) return [];
44019
44126
  if (this.vector && config.semanticRecall) {
44020
- const messagesWithContent = messages.filter((m) => m.content !== void 0);
44021
- if (messagesWithContent.length > 0) {
44022
- const existingMessagesResult = await memoryStore.listMessagesById({ messageIds: messagesWithContent.map((m) => m.id) });
44023
- const existingMessagesMap = new Map(existingMessagesResult.messages.map((m) => [m.id, m]));
44127
+ const messagesWithTextUpdates = [...textForEmbeddingById.keys()].map((id) => ({ id }));
44128
+ if (messagesWithTextUpdates.length > 0) {
44129
+ const existingMessagesMap = new Map(existing.messages.map((m) => [m.id, m]));
44024
44130
  const embeddingData = [];
44025
44131
  let dimension;
44026
44132
  const messageIdsWithNewEmbeddings = /* @__PURE__ */ new Set();
44027
44133
  const messageIdsWithClearedContent = /* @__PURE__ */ new Set();
44028
- await Promise.all(messagesWithContent.map(async (message) => {
44134
+ await Promise.all(messagesWithTextUpdates.map(async (message) => {
44029
44135
  const existingMessage = existingMessagesMap.get(message.id);
44030
44136
  if (!existingMessage) return;
44031
- let textForEmbedding = null;
44032
- const content = message.content;
44033
- if (content) {
44034
- if ("content" in content && content.content && typeof content.content === "string" && content.content.trim() !== "") textForEmbedding = content.content;
44035
- else if ("parts" in content && content.parts && Array.isArray(content.parts) && content.parts.length > 0) {
44036
- const joined = content.parts.filter((part) => part?.type === "text").map((part) => part.text).join(" ").trim();
44037
- if (joined) textForEmbedding = joined;
44038
- }
44039
- }
44137
+ const textForEmbedding = textForEmbeddingById.get(message.id) ?? null;
44040
44138
  if (textForEmbedding) {
44041
44139
  let embeddings = [];
44042
44140
  let documents;
@@ -44739,9 +44837,9 @@ Notes:
44739
44837
  if (configuredProcessors.some((p) => !("workflow" in p) && p.id === "observational-memory")) return null;
44740
44838
  const runtimeMemory = context?.get("MastraMemory");
44741
44839
  const runtimeObservationalMemory = normalizeObservationalMemoryConfig(runtimeMemory?.memoryConfig?.observationalMemory);
44742
- const effectiveConfig = normalizeObservationalMemoryConfig((runtimeObservationalMemory ? this.getMergedThreadConfig({
44840
+ const effectiveConfig = normalizeObservationalMemoryConfig((runtimeMemory?.memoryConfig?.observationalMemory !== void 0 ? this.getMergedThreadConfig({
44743
44841
  ...runtimeMemory?.memoryConfig,
44744
- observationalMemory: runtimeObservationalMemory
44842
+ observationalMemory: runtimeObservationalMemory ?? false
44745
44843
  }) : this.threadConfig).observationalMemory);
44746
44844
  if (!effectiveConfig) return null;
44747
44845
  const engine = await this.omEngine;
@@ -45088,4 +45186,4 @@ Object.defineProperty(exports, "wrapInObservationGroup", {
45088
45186
  }
45089
45187
  });
45090
45188
 
45091
- //# sourceMappingURL=src-IWcrqO0n.cjs.map
45189
+ //# sourceMappingURL=src-BjH9gT88.cjs.map