@mastra/memory 1.26.2 → 1.27.0-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 (45) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/dist/docs/SKILL.md +6 -6
  3. package/dist/docs/assets/SOURCE_MAP.json +1 -1
  4. package/dist/docs/references/{docs-agents-agent-approval.md → docs-agents-human-in-the-loop.md} +7 -5
  5. package/dist/docs/references/docs-agents-networks.md +3 -3
  6. package/dist/docs/references/{docs-long-running-agents-background-tasks.md → docs-harness-background-tasks.md} +5 -5
  7. package/dist/docs/references/{docs-long-running-agents-goals.md → docs-harness-goals.md} +6 -6
  8. package/dist/docs/references/docs-memory-message-history.md +1 -1
  9. package/dist/docs/references/docs-memory-overview.md +4 -4
  10. package/dist/docs/references/docs-memory-working-memory.md +1 -1
  11. package/dist/docs/references/{docs-storage-overview.md → docs-storage.md} +1 -1
  12. package/dist/docs/references/{docs-capabilities-subagents.md → docs-subagents.md} +35 -5
  13. package/dist/docs/references/integrations-channels-github.md +1 -1
  14. package/dist/docs/references/integrations-databases-postgresql.md +3 -1
  15. package/dist/docs/references/reference-file-based-agents-memory.md +2 -2
  16. package/dist/docs/references/reference-memory-observational-memory.md +4 -0
  17. package/dist/index.cjs +1 -1
  18. package/dist/index.js +1 -1
  19. package/dist/processors/index.cjs +1 -1
  20. package/dist/processors/index.js +1 -1
  21. package/dist/processors/observational-memory/built-in-extractors.d.ts +13 -4
  22. package/dist/processors/observational-memory/built-in-extractors.d.ts.map +1 -1
  23. package/dist/processors/observational-memory/index.d.ts +1 -1
  24. package/dist/processors/observational-memory/index.d.ts.map +1 -1
  25. package/dist/processors/observational-memory/observation-turn/step.d.ts.map +1 -1
  26. package/dist/processors/observational-memory/observation-turn/turn.d.ts +4 -0
  27. package/dist/processors/observational-memory/observation-turn/turn.d.ts.map +1 -1
  28. package/dist/processors/observational-memory/observational-memory.d.ts +5 -1
  29. package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
  30. package/dist/processors/observational-memory/observer-agent.d.ts +13 -0
  31. package/dist/processors/observational-memory/observer-agent.d.ts.map +1 -1
  32. package/dist/processors/observational-memory/processor.d.ts.map +1 -1
  33. package/dist/processors/observational-memory/reflector-agent.d.ts +1 -0
  34. package/dist/processors/observational-memory/reflector-agent.d.ts.map +1 -1
  35. package/dist/processors/observational-memory/token-counter.d.ts +1 -0
  36. package/dist/processors/observational-memory/token-counter.d.ts.map +1 -1
  37. package/dist/processors/observational-memory/types.d.ts +31 -0
  38. package/dist/processors/observational-memory/types.d.ts.map +1 -1
  39. package/dist/{src-BYD6Wp5m.js → src-BKRU-0Fx.js} +164 -64
  40. package/dist/{src-BYD6Wp5m.js.map → src-BKRU-0Fx.js.map} +1 -1
  41. package/dist/{src-b5E69E65.cjs → src-_7ADtEwc.cjs} +164 -64
  42. package/dist/{src-b5E69E65.cjs.map → src-_7ADtEwc.cjs.map} +1 -1
  43. package/dist/tools/working-memory.d.ts +3 -1
  44. package/dist/tools/working-memory.d.ts.map +1 -1
  45. package/package.json +3 -3
@@ -15925,21 +15925,17 @@ Or as a standalone observation when closing out a broader task:
15925
15925
  Completion observations should be terse but specific about WHAT was completed.
15926
15926
  Prefer concrete resolved outcomes over abstract workflow status so the assistant remembers what is already done.`;
15927
15927
  buildObserverOutputFormat();
15928
- function buildObserverOutputFormat(extractors = []) {
15929
- const extractorSections = buildExtractorOutputSections(extractors);
15930
- const legacyContinuationSections = extractors.length === 0 ? `
15931
- <current-task>
15932
- State the current task(s) explicitly:
15933
- - Primary: What the agent is currently working on
15934
- - Secondary: Other pending tasks (mark as "waiting for user" if appropriate)
15935
- </current-task>
15936
-
15937
- <suggested-response>
15938
- Hint for the agent's immediate next message. Examples:
15939
- - "I've updated the navigation model. Let me walk you through the changes..."
15940
- - "The assistant should wait for the user to respond before continuing."
15941
- - Call the view tool on src/example.ts to continue debugging.
15942
- </suggested-response>` : "";
15928
+ /**
15929
+ * Build the Observer's output format.
15930
+ *
15931
+ * `extractors` distinguishes two cases that both look empty:
15932
+ * - `undefined` — the no-arg call behind the exported defaults (OBSERVER_OUTPUT_FORMAT_BASE,
15933
+ * OBSERVER_SYSTEM_PROMPT, REFLECTOR_SYSTEM_PROMPT), which keep describing both built-in
15934
+ * sections with their historical text. Runtime callers always pass the composed list.
15935
+ * - `[]` — the caller composed extractors and every section was disabled, so no continuation
15936
+ * sections are described at all.
15937
+ */
15938
+ function buildObserverOutputFormat(extractors) {
15943
15939
  return `Use priority levels:
