@mastra/memory 1.25.0-alpha.1 → 1.25.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.
@@ -14604,7 +14604,7 @@ var constants_exports = /* @__PURE__ */ __exportAll({
14604
14604
  OBSERVATION_CONTEXT_INSTRUCTIONS: () => OBSERVATION_CONTEXT_INSTRUCTIONS,
14605
14605
  OBSERVATION_CONTEXT_PROMPT: () => OBSERVATION_CONTEXT_PROMPT,
14606
14606
  OBSERVATION_CONTINUATION_HINT: () => OBSERVATION_CONTINUATION_HINT,
14607
- OBSERVATION_RETRIEVAL_INSTRUCTIONS: () => OBSERVATION_RETRIEVAL_INSTRUCTIONS
14607
+ getRetrievalInstructions: () => getRetrievalInstructions
14608
14608
  });
14609
14609
  /**
14610
14610
  * Default configuration values matching the spec
@@ -14667,8 +14667,22 @@ SYSTEM REMINDERS: Messages wrapped in <system-reminder>...</system-reminder> con
14667
14667
  /**
14668
14668
  * Instructions for retrieval mode — explains observation-group ranges and the recall tool.
14669
14669
  * Appended to context when `retrieval` is enabled.
14670
+ *
14671
+ * The content adapts to the retrieval scope:
14672
+ * - `'resource'`: covers routing between `search`, `threads`, and `messages` across
14673
+ * all of the user's threads, including fallback when search results are unsuitable.
14674
+ * - `'thread'`: covers cursor-based browsing and search within the current thread.
14675
+ *
14676
+ * @param scope - The retrieval scope the recall tool was registered with.
14677
+ * @param customInstructions - Optional application-provided guidance appended after
14678
+ * the native instructions. Never replaces them.
14679
+ * @param searchEnabled - Whether semantic search (`retrieval: { vector: true }`) is
14680
+ * available. When false, the guidance only covers \`threads\`/\`messages\` browsing so
14681
+ * the agent is not steered toward a mode that cannot work.
14670
14682
  */
14671
- const OBSERVATION_RETRIEVAL_INSTRUCTIONS = `## Recall looking up source messages
14683
+ function getRetrievalInstructions(scope = "resource", customInstructions, searchEnabled = true) {
14684
+ const isResource = scope === "resource";
14685
+ const base = `## Recall — looking up source messages
14672
14686
 
14673
14687
  Your memory is comprised of observations which are sometimes wrapped in <observation-group> xml tags containing ranges like <observation-group range="startId:endId">. These ranges point back to the raw messages that each observation group was derived from. The original messages are still available — use the **recall** tool to retrieve them.
14674
14688
 
@@ -14676,11 +14690,32 @@ Your memory is comprised of observations which are sometimes wrapped in <observa
14676
14690
  - The user asks you to **repeat, show, or reproduce** something from a past conversation
14677
14691
  - The user asks for **exact content** — code, text, quotes, error messages, URLs, file paths, specific numbers
14678
14692
  - Your observations mention something but your memory lacks the detail needed to fully answer (e.g. you know a blog post was shared but only have a summary of it)
14679
- - You want to **verify or expand on** an observation before responding
14693
+ - You want to **verify or expand on** an observation before responding${isResource ? `
14694
+ - The user references another conversation that your observations don't cover — even if you have no observations yet, their other threads may contain it` : ""}
14680
14695
 
14681
14696
  **Default to using recall when the user references specific past content.** Your observations capture the gist, not the details. If there's any doubt whether your memory is complete enough, use recall.
14682
14697
 
