@mastra/memory 1.8.4-alpha.0 → 1.9.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 (32) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/{chunk-4KPXPQX3.js → chunk-5SMKVGJP.js} +205 -37
  3. package/dist/chunk-5SMKVGJP.js.map +1 -0
  4. package/dist/{chunk-LGCREJMO.cjs → chunk-AR52LM55.cjs} +205 -37
  5. package/dist/chunk-AR52LM55.cjs.map +1 -0
  6. package/dist/docs/SKILL.md +1 -1
  7. package/dist/docs/assets/SOURCE_MAP.json +27 -27
  8. package/dist/docs/references/docs-memory-observational-memory.md +2 -0
  9. package/dist/docs/references/reference-memory-observational-memory.md +2 -0
  10. package/dist/index.cjs +5 -4
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +4 -3
  14. package/dist/index.js.map +1 -1
  15. package/dist/{observational-memory-UEDVTWS2.js → observational-memory-5NFPG6M3.js} +3 -3
  16. package/dist/{observational-memory-UEDVTWS2.js.map → observational-memory-5NFPG6M3.js.map} +1 -1
  17. package/dist/{observational-memory-4TV5KKFV.cjs → observational-memory-NH7VDTXM.cjs} +18 -18
  18. package/dist/{observational-memory-4TV5KKFV.cjs.map → observational-memory-NH7VDTXM.cjs.map} +1 -1
  19. package/dist/processors/index.cjs +16 -16
  20. package/dist/processors/index.js +1 -1
  21. package/dist/processors/observational-memory/markers.d.ts +10 -1
  22. package/dist/processors/observational-memory/markers.d.ts.map +1 -1
  23. package/dist/processors/observational-memory/observational-memory.d.ts +2 -0
  24. package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
  25. package/dist/processors/observational-memory/observer-agent.d.ts +16 -6
  26. package/dist/processors/observational-memory/observer-agent.d.ts.map +1 -1
  27. package/dist/processors/observational-memory/reflector-agent.d.ts.map +1 -1
  28. package/dist/processors/observational-memory/types.d.ts +27 -1
  29. package/dist/processors/observational-memory/types.d.ts.map +1 -1
  30. package/package.json +5 -5
  31. package/dist/chunk-4KPXPQX3.js.map +0 -1
  32. package/dist/chunk-LGCREJMO.cjs.map +0 -1
@@ -307,6 +307,18 @@ function createActivationMarker(params) {
307
307
  }
308
308
  };
309
309
  }
310
+ function createThreadUpdateMarker(params) {
311
+ return {
312
+ type: "data-om-thread-update",
313
+ data: {
314
+ cycleId: params.cycleId,
315
+ threadId: params.threadId,
316
+ oldTitle: params.oldTitle,
317
+ newTitle: params.newTitle,
318
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
319
+ }
320
+ };
321
+ }
310
322
  var ENCRYPTED_CONTENT_KEY = "encryptedContent";
311
323
  var ENCRYPTED_CONTENT_REDACTION_THRESHOLD = 256;
312
324
  var DEFAULT_OBSERVER_TOOL_RESULT_MAX_TOKENS = 1e4;
@@ -616,17 +628,60 @@ Only add a new observation for a repeated action if the NEW result changes the p
616
628
  ACTIONABLE INSIGHTS:
617
629
  - What worked well in explanations
618
630
  - What needs follow-up or clarification
