@mastra/memory 1.27.0-alpha.3 → 1.27.1-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 (28) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/dist/docs/SKILL.md +2 -1
  3. package/dist/docs/assets/SOURCE_MAP.json +1 -1
  4. package/dist/docs/references/docs-guides-context-engineering.md +297 -0
  5. package/dist/index.cjs +1 -1
  6. package/dist/index.d.ts +6 -3
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +1 -1
  9. package/dist/processors/index.cjs +1 -1
  10. package/dist/processors/index.js +1 -1
  11. package/dist/processors/observational-memory/observation-strategies/async-buffer.d.ts.map +1 -1
  12. package/dist/processors/observational-memory/observation-strategies/sync.d.ts.map +1 -1
  13. package/dist/processors/observational-memory/observation-turn/load-memory-context.d.ts +3 -1
  14. package/dist/processors/observational-memory/observation-turn/load-memory-context.d.ts.map +1 -1
  15. package/dist/processors/observational-memory/observation-turn/turn.d.ts +2 -1
  16. package/dist/processors/observational-memory/observation-turn/turn.d.ts.map +1 -1
  17. package/dist/processors/observational-memory/observer-agent.d.ts +13 -0
  18. package/dist/processors/observational-memory/observer-agent.d.ts.map +1 -1
  19. package/dist/processors/observational-memory/observer-runner.d.ts.map +1 -1
  20. package/dist/processors/observational-memory/processor.d.ts +2 -0
  21. package/dist/processors/observational-memory/processor.d.ts.map +1 -1
  22. package/dist/processors/observational-memory/reflector-runner.d.ts.map +1 -1
  23. package/dist/processors/observational-memory/tracing.d.ts.map +1 -1
  24. package/dist/{src-t_4yoTX9.js → src-BlQjkJzk.js} +129 -44
  25. package/dist/{src-t_4yoTX9.js.map → src-BlQjkJzk.js.map} +1 -1
  26. package/dist/{src-Ik0ksTOt.cjs → src-bE5dqCVp.cjs} +129 -44
  27. package/dist/{src-Ik0ksTOt.cjs.map → src-bE5dqCVp.cjs.map} +1 -1
  28. package/package.json +7 -7
@@ -18966,6 +18966,52 @@ function detectDegenerateRepetition(text) {
18966
18966
  return false;
18967
18967
  }
18968
18968
  /**
18969
+ * Build a single-line diagnostic description of output flagged by
18970
+ * {@link detectDegenerateRepetition}. Used when logging or surfacing a
18971
+ * degenerate-output failure so the discarded model output can be inspected —
18972
+ * without it there is no way to tell a real repetition loop apart from a
18973
+ * detector false-positive on legitimately repetitive content.
18974
+ *
18975
+ * Reuses the detector's sampling parameters (200-char windows, ~50 samples)
18976
+ * so the reported duplicate ratio and most-repeated window match what
18977
+ * triggered the detection. Snippets are JSON-escaped so the result stays on
18978
+ * one line.
18979
+ */
18980
+ function describeDegenerateOutput(text, snippetChars = 400) {
18981
+ const windowSize = 200;
18982
+ const step = Math.max(1, Math.floor(text.length / 50));
18983
+ const seen = /* @__PURE__ */ new Map();
18984
+ let duplicateWindows = 0;
18985
+ let totalWindows = 0;
18986
+ for (let i = 0; i + windowSize <= text.length; i += step) {
18987
+ const window = text.slice(i, i + windowSize);
18988
+ totalWindows++;
18989
+ const count = (seen.get(window) ?? 0) + 1;
18990
+ seen.set(window, count);
18991
+ if (count > 1) duplicateWindows++;
18992
+ }
18993
+ let topWindow = "";
18994
+ let topCount = 0;
18995
+ for (const [window, count] of seen) if (count > topCount) {
18996
+ topCount = count;
18997
+ topWindow = window;
18998
+ }
18999
+ let longestLine = 0;
19000
+ for (const line of text.split("\n")) if (line.length > longestLine) longestLine = line.length;
19001
+ const duplicateRatio = totalWindows > 0 ? (duplicateWindows / totalWindows).toFixed(2) : "n/a";
19002
+ const parts = [
19003
+ `length=${text.length}`,
19004
+ `sampledWindows=${totalWindows}`,
19005
+ `duplicateRatio=${duplicateRatio}`,
19006
+ `longestLine=${longestLine}`,
19007
+ `topWindowCount=${topCount}`
19008
+ ];
19009
+ if (topCount > 1) parts.push(`topWindow=${JSON.stringify(topWindow)}`);
19010
+ parts.push(`head=${JSON.stringify(text.slice(0, snippetChars))}`);
19011
+ if (text.length > snippetChars * 2) parts.push(`tail=${JSON.stringify(text.slice(-snippetChars))}`);
19012
+ return parts.join(" ");
19013
+ }
19014
+ /**
18969
19015
  * Check if observations contain a Current Task section.
18970
19016
  * Supports both XML format and legacy markdown format.
18971
19017
  */