14683
- ### How to use recall
14698
+ ${isResource ? searchEnabled ? `### Choosing a mode
14699
+ The recall tool works across ALL of this user's conversation threads, not just the current one.
14700
+
14701
+ - Use \`mode: "search"\` with a \`query\` when you don't know which thread contains the answer. Each result includes its thread ID and the raw message IDs it came from, which you can use as a \`cursor\`.
14702
+ - Use \`mode: "messages"\` when you already know the thread — pass \`threadId\` to read another thread, or a \`cursor\` from an observation-group range or a search result.
14703
+ - Use \`mode: "threads"\` to list the user's threads (IDs, titles, dates) when you need to discover where something was discussed. Use \`before\`/\`after\` to narrow by date.
14704
+
14705
+ **If search results look irrelevant, do not give up.** Search only covers content that has been indexed — a short or recent conversation may exist in raw message history before any observation of it was created. When search returns nothing suitable but the user is clearly referring to a past conversation, call \`mode: "threads"\` to find candidate threads (titles and dates are strong clues), then read them with \`mode: "messages"\`. If a search result already gives you a thread ID, go straight to \`mode: "messages"\`.` : `### Choosing a mode
14706
+ The recall tool works across ALL of this user's conversation threads, not just the current one.
14707
+
14708
+ - Use \`mode: "threads"\` to list the user's threads (IDs, titles, dates) when you need to discover where something was discussed. Use \`before\`/\`after\` to narrow by date.
14709
+ - Use \`mode: "messages"\` when you know the thread — pass \`threadId\` to read another thread, or a \`cursor\` from an observation-group range.
14710
+
14711
+ When the user refers to a past conversation you don't have a cursor for, call \`mode: "threads"\` to find candidate threads (titles and dates are strong clues), then read them with \`mode: "messages"\`. Raw history may exist for threads that have no observations yet.` : `### Choosing a mode
14712
+ The recall tool is limited to the current conversation thread.
14713
+
14714
+ - Use \`mode: "messages"\` (default) to page through this thread's message history near a cursor.${searchEnabled ? `
14715
+ - Use \`mode: "search"\` with a \`query\` to find messages by content within this thread.` : ""}
14716
+ - Use \`mode: "threads"\` to get the current thread's ID, title, and dates.`}
14717
+
14718
+ ### How to use recall with a cursor
14684
14719
  Each range has the format \`startId:endId\` where both are message IDs separated by a colon.
14685
14720
 
14686
14721
  1. Find the observation group relevant to the user's question and extract the start or end ID from its range.
@@ -14706,9 +14741,16 @@ Low-detail results may include truncation hints like:
14706
14741
  ### When recall is NOT needed
14707
14742
  - The user is asking for a high-level summary and your observations already cover it
14708
14743
  - The question is about general preferences or facts that don't require source text
14709
- - There is no relevant range in your observations for the topic
14744
+ ${isResource ? `- No relevant observation range exists AND ${searchEnabled ? "`search`/`threads`" : "`threads`"} turned up nothing — but remember that raw history may exist for threads that have no observations yet, so check before concluding the information is unavailable` : `- There is no relevant range in your observations for the topic`}
14710
14745
 
14711
14746
  Observation groups with range IDs and your recall tool allows you to think back and remember details you're fuzzy on.`;
14747
+ const custom = customInstructions?.trim();
14748
+ if (!custom) return base;
14749
+ return `${base}
14750
+
14751
+ ### Additional recall guidance
14752
+ ${custom}`;
14753
+ }
14712
14754
  //#endregion
14713
14755
  //#region src/processors/observational-memory/extractor.ts