619
- - User's stated goals or next steps (note if the user tells you not to do a next step, or asks for something specific, other next steps besides the users request should be marked as "waiting for user", unless the user explicitly says to continue all next steps)`;
620
- var OBSERVER_OUTPUT_FORMAT_BASE = `Use priority levels:
621
- - \u{1F534} High: explicit user facts, preferences, goals achieved, critical context
631
+ - User's stated goals or next steps (note if the user tells you not to do a next step, or asks for something specific, other next steps besides the users request should be marked as "waiting for user", unless the user explicitly says to continue all next steps)
632
+
633
+ COMPLETION TRACKING:
634
+ Completion observations are not just summaries. They are explicit memory signals to the assistant that a task, question, or subtask has been resolved.
635
+ Without clear completion markers, the assistant may forget that work is already finished and may repeat, reopen, or continue an already-completed task.
636
+
637
+ Use \u2705 to answer: "What exactly is now done?"
638
+ Choose completion observations that help the assistant know what is finished and should not be reworked unless new information appears.
639
+
640
+ Use \u2705 when:
641
+ - The user explicitly confirms something worked or was answered ("thanks, that fixed it", "got it", "perfect")
642
+ - The assistant provided a definitive, complete answer to a factual question and the user moved on
643
+ - A multi-step task reached its stated goal
644
+ - The user acknowledged receipt of requested information
645
+ - A concrete subtask, fix, deliverable, or implementation step became complete during ongoing work
646
+
647
+ Do NOT use \u2705 when:
648
+ - The assistant merely responded \u2014 the user might follow up with corrections
649
+ - The topic is paused but not resolved ("I'll try that later")
650
+ - The user's reaction is ambiguous
651
+
652
+ FORMAT:
653
+ As a sub-bullet under the related observation group:
654
+ * \u{1F534} (14:30) User asked how to configure auth middleware
655
+ * -> Agent explained JWT setup with code example
656
+ * \u2705 User confirmed auth is working
657
+
658
+ Or as a standalone observation when closing out a broader task:
659
+ * \u2705 (14:45) Auth configuration task completed \u2014 user confirmed middleware is working
660
+
661
+ Completion observations should be terse but specific about WHAT was completed.
662
+ Prefer concrete resolved outcomes over abstract workflow status so the assistant remembers what is already done.`;
663
+ var OBSERVER_OUTPUT_FORMAT_BASE = buildObserverOutputFormat();
664
+ function buildObserverOutputFormat(includeThreadTitle = false) {
665
+ const threadTitleSection = includeThreadTitle ? `
666
+ <thread-title>
667
+ A short, noun-phrase title for this conversation (2-5 words). Examples:
668
+ - "Auth bug fix" \u2014 not "Fixing the auth bug"
669
+ - "Dark mode toggle" \u2014 not "User wants dark mode toggle added"
670
+ - "Deployment pipeline setup" \u2014 not "Setting up deployment pipeline for project"
671
+ Only update when the topic meaningfully changes.
672
+ </thread-title>` : "";
673
+ return `Use priority levels:
674
+ - \u{1F534} High: explicit user facts, preferences, unresolved goals, critical context
622
675
  - \u{1F7E1} Medium: project details, learned information, tool results
623
676
  - \u{1F7E2} Low: minor details, uncertain observations
677
+ - \u2705 Completed: concrete task finished, question answered, issue resolved, goal achieved, or subtask completed in a way that helps the assistant know it is done
624
678
 
625
679
  Group related observations (like tool sequences) by indenting:
626
680
  * \u{1F534} (14:33) Agent debugging auth issue
627
681
  * -> ran git status, found 3 modified files
628
682
  * -> viewed auth.ts:45-60, found missing null check
629
683
  * -> applied fix, tests now pass
684
+ * \u2705 Tests passing, auth issue resolved
630
685
 
631
686
  Group observations by date, then list each with 24-hour time.
632
687
 
@@ -653,7 +708,8 @@ Hint for the agent's immediate next message. Examples:
653
708
  - "I've updated the navigation model. Let me walk you through the changes..."
654
709
  - "The assistant should wait for the user to respond before continuing."
655
710
  - Call the view tool on src/example.ts to continue debugging.
656
- </suggested-response>`;
711
+ </suggested-response>${threadTitleSection}`;
712
+ }
657
713
  var OBSERVER_GUIDELINES = `- Be specific enough for the assistant to act on
658
714
  - Good: "User prefers short, direct answers without lengthy explanations"
659
715
  - Bad: "User stated a preference" (too vague)
@@ -663,12 +719,21 @@ var OBSERVER_GUIDELINES = `- Be specific enough for the assistant to act on
663
719
  - If the agent calls tools, observe what was called, why, and what was learned
664
720
  - When observing files with line numbers, include the line number if useful
665
721
  - If the agent provides a detailed response, observe the contents so it could be repeated
666
- - Make sure you start each observation with a priority emoji (\u{1F534}, \u{1F7E1}, \u{1F7E2})
667
- - User messages are always \u{1F534} priority, so are the completions of tasks. Capture the user's words closely \u2014 short/medium messages near-verbatim, long messages summarized with key quotes
722
+ - Make sure you start each observation with a priority emoji (\u{1F534}, \u{1F7E1}, \u{1F7E2}) or a completion marker (\u2705)
723
+ - Capture the user's words closely \u2014 short/medium messages near-verbatim, long messages summarized with key quotes. User confirmations or explicit resolved outcomes should be \u2705 when they clearly signal something is done; unresolved or critical user facts remain \u{1F534}
724
+ - Treat \u2705 as a memory signal that tells the assistant something is finished and should not be repeated unless new information changes it
725
+ - Make completion observations answer "What exactly is now done?"
726
+ - Prefer concrete resolved outcomes over meta-level workflow or bookkeeping updates
727
+ - When multiple concrete things were completed, capture the concrete completed work rather than collapsing it into a vague progress summary
668
728
  - Observe WHAT the agent did and WHAT it means
669
729
  - If the user provides detailed messages or code snippets, observe all important details`;
670
- function buildObserverSystemPrompt(multiThread = false, instruction) {
671
- const outputFormat = OBSERVER_OUTPUT_FORMAT_BASE;
730
+ function buildObserverSystemPrompt(multiThread = false, instruction, includeThreadTitle = false) {
731
+ const outputFormat = buildObserverOutputFormat(includeThreadTitle);
732
+ 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>.`;
733
+ const multiThreadTitleExample = includeThreadTitle ? `
734
+ <thread-title>Feature X implementation</thread-title>` : "";
735
+ const multiThreadSecondTitleExample = includeThreadTitle ? `
736
+ <thread-title>Deployment setup</thread-title>` : "";
672
737
  if (multiThread) {
673
738
  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.
674
739
 
@@ -683,7 +748,13 @@ Process each thread separately and output observations for each thread.
683
748
 
684
749
  === OUTPUT FORMAT ===
685
750
 
686
- Your output MUST use XML tags to structure the response. Each thread's observations, current-task, and suggested-response should be nested inside a <thread id="..."> block within <observations>.
751
+ Your output MUST use XML tags to structure the response.${multiThreadTitleInstruction}
752
+
753
+ Use this observation format inside each thread block:
754
+
755
+ ${outputFormat}
756
+
757
+ For multi-thread output, wrap each thread's observations like this:
687
758
 
688
759
  <observations>
689
760
  <thread id="thread_id_1">
@@ -697,7 +768,7 @@ What the agent is currently working on in this thread
697
768
 
698
769
  <suggested-response>
699
770
  Hint for the agent's next message in this thread
700
- </suggested-response>
771
+ </suggested-response>${multiThreadTitleExample}
701
772
  </thread>
702
773
 
703
774
  <thread id="thread_id_2">
@@ -710,15 +781,10 @@ Current task for this thread
710
781
 
711
782
  <suggested-response>
712
783
  Suggested response for this thread
713
- </suggested-response>
784
+ </suggested-response>${multiThreadSecondTitleExample}
714
785
  </thread>
715
786
  </observations>
716
787
 
717
- Use priority levels:
718
- - \u{1F534} High: explicit user facts, preferences, goals achieved, critical context, user messages
719
- - \u{1F7E1} Medium: project details, learned information, tool results
720
- - \u{1F7E2} Low: minor details, uncertain observations
721
-
722
788
  === GUIDELINES ===
723
789
 
724
790
  ${OBSERVER_GUIDELINES}
@@ -998,7 +1064,7 @@ The following messages are from ${threadOrder.length} different conversation thr
998
1064
  content
999
1065
  };
1000
1066
  }
1001
- function buildMultiThreadObserverTaskPrompt(existingObservations, threadOrder, priorMetadataByThread, wasTruncated) {
1067
+ function buildMultiThreadObserverTaskPrompt(existingObservations, threadOrder, priorMetadataByThread, wasTruncated, includeThreadTitle) {
1002
1068
  let prompt = "";
1003
1069
  if (existingObservations) {
1004
1070
  prompt += `## Previous Observations
@@ -1013,7 +1079,8 @@ ${existingObservations}
1013
1079
  const hasTruncatedObservations = wasTruncated ?? false;
1014
1080
  const threadMetadataLines = threadOrder?.map((threadId) => {
1015
1081
  const metadata = priorMetadataByThread?.get(threadId);
1016
- if (!metadata?.currentTask && !metadata?.suggestedResponse) {
1082
+ const hasRelevantMetadata = metadata?.currentTask || metadata?.suggestedResponse || includeThreadTitle && metadata?.threadTitle;
1083
+ if (!hasRelevantMetadata) {
1017
1084
  return "";
1018
1085
  }
1019
1086
  const lines = [`- thread ${threadId}`];
@@ -1023,6 +1090,9 @@ ${existingObservations}
1023
1090
  if (metadata.suggestedResponse) {
1024
1091
  lines.push(` - prior suggested-response: ${metadata.suggestedResponse}`);
1025
1092
  }
1093
+ if (includeThreadTitle && metadata.threadTitle) {
1094
+ lines.push(` - prior thread-title: ${metadata.threadTitle}`);
1095
+ }
1026
1096
  return lines.join("\n");
1027
1097
  }).filter(Boolean).join("\n");
1028
1098
  if (threadMetadataLines) {
@@ -1037,7 +1107,8 @@ ${threadMetadataLines}
1037
1107
  prompt += `The main agent still has full memory context outside this observer window.
1038
1108
  `;
1039
1109
  }
1040
- prompt += `Use each thread's prior current-task and suggested-response as continuity hints, then update them based on that thread's new messages.
1110
+ const titleHint = includeThreadTitle ? ", and thread-title" : "";
1111
+ prompt += `Use each thread's prior current-task, suggested-response${titleHint} as continuity hints, then update them based on that thread's new messages.
1041
1112
 
1042
1113
  ---
1043
1114
 
@@ -1046,7 +1117,8 @@ ${threadMetadataLines}
1046
1117
  prompt += `## Your Task
1047
1118
 
1048
1119
  `;
1049
- prompt += `Extract new observations from each thread. Output your observations grouped by thread using <thread id="..."> tags inside your <observations> block. Each thread block should contain that thread's observations, current-task, and suggested-response.
1120
+ const titleInstruction = includeThreadTitle ? ", and thread-title" : "";
1121
+ prompt += `Extract new observations from each thread. Output your observations grouped by thread using <thread id="..."> tags inside your <observations> block. Each thread block should contain that thread's observations, current-task, suggested-response${titleInstruction}.
1050
1122
 
1051
1123
  `;
1052
1124
  prompt += `Example output format:
@@ -1062,6 +1134,8 @@ ${threadMetadataLines}
1062
1134
  prompt += `<current-task>Working on feature X</current-task>
1063
1135
  `;
1064
1136
  prompt += `<suggested-response>Continue with the implementation</suggested-response>
1137
+ `;
1138
+ if (includeThreadTitle) prompt += `<thread-title>Feature X implementation</thread-title>
1065
1139
  `;
1066
1140
  prompt += `</thread>
1067
1141
  `;
@@ -1074,6 +1148,8 @@ ${threadMetadataLines}
1074
1148
  prompt += `<current-task>Discussing deployment options</current-task>
1075
1149
  `;
1076
1150
  prompt += `<suggested-response>Explain the deployment process</suggested-response>
1151
+ `;
1152
+ if (includeThreadTitle) prompt += `<thread-title>Deployment setup</thread-title>
1077
1153
  `;
1078
1154
  prompt += `</thread>
1079
1155
  `;
@@ -1106,11 +1182,18 @@ function parseMultiThreadObserverOutput(output) {
1106
1182
  suggestedContinuation = suggestedMatch[1].trim();
1107
1183
  observations = observations.replace(/<suggested-response>[\s\S]*?<\/suggested-response>/i, "");
1108
1184
  }
1185
+ let threadTitle;
1186
+ const threadTitleMatch = threadContent.match(/<thread-title>([\s\S]*?)<\/thread-title>/i);
1187
+ if (threadTitleMatch?.[1]) {
1188
+ threadTitle = threadTitleMatch[1].trim();
1189
+ observations = observations.replace(/<thread-title>[\s\S]*?<\/thread-title>/i, "");
1190
+ }
1109
1191
  observations = sanitizeObservationLines(observations.trim());
1110
1192
  threads.set(threadId, {
1111
1193
  observations,
1112
1194
  currentTask,
1113
1195
  suggestedContinuation,
1196
+ threadTitle,
1114
1197
  rawOutput: threadContent
1115
1198
  });
1116
1199
  }
@@ -1139,6 +1222,9 @@ ${existingObservations}
1139
1222
  if (options?.priorSuggestedResponse) {
1140
1223
  priorMetadataLines.push(`- prior suggested-response: ${options.priorSuggestedResponse}`);
1141
1224
  }
1225
+ if (options?.includeThreadTitle && options?.priorThreadTitle) {
1226
+ priorMetadataLines.push(`- prior thread-title: ${options.priorThreadTitle}`);
1227
+ }
1142
1228
  if (priorMetadataLines.length > 0) {
1143
1229
  prompt += `## Prior Thread Metadata
1144
1230
 
@@ -1151,7 +1237,8 @@ ${priorMetadataLines.join("\n")}
1151
1237
  prompt += `The main agent still has full memory context outside this observer window.
1152
1238
  `;
1153
1239
  }
1154
- prompt += `Use the prior current-task and suggested-response as continuity hints, then update them based on the new messages.
1240
+ const titleHint = options?.includeThreadTitle ? ", and thread-title" : "";
1241
+ prompt += `Use the prior current-task, suggested-response${titleHint} as continuity hints, then update them based on the new messages.
1155
1242
 
1156
1243
  ---
1157
1244
 
@@ -1161,10 +1248,15 @@ ${priorMetadataLines.join("\n")}
1161
1248
 
1162
1249
  `;
1163
1250
  prompt += `Extract new observations from the message history above. Do not repeat observations that are already in the previous observations. Add your new observations in the format specified in your instructions.`;
1251
+ if (options?.includeThreadTitle) {
1252
+ prompt += `
1253
+
1254
+ Also output a <thread-title> \u2014 a short noun-phrase label for this conversation (2-5 words). Write it like a file name or PR title: "Auth bug fix", "Memory config refactor", "RAG pipeline setup". Avoid verbs/sentences ("Fixing the auth bug"), filler ("Working on stuff"), and generic labels ("Code review"). Only change it from the prior title if the topic meaningfully shifted.`;
1255
+ }
1164
1256
  if (options?.skipContinuationHints) {
1165
1257
  prompt += `
1166
1258
 
1167
- IMPORTANT: Do NOT include <current-task> or <suggested-response> sections in your output. Only output <observations>.`;
1259
+ IMPORTANT: Do NOT include <current-task> or <suggested-response> sections in your output. Only output <observations>${options?.includeThreadTitle ? " and <thread-title>" : ""}.`;
1168
1260
  }
1169
1261
  return prompt;
1170
1262
  }
@@ -1192,6 +1284,7 @@ function parseObserverOutput(output) {
1192
1284
  observations,
1193
1285
  currentTask: parsed.currentTask || void 0,
1194
1286
  suggestedContinuation: parsed.suggestedResponse || void 0,
1287
+ threadTitle: parsed.threadTitle || void 0,
1195
1288
  rawOutput: output
1196
1289
  };
1197
1290
  }
@@ -1199,7 +1292,8 @@ function parseMemorySectionXml(content) {
1199
1292
  const result = {
1200
1293
  observations: "",
1201
1294
  currentTask: "",
1202
- suggestedResponse: ""
1295
+ suggestedResponse: "",
1296
+ threadTitle: ""
1203
1297
  };
1204
1298
  const observationsRegex = /^[ \t]*<observations>([\s\S]*?)^[ \t]*<\/observations>/gim;
1205
1299
  const observationsMatches = [...content.matchAll(observationsRegex)];
@@ -1216,6 +1310,10 @@ function parseMemorySectionXml(content) {
1216
1310
  if (suggestedResponseMatch?.[1]) {
1217
1311
  result.suggestedResponse = suggestedResponseMatch[1].trim();
1218
1312
  }
1313
+ const threadTitleMatch = content.match(/^[ \t]*<thread-title>([\s\S]*?)<\/thread-title>/im);
1314
+ if (threadTitleMatch?.[1]) {
1315
+ result.threadTitle = threadTitleMatch[1].trim();
1316
+ }
1219
1317
  return result;
1220
1318
  }
1221
1319
  function extractListItemsOnly(content) {
@@ -1353,6 +1451,8 @@ When consolidating observations:
1353
1451
  - Preserve and include dates/times when present (temporal context is critical)
1354
1452
  - Retain the most relevant timestamps (start times, completion times, significant events)
1355
1453
  - Combine related items where it makes sense (e.g., "agent called view tool 5 times on file x")
1454
+ - Preserve \u2705 completion markers \u2014 they are memory signals that tell the assistant what is already resolved and help prevent repeated work
1455
+ - Preserve the concrete resolved outcome captured by \u2705 markers so the assistant knows what exactly is done
1356
1456
  - Condense older observations more aggressively, retain more detail for recent ones
1357
1457
 
1358
1458
  CRITICAL: USER ASSERTIONS vs QUESTIONS
@@ -1433,6 +1533,8 @@ Please re-process with slightly more compression:
1433
1533
  - Closer to the end, retain more fine details (recent context matters more)
1434
1534
  - Memory is getting long - use a more condensed style throughout
1435
1535
  - Combine related items more aggressively but do not lose important specific details of names, places, events, and people
1536
+ - Preserve \u2705 completion markers \u2014 they are memory signals that tell the assistant what is already resolved and help prevent repeated work
1537
+ - Preserve the concrete resolved outcome captured by \u2705 markers so the assistant knows what exactly is done
1436
1538
  - For example if there is a long nested observation list about repeated tool calls, you can combine those into a single line and observe that the tool was called multiple times for x reason, and finally y outcome happened.
1437
1539
 
1438
1540
  Your current detail level was a 10/10, lets aim for a 8/10 detail level.
@@ -1447,6 +1549,8 @@ Please re-process with much more aggressive compression:
1447
1549
  - Closer to the end, retain fine details (recent context matters more)
1448
1550
  - Memory is getting very long - use a significantly more condensed style throughout
1449
1551
  - Combine related items aggressively but do not lose important specific details of names, places, events, and people
1552
+ - Preserve \u2705 completion markers \u2014 they are memory signals that tell the assistant what is already resolved and help prevent repeated work
1553
+ - Preserve the concrete resolved outcome captured by \u2705 markers so the assistant knows what exactly is done
1450
1554
  - For example if there is a long nested observation list about repeated tool calls, you can combine those into a single line and observe that the tool was called multiple times for x reason, and finally y outcome happened.
1451
1555
  - Remove redundant information and merge overlapping observations
1452
1556
 
@@ -1463,6 +1567,8 @@ Please re-process with maximum compression:
1463
1567
  - Ruthlessly merge related observations \u2014 if 10 observations are about the same topic, combine into 1-2 lines
1464
1568
  - Drop procedural details (tool calls, retries, intermediate steps) \u2014 keep only final outcomes
1465
1569
  - Drop observations that are no longer relevant or have been superseded by newer information
1570
+ - Preserve \u2705 completion markers \u2014 they are memory signals that tell the assistant what is already resolved and help prevent repeated work
1571
+ - Preserve the concrete resolved outcome captured by \u2705 markers so the assistant knows what exactly is done
1466
1572
  - Preserve: names, dates, decisions, errors, user preferences, and architectural choices
1467
1573
 
1468
1574
  Your current detail level was a 10/10, lets aim for a 4/10 detail level.
@@ -3443,7 +3549,8 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
3443
3549
  config.observation?.messageTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.messageTokens
3444
3550
  ),
3445
3551
  previousObserverTokens: config.observation?.previousObserverTokens ?? 2e3,
3446
- instruction: config.observation?.instruction
3552
+ instruction: config.observation?.instruction,
3553
+ threadTitle: config.observation?.threadTitle ?? false
3447
3554
  };
3448
3555
  this.reflectionConfig = {
3449
3556
  model: reflectionModel,
@@ -3669,7 +3776,11 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
3669
3776
  */
3670
3777
  getObserverAgent() {
3671
3778
  if (!this.observerAgent) {
3672
- const systemPrompt = buildObserverSystemPrompt(false, this.observationConfig.instruction);
3779
+ const systemPrompt = buildObserverSystemPrompt(
3780
+ false,
3781
+ this.observationConfig.instruction,
3782
+ this.observationConfig.threadTitle
3783
+ );
3673
3784
  this.observerAgent = new agent.Agent({
3674
3785
  id: "observational-memory-observer",
3675
3786
  name: "Observer",
@@ -4091,7 +4202,7 @@ ${unreflectedContent}` : bufferedReflection;
4091
4202
  const isImportant = new Array(totalCount);
4092
4203
  for (let i = 0; i < totalCount; i++) {
4093
4204
  lineTokens[i] = this.tokenCounter.countString(lines[i]);
4094
- isImportant[i] = lines[i].includes("\u{1F534}");
4205
+ isImportant[i] = lines[i].includes("\u{1F534}") || lines[i].includes("\u2705");
4095
4206
  }
4096
4207
  const suffixTokens = new Array(totalCount + 1);
4097
4208
  suffixTokens[totalCount] = 0;
@@ -4177,7 +4288,9 @@ ${unreflectedContent}` : bufferedReflection;
4177
4288
  skipContinuationHints: options?.skipContinuationHints,
4178
4289
  priorCurrentTask: options?.priorCurrentTask,
4179
4290
  priorSuggestedResponse: options?.priorSuggestedResponse,
4180
- wasTruncated: options?.wasTruncated
4291
+ priorThreadTitle: options?.priorThreadTitle,
4292
+ wasTruncated: options?.wasTruncated,
4293
+ includeThreadTitle: this.observationConfig.threadTitle
4181
4294
  })
4182
4295
  },
4183
4296
  buildObserverHistoryMessage(messagesToObserve)
@@ -4212,6 +4325,7 @@ ${unreflectedContent}` : bufferedReflection;
4212
4325
  observations: parsed.observations,
4213
4326
  currentTask: parsed.currentTask,
4214
4327
  suggestedContinuation: parsed.suggestedContinuation,
4328
+ threadTitle: parsed.threadTitle,
4215
4329
  usage: usage ? {
4216
4330
  inputTokens: usage.inputTokens,
4217
4331
  outputTokens: usage.outputTokens,
@@ -4226,7 +4340,11 @@ ${unreflectedContent}` : bufferedReflection;
4226
4340
  * plus the total usage for the batch.
4227
4341
  */
4228
4342
  async callMultiThreadObserver(existingObservations, messagesByThread, threadOrder, priorMetadataByThread, abortSignal, requestContext, wasTruncated) {
4229
- const systemPrompt = buildObserverSystemPrompt(true, this.observationConfig.instruction);
4343
+ const systemPrompt = buildObserverSystemPrompt(
4344
+ true,
4345
+ this.observationConfig.instruction,
4346
+ this.observationConfig.threadTitle
4347
+ );
4230
4348
  const agent$1 = new agent.Agent({
4231
4349
  id: "multi-thread-observer",
4232
4350
  name: "multi-thread-observer",
@@ -4240,7 +4358,8 @@ ${unreflectedContent}` : bufferedReflection;
4240
4358
  existingObservations,
4241
4359
  threadOrder,
4242
4360
  priorMetadataByThread,
4243
- wasTruncated
4361
+ wasTruncated,
4362
+ this.observationConfig.threadTitle
4244
4363
  )
4245
4364
  },
4246
4365
  buildMultiThreadObserverHistoryMessage(messagesByThread, threadOrder)
@@ -4282,7 +4401,8 @@ ${unreflectedContent}` : bufferedReflection;
4282
4401
  results.set(threadId, {
4283
4402
  observations: threadResult.observations,
4284
4403
  currentTask: threadResult.currentTask,
4285
- suggestedContinuation: threadResult.suggestedContinuation
4404
+ suggestedContinuation: threadResult.suggestedContinuation,
4405
+ threadTitle: threadResult.threadTitle
4286
4406
  });
4287
4407
  }
4288
4408
  for (const threadId of threadOrder) {
@@ -5725,6 +5845,7 @@ ${threadClose}`;
5725
5845
  requestContext,
5726
5846
  priorCurrentTask: threadOMMetadata?.currentTask,
5727
5847
  priorSuggestedResponse: threadOMMetadata?.suggestedResponse,
5848
+ priorThreadTitle: thread?.title,
5728
5849
  wasTruncated
5729
5850
  });
5730
5851
  const lastObservedAt = this.getMaxMessageTimestamp(messagesToObserve);
@@ -5755,10 +5876,31 @@ ${threadClose}`;
5755
5876
  });
5756
5877
  await this.storage.updateThread({
5757
5878
  id: threadId,
5758
- title: threadForMetadata.title ?? "",
5879
+ title: threadForMetadata.title || "",
5759
5880
  metadata: newMetadata
5760
5881
  });
5761
5882
  }
5883
+ if (this.observationConfig.threadTitle && threadForMetadata && result.threadTitle) {
5884
+ const oldTitle = threadForMetadata.title;
5885
+ const newTitle = result.threadTitle;
5886
+ if (newTitle.trim().length >= 3 && newTitle !== oldTitle) {
5887
+ await this.storage.updateThread({
5888
+ id: threadId,
5889
+ title: newTitle,
5890
+ metadata: threadForMetadata.metadata ?? {}
5891
+ });
5892
+ if (writer) {
5893
+ const threadUpdateMarker = createThreadUpdateMarker({
5894
+ cycleId,
5895
+ threadId,
5896
+ oldTitle: oldTitle ?? void 0,
5897
+ newTitle
5898
+ });
5899
+ await writer.custom(threadUpdateMarker).catch(() => {
5900
+ });
5901
+ }
5902
+ }
5903
+ }
5762
5904
  await this.storage.updateActiveObservations({
5763
5905
  id: record.id,
5764
5906
  observations: newObservations,
@@ -6002,6 +6144,7 @@ ${threadClose}`;
6002
6144
  requestContext,
6003
6145
  priorCurrentTask: threadOMMetadata?.currentTask,
6004
6146
  priorSuggestedResponse: threadOMMetadata?.suggestedResponse,
6147
+ priorThreadTitle: thread?.title,
6005
6148
  wasTruncated
6006
6149
  }
6007
6150
  );