15944
15940
  - 🔴 High: explicit user facts, preferences, unresolved goals, critical context
15945
15941
  - 🟡 Medium: project details, learned information, tool results
@@ -15965,7 +15961,19 @@ Date: Dec 5, 2025
15965
15961
  * 🔴 (09:15) Continued work on feature X
15966
15962
  </observations>
15967
15963
 
15968
- ${extractorSections || legacyContinuationSections}`;
15964
+ ${buildExtractorOutputSections(extractors ?? []) || (extractors === void 0 ? `
15965
+ <current-task>
15966
+ State the current task(s) explicitly:
15967
+ - Primary: What the agent is currently working on
15968
+ - Secondary: Other pending tasks (mark as "waiting for user" if appropriate)
15969
+ </current-task>
15970
+
15971
+ <suggested-response>
15972
+ Hint for the agent's immediate next message. Examples:
15973
+ - "I've updated the navigation model. Let me walk you through the changes..."
15974
+ - "The assistant should wait for the user to respond before continuing."
15975
+ - Call the view tool on src/example.ts to continue debugging.
15976
+ </suggested-response>` : "")}`;
15969
15977
  }
15970
15978
  /**
15971
15979
  * The guidelines for the Observer.
@@ -15992,10 +16000,22 @@ const OBSERVER_GUIDELINES = `- Be specific enough for the assistant to act on
15992
16000
  * Build the complete observer system prompt.
15993
16001
  * @param multiThread - Whether this is for multi-thread batched observation (default: false)
15994
16002
  * @param instruction - Optional custom instructions to append to the prompt
16003
+ * @param includeThreadTitle - Whether the Observer should also produce a thread title
16004
+ * @param extractors - Active extractors, used to decide which sections the prompt describes.
16005
+ * Omitted only by the exported no-arg defaults; pass `[]` to describe no continuation sections at all.
15995
16006
  */