14714
14756
  const BUILT_IN_SLUGS = /* @__PURE__ */ new Set([
@@ -23732,6 +23774,11 @@ var ObservationalMemory = class ObservationalMemory {
23732
23774
  scope;
23733
23775
  /** Whether retrieval-mode observation groups are enabled. */
23734
23776
  retrieval;
23777
+ /** Scope the recall tool was registered with — controls which retrieval instructions are injected. */
23778
+ retrievalScope;
23779
+ /** Application-provided guidance appended after the native retrieval instructions. */
23780
+ retrievalInstructions;
23781
+ retrievalSearch;
23735
23782
  observationConfig;
23736
23783
  reflectionConfig;
23737
23784
  onDebugEvent;
@@ -23797,6 +23844,9 @@ var ObservationalMemory = class ObservationalMemory {
23797
23844
  this.storage = config.storage;
23798
23845
  this.scope = config.scope ?? "thread";
23799
23846
  this.retrieval = Boolean(config.retrieval);
23847
+ this.retrievalScope = typeof config.retrieval === "object" ? config.retrieval.scope ?? "resource" : "resource";
23848
+ this.retrievalInstructions = typeof config.retrieval === "object" ? config.retrieval.instructions : void 0;
23849
+ this.retrievalSearch = typeof config.retrieval === "object" && Boolean(config.retrieval.vector);
23800
23850
  this.onIndexObservations = config.onIndexObservations;
23801
23851
  this.hooks = config.hooks;
23802
23852
  this.mastra = config.mastra;
@@ -24445,7 +24495,7 @@ var ObservationalMemory = class ObservationalMemory {
24445
24495
  formatObservationsForContext(observations, currentTask, suggestedResponse, extractedValues, unobservedContextBlocks, currentDate, retrieval = false) {
24446
24496
  let optimized = retrieval ? renderObservationGroupsForReflection(observations) ?? optimizeObservationsForContext(observations) : optimizeObservationsForContext(observations);
24447
24497
  if (currentDate) optimized = addRelativeTimeToObservations(optimized, currentDate);
24448
- const messages = [`${OBSERVATION_CONTEXT_PROMPT}\n\n${OBSERVATION_CONTEXT_INSTRUCTIONS}${retrieval ? `\n\n${OBSERVATION_RETRIEVAL_INSTRUCTIONS}` : ""}`];
24498
+ const messages = [`${OBSERVATION_CONTEXT_PROMPT}\n\n${OBSERVATION_CONTEXT_INSTRUCTIONS}${retrieval ? `\n\n${getRetrievalInstructions(this.retrievalScope, this.retrievalInstructions, this.retrievalSearch)}` : ""}`];
24449
24499
  if (unobservedContextBlocks) messages.push(`The following content is from OTHER conversations different from the current conversation, they're here for reference, but they're not necessarily your focus:\nSTART_OTHER_CONVERSATIONS_BLOCK\n${unobservedContextBlocks}\nEND_OTHER_CONVERSATIONS_BLOCK`);
24450
24500
  const observationChunks = this.splitObservationContextChunks(optimized);
24451
24501
  if (observationChunks.length > 0) messages.push("<observations>", ...observationChunks);
@@ -24947,7 +24997,10 @@ ${formattedMessages}
24947
24997
  async buildContextSystemMessages(opts) {
24948
24998
  const { threadId, resourceId, unobservedContextBlocks } = opts;
24949
24999
  const record = opts.record ?? await this.getOrCreateRecord(threadId, resourceId);
24950
- if (!record.activeObservations) return void 0;
25000
+ if (!record.activeObservations) {
25001
+ if (this.retrieval && this.retrievalScope === "resource") return [getRetrievalInstructions(this.retrievalScope, this.retrievalInstructions, this.retrievalSearch)];
25002
+ return;
25003
+ }
24951
25004
  const omMetadata = (0, _mastra_core_memory.getThreadOMMetadata)((await this.storage.getThreadById({ threadId }))?.metadata);
24952
25005
  const currentTask = omMetadata?.currentTask;
24953
25006
  const suggestedResponse = omMetadata?.suggestedResponse;
@@ -26079,7 +26132,7 @@ var ObservationalMemoryProcessor = class {
26079
26132
  threadId,
26080
26133
  resourceId
26081
26134
  });
26082
- const systemMessages = ctx.hasObservations && ctx.omRecord ? await this.engine.buildContextSystemMessages({
26135
+ const systemMessages = ctx.omRecord ? await this.engine.buildContextSystemMessages({
26083
26136
  threadId,
26084
26137
  resourceId,
26085
26138
  record: ctx.omRecord,
@@ -28507,4 +28560,4 @@ Object.defineProperty(exports, "wrapInObservationGroup", {
28507
28560
  }
28508
28561
  });
28509
28562
 
28510
- //# sourceMappingURL=src-C3u7zaSu.cjs.map
28563
+ //# sourceMappingURL=src-DQO6B1AU.cjs.map