@@ -6009,6 +6152,22 @@ ${threadClose}`;
6009
6152
  omDebug(`[OM:doAsyncBufferedObservation] empty observations returned, skipping buffer storage`);
6010
6153
  return;
6011
6154
  }
6155
+ if (this.observationConfig.threadTitle && result.threadTitle) {
6156
+ const newTitle = result.threadTitle;
6157
+ if (newTitle.length >= 3 && newTitle !== thread?.title) {
6158
+ await this.storage.updateThread({ id: threadId, title: newTitle, metadata: thread?.metadata ?? {} });
6159
+ if (writer) {
6160
+ const marker = createThreadUpdateMarker({
6161
+ cycleId,
6162
+ threadId,
6163
+ oldTitle: thread?.title,
6164
+ newTitle
6165
+ });
6166
+ void writer.custom(marker).catch(() => {
6167
+ });
6168
+ }
6169
+ }
6170
+ }
6012
6171
  let newObservations;
6013
6172
  if (this.scope === "resource") {
6014
6173
  newObservations = await this.wrapWithThreadTag(threadId, result.observations);
@@ -6432,7 +6591,8 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
6432
6591
  threadMetadataMap.set(thread.id, {
6433
6592
  lastObservedAt: omMetadata?.lastObservedAt,
6434
6593
  currentTask: omMetadata?.currentTask,
6435
- suggestedResponse: omMetadata?.suggestedResponse
6594
+ suggestedResponse: omMetadata?.suggestedResponse,
6595
+ threadTitle: thread.title
6436
6596
  });
6437
6597
  }
6438
6598
  const messagesByThread = /* @__PURE__ */ new Map();
@@ -6585,10 +6745,11 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
6585
6745
  const batchPriorMetadata = /* @__PURE__ */ new Map();
6586
6746
  for (const threadId of batch.threadIds) {
6587
6747
  const metadata = threadMetadataMap.get(threadId);
6588
- if (metadata?.currentTask || metadata?.suggestedResponse) {
6748
+ if (metadata?.currentTask || metadata?.suggestedResponse || metadata?.threadTitle) {
6589
6749
  batchPriorMetadata.set(threadId, {
6590
6750
  currentTask: metadata.currentTask,
6591
- suggestedResponse: metadata.suggestedResponse
6751
+ suggestedResponse: metadata.suggestedResponse,
6752
+ threadTitle: metadata.threadTitle
6592
6753
  });
6593
6754
  }
6594
6755
  }
@@ -6646,6 +6807,13 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
6646
6807
  );
6647
6808
  const thread = await this.storage.getThreadById({ threadId });
6648
6809
  if (thread) {
6810
+ let titleForUpdate = thread.title ?? "";
6811
+ if (this.observationConfig.threadTitle && result.threadTitle) {
6812
+ const newTitle = result.threadTitle.trim();
6813
+ if (newTitle.length >= 3 && newTitle !== thread.title) {
6814
+ titleForUpdate = newTitle;
6815
+ }
6816
+ }
6649
6817
  const newMetadata = memory.setThreadOMMetadata(thread.metadata, {
6650
6818
  lastObservedAt: threadLastObservedAt.toISOString(),
6651
6819
  suggestedResponse: result.suggestedContinuation,
@@ -6654,7 +6822,7 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
6654
6822
  });
6655
6823
  await this.storage.updateThread({
6656
6824
  id: threadId,
6657
- title: thread.title ?? "",
6825
+ title: titleForUpdate,
6658
6826
  metadata: newMetadata
6659
6827
  });
6660
6828
  }
@@ -7127,5 +7295,5 @@ exports.getObservationsAsOf = getObservationsAsOf;
7127
7295
  exports.hasCurrentTaskSection = hasCurrentTaskSection;
7128
7296
  exports.optimizeObservationsForContext = optimizeObservationsForContext;
7129
7297
  exports.parseObserverOutput = parseObserverOutput;
7130
- //# sourceMappingURL=chunk-LGCREJMO.cjs.map
7131
- //# sourceMappingURL=chunk-LGCREJMO.cjs.map
7298
+ //# sourceMappingURL=chunk-AR52LM55.cjs.map
7299
+ //# sourceMappingURL=chunk-AR52LM55.cjs.map