@mastra/memory 1.8.2 → 1.8.3-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 (78) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/chunk-3PUO6DLX.js +439 -0
  3. package/dist/chunk-3PUO6DLX.js.map +1 -0
  4. package/dist/{chunk-SUU4IAZJ.js → chunk-4KPXPQX3.js} +212 -75
  5. package/dist/chunk-4KPXPQX3.js.map +1 -0
  6. package/dist/{chunk-23EXJLET.cjs → chunk-CK4U3AYR.cjs} +4 -4
  7. package/dist/{chunk-23EXJLET.cjs.map → chunk-CK4U3AYR.cjs.map} +1 -1
  8. package/dist/chunk-DAJJSFVA.cjs +441 -0
  9. package/dist/chunk-DAJJSFVA.cjs.map +1 -0
  10. package/dist/{chunk-YPFNHFT6.cjs → chunk-LGCREJMO.cjs} +212 -74
  11. package/dist/chunk-LGCREJMO.cjs.map +1 -0
  12. package/dist/{chunk-BSDWQEU3.js → chunk-SVPZMV27.js} +4 -4
  13. package/dist/{chunk-BSDWQEU3.js.map → chunk-SVPZMV27.js.map} +1 -1
  14. package/dist/docs/SKILL.md +1 -1
  15. package/dist/docs/assets/SOURCE_MAP.json +30 -25
  16. package/dist/docs/references/docs-agents-agent-approval.md +4 -4
  17. package/dist/docs/references/docs-agents-network-approval.md +1 -1
  18. package/dist/docs/references/docs-agents-networks.md +1 -1
  19. package/dist/docs/references/docs-agents-supervisor-agents.md +3 -3
  20. package/dist/docs/references/docs-memory-memory-processors.md +6 -6
  21. package/dist/docs/references/docs-memory-semantic-recall.md +1 -1
  22. package/dist/docs/references/docs-memory-storage.md +1 -1
  23. package/dist/docs/references/docs-memory-working-memory.md +1 -1
  24. package/dist/docs/references/reference-memory-memory-class.md +3 -3
  25. package/dist/docs/references/reference-memory-observational-memory.md +5 -5
  26. package/dist/docs/references/reference-processors-token-limiter-processor.md +3 -3
  27. package/dist/docs/references/reference-storage-mongodb.md +1 -1
  28. package/dist/docs/references/reference-storage-postgresql.md +1 -1
  29. package/dist/docs/references/reference-storage-upstash.md +1 -1
  30. package/dist/docs/references/reference-vectors-libsql.md +1 -1
  31. package/dist/docs/references/reference-vectors-mongodb.md +1 -1
  32. package/dist/docs/references/reference-vectors-pg.md +1 -1
  33. package/dist/docs/references/reference-vectors-upstash.md +1 -1
  34. package/dist/index.cjs +891 -255
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +881 -249
  39. package/dist/index.js.map +1 -1
  40. package/dist/{observational-memory-3HFM7PY2.cjs → observational-memory-4TV5KKFV.cjs} +21 -17
  41. package/dist/{observational-memory-3HFM7PY2.cjs.map → observational-memory-4TV5KKFV.cjs.map} +1 -1
  42. package/dist/observational-memory-UEDVTWS2.js +3 -0
  43. package/dist/{observational-memory-XXD6E2SO.js.map → observational-memory-UEDVTWS2.js.map} +1 -1
  44. package/dist/processors/index.cjs +19 -15
  45. package/dist/processors/index.js +1 -1
  46. package/dist/processors/observational-memory/index.d.ts +1 -0
  47. package/dist/processors/observational-memory/index.d.ts.map +1 -1
  48. package/dist/processors/observational-memory/observation-utils.d.ts +16 -0
  49. package/dist/processors/observational-memory/observation-utils.d.ts.map +1 -0
  50. package/dist/processors/observational-memory/observational-memory.d.ts +13 -4
  51. package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
  52. package/dist/processors/observational-memory/observer-agent.d.ts +9 -7
  53. package/dist/processors/observational-memory/observer-agent.d.ts.map +1 -1
  54. package/dist/processors/observational-memory/token-counter.d.ts.map +1 -1
  55. package/dist/processors/observational-memory/tool-result-helpers.d.ts +12 -0
  56. package/dist/processors/observational-memory/tool-result-helpers.d.ts.map +1 -0
  57. package/dist/{token-6GSAFR2W-TW2P7HCS.cjs → token-APYSY3BW-POD4OUWN.cjs} +14 -14
  58. package/dist/token-APYSY3BW-POD4OUWN.cjs.map +1 -0
  59. package/dist/{token-6GSAFR2W-ABXTQD64.js → token-APYSY3BW-YTVQELJT.js} +11 -11
  60. package/dist/token-APYSY3BW-YTVQELJT.js.map +1 -0
  61. package/dist/token-util-RMHT2CPJ-77HHGIQN.cjs +10 -0
  62. package/dist/token-util-RMHT2CPJ-77HHGIQN.cjs.map +1 -0
  63. package/dist/token-util-RMHT2CPJ-WJZ2SYAR.js +8 -0
  64. package/dist/token-util-RMHT2CPJ-WJZ2SYAR.js.map +1 -0
  65. package/package.json +8 -8
  66. package/dist/chunk-HJYHDIOC.js +0 -250
  67. package/dist/chunk-HJYHDIOC.js.map +0 -1
  68. package/dist/chunk-LIBOSOHM.cjs +0 -252
  69. package/dist/chunk-LIBOSOHM.cjs.map +0 -1
  70. package/dist/chunk-SUU4IAZJ.js.map +0 -1
  71. package/dist/chunk-YPFNHFT6.cjs.map +0 -1
  72. package/dist/observational-memory-XXD6E2SO.js +0 -3
  73. package/dist/token-6GSAFR2W-ABXTQD64.js.map +0 -1
  74. package/dist/token-6GSAFR2W-TW2P7HCS.cjs.map +0 -1
  75. package/dist/token-util-NEHG7TUY-GYFEVMWP.cjs +0 -10
  76. package/dist/token-util-NEHG7TUY-GYFEVMWP.cjs.map +0 -1
  77. package/dist/token-util-NEHG7TUY-XQP3QSPX.js +0 -8
  78. package/dist/token-util-NEHG7TUY-XQP3QSPX.js.map +0 -1