15996
- function buildObserverSystemPrompt(multiThread = false, instruction, includeThreadTitle = false, extractors = []) {
16007
+ function buildObserverSystemPrompt(multiThread = false, instruction, includeThreadTitle = false, extractors) {
15997
16008
  const outputFormat = buildObserverOutputFormat(extractors);
15998
- const multiThreadTitleInstruction = includeThreadTitle ? ` Each thread's observations, current-task, suggested-response, and thread-title should be nested inside a <thread id="..."> block within <observations>.` : ` Each thread's observations, current-task, and suggested-response should be nested inside a <thread id="..."> block within <observations>.`;
16009
+ const customInstructions = instruction ? `\n\n=== CUSTOM INSTRUCTIONS ===\n\n${instruction}` : "";
16010
+ const currentTaskEnabled = extractors === void 0 || extractors.some((extractor) => extractor.slug === "current-task");
16011
+ const suggestedResponseEnabled = extractors === void 0 || extractors.some((extractor) => extractor.slug === "suggested-response");
16012
+ const multiThreadSections = [
16013
+ "observations",
16014
+ ...currentTaskEnabled ? ["current-task"] : [],
16015
+ ...suggestedResponseEnabled ? ["suggested-response"] : [],
16016
+ ...includeThreadTitle ? ["thread-title"] : []
16017
+ ];
16018
+ const multiThreadTitleInstruction = ` Each thread's ${multiThreadSections.length <= 2 ? multiThreadSections.join(" and ") : `${multiThreadSections.slice(0, -1).join(", ")}, and ${multiThreadSections[multiThreadSections.length - 1]}`} should be nested inside a <thread id="..."> block within <observations>.`;
15999
16019
  const multiThreadTitleExample = includeThreadTitle ? `
16000
16020
  <thread-title>Feature X implementation</thread-title>` : "";
16001
16021
  const multiThreadSecondTitleExample = includeThreadTitle ? `
@@ -16025,28 +16045,28 @@ For multi-thread output, wrap each thread's observations like this:
16025
16045
  <thread id="thread_id_1">
16026
16046
  Date: Dec 4, 2025
16027
16047
  * 🔴 (14:30) User prefers direct answers
16028
- * 🔴 (14:31) Working on feature X
16048
+ * 🔴 (14:31) Working on feature X${currentTaskEnabled ? `
16029
16049
 
16030
16050
  <current-task>
16031
16051
  What the agent is currently working on in this thread
16032
- </current-task>
16052
+ </current-task>` : ""}${suggestedResponseEnabled ? `
16033
16053
 
16034
16054
  <suggested-response>
16035
16055
  Hint for the agent's next message in this thread
16036
- </suggested-response>${multiThreadTitleExample}
16056
+ </suggested-response>` : ""}${multiThreadTitleExample}
16037
16057
  </thread>
16038
16058
 
16039
16059
  <thread id="thread_id_2">
16040
16060
  Date: Dec 5, 2025
16041
- * 🔴 (09:15) User asked about deployment
16061
+ * 🔴 (09:15) User asked about deployment${currentTaskEnabled ? `
16042
16062
 
16043
16063
  <current-task>
16044
16064
  Current task for this thread
16045
- </current-task>
16065
+ </current-task>` : ""}${suggestedResponseEnabled ? `
16046
16066
 
16047
16067
  <suggested-response>
16048
16068
  Suggested response for this thread
16049
- </suggested-response>${multiThreadSecondTitleExample}
16069
+ </suggested-response>` : ""}${multiThreadSecondTitleExample}
16050
16070
  </thread>
16051
16071
  </observations>
16052
16072
 
@@ -16056,7 +16076,7 @@ ${OBSERVER_GUIDELINES}
16056
16076
 
16057
16077
  Remember: These observations are the assistant's ONLY memory. Make them count.
16058
16078
 
16059
- User messages are extremely important. If the user asks a question or gives a new task, make it clear in <current-task> that this is the priority.${instruction ? `\n\n=== CUSTOM INSTRUCTIONS ===\n\n${instruction}` : ""}`;
16079
+ User messages are extremely important.${currentTaskEnabled ? " If the user asks a question or gives a new task, make it clear in <current-task> that this is the priority." : ""}${customInstructions}`;
16060
16080
  return `You are the memory consciousness of an AI assistant. Your observations will be the ONLY information the assistant has about past interactions with this user.
16061
16081
 
16062
16082
  Extract observations that will help the assistant remember:
@@ -16081,7 +16101,7 @@ Simply output your observations without any thread-related markup.
16081
16101
 
16082
16102
  Remember: These observations are the assistant's ONLY memory. Make them count.
16083
16103
 
16084
- User messages are extremely important. If the user asks a question or gives a new task, make it clear in <current-task> that this is the priority. If the assistant needs to respond to the user, indicate in <suggested-response> that it should pause for user reply before continuing other tasks.${instruction ? `\n\n=== CUSTOM INSTRUCTIONS ===\n\n${instruction}` : ""}`;
16104
+ User messages are extremely important.${currentTaskEnabled ? " If the user asks a question or gives a new task, make it clear in <current-task> that this is the priority." : ""}${suggestedResponseEnabled ? " If the assistant needs to respond to the user, indicate in <suggested-response> that it should pause for user reply before continuing other tasks." : ""}${customInstructions}`;
16085
16105
  }
16086
16106
  /**
16087
16107
  * Observer Agent System Prompt (default - for backwards compatibility)
@@ -16773,7 +16793,7 @@ function optimizeObservationsForContext(observations) {
16773
16793
  let optimized = stripEphemeralAnchorIds(observations);
16774
16794
  optimized = optimized.replace(/🟡\s*/g, "");
16775
16795
  optimized = optimized.replace(/🟢\s*/g, "");
16776
- optimized = optimized.replace(/\[(?![\d\s]*items collapsed)[^\]]+\]/g, "");
16796
+ optimized = optimized.replace(/\[(?![\d\s]*items collapsed)[^\]]+\](?!\()/g, "");
16777
16797
  optimized = optimized.replace(/\s*->\s*/g, " ");
16778
16798
  optimized = optimized.replace(/ +/g, " ");
16779
16799
  optimized = optimized.replace(/\n{3,}/g, "\n\n");