@@ -19230,7 +19276,19 @@ async function withOmTracingSpan({ phase, model, inputTokens, requestContext, ob
19230
19276
  });
19231
19277
  const childObservabilityContext = (0, _mastra_core_observability.createObservabilityContext)({ currentSpan: span });
19232
19278
  if (!span) return callback(childObservabilityContext);
19233
- return span.executeInContext(() => callback(childObservabilityContext));
19279
+ return span.executeInContext(async () => {
19280
+ try {
19281
+ const result = await callback(childObservabilityContext);
19282
+ span.end();
19283
+ return result;
19284
+ } catch (error) {
19285
+ span.error({
19286
+ error,
19287
+ endSpan: true
19288
+ });
19289
+ throw error;
19290
+ }
19291
+ });
19234
19292
  }
19235
19293
  //#endregion
19236
19294
  //#region src/processors/observational-memory/observer-runner.ts
@@ -19368,13 +19426,13 @@ var ObserverRunner = class {
19368
19426
  let parsed = parseObserverOutput(result.text, activeExtractors);
19369
19427
  let retriedDueToDegenerate = false;
19370
19428
  if (parsed.degenerate) {
19371
- omDebug(`[OM:callObserver] degenerate repetition detected, retrying once`);
19429
+ omDebug(`[OM:callObserver] degenerate repetition detected, retrying once. ${describeDegenerateOutput(result.text, 2e3)}`);
19372
19430
  result = await doGenerate();
19373
19431
  parsed = parseObserverOutput(result.text, activeExtractors);
19374
19432
  retriedDueToDegenerate = true;
19375
19433
  if (parsed.degenerate) {
19376
- omDebug(`[OM:callObserver] degenerate repetition on retry, failing`);
19377
- throw new Error("Observer produced degenerate output after retry");
19434
+ omDebug(`[OM:callObserver] degenerate repetition on retry, failing. ${describeDegenerateOutput(result.text, 2e3)}`);
19435
+ throw new Error(`Observer produced degenerate output after retry. ${describeDegenerateOutput(result.text)}`);
19378
19436
  }
19379
19437
  }
19380
19438
  const structuredExtraction = await extractStructuredValues({
@@ -19518,13 +19576,13 @@ var ObserverRunner = class {
19518
19576
  let parsed = parseMultiThreadObserverOutput(result.text, activeExtractors);
19519
19577
  let retriedDueToDegenerate = false;
19520
19578
  if (parsed.degenerate) {
19521
- omDebug(`[OM:callMultiThreadObserver] degenerate repetition detected, retrying once`);
19579
+ omDebug(`[OM:callMultiThreadObserver] degenerate repetition detected, retrying once. ${describeDegenerateOutput(result.text, 2e3)}`);
19522
19580
  result = await doGenerate();
19523
19581
  parsed = parseMultiThreadObserverOutput(result.text, activeExtractors);
19524
19582
  retriedDueToDegenerate = true;
19525
19583
  if (parsed.degenerate) {
19526
- omDebug(`[OM:callMultiThreadObserver] degenerate repetition on retry, failing`);
19527
- throw new Error("Multi-thread observer produced degenerate output after retry");
19584
+ omDebug(`[OM:callMultiThreadObserver] degenerate repetition on retry, failing. ${describeDegenerateOutput(result.text, 2e3)}`);
19585
+ throw new Error(`Multi-thread observer produced degenerate output after retry. ${describeDegenerateOutput(result.text)}`);
19528
19586
  }
19529
19587
  }
19530
19588
  const structuredExtractionByThread = /* @__PURE__ */ new Map();
@@ -24367,10 +24425,11 @@ ObservationStrategy.create = ((om, opts) => {
24367
24425
  });
24368
24426
  //#endregion
24369
24427
  //#region src/processors/observational-memory/observation-turn/load-memory-context.ts
24370
- async function loadMemoryContextMessages({ memory, messageList, threadId, resourceId }) {
24428
+ async function loadMemoryContextMessages({ memory, messageList, threadId, resourceId, runState }) {
24371
24429
  const ctx = await memory.getContext({
24372
24430
  threadId,
24373
- resourceId
24431
+ resourceId,
24432
+ runState
24374
24433
  });
24375
24434
  for (const msg of ctx.messages) if (msg.role !== "system") messageList.add(msg, "memory");
24376
24435
  return ctx;
@@ -24828,10 +24887,11 @@ var ObservationTurn = class {
24828
24887
  * If a MemoryContextProvider is passed, loads historical messages and adds
24829
24888
  * them to the MessageList. Without a provider, only fetches/caches the record.
24830
24889
  */
24831
- async start(memory) {
24890
+ async start(memory, runState) {
24832
24891
  if (this._started) throw new Error("Turn already started");
24833
24892
  this._started = true;
24834
24893
  this._record = await this.om.getOrCreateRecord(this.threadId, this.resourceId);
24894
+ runState?.set(`observational-memory:record:${this.threadId}:${this.resourceId ?? ""}`, this._record);
24835
24895
  this._generationCountAtStart = this._record.generationCount;
24836
24896
  this.memory = memory;
24837
24897
  if (memory) {
@@ -24839,7 +24899,8 @@ var ObservationTurn = class {
24839
24899
  memory,
24840
24900
  messageList: this.messageList,
24841
24901
  threadId: this.threadId,
24842
- resourceId: this.resourceId
24902
+ resourceId: this.resourceId,
24903
+ runState
24843
24904
  });
24844
24905
  this._context = {
24845
24906
  messages: ctx.messages,
@@ -25467,7 +25528,7 @@ var ReflectorRunner = class {
25467
25528
  finalProviderMetadata = result.providerMetadata ?? finalProviderMetadata;
25468
25529
  parsed = parseReflectorOutput(result.text, observations, activeExtractors);
25469
25530
  if (parsed.degenerate) {
25470
- omDebug(`[OM:callReflector] attempt #${attemptNumber}: degenerate repetition detected, treating as compression failure`);
25531
+ omDebug(`[OM:callReflector] attempt #${attemptNumber}: degenerate repetition detected, treating as compression failure. ${describeDegenerateOutput(result.text, 2e3)}`);
25471
25532
  reflectedTokens = originalTokens;
25472
25533
  } else reflectedTokens = this.tokenCounter.countObservations(parsed.observations);
25473
25534
  omDebug(`[OM:callReflector] attempt #${attemptNumber} parsed: reflectedTokens=${reflectedTokens}, targetThreshold=${targetThreshold}, compressionValid=${validateCompression(reflectedTokens, targetThreshold)}, parsedObsLen=${parsed.observations?.length}, degenerate=${parsed.degenerate ?? false}`);
@@ -28921,7 +28982,9 @@ var ObservationalMemoryProcessor = class {
28921
28982
  return messageList;
28922
28983
  }
28923
28984
  const { threadId, resourceId } = context;
28924
- const readOnly = (0, _mastra_core_memory.parseMemoryRequestContext)(requestContext)?.memoryConfig?.readOnly;
28985
+ const memoryContext = (0, _mastra_core_memory.parseMemoryRequestContext)(requestContext);
28986
+ const runState = memoryContext?.runState?.();
28987
+ const readOnly = memoryContext?.memoryConfig?.readOnly;
28925
28988
  const actorModelContext = model?.modelId ? {
28926
28989
  provider: model.provider,
28927
28990
  modelId: model.modelId,
@@ -28938,7 +29001,8 @@ var ObservationalMemoryProcessor = class {
28938
29001
  memory: this.memory,
28939
29002
  messageList,
28940
29003
  threadId,
28941
- resourceId
29004
+ resourceId,
29005
+ runState
28942
29006
  });
28943
29007
  const systemMessages = ctx.omRecord ? await this.engine.buildContextSystemMessages({
28944
29008
  threadId,
@@ -28979,7 +29043,7 @@ var ObservationalMemoryProcessor = class {
28979
29043
  this.turn.sendStateSignal = args.sendStateSignal;
28980
29044
  this.turn.agent = args.agent;
28981
29045
  this.turn.requestContext = requestContext;
28982
- await this.turn.start(this.memory);
29046
+ await this.turn.start(this.memory, runState);
28983
29047
  if (stepNumber === 0 && this.temporalMarkers) await insertTemporalGapMarkers({
28984
29048
  messageList,
28985
29049
  sendSignal: args.sendSignal
@@ -30149,14 +30213,18 @@ ${workingMemory}`;
30149
30213
  if (!this.threadConfig.workingMemory?.enabled) return null;
30150
30214
  return extractWorkingMemoryContent(text)?.trim() ?? null;
30151
30215
  }
30152
- async getWorkingMemory({ threadId, resourceId, memoryConfig }) {
30216
+ async getWorkingMemory({ threadId, resourceId, memoryConfig, runState }) {
30153
30217
  const config = this.getMergedThreadConfig(memoryConfig || {});
30154
30218
  if (!config.workingMemory?.enabled) return null;
30155
30219
  const scope = config.workingMemory.scope || "resource";
30156
30220
  let workingMemoryData = null;
30157
30221
  if (scope === "resource" && !resourceId) throw new Error("Memory error: Resource-scoped working memory is enabled but no resourceId was provided. Either provide a resourceId or explicitly set workingMemory.scope to 'thread'.");
30158
- if (scope === "resource" && resourceId) workingMemoryData = (await (await this.getMemoryStore()).getResourceById({ resourceId }))?.workingMemory || null;
30159
- else workingMemoryData = (await this.getThreadById({ threadId }))?.metadata?.workingMemory;
30222
+ if (scope === "resource" && resourceId) {
30223
+ const loadWorkingMemory = async () => {
30224
+ return (await (await this.getMemoryStore()).getResourceById({ resourceId }))?.workingMemory || null;
30225
+ };
30226
+ workingMemoryData = runState ? await runState.load(`working-memory:resource:${resourceId}`, loadWorkingMemory) : await loadWorkingMemory();
30227
+ } else workingMemoryData = (runState?.threadLoaded ? runState.thread : await this.getThreadById({ threadId }))?.metadata?.workingMemory;
30160
30228
  if (!workingMemoryData) return null;
30161
30229
  return workingMemoryData;
30162
30230
  }
@@ -30188,16 +30256,18 @@ ${workingMemory}`;
30188
30256
  content: (config.workingMemory.template || this.defaultWorkingMemoryTemplate).trim()
30189
30257
  };
30190
30258
  }
30191
- async getSystemMessage({ threadId, resourceId, memoryConfig }) {
30259
+ async getSystemMessage({ threadId, resourceId, memoryConfig, runState }) {
30192
30260
  const config = this.getMergedThreadConfig(memoryConfig);
30193
30261
  this.assertWorkingMemoryStateSignalsCompatibility(config);
30194
30262
  if (!config.workingMemory?.enabled) return null;
30195
30263
  if (config.workingMemory?.useStateSignals) return null;
30196
- const workingMemoryTemplate = await this.getWorkingMemoryTemplate({ memoryConfig });
30264
+ const loadTemplate = () => this.getWorkingMemoryTemplate({ memoryConfig });
30265
+ const workingMemoryTemplate = runState ? await runState.load("working-memory:template", loadTemplate) : await loadTemplate();
30197
30266
  const workingMemoryData = await this.getWorkingMemory({
30198
30267
  threadId,
30199
30268
  resourceId,
30200
- memoryConfig: config
30269
+ memoryConfig: config,
30270
+ runState
30201
30271
  });
30202
30272
  if (!workingMemoryTemplate) return null;
30203
30273
  const workingMemoryConfig = config.workingMemory;
@@ -30230,7 +30300,7 @@ ${workingMemory}`;
30230
30300
  * ```
30231
30301
  */
30232
30302
  async getContext(opts) {
30233
- const { threadId, resourceId, memoryConfig } = opts;
30303
+ const { threadId, resourceId, memoryConfig, runState } = opts;
30234
30304
  const config = this.getMergedThreadConfig(memoryConfig);
30235
30305
  const memoryStore = await this.getMemoryStore();
30236
30306
  const systemParts = [];
@@ -30240,10 +30310,14 @@ ${workingMemory}`;
30240
30310
  let otherThreadsContext;
30241
30311
  const omEngine = await this.omEngine;
30242
30312
  if (omEngine) {
30243
- omRecord = await omEngine.getRecord(threadId, resourceId);
30313
+ const loadOmRecord = () => omEngine.getRecord(threadId, resourceId);
30314
+ omRecord = runState ? await runState.load(`observational-memory:record:${threadId}:${resourceId ?? ""}`, loadOmRecord) : await loadOmRecord();
30244
30315
  if (omRecord?.activeObservations) {
30245
30316
  hasObservations = true;
30246
- if (omEngine.scope === "resource" && resourceId) otherThreadsContext = await omEngine.getOtherThreadsContext(resourceId, threadId);
30317
+ if (omEngine.scope === "resource" && resourceId) {
30318
+ const loadOtherThreadsContext = () => omEngine.getOtherThreadsContext(resourceId, threadId);
30319
+ otherThreadsContext = runState ? await runState.load(`observational-memory:other-threads:${resourceId}:${threadId}:${omRecord.lastObservedAt ?? ""}`, loadOtherThreadsContext) : await loadOtherThreadsContext();
30320
+ }
30247
30321
  const obsSystemMessage = await omEngine.buildContextSystemMessage({
30248
30322
  threadId,
30249
30323
  resourceId,
@@ -30271,30 +30345,41 @@ ${workingMemory}`;
30271
30345
  const workingMemoryMessage = await this.getSystemMessage({
30272
30346
  threadId,
30273
30347
  resourceId,
30274
- memoryConfig: config
30348
+ memoryConfig: config,
30349
+ runState
30275
30350
  });
30276
30351
  if (workingMemoryMessage) systemParts.push(workingMemoryMessage);
30277
30352
  let messages;
30278
30353
  if (omEngine && omRecord) {
30279
30354
  const dateFilter = omRecord.lastObservedAt ? { dateRange: { start: new Date(new Date(omRecord.lastObservedAt).getTime() + 1) } } : void 0;
30280
- if (omEngine.scope === "resource" && resourceId) messages = (await memoryStore.listMessagesByResourceId({
30281
- resourceId,
30282
- orderBy: {
30283
- field: "createdAt",
30284
- direction: "ASC"
30285
- },
30286
- perPage: false,
30287
- filter: dateFilter
30288
- })).messages;
30289
- else messages = (await memoryStore.listMessages({
30290
- threadId,
30291
- orderBy: {
30292
- field: "createdAt",
30293
- direction: "ASC"
30294
- },
30295
- perPage: false,
30296
- filter: dateFilter
30297
- })).messages;
30355
+ const boundary = omRecord.lastObservedAt ? new Date(omRecord.lastObservedAt).toISOString() : "";
30356
+ if (omEngine.scope === "resource" && resourceId) {
30357
+ const loadMessages = async () => {
30358
+ return (await memoryStore.listMessagesByResourceId({
30359
+ resourceId,
30360
+ orderBy: {
30361
+ field: "createdAt",
30362
+ direction: "ASC"
30363
+ },
30364
+ perPage: false,
30365
+ filter: dateFilter
30366
+ })).messages;
30367
+ };
30368
+ messages = runState ? await runState.load(`observational-memory:messages:resource:${resourceId}:${boundary}`, loadMessages) : await loadMessages();
30369
+ } else {
30370
+ const loadMessages = async () => {
30371
+ return (await memoryStore.listMessages({
30372
+ threadId,
30373
+ orderBy: {
30374
+ field: "createdAt",
30375
+ direction: "ASC"
30376
+ },
30377
+ perPage: false,
30378
+ filter: dateFilter
30379
+ })).messages;
30380
+ };
30381
+ messages = runState ? await runState.load(`observational-memory:messages:thread:${threadId}:${boundary}`, loadMessages) : await loadMessages();
30382
+ }
30298
30383
  } else {
30299
30384
  const lastMessages = config.lastMessages;
30300
30385
  if (lastMessages === false) messages = [];
@@ -31599,4 +31684,4 @@ Object.defineProperty(exports, "wrapInObservationGroup", {
31599
31684
  }
31600
31685
  });
31601
31686
 
31602
- //# sourceMappingURL=src-Ik0ksTOt.cjs.map
31687
+ //# sourceMappingURL=src-bE5dqCVp.cjs.map