@@ -8,10 +8,10 @@ var llm = require('@mastra/core/llm');
8
8
  var memory = require('@mastra/core/memory');
9
9
  var processors = require('@mastra/core/processors');
10
10
  var xxhash = require('xxhash-wasm');
11
+ var tokenx = require('tokenx');
11
12
  var crypto$1 = require('crypto');
12
13
  var async_hooks = require('async_hooks');
13
14
  var imageSize = require('image-size');
14
- var tokenx = require('tokenx');
15
15
 
16
16
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
17
17
 
@@ -307,6 +307,97 @@ function createActivationMarker(params) {
307
307
  }
308
308
  };
309
309
  }
310
+ var ENCRYPTED_CONTENT_KEY = "encryptedContent";
311
+ var ENCRYPTED_CONTENT_REDACTION_THRESHOLD = 256;
312
+ var DEFAULT_OBSERVER_TOOL_RESULT_MAX_TOKENS = 1e4;
313
+ function isObjectLike(value) {
314
+ return typeof value === "object" && value !== null;
315
+ }
316
+ function sanitizeToolResultValue(value, seen = /* @__PURE__ */ new WeakMap()) {
317
+ if (!isObjectLike(value)) {
318
+ return value;
319
+ }
320
+ if (seen.has(value)) {
321
+ return seen.get(value);
322
+ }
323
+ if (Array.isArray(value)) {
324
+ const sanitizedArray = [];
325
+ seen.set(value, sanitizedArray);
326
+ for (const item of value) {
327
+ sanitizedArray.push(sanitizeToolResultValue(item, seen));
328
+ }
329
+ return sanitizedArray;
330
+ }
331
+ const sanitizedObject = {};
332
+ seen.set(value, sanitizedObject);
333
+ for (const [key, entry] of Object.entries(value)) {
334
+ if (key === ENCRYPTED_CONTENT_KEY && typeof entry === "string" && entry.length > ENCRYPTED_CONTENT_REDACTION_THRESHOLD) {
335
+ sanitizedObject[key] = `[stripped encryptedContent: ${entry.length} characters]`;
336
+ continue;
337
+ }
338
+ sanitizedObject[key] = sanitizeToolResultValue(entry, seen);
339
+ }
340
+ return sanitizedObject;
341
+ }
342
+ function stringifyToolResult(value) {
343
+ if (typeof value === "string") {
344
+ return value;
345
+ }
346
+ const sanitized = sanitizeToolResultValue(value);
347
+ try {
348
+ return JSON.stringify(sanitized, null, 2);
349
+ } catch {
350
+ return String(sanitized);
351
+ }
352
+ }
353
+ function resolveToolResultValue(part, invocationResult) {
354
+ const mastraMetadata = part?.providerMetadata?.mastra;
355
+ if (mastraMetadata && typeof mastraMetadata === "object" && "modelOutput" in mastraMetadata) {
356
+ return {
357
+ value: mastraMetadata.modelOutput,
358
+ usingStoredModelOutput: true
359
+ };
360
+ }
361
+ return {
362
+ value: invocationResult,
363
+ usingStoredModelOutput: false
364
+ };
365
+ }
366
+ function truncateStringByTokens(text, maxTokens) {
367
+ if (!text || maxTokens <= 0) {
368
+ return "";
369
+ }
370
+ const totalTokens = tokenx.estimateTokenCount(text);
371
+ if (totalTokens <= maxTokens) {
372
+ return text;
373
+ }
374
+ const buildCandidate = (sliceEnd) => {
375
+ const visible = text.slice(0, sliceEnd);
376
+ const omittedChars = text.length - sliceEnd;
377
+ return `${visible}
378
+ ... [truncated ~${totalTokens - tokenx.estimateTokenCount(visible)} tokens / ${omittedChars} characters]`;
379
+ };
380
+ let low = 0;
381
+ let high = text.length;
382
+ let best = buildCandidate(0);
383
+ while (low <= high) {
384
+ const mid = Math.floor((low + high) / 2);
385
+ const candidate = buildCandidate(mid);
386
+ const candidateTokens = tokenx.estimateTokenCount(candidate);
387
+ if (candidateTokens <= maxTokens) {
388
+ best = candidate;
389
+ low = mid + 1;
390
+ } else {
391
+ high = mid - 1;
392
+ }
393
+ }
394
+ return best;
395
+ }
396
+ function formatToolResultForObserver(value, options) {
397
+ const serialized = stringifyToolResult(value);
398
+ const maxTokens = options?.maxTokens ?? DEFAULT_OBSERVER_TOOL_RESULT_MAX_TOKENS;
399
+ return truncateStringByTokens(serialized, maxTokens);
400
+ }
310
401
 
311
402
  // src/processors/observational-memory/observer-agent.ts
312
403
  var OBSERVER_EXTRACTION_INSTRUCTIONS = `CRITICAL: DISTINGUISH USER ASSERTIONS FROM QUESTIONS
@@ -781,6 +872,7 @@ function formatObserverAttachmentPlaceholder(part, counter) {
781
872
  }
782
873
  function formatObserverMessage(msg, counter, options) {
783
874
  const maxLen = options?.maxPartLength;
875
+ const maxToolResultTokens = options?.maxToolResultTokens ?? DEFAULT_OBSERVER_TOOL_RESULT_MAX_TOKENS;
784
876
  const timestamp = formatObserverTimestamp(msg.createdAt);
785
877
  const role = msg.role.charAt(0).toUpperCase() + msg.role.slice(1);
786
878
  const timestampStr = timestamp ? ` (${timestamp})` : "";
@@ -794,7 +886,11 @@ function formatObserverMessage(msg, counter, options) {
794
886
  if (part.type === "tool-invocation") {
795
887
  const inv = part.toolInvocation;
796
888
  if (inv.state === "result") {
797
- const resultStr = JSON.stringify(inv.result, null, 2);
889
+ const { value: resultForObserver } = resolveToolResultValue(
890
+ part,
891
+ inv.result
892
+ );
893
+ const resultStr = formatToolResultForObserver(resultForObserver, { maxTokens: maxToolResultTokens });
798
894
  return `[Tool Result: ${inv.toolName}]