@@ -18195,6 +18215,7 @@ var TokenCounter = class TokenCounter {
18195
18215
  defaultModelContext;
18196
18216
  modelContextStorage = new AsyncLocalStorage();
18197
18217
  inFlightAttachmentCounts = /* @__PURE__ */ new Map();
18218
+ multimodalToolResultCounts = /* @__PURE__ */ new WeakMap();
18198
18219
  static TOKENS_PER_MESSAGE = 3.8;
18199
18220
  static TOKENS_PER_CONVERSATION = 24;
18200
18221
  constructor(options) {
@@ -18257,6 +18278,9 @@ var TokenCounter = class TokenCounter {
18257
18278
  }
18258
18279
  countMultimodalToolResultContent(part, toolResult) {
18259
18280
  if (!toolResult || typeof toolResult !== "object") return;
18281
+ const resultKey = buildEstimateKey("tool-result-multimodal-content-source", JSON.stringify(toolResult));
18282
+ const cached = this.multimodalToolResultCounts.get(part);
18283
+ if (cached?.resultKey === resultKey) return cached.tokens;
18260
18284
  const output = toolResult;
18261
18285
  const content = output.type === "content" && Array.isArray(output.value) ? output.value : output.content;
18262
18286
  if (!Array.isArray(content)) return;
@@ -18368,10 +18392,15 @@ var TokenCounter = class TokenCounter {
18368
18392
  countJsonContentPart(contentPart);
18369
18393
  }
18370
18394
  if (!hasAttachment) return;
18371
- return this.readOrPersistFixedPartEstimate(part, "tool-result-multimodal-content", JSON.stringify({
18395
+ const estimate = this.readOrPersistFixedPartEstimate(part, "tool-result-multimodal-content", JSON.stringify({
18372
18396
  type: "content",
18373
18397
  value: cacheParts
18374
18398
  }), tokens);
18399
+ this.multimodalToolResultCounts.set(part, {
18400
+ resultKey,
18401
+ tokens: estimate
18402
+ });
18403
+ return estimate;
18375
18404
  }
18376
18405
  estimateImageAssetTokens(part, asset, kind) {
18377
18406
  const modelContext = this.getModelContext();
@@ -19853,21 +19882,22 @@ const SET_WORKING_MEMORY_TOOL_NAME = "setWorkingMemory";
19853
19882
  /**
19854
19883
  * Deep merges two objects, with special handling for null values (delete) and arrays (replace).
19855
19884
  * - Object properties are recursively merged
19856
- * - null values in the update will delete the corresponding property
19885
+ * - null values in the update will delete the corresponding property, even when the property
19886
+ * or its parent object does not exist yet (so padded nulls never get stored literally)
19857
19887
  * - Arrays are replaced entirely (not merged element-by-element)
19858
19888
  * - Primitive values are overwritten
19889
+ * - The returned object is always newly constructed and never aliases `update`
19859
19890
  */
19860
19891
  function deepMergeWorkingMemory(existing, update) {
19861
19892
  if (!update || typeof update !== "object" || Object.keys(update).length === 0) return existing && typeof existing === "object" ? { ...existing } : {};
19862
- if (!existing || typeof existing !== "object") return update;
19863
- const result = { ...existing };
19893
+ const result = { ...existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {} };
19864
19894
  for (const key of Object.keys(update)) {
19865
19895
  const updateValue = update[key];
19866
19896
  const existingValue = result[key];
19867
19897
  if (updateValue === void 0) continue;
19868
19898
  if (updateValue === null) delete result[key];
19869
19899
  else if (Array.isArray(updateValue)) result[key] = updateValue;
19870
- else if (typeof updateValue === "object" && updateValue !== null && typeof existingValue === "object" && existingValue !== null && !Array.isArray(existingValue)) result[key] = deepMergeWorkingMemory(existingValue, updateValue);
19900
+ else if (typeof updateValue === "object") result[key] = deepMergeWorkingMemory(existingValue && typeof existingValue === "object" && !Array.isArray(existingValue) ? existingValue : void 0, updateValue);
19871
19901
  else result[key] = updateValue;
19872
19902
  }
19873
19903
  return result;
@@ -20358,23 +20388,43 @@ function createThreadTitleExtractor() {
20358
20388
  metadataKeyPath: "threadTitle"
20359
20389
  }, true);
20360
20390
  }
20391
+ /**
20392
+ * Normalize the user-facing `continuationHints` config into explicit per-section flags.
20393
+ * Both sections stay enabled unless the caller opts out, so omitting the config is a no-op.
20394
+ */
20395
+ function resolveContinuationHints(config) {
20396
+ if (config === void 0 || config === true) return {
20397
+ currentTask: true,
20398
+ suggestedResponse: true
20399
+ };
20400
+ if (config === false) return {
20401
+ currentTask: false,
20402
+ suggestedResponse: false
20403
+ };
20404
+ return {
20405
+ currentTask: config.currentTask ?? true,
20406
+ suggestedResponse: config.suggestedResponse ?? true
20407
+ };
20408
+ }
20361
20409
  function composeExtractors(options) {
20410
+ const continuationHints = resolveContinuationHints(options.continuationHints);
20362
20411
  const extractors = [];
20363
- if (options.includeContinuationHints) extractors.push(createCurrentTaskExtractor(), createSuggestedResponseExtractor());
20412
+ if (continuationHints.currentTask) extractors.push(createCurrentTaskExtractor());
20413
+ if (continuationHints.suggestedResponse) extractors.push(createSuggestedResponseExtractor());
20364
20414
  if (options.includeThreadTitle) extractors.push(createThreadTitleExtractor());
20365
20415
  extractors.push(...options.userExtractors ?? []);
20366
20416
  return validateExtractorList(extractors);
20367
20417
  }
20368
20418
  function composeObservationExtractors(config) {
20369
20419
  return composeExtractors({
20370
- includeContinuationHints: true,
20420
+ continuationHints: config.continuationHints,
20371
20421
  includeThreadTitle: config.threadTitle,
20372
20422
  userExtractors: config.extract
20373
20423
  });
20374
20424
  }
20375
20425
  function composeReflectionExtractors(config) {
20376
20426
  return composeExtractors({
20377
- includeContinuationHints: true,
20427
+ continuationHints: config.continuationHints,
20378
20428
  userExtractors: config.extract
20379
20429
  });
20380
20430
  }
@@ -22159,10 +22209,12 @@ var ObservationStep = class {
22159
22209
  resourceId,
22160
22210
  checkThreshold: true,
22161
22211
  messages: step0Messages,
22212
+ record: this.turn.record,
22162
22213
  currentModel: this.turn.actorModelContext,
22163
22214
  writer: this.turn.writer,
22164
22215
  messageList
22165
22216
  });
22217
+ this.turn.setRecord(activation.record);
22166
22218
  if (activation.activated) {
22167
22219
  activated = true;
22168
22220
  if (activation.activatedMessageIds?.length) messageList.removeByIds(activation.activatedMessageIds);
@@ -22204,6 +22256,7 @@ var ObservationStep = class {
22204
22256
  let statusSnapshot = await om.getStatus({
22205
22257
  threadId,
22206
22258
  resourceId,
22259
+ record: this.turn.record,
22207
22260
  messages: getObservableMessages(messageList)
22208
22261
  });
22209
22262
  if (statusSnapshot.shouldBuffer && !hasIncompleteToolCalls) {
@@ -22299,6 +22352,7 @@ var ObservationStep = class {
22299
22352
  statusSnapshot = await om.getStatus({
22300
22353
  threadId,
22301
22354
  resourceId,
22355
+ record: this.turn.record,
22302
22356
  messages: getObservableMessages(messageList)
22303
22357
  });
22304
22358
  }
@@ -22349,10 +22403,12 @@ var ObservationStep = class {
22349
22403
  const { threadId, resourceId, messageList } = this.turn;
22350
22404
  const om = this.turn.om;
22351
22405
  await om.waitForBuffering(threadId, resourceId);
22406
+ await this.turn.refreshRecord();
22352
22407
  const observableMessages = this.seededResponseMessage ? getObservableMessages(messageList).filter((msg) => msg.id !== this.turn.responseMessageId) : getObservableMessages(messageList);
22353
22408
  const freshStatus = await om.getStatus({
22354
22409
  threadId,
22355
22410
  resourceId,
22411
+ record: this.turn.record,
22356
22412
  messages: observableMessages
22357
22413
  });
22358
22414
  if (!freshStatus.shouldObserve) return {
@@ -22363,11 +22419,13 @@ var ObservationStep = class {
22363
22419
  const activation = await om.activate({
22364
22420
  threadId,
22365
22421
  resourceId,
22422
+ record: this.turn.record,
22366
22423
  messages: observableMessages,
22367
22424
  currentModel: this.turn.actorModelContext,
22368
22425
  writer: this.turn.writer,
22369
22426
  messageList
22370
22427
  });
22428
+ this.turn.setRecord(activation.record);
22371
22429
  if (activation.activated) {
22372
22430
  const postActivationRecord = activation.record;
22373
22431
  await om.reflector.maybeReflect({
@@ -22552,6 +22610,18 @@ var ObservationTurn = class {
22552
22610
  };
22553
22611
  return this._context;
22554
22612
  }
22613
+ /** Replace the cached turn record with a specific instance. */
22614
+ setRecord(record) {
22615
+ this._record = record;
22616
+ if (this._context) this._context.record = record;
22617
+ }
22618
+ /** Patch the cached turn record with merged fields. */
22619
+ patchRecord(patch) {
22620
+ this.setRecord({
22621
+ ...this.record,
22622
+ ...patch
22623
+ });
22624
+ }
22555
22625
  /**
22556
22626
  * Create a step handle. If a previous step exists, it is finalized
22557
22627
  * (its output messages will be saved at the start of the new step's prepare()).
@@ -22606,7 +22676,7 @@ var ObservationTurn = class {
22606
22676
  * @internal
22607
22677
  */
22608
22678
  async refreshRecord() {
22609
- this._record = await this.om.getOrCreateRecord(this.threadId, this.resourceId);
22679
+ this.setRecord(await this.om.getOrCreateRecord(this.threadId, this.resourceId));
22610
22680
  }
22611
22681
  /**
22612
22682
  * Refresh cross-thread context for resource scope. Called per-step.
@@ -22661,9 +22731,13 @@ var ObservationTurn = class {
22661
22731
  * - Preserving ALL important information (reflections become the ENTIRE memory)
22662
22732
  *
22663
22733
  * @param instruction - Optional custom instructions to append to the prompt
22734
+ * @param extractors - Active extractors, used to decide which sections the prompt describes
22664
22735
  */
22665
- function buildReflectorSystemPrompt(instruction, extractors = []) {
22736
+ function buildReflectorSystemPrompt(instruction, extractors) {
22666
22737
  const outputFormat = buildObserverOutputFormat(extractors);
22738
+ const customInstructions = instruction ? `\n\n=== CUSTOM INSTRUCTIONS ===\n\n${instruction}` : "";
22739
+ const currentTaskEnabled = extractors === void 0 || extractors.some((extractor) => extractor.slug === "current-task");
22740
+ const suggestedResponseEnabled = extractors === void 0 || extractors.some((extractor) => extractor.slug === "suggested-response");
22667
22741
  return `You are the memory consciousness of an AI assistant. Your memory observation reflections will be the ONLY information the assistant has about past interactions with this user.
22668
22742
 
22669
22743
  The following instructions were given to another part of your psyche (the observer) to create memories.
@@ -22740,7 +22814,7 @@ Date: Dec 4, 2025
22740
22814
 
22741
22815
  ${outputFormat}
22742
22816
 
22743
- User messages are extremely important. If the user asks a question or gives a new task, make it clear in <current-task> that this is the priority. If the assistant needs to respond to the user, indicate in <suggested-response> that it should pause for user reply before continuing other tasks.${instruction ? `\n\n=== CUSTOM INSTRUCTIONS ===\n\n${instruction}` : ""}`;
22817
+ User messages are extremely important.${currentTaskEnabled ? " If the user asks a question or gives a new task, make it clear in <current-task> that this is the priority." : ""}${suggestedResponseEnabled ? " If the assistant needs to respond to the user, indicate in <suggested-response> that it should pause for user reply before continuing other tasks." : ""}${customInstructions}`;
22744
22818
  }
22745
22819
  buildReflectorSystemPrompt();
22746
22820
  /**
@@ -24204,7 +24278,8 @@ var ObservationalMemory = class ObservationalMemory {
24204
24278
  observeAttachments: config.observation?.observeAttachments ?? true,
24205
24279
  extractors: composeObservationExtractors({
24206
24280
  threadTitle: config.observation?.threadTitle ?? false,
24207
- extract: config.observation?.extract
24281
+ extract: config.observation?.extract,
24282
+ continuationHints: config.observation?.continuationHints
24208
24283
  })
24209
24284
  };
24210
24285
  this.reflectionConfig = {
@@ -24221,7 +24296,10 @@ var ObservationalMemory = class ObservationalMemory {
24221
24296
  activateOnProviderChange: config.reflection?.activateOnProviderChange ?? false,
24222
24297
  blockAfter: asyncBufferingDisabled ? void 0 : resolveBlockAfter(config.reflection?.blockAfter ?? (config.reflection?.bufferActivation ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.bufferActivation ? 1.2 : void 0), config.reflection?.observationTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.observationTokens),
24223
24298
  instruction: config.reflection?.instruction,
24224
- extractors: composeReflectionExtractors({ extract: config.reflection?.extract })
24299
+ extractors: composeReflectionExtractors({
24300
+ extract: config.reflection?.extract,
24301
+ continuationHints: config.reflection?.continuationHints
24302
+ })
24225
24303
  };
24226
24304
  this.tokenCounter = new TokenCounter({ model: typeof observationModel === "string" ? observationModel : void 0 });
24227
24305
  this.onDebugEvent = config.onDebugEvent;
@@ -25336,8 +25414,9 @@ ${formattedMessages}
25336
25414
  return;
25337
25415
  }
25338
25416
  const omMetadata = getThreadOMMetadata((await this.storage.getThreadById({ threadId }))?.metadata);
25339
- const currentTask = omMetadata?.currentTask;
25340
- const suggestedResponse = omMetadata?.suggestedResponse;
25417
+ const activeExtractors = [...this.observationConfig.extractors, ...this.reflectionConfig.extractors];
25418
+ const currentTask = activeExtractors.some((extractor) => extractor.slug === "current-task") ? omMetadata?.currentTask : void 0;
25419
+ const suggestedResponse = activeExtractors.some((extractor) => extractor.slug === "suggested-response") ? omMetadata?.suggestedResponse : void 0;
25341
25420
  const currentDate = opts.currentDate ?? /* @__PURE__ */ new Date();
25342
25421
  return this.formatObservationsForContext(record.activeObservations, currentTask, suggestedResponse, omMetadata?.extracted, unobservedContextBlocks, currentDate, this.retrieval);
25343
25422
  }
@@ -25436,7 +25515,10 @@ ${formattedMessages}
25436
25515
  }
25437
25516
  };
25438
25517
  omDebug(`[OM:status] step=${stepNumber} msgs=${pendingTokens}/${threshold} obs=${currentObservationTokens}/${effectiveObservationTokensThreshold} gen=${record.generationCount}`);
25439
- await writer.custom(statusPart).catch(() => {});
25518
+ await writer.custom({
25519
+ ...statusPart,
25520
+ transient: true
25521
+ }).catch(() => {});
25440
25522
  }
25441
25523
  }
25442
25524
  /**
@@ -25462,11 +25544,11 @@ ${formattedMessages}
25462
25544
  * ```
25463
25545
  */
25464
25546
  async getStatus(opts) {
25465
- const { threadId, resourceId } = opts;
25466
- const record = await this.getOrCreateRecord(threadId, resourceId);
25547
+ const { threadId, resourceId, record: providedRecord, messages } = opts;
25548
+ const record = providedRecord ?? await this.getOrCreateRecord(threadId, resourceId);
25467
25549
  const currentObservationTokens = record.observationTokenCount ?? 0;
25468
25550
  let unobservedMessages;
25469
- if (opts.messages) unobservedMessages = this.getUnobservedMessages(opts.messages, record);
25551
+ if (messages) unobservedMessages = this.getUnobservedMessages(messages, record);
25470
25552
  else {
25471
25553
  const rawMessages = await this.loadMessagesFromStorage(threadId, resourceId, record.lastObservedAt ? new Date(record.lastObservedAt) : void 0);
25472
25554
  unobservedMessages = this.getUnobservedMessages(rawMessages, record);
@@ -25623,6 +25705,7 @@ ${formattedMessages}
25623
25705
  async buffer(opts) {
25624
25706
  const { threadId, resourceId, requestContext, observabilityContext } = opts;
25625
25707
  let record = opts.record ?? await this.getOrCreateRecord(threadId, resourceId);
25708
+ const inMemoryRecord = record;
25626
25709
  if (!this.buffering.isAsyncObservationEnabled()) return {
25627
25710
  buffered: false,
25628
25711
  record
@@ -25641,6 +25724,8 @@ ${formattedMessages}
25641
25724
  await existingOp;
25642
25725
  } catch {}
25643
25726
  registerOp(record.id, "bufferingObservation");
25727
+ inMemoryRecord.isBufferingObservation = true;
25728
+ inMemoryRecord.lastBufferedAtTokens = currentTokens;
25644
25729
  this.storage.setBufferingObservationFlag(record.id, true, currentTokens).catch((err) => {
25645
25730
  omError("[OM] Failed to set buffering observation flag", err);
25646
25731
  });
@@ -25650,6 +25735,14 @@ ${formattedMessages}
25650
25735
  });
25651
25736
  BufferingCoordinator.asyncBufferingOps.set(bufferKey, opPromise);
25652
25737
  record = await this.storage.getObservationalMemory(record.threadId, record.resourceId) ?? record;
25738
+ const setBufferingState = (isBufferingObservation, lastBufferedAtTokens) => {
25739
+ inMemoryRecord.isBufferingObservation = isBufferingObservation;
25740
+ record.isBufferingObservation = isBufferingObservation;
25741
+ if (lastBufferedAtTokens !== void 0) {
25742
+ inMemoryRecord.lastBufferedAtTokens = lastBufferedAtTokens;
25743
+ record.lastBufferedAtTokens = lastBufferedAtTokens;
25744
+ }
25745
+ };
25653
25746
  let flagCleared = false;
25654
25747
  try {
25655
25748
  let candidateMessages;
@@ -25671,10 +25764,13 @@ ${formattedMessages}
25671
25764
  }
25672
25765
  const minNewTokens = (this.observationConfig.bufferTokens ?? 5e3) / 2;
25673
25766
  const newTokens = await this.tokenCounter.countMessagesAsync(candidateMessages);
25674
- if (candidateMessages.length === 0 || !opts.skipMinimumTokenCheck && newTokens < minNewTokens) return {
25675
- buffered: false,
25676
- record
25677
- };
25767
+ if (candidateMessages.length === 0 || !opts.skipMinimumTokenCheck && newTokens < minNewTokens) {
25768
+ setBufferingState(false);
25769
+ return {
25770
+ buffered: false,
25771
+ record
25772
+ };
25773
+ }
25678
25774
  if (opts.beforeBuffer) await opts.beforeBuffer(candidateMessages);
25679
25775
  else if (opts.messages) this.sealMessagesForBuffering(candidateMessages);
25680
25776
  const cycleId = `buffer-obs-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
@@ -25729,13 +25825,14 @@ ${formattedMessages}
25729
25825
  });
25730
25826
  await this.storage.setBufferingObservationFlag(record.id, false, newTokens).catch(() => {});
25731
25827
  flagCleared = true;
25828
+ setBufferingState(false, newTokens);
25732
25829
  BufferingCoordinator.lastBufferedBoundary.set(bufferKey, newTokens);
25733
25830
  const maxTimestamp = this.getMaxMessageTimestamp(candidateMessages);
25734
25831
  const cursor = new Date(maxTimestamp.getTime() + 1);
25735
25832
  BufferingCoordinator.lastBufferedAtTime.set(bufferKey, cursor);
25736
25833
  return {
25737
25834
  buffered: true,
25738
- record: await this.getOrCreateRecord(threadId, resourceId)
25835
+ record: await this.storage.getObservationalMemory(record.threadId, record.resourceId) ?? record
25739
25836
  };
25740
25837
  } catch (error) {
25741
25838
  omError("[OM] buffer() failed", error);
@@ -25747,7 +25844,10 @@ ${formattedMessages}
25747
25844
  unregisterOp(record.id, "bufferingObservation");
25748
25845
  BufferingCoordinator.asyncBufferingOps.delete(bufferKey);
25749
25846
  resolveOp();
25750
- if (!flagCleared) await this.storage.setBufferingObservationFlag(record.id, false).catch(() => {});
25847
+ if (!flagCleared) {
25848
+ setBufferingState(false);
25849
+ await this.storage.setBufferingObservationFlag(record.id, false).catch(() => {});
25850
+ }
25751
25851
  }
25752
25852
  }
25753
25853
  /**
@@ -25773,7 +25873,7 @@ ${formattedMessages}
25773
25873
  /** @internal Used by ObservationStep. */
25774
25874
  async activate(opts) {
25775
25875
  const { threadId, resourceId } = opts;
25776
- const record = await this.getOrCreateRecord(threadId, resourceId);
25876
+ const record = opts.record ?? await this.getOrCreateRecord(threadId, resourceId);
25777
25877
  if (this.buffering.isAsyncObservationEnabled()) {
25778
25878
  const lockKey = this.buffering.getLockKey(threadId, resourceId);
25779
25879
  const bufKey = this.buffering.getObservationBufferKey(lockKey);
@@ -25819,6 +25919,7 @@ ${formattedMessages}
25819
25919
  const status = await this.getStatus({
25820
25920
  threadId,
25821
25921
  resourceId,
25922
+ record,
25822
25923
  messages: thresholdMessages
25823
25924
  });
25824
25925
  if (status.pendingTokens < status.threshold) return {
@@ -26538,31 +26639,30 @@ var ObservationalMemoryProcessor = class {
26538
26639
  threadId,
26539
26640
  resourceId
26540
26641
  });
26541
- const freshRecord = await this.engine.getOrCreateRecord(threadId, resourceId);
26642
+ const turnRecord = this.turn.record;
26542
26643
  await this.engine.emitProgress({
26543
- record: freshRecord,
26644
+ record: turnRecord,
26544
26645
  stepNumber,
26545
26646
  pendingTokens: ctx.status.pendingTokens,
26546
26647
  threshold: ctx.status.threshold,
26547
26648
  effectiveObservationTokensThreshold: ctx.status.effectiveObservationTokensThreshold,
26548
- currentObservationTokens: freshRecord.observationTokenCount ?? 0,
26649
+ currentObservationTokens: turnRecord.observationTokenCount ?? 0,
26549
26650
  writer,
26550
26651
  threadId,
26551
26652
  resourceId
26552
26653
  });
26553
- const allDbMsgs = getObservableMessages(messageList);
26554
- const tokenCounter = this.engine.getTokenCounter();
26555
- const contextTokens = await tokenCounter.countMessagesAsync(allDbMsgs);
26556
- const otherThreadsContext = this.turn.context.otherThreadsContext;
26557
- const finalTotalPending = contextTokens + (otherThreadsContext ? tokenCounter.countString(otherThreadsContext) : 0);
26558
- await this.engine.getStorage().setPendingMessageTokens(freshRecord.id, finalTotalPending).catch(() => {});
26654
+ const finalTotalPending = ctx.status.pendingTokens;
26655
+ try {
26656
+ await this.engine.getStorage().setPendingMessageTokens(turnRecord.id, finalTotalPending);
26657
+ this.turn.patchRecord({ pendingMessageTokens: finalTotalPending });
26658
+ } catch {}
26559
26659
  if (reproCaptureEnabled) writeProcessInputStepReproCapture({
26560
26660
  threadId,
26561
26661
  resourceId,
26562
26662
  stepNumber,
26563
26663
  args,
26564
26664
  preRecord: preRecordSnapshot,
26565
- postRecord: safeCaptureJson(freshRecord),
26665
+ postRecord: safeCaptureJson(turnRecord),
26566
26666
  preMessages: preMessagesSnapshot,
26567
26667
  preBufferedChunks: [],
26568
26668
  preContextTokenCount: 0,
@@ -28696,4 +28796,4 @@ Notes:
28696
28796
  //#endregion
28697
28797
  export { extractCurrentTask as A, OBSERVATION_CONTEXT_INSTRUCTIONS as B, WorkingMemoryExtractor as C, OBSERVER_SYSTEM_PROMPT as D, TokenCounter as E, injectAnchorIds as F, OBSERVATION_CONTINUATION_HINT as H, parseAnchorId as I, stripEphemeralAnchorIds as L, hasCurrentTaskSection as M, optimizeObservationsForContext as N, buildObserverPrompt as O, parseObserverOutput as P, Extractor as R, deepMergeWorkingMemory as S, summarizeConversation as T, OBSERVATION_CONTEXT_PROMPT as V, reconcileObservationGroupsFromReflection as _, extractWorkingMemoryContent as a, wrapInObservationGroup as b, WORKING_MEMORY_STATE_ID as c, getObservationsAsOf as d, ObservationalMemoryProcessor as f, parseObservationGroups as g, deriveObservationGroupProvenance as h, WorkingMemory as i, formatMessagesForObserver as j, buildObserverSystemPrompt as k, WORKING_MEMORY_STATE_PROCESSOR_ID as l, combineObservationGroupRanges as m, MessageHistory$1 as n, extractWorkingMemoryTags as o, ObservationalMemory as p, SemanticRecall as r, removeWorkingMemoryTags as s, Memory as t, WorkingMemoryStateProcessor as u, renderObservationGroupsForReflection as v, SUMMARIZE_THREAD_DEFAULTS as w, ModelByInputTokens as x, stripObservationGroups as y, OBSERVATIONAL_MEMORY_DEFAULTS as z };
28698
28798
 
28699
- //# sourceMappingURL=src-BYD6Wp5m.js.map
28799
+ //# sourceMappingURL=src-BKRU-0Fx.js.map