799
895
  ${maybeTruncate(resultStr, maxLen)}`;
800
896
  }
@@ -835,12 +931,12 @@ function formatMessagesForObserver(messages, options) {
835
931
  const counter = { nextImageId: 1, nextFileId: 1 };
836
932
  return messages.map((msg) => formatObserverMessage(msg, counter, options).text).filter(Boolean).join("\n\n---\n\n");
837
933
  }
838
- function buildObserverHistoryMessage(messages) {
934
+ function buildObserverHistoryMessage(messages, options) {
839
935
  const counter = { nextImageId: 1, nextFileId: 1 };
840
936
  const content = [{ type: "text", text: "## New Message History to Observe\n\n" }];
841
937
  let visibleCount = 0;
842
938
  messages.forEach((message) => {
843
- const formatted = formatObserverMessage(message, counter);
939
+ const formatted = formatObserverMessage(message, counter, options);
844
940
  if (!formatted.text && formatted.attachments.length === 0) return;
845
941
  if (visibleCount > 0) {
846
942
  content.push({ type: "text", text: "\n\n---\n\n" });
@@ -861,7 +957,7 @@ function maybeTruncate(str, maxLen) {
861
957
  return `${truncated}
862
958
  ... [truncated ${remaining} characters]`;
863
959
  }
864
- function buildMultiThreadObserverHistoryMessage(messagesByThread, threadOrder) {
960
+ function buildMultiThreadObserverHistoryMessage(messagesByThread, threadOrder, options) {
865
961
  const counter = { nextImageId: 1, nextFileId: 1 };
866
962
  const content = [
867
963
  {
@@ -879,7 +975,7 @@ The following messages are from ${threadOrder.length} different conversation thr
879
975
  const threadContent = [];
880
976
  let visibleCount = 0;
881
977
  messages.forEach((message) => {
882
- const formatted = formatObserverMessage(message, counter);
978
+ const formatted = formatObserverMessage(message, counter, options);
883
979
  if (!formatted.text && formatted.attachments.length === 0) return;
884
980
  if (visibleCount > 0) {
885
981
  threadContent.push({ type: "text", text: "\n\n---\n\n" });
@@ -2523,17 +2619,7 @@ var TokenCounter = class _TokenCounter {
2523
2619
  return tokens;
2524
2620
  }
2525
2621
  resolveToolResultForTokenCounting(part, invocationResult) {
2526
- const mastraMetadata = part?.providerMetadata?.mastra;
2527
- if (mastraMetadata && typeof mastraMetadata === "object" && "modelOutput" in mastraMetadata) {
2528
- return {
2529
- value: mastraMetadata.modelOutput,
2530
- usingStoredModelOutput: true
2531
- };
2532
- }
2533
- return {
2534
- value: invocationResult,
2535
- usingStoredModelOutput: false
2536
- };
2622
+ return resolveToolResultValue(part, invocationResult);
2537
2623
  }
2538
2624
  estimateImageAssetTokens(part, asset, kind) {
2539
2625
  const modelContext = this.getModelContext();
@@ -2772,19 +2858,13 @@ var TokenCounter = class _TokenCounter {
2772
2858
  invocation.result
2773
2859
  );
2774
2860
  if (resultForCounting !== void 0) {
2775
- if (typeof resultForCounting === "string") {
2776
- tokens += this.readOrPersistPartEstimate(
2777
- part,
2778
- usingStoredModelOutput ? "tool-result-model-output" : "tool-result",
2779
- resultForCounting
2780
- );
2781
- } else {
2782
- const resultJson = JSON.stringify(resultForCounting);
2783
- tokens += this.readOrPersistPartEstimate(
2784
- part,
2785
- usingStoredModelOutput ? "tool-result-model-output-json" : "tool-result-json",
2786
- resultJson
2787
- );
2861
+ const formattedResult = formatToolResultForObserver(resultForCounting);
2862
+ tokens += this.readOrPersistPartEstimate(
2863
+ part,
2864
+ usingStoredModelOutput ? "tool-result-model-output-json" : "tool-result-json",
2865
+ formattedResult
2866
+ );
2867
+ if (typeof resultForCounting !== "string") {
2788
2868
  overheadDelta -= 12;
2789
2869
  }
2790
2870
  }
@@ -2900,6 +2980,14 @@ function omDebug(msg) {
2900
2980
  } catch {
2901
2981
  }
2902
2982
  }
2983
+ function getLatestStepParts(parts) {
2984
+ for (let i = parts.length - 1; i >= 0; i--) {
2985
+ if (parts[i]?.type === "step-start") {
2986
+ return parts.slice(i + 1);
2987
+ }
2988
+ }
2989
+ return parts;
2990
+ }
2903
2991
  function omError(msg, err) {
2904
2992
  const errStr = err instanceof Error ? err.stack ?? err.message : err !== void 0 ? String(err) : "";
2905
2993
  const full = errStr ? `${msg}: ${errStr}` : msg;
@@ -4346,38 +4434,51 @@ ${unreflectedContent}` : bufferedReflection;
4346
4434
  if (currentDate) {
4347
4435
  optimized = addRelativeTimeToObservations(optimized, currentDate);
4348
4436
  }
4349
- let content = `
4350
- ${OBSERVATION_CONTEXT_PROMPT}
4351
-
4352
- <observations>
4353
- ${optimized}
4354
- </observations>
4437
+ const messages = [`${OBSERVATION_CONTEXT_PROMPT}
4355
4438
 
4356
- ${OBSERVATION_CONTEXT_INSTRUCTIONS}`;
4439
+ ${OBSERVATION_CONTEXT_INSTRUCTIONS}`];
4357
4440
  if (unobservedContextBlocks) {
4358
- content += `
4359
-
4360
- The following content is from OTHER conversations different from the current conversation, they're here for reference, but they're not necessarily your focus:
4441
+ messages.push(
4442
+ `The following content is from OTHER conversations different from the current conversation, they're here for reference, but they're not necessarily your focus:
4361
4443
  START_OTHER_CONVERSATIONS_BLOCK
4362
4444
  ${unobservedContextBlocks}
4363
- END_OTHER_CONVERSATIONS_BLOCK`;
4445
+ END_OTHER_CONVERSATIONS_BLOCK`
4446
+ );
4447
+ }
4448
+ const observationChunks = this.splitObservationContextChunks(optimized);
4449
+ if (observationChunks.length > 0) {
4450
+ messages.push("<observations>", ...observationChunks);
4364
4451
  }
4365
4452
  if (currentTask) {
4366
- content += `
4367
-
4368
- <current-task>
4453
+ messages.push(`<current-task>
4369
4454
  ${currentTask}
4370
- </current-task>`;
4455
+ </current-task>`);
4371
4456
  }
4372
4457
  if (suggestedResponse) {
4373
- content += `
4374
-
4375
- <suggested-response>
4458
+ messages.push(`<suggested-response>
4376
4459
  ${suggestedResponse}
4377
- </suggested-response>
4378
- `;
4460
+ </suggested-response>`);
4461
+ }
4462
+ return messages;
4463
+ }
4464
+ splitObservationContextChunks(observations) {
4465
+ const trimmed = observations.trim();
4466
+ if (!trimmed) {
4467
+ return [];
4379
4468
  }
4380
- return content;
4469
+ return trimmed.split(/\n{2,}--- message boundary \(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z\) ---\n{2,}/).map((chunk) => chunk.trim()).filter(Boolean);
4470
+ }
4471
+ /**
4472
+ * Create a message boundary delimiter with an ISO 8601 date.
4473
+ * The date should be the lastObservedAt timestamp — the latest message
4474
+ * timestamp that was observed to produce the observations following this boundary.
4475
+ */
4476
+ static createMessageBoundary(date) {
4477
+ return `
4478
+
4479
+ --- message boundary (${date.toISOString()}) ---
4480
+
4481
+ `;
4381
4482
  }
4382
4483
  /**
4383
4484
  * Get threadId and resourceId from either RequestContext or MessageList
@@ -4815,7 +4916,7 @@ ${suggestedResponse}
4815
4916
  if (!record.activeObservations) {
4816
4917
  return;
4817
4918
  }
4818
- const observationSystemMessage = this.formatObservationsForContext(
4919
+ const observationSystemMessages = this.formatObservationsForContext(
4819
4920
  record.activeObservations,
4820
4921
  currentTask,
4821
4922
  suggestedResponse,
@@ -4823,7 +4924,7 @@ ${suggestedResponse}
4823
4924
  currentDate
4824
4925
  );
4825
4926
  messageList.clearSystemMessages("observational-memory");
4826
- messageList.addSystem(observationSystemMessage, "observational-memory");
4927
+ messageList.addSystem(observationSystemMessages, "observational-memory");
4827
4928
  const continuationMessage = {
4828
4929
  id: `om-continuation`,
4829
4930
  role: "user",
@@ -5099,12 +5200,20 @@ ${suggestedResponse}
5099
5200
  const sealedIds = /* @__PURE__ */ new Set([...stateSealedIds, ...staticSealedIds]);
5100
5201
  state.sealedIds = sealedIds;
5101
5202
  const lockKey = this.getLockKey(threadId, resourceId);
5203
+ const lastMessage = allMessages[allMessages.length - 1];
5204
+ const latestStepParts = getLatestStepParts(lastMessage?.content?.parts ?? []);
5205
+ const hasIncompleteToolCalls = latestStepParts.some(
5206
+ (part) => part?.type === "tool-invocation" && part.toolInvocation?.state === "call"
5207
+ );
5208
+ omDebug(
5209
+ `[OM:deferred-check] hasIncompleteToolCalls=${hasIncompleteToolCalls}, latestStepPartsCount=${latestStepParts.length}`
5210
+ );
5102
5211
  if (this.isAsyncObservationEnabled() && totalPendingTokens < threshold) {
5103
5212
  const shouldTrigger = this.shouldTriggerAsyncObservation(totalPendingTokens, lockKey, record, threshold);
5104
5213
  omDebug(
5105
- `[OM:async-obs] belowThreshold: pending=${totalPendingTokens}, unbuffered=${unbufferedPendingTokens}, threshold=${threshold}, shouldTrigger=${shouldTrigger}, isBufferingObs=${record.isBufferingObservation}, lastBufferedAt=${record.lastBufferedAtTokens}`
5214
+ `[OM:async-obs] belowThreshold: pending=${totalPendingTokens}, unbuffered=${unbufferedPendingTokens}, threshold=${threshold}, shouldTrigger=${shouldTrigger}, isBufferingObs=${record.isBufferingObservation}, lastBufferedAt=${record.lastBufferedAtTokens}, hasIncompleteToolCalls=${hasIncompleteToolCalls}`
5106
5215
  );
5107
- if (shouldTrigger) {
5216
+ if (shouldTrigger && !hasIncompleteToolCalls) {
5108
5217
  void this.startAsyncBufferedObservation(
5109
5218
  record,
5110
5219
  threadId,
@@ -5118,9 +5227,9 @@ ${suggestedResponse}
5118
5227
  } else if (this.isAsyncObservationEnabled()) {
5119
5228
  const shouldTrigger = this.shouldTriggerAsyncObservation(totalPendingTokens, lockKey, record, threshold);
5120
5229
  omDebug(
5121
- `[OM:async-obs] atOrAboveThreshold: pending=${totalPendingTokens}, unbuffered=${unbufferedPendingTokens}, threshold=${threshold}, step=${stepNumber}, shouldTrigger=${shouldTrigger}`
5230
+ `[OM:async-obs] atOrAboveThreshold: pending=${totalPendingTokens}, unbuffered=${unbufferedPendingTokens}, threshold=${threshold}, step=${stepNumber}, shouldTrigger=${shouldTrigger}, hasIncompleteToolCalls=${hasIncompleteToolCalls}`
5122
5231
  );
5123
- if (shouldTrigger) {
5232
+ if (shouldTrigger && !hasIncompleteToolCalls) {
5124
5233
  void this.startAsyncBufferedObservation(
5125
5234
  record,
5126
5235
  threadId,
@@ -5135,7 +5244,7 @@ ${suggestedResponse}
5135
5244
  if (stepNumber > 0) {
5136
5245
  await this.handlePerStepSave(messageList, sealedIds, threadId, resourceId, state);
5137
5246
  }
5138
- if (stepNumber > 0 && totalPendingTokens >= threshold) {
5247
+ if (stepNumber > 0 && !hasIncompleteToolCalls && totalPendingTokens >= threshold) {
5139
5248
  reproCaptureDetails.thresholdReached = true;
5140
5249
  const { observationSucceeded, updatedRecord, activatedMessageIds } = await this.handleThresholdReached(
5141
5250
  messageList,
@@ -5493,16 +5602,14 @@ ${cleanObservations}
5493
5602
  * merge the observations into that section to reduce token usage.
5494
5603
  * Otherwise, append as a new section.
5495
5604
  */
5496
- replaceOrAppendThreadSection(existingObservations, _threadId, newThreadSection) {
5605
+ replaceOrAppendThreadSection(existingObservations, _threadId, newThreadSection, lastObservedAt) {
5497
5606
  if (!existingObservations) {
5498
5607
  return newThreadSection;
5499
5608
  }
5500
5609
  const threadIdMatch = newThreadSection.match(/<thread id="([^"]+)">/);
5501
5610
  const dateMatch = newThreadSection.match(/Date:\s*([A-Za-z]+\s+\d+,\s+\d+)/);
5502
5611
  if (!threadIdMatch || !dateMatch) {
5503
- return `${existingObservations}
5504
-
5505
- ${newThreadSection}`;
5612
+ return `${existingObservations}${_ObservationalMemory.createMessageBoundary(lastObservedAt)}${newThreadSection}`;
5506
5613
  }
5507
5614
  const newThreadId = threadIdMatch[1];
5508
5615
  const newDate = dateMatch[1];
@@ -5537,9 +5644,7 @@ ${threadClose}`;
5537
5644
  }
5538
5645
  }
5539
5646
  }
5540
- return `${existingObservations}
5541
-
5542
- ${newThreadSection}`;
5647
+ return `${existingObservations}${_ObservationalMemory.createMessageBoundary(lastObservedAt)}${newThreadSection}`;
5543
5648
  }
5544
5649
  /**
5545
5650
  * Sort threads by their oldest unobserved message.
@@ -5622,19 +5727,22 @@ ${newThreadSection}`;
5622
5727
  priorSuggestedResponse: threadOMMetadata?.suggestedResponse,
5623
5728
  wasTruncated
5624
5729
  });
5730
+ const lastObservedAt = this.getMaxMessageTimestamp(messagesToObserve);
5625
5731
  const existingObservations = freshRecord?.activeObservations ?? record.activeObservations ?? "";
5626
5732
  let newObservations;
5627
5733
  if (this.scope === "resource") {
5628
5734
  const threadSection = await this.wrapWithThreadTag(threadId, result.observations);
5629
- newObservations = this.replaceOrAppendThreadSection(existingObservations, threadId, threadSection);
5735
+ newObservations = this.replaceOrAppendThreadSection(
5736
+ existingObservations,
5737
+ threadId,
5738
+ threadSection,
5739
+ lastObservedAt
5740
+ );
5630
5741
  } else {
5631
- newObservations = existingObservations ? `${existingObservations}
5632
-
5633
- ${result.observations}` : result.observations;
5742
+ newObservations = existingObservations ? `${existingObservations}${_ObservationalMemory.createMessageBoundary(lastObservedAt)}${result.observations}` : result.observations;
5634
5743
  }
5635
5744
  let totalTokenCount = this.tokenCounter.countObservations(newObservations);
5636
5745
  const cycleObservationTokens = this.tokenCounter.countObservations(result.observations);
5637
- const lastObservedAt = this.getMaxMessageTimestamp(messagesToObserve);
5638
5746
  const newMessageIds = messagesToObserve.map((m) => m.id);
5639
5747
  const existingIds = freshRecord?.observedMessageIds ?? record.observedMessageIds ?? [];
5640
5748
  const allObservedIds = [.../* @__PURE__ */ new Set([...Array.isArray(existingIds) ? existingIds : [], ...newMessageIds])];
@@ -6528,9 +6636,14 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
6528
6636
  if (!obsResult) continue;
6529
6637
  const { threadId, threadMessages, result } = obsResult;
6530
6638
  cycleObservationTokens += this.tokenCounter.countObservations(result.observations);
6531
- const threadSection = await this.wrapWithThreadTag(threadId, result.observations);
6532
- currentObservations = this.replaceOrAppendThreadSection(currentObservations, threadId, threadSection);
6533
6639
  const threadLastObservedAt = this.getMaxMessageTimestamp(threadMessages);
6640
+ const threadSection = await this.wrapWithThreadTag(threadId, result.observations);
6641
+ currentObservations = this.replaceOrAppendThreadSection(
6642
+ currentObservations,
6643
+ threadId,
6644
+ threadSection,
6645
+ threadLastObservedAt
6646
+ );
6534
6647
  const thread = await this.storage.getThreadById({ threadId });
6535
6648
  if (thread) {
6536
6649
  const newMetadata = memory.setThreadOMMetadata(thread.metadata, {
@@ -6975,6 +7088,30 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
6975
7088
  }
6976
7089
  };
6977
7090
 
7091
+ // src/processors/observational-memory/observation-utils.ts
7092
+ var BOUNDARY_WITH_DATE_RE = /\n{2,}--- message boundary \((\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z)\) ---\n{2,}/;
7093
+ function getObservationsAsOf(activeObservations, asOf) {
7094
+ const trimmed = activeObservations.trim();
7095
+ if (!trimmed) return "";
7096
+ const parts = trimmed.split(BOUNDARY_WITH_DATE_RE);
7097
+ const chunks = [];
7098
+ const firstChunk = parts[0]?.trim();
7099
+ if (firstChunk) {
7100
+ chunks.push(firstChunk);
7101
+ }
7102
+ for (let i = 1; i < parts.length; i += 2) {
7103
+ const dateStr = parts[i];
7104
+ const chunk = parts[i + 1]?.trim();
7105
+ if (!chunk) continue;
7106
+ const boundaryDate = new Date(dateStr);
7107
+ if (isNaN(boundaryDate.getTime())) continue;
7108
+ if (boundaryDate <= asOf) {
7109
+ chunks.push(chunk);
7110
+ }
7111
+ }
7112
+ return chunks.join("\n\n");
7113
+ }
7114
+
6978
7115
  exports.OBSERVATIONAL_MEMORY_DEFAULTS = OBSERVATIONAL_MEMORY_DEFAULTS;
6979
7116
  exports.OBSERVATION_CONTEXT_INSTRUCTIONS = OBSERVATION_CONTEXT_INSTRUCTIONS;
6980
7117
  exports.OBSERVATION_CONTEXT_PROMPT = OBSERVATION_CONTEXT_PROMPT;
@@ -6986,8 +7123,9 @@ exports.buildObserverPrompt = buildObserverPrompt;
6986
7123
  exports.buildObserverSystemPrompt = buildObserverSystemPrompt;
6987
7124
  exports.extractCurrentTask = extractCurrentTask;
6988
7125
  exports.formatMessagesForObserver = formatMessagesForObserver;
7126
+ exports.getObservationsAsOf = getObservationsAsOf;
6989
7127
  exports.hasCurrentTaskSection = hasCurrentTaskSection;
6990
7128
  exports.optimizeObservationsForContext = optimizeObservationsForContext;
6991
7129
  exports.parseObserverOutput = parseObserverOutput;
6992
- //# sourceMappingURL=chunk-YPFNHFT6.cjs.map
6993
- //# sourceMappingURL=chunk-YPFNHFT6.cjs.map
7130
+ //# sourceMappingURL=chunk-LGCREJMO.cjs.map
7131
+ //# sourceMappingURL=chunk-LGCREJMO.cjs.map