@mastra/memory 1.9.0-alpha.1 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/dist/{chunk-5SMKVGJP.js → chunk-JJBSFPC5.js} +315 -25
  3. package/dist/chunk-JJBSFPC5.js.map +1 -0
  4. package/dist/{chunk-AR52LM55.cjs → chunk-LVV2RT42.cjs} +327 -24
  5. package/dist/chunk-LVV2RT42.cjs.map +1 -0
  6. package/dist/docs/SKILL.md +5 -7
  7. package/dist/docs/assets/SOURCE_MAP.json +77 -27
  8. package/dist/docs/references/docs-agents-agent-approval.md +114 -193
  9. package/dist/docs/references/docs-agents-networks.md +88 -205
  10. package/dist/docs/references/docs-agents-supervisor-agents.md +24 -18
  11. package/dist/docs/references/docs-memory-observational-memory.md +30 -2
  12. package/dist/docs/references/docs-memory-overview.md +219 -24
  13. package/dist/docs/references/docs-memory-semantic-recall.md +1 -1
  14. package/dist/docs/references/docs-memory-storage.md +4 -4
  15. package/dist/docs/references/docs-memory-working-memory.md +1 -1
  16. package/dist/docs/references/reference-core-getMemory.md +1 -2
  17. package/dist/docs/references/reference-core-listMemory.md +1 -2
  18. package/dist/docs/references/reference-memory-cloneThread.md +1 -1
  19. package/dist/docs/references/reference-memory-observational-memory.md +39 -1
  20. package/dist/index.cjs +432 -11
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +432 -10
  24. package/dist/index.js.map +1 -1
  25. package/dist/observational-memory-3XFCO6MX.js +3 -0
  26. package/dist/{observational-memory-5NFPG6M3.js.map → observational-memory-3XFCO6MX.js.map} +1 -1
  27. package/dist/observational-memory-MJJFU26W.cjs +108 -0
  28. package/dist/{observational-memory-NH7VDTXM.cjs.map → observational-memory-MJJFU26W.cjs.map} +1 -1
  29. package/dist/processors/index.cjs +56 -16
  30. package/dist/processors/index.js +1 -1
  31. package/dist/processors/observational-memory/anchor-ids.d.ts +4 -0
  32. package/dist/processors/observational-memory/anchor-ids.d.ts.map +1 -0
  33. package/dist/processors/observational-memory/index.d.ts +2 -0
  34. package/dist/processors/observational-memory/index.d.ts.map +1 -1
  35. package/dist/processors/observational-memory/observation-groups.d.ts +15 -0
  36. package/dist/processors/observational-memory/observation-groups.d.ts.map +1 -0
  37. package/dist/processors/observational-memory/observational-memory.d.ts +14 -0
  38. package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
  39. package/dist/processors/observational-memory/observer-agent.d.ts.map +1 -1
  40. package/dist/processors/observational-memory/reflector-agent.d.ts +1 -1
  41. package/dist/processors/observational-memory/reflector-agent.d.ts.map +1 -1
  42. package/dist/processors/observational-memory/tool-result-helpers.d.ts.map +1 -1
  43. package/dist/tools/om-tools.d.ts +77 -0
  44. package/dist/tools/om-tools.d.ts.map +1 -0
  45. package/package.json +8 -8
  46. package/dist/chunk-5SMKVGJP.js.map +0 -1
  47. package/dist/chunk-AR52LM55.cjs.map +0 -1
  48. package/dist/docs/references/docs-agents-agent-memory.md +0 -209
  49. package/dist/docs/references/docs-agents-network-approval.md +0 -278
  50. package/dist/observational-memory-5NFPG6M3.js +0 -3
  51. package/dist/observational-memory-NH7VDTXM.cjs +0 -68
@@ -8,8 +8,8 @@ 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');
12
11
  var crypto$1 = require('crypto');
12
+ var tokenx = require('tokenx');
13
13
  var async_hooks = require('async_hooks');
14
14
  var imageSize = require('image-size');
15
15
 
@@ -319,6 +319,222 @@ function createThreadUpdateMarker(params) {
319
319
  }
320
320
  };
321
321
  }
322
+ var OBSERVATION_GROUP_PATTERN = /<observation-group\s([^>]*)>([\s\S]*?)<\/observation-group>/g;
323
+ var ATTRIBUTE_PATTERN = /([\w][\w-]*)="([^"]*)"/g;
324
+ var REFLECTION_GROUP_SPLIT_PATTERN = /^##\s+Group\s+/m;
325
+ function parseObservationGroupAttributes(attributeString) {
326
+ const attributes = {};
327
+ for (const match of attributeString.matchAll(ATTRIBUTE_PATTERN)) {
328
+ const [, key, value] = match;
329
+ if (key && value !== void 0) {
330
+ attributes[key] = value;
331
+ }
332
+ }
333
+ return attributes;
334
+ }
335
+ function parseReflectionObservationGroupSections(content) {
336
+ const normalizedContent = content.trim();
337
+ if (!normalizedContent || !REFLECTION_GROUP_SPLIT_PATTERN.test(normalizedContent)) {
338
+ return [];
339
+ }
340
+ return normalizedContent.split(REFLECTION_GROUP_SPLIT_PATTERN).map((section) => section.trim()).filter(Boolean).map((section) => {
341
+ const newlineIndex = section.indexOf("\n");
342
+ const heading = (newlineIndex >= 0 ? section.slice(0, newlineIndex) : section).trim();
343
+ const body = (newlineIndex >= 0 ? section.slice(newlineIndex + 1) : "").trim();
344
+ return {
345
+ heading,
346
+ body: stripReflectionGroupMetadata(body)
347
+ };
348
+ });
349
+ }
350
+ function stripReflectionGroupMetadata(body) {
351
+ return body.replace(/^_range:\s*`[^`]*`_\s*\n?/m, "").trim();
352
+ }
353
+ function generateAnchorId() {
354
+ return crypto$1.randomBytes(8).toString("hex");
355
+ }
356
+ function wrapInObservationGroup(observations, range, id = generateAnchorId(), sourceGroupIds) {
357
+ const content = observations.trim();
358
+ const sourceGroupIdsAttr = sourceGroupIds?.length ? ` source-group-ids="${sourceGroupIds.join(",")}"` : "";
359
+ return `<observation-group id="${id}" range="${range}"${sourceGroupIdsAttr}>
360
+ ${content}
361
+ </observation-group>`;
362
+ }
363
+ function parseObservationGroups(observations) {
364
+ if (!observations) {
365
+ return [];
366
+ }
367
+ const groups = [];
368
+ let match;
369
+ while ((match = OBSERVATION_GROUP_PATTERN.exec(observations)) !== null) {
370
+ const attributes = parseObservationGroupAttributes(match[1] ?? "");
371
+ const id = attributes.id;
372
+ const range = attributes.range;
373
+ if (!id || !range) {
374
+ continue;
375
+ }
376
+ groups.push({
377
+ id,
378
+ range,
379
+ content: match[2].trim(),
380
+ sourceGroupIds: attributes["source-group-ids"]?.split(",").map((part) => part.trim()).filter(Boolean)
381
+ });
382
+ }
383
+ return groups;
384
+ }
385
+ function stripObservationGroups(observations) {
386
+ if (!observations) {
387
+ return observations;
388
+ }
389
+ return observations.replace(OBSERVATION_GROUP_PATTERN, (_match, _attributes, content) => content.trim()).replace(/\n{3,}/g, "\n\n").trim();
390
+ }
391
+ function combineObservationGroupRanges(groups) {
392
+ return Array.from(
393
+ new Set(
394
+ groups.flatMap((group) => group.range.split(",")).map((range) => range.trim()).filter(Boolean)
395
+ )
396
+ ).join(",");
397
+ }
398
+ function renderObservationGroupsForReflection(observations) {
399
+ const groups = parseObservationGroups(observations);
400
+ if (groups.length === 0) {
401
+ return null;
402
+ }
403
+ const groupsByContent = new Map(groups.map((g) => [g.content.trim(), g]));
404
+ const result = observations.replace(OBSERVATION_GROUP_PATTERN, (_match, _attrs, content) => {
405
+ const group = groupsByContent.get(content.trim());
406
+ if (!group) return content.trim();
407
+ return `## Group \`${group.id}\`
408
+ _range: \`${group.range}\`_
409
+
410
+ ${group.content}`;
411
+ });
412
+ return result.replace(/\n{3,}/g, "\n\n").trim();
413
+ }
414
+ function getCanonicalGroupId(sectionHeading, fallbackIndex) {
415
+ const match = sectionHeading.match(/`([^`]+)`/);
416
+ return match?.[1]?.trim() || `derived-group-${fallbackIndex + 1}`;
417
+ }
418
+ function deriveObservationGroupProvenance(content, groups) {
419
+ const sections = parseReflectionObservationGroupSections(content);
420
+ if (sections.length === 0 || groups.length === 0) {
421
+ return [];
422
+ }
423
+ return sections.map((section, index) => {
424
+ const bodyLines = new Set(
425
+ section.body.split("\n").map((line) => line.trim()).filter(Boolean)
426
+ );
427
+ const matchingGroups = groups.filter((group) => {
428
+ const groupLines = group.content.split("\n").map((line) => line.trim()).filter(Boolean);
429
+ return groupLines.some((line) => bodyLines.has(line));
430
+ });
431
+ const fallbackGroup = groups[Math.min(index, groups.length - 1)];
432
+ const resolvedGroups = matchingGroups.length > 0 ? matchingGroups : fallbackGroup ? [fallbackGroup] : [];
433
+ const sourceGroupIds = Array.from(
434
+ new Set(resolvedGroups.flatMap((group) => [group.id, ...group.sourceGroupIds ?? []]))
435
+ );
436
+ const canonicalGroupId = getCanonicalGroupId(section.heading, index);
437
+ return {
438
+ id: canonicalGroupId,
439
+ range: combineObservationGroupRanges(resolvedGroups),
440
+ content: section.body,
441
+ sourceGroupIds
442
+ };
443
+ });
444
+ }
445
+ function reconcileObservationGroupsFromReflection(content, sourceObservations) {
446
+ const sourceGroups = parseObservationGroups(sourceObservations);
447
+ if (sourceGroups.length === 0) {
448
+ return null;
449
+ }
450
+ const normalizedContent = content.trim();
451
+ if (!normalizedContent) {
452
+ return "";
453
+ }
454
+ const derivedGroups = deriveObservationGroupProvenance(normalizedContent, sourceGroups);
455
+ if (derivedGroups.length > 0) {
456
+ return derivedGroups.map((group) => wrapInObservationGroup(group.content, group.range, group.id, group.sourceGroupIds)).join("\n\n");
457
+ }
458
+ return wrapInObservationGroup(
459
+ normalizedContent,
460
+ combineObservationGroupRanges(sourceGroups),
461
+ generateAnchorId(),
462
+ Array.from(new Set(sourceGroups.flatMap((group) => [group.id, ...group.sourceGroupIds ?? []])))
463
+ );
464
+ }
465
+
466
+ // src/processors/observational-memory/anchor-ids.ts
467
+ var ANCHOR_ID_PATTERN = /^\[(O\d+(?:-N\d+)?)\]\s*/;
468
+ var OBSERVATION_DATE_HEADER_PATTERN = /^\s*Date:\s+/;
469
+ var XML_TAG_PATTERN = /^\s*<\/?[a-z][^>]*>\s*$/i;
470
+ var MARKDOWN_GROUP_HEADING_PATTERN = /^\s*##\s+Group\s+`[^`]+`\s*$/;
471
+ var MARKDOWN_GROUP_METADATA_PATTERN = /^\s*_range:\s*`[^`]*`_\s*$/;
472
+ function buildEphemeralAnchorId(topLevelCounter, nestedCounter) {
473
+ return nestedCounter === 0 ? `O${topLevelCounter}` : `O${topLevelCounter}-N${nestedCounter}`;
474
+ }
475
+ function parseAnchorId(line) {
476
+ const match = line.match(ANCHOR_ID_PATTERN);
477
+ return match?.[1] ?? null;
478
+ }
479
+ function shouldAnchorLine(line) {
480
+ const trimmed = line.trim();
481
+ if (!trimmed) {
482
+ return false;
483
+ }
484
+ if (parseAnchorId(trimmed)) {
485
+ return false;
486
+ }
487
+ if (OBSERVATION_DATE_HEADER_PATTERN.test(trimmed)) {
488
+ return false;
489
+ }
490
+ if (XML_TAG_PATTERN.test(trimmed)) {
491
+ return false;
492
+ }
493
+ if (MARKDOWN_GROUP_HEADING_PATTERN.test(trimmed) || MARKDOWN_GROUP_METADATA_PATTERN.test(trimmed)) {
494
+ return false;
495
+ }
496
+ return true;
497
+ }
498
+ function getIndentationDepth(line) {
499
+ const leadingWhitespace = line.match(/^\s*/)?.[0] ?? "";
500
+ return Math.floor(leadingWhitespace.replace(/\t/g, " ").length / 2);
501
+ }
502
+ function injectAnchorIds(observations) {
503
+ if (!observations) {
504
+ return observations;
505
+ }
506
+ const lines = observations.split("\n");
507
+ let topLevelCounter = 0;
508
+ let nestedCounter = 0;
509
+ let changed = false;
510
+ for (let i = 0; i < lines.length; i++) {
511
+ const line = lines[i];
512
+ if (!shouldAnchorLine(line)) {
513
+ continue;
514
+ }
515
+ const indentationDepth = getIndentationDepth(line);
516
+ if (indentationDepth === 0) {
517
+ topLevelCounter += 1;
518
+ nestedCounter = 0;
519
+ } else {
520
+ if (topLevelCounter === 0) {
521
+ topLevelCounter = 1;
522
+ }
523
+ nestedCounter += 1;
524
+ }
525
+ const anchorId = buildEphemeralAnchorId(topLevelCounter, nestedCounter);
526
+ const leadingWhitespace = line.match(/^\s*/)?.[0] ?? "";
527
+ lines[i] = `${leadingWhitespace}[${anchorId}] ${line.slice(leadingWhitespace.length)}`;
528
+ changed = true;
529
+ }
530
+ return changed ? lines.join("\n") : observations;
531
+ }
532
+ function stripEphemeralAnchorIds(observations) {
533
+ if (!observations) {
534
+ return observations;
535
+ }
536
+ return observations.replace(/(^|\n)([^\S\n]*)\[(O\d+(?:-N\d+)?)\][^\S\n]*/g, "$1$2");
537
+ }
322
538
  var ENCRYPTED_CONTENT_KEY = "encryptedContent";
323
539
  var ENCRYPTED_CONTENT_REDACTION_THRESHOLD = 256;
324
540
  var DEFAULT_OBSERVER_TOOL_RESULT_MAX_TOKENS = 1e4;
@@ -385,9 +601,8 @@ function truncateStringByTokens(text, maxTokens) {
385
601
  }
386
602
  const buildCandidate = (sliceEnd) => {
387
603
  const visible = text.slice(0, sliceEnd);
388
- const omittedChars = text.length - sliceEnd;
389
604
  return `${visible}
390
- ... [truncated ~${totalTokens - tokenx.estimateTokenCount(visible)} tokens / ${omittedChars} characters]`;
605
+ ... [truncated ~${totalTokens - tokenx.estimateTokenCount(visible)} tokens]`;
391
606
  };
392
607
  let low = 0;
393
608
  let high = text.length;
@@ -1386,7 +1601,7 @@ function extractCurrentTask(observations) {
1386
1601
  return content || null;
1387
1602
  }
1388
1603
  function optimizeObservationsForContext(observations) {
1389
- let optimized = observations;
1604
+ let optimized = stripEphemeralAnchorIds(observations);
1390
1605
  optimized = optimized.replace(/🟡\s*/g, "");
1391
1606
  optimized = optimized.replace(/🟢\s*/g, "");
1392
1607
  optimized = optimized.replace(/\[(?![\d\s]*items collapsed)[^\]]+\]/g, "");
@@ -1576,9 +1791,11 @@ Your current detail level was a 10/10, lets aim for a 4/10 detail level.
1576
1791
  };
1577
1792
  function buildReflectorPrompt(observations, manualPrompt, compressionLevel, skipContinuationHints) {
1578
1793
  const level = typeof compressionLevel === "number" ? compressionLevel : compressionLevel ? 1 : 0;
1794
+ const reflectionView = renderObservationGroupsForReflection(observations) ?? observations;
1795
+ const anchoredObservations = injectAnchorIds(reflectionView);
1579
1796
  let prompt = `## OBSERVATIONS TO REFLECT ON
1580
1797
 
1581
- ${observations}
1798
+ ${anchoredObservations}
1582
1799
 
1583
1800
  ---
1584
1801
 
@@ -1603,7 +1820,7 @@ IMPORTANT: Do NOT include <current-task> or <suggested-response> sections in you
1603
1820
  }
1604
1821
  return prompt;
1605
1822
  }
1606
- function parseReflectorOutput(output) {
1823
+ function parseReflectorOutput(output, sourceObservations) {
1607
1824
  if (detectDegenerateRepetition(output)) {
1608
1825
  return {
1609
1826
  observations: "",
@@ -1611,9 +1828,10 @@ function parseReflectorOutput(output) {
1611
1828
  };
1612
1829
  }
1613
1830
  const parsed = parseReflectorSectionXml(output);
1614
- const observations = sanitizeObservationLines(parsed.observations || "");
1831
+ const sanitizedObservations = sanitizeObservationLines(stripEphemeralAnchorIds(parsed.observations || ""));
1832
+ const reconciledObservations = sourceObservations ? reconcileObservationGroupsFromReflection(sanitizedObservations, sourceObservations) : null;
1615
1833
  return {
1616
- observations,
1834
+ observations: reconciledObservations ?? sanitizedObservations,
1617
1835
  suggestedContinuation: parsed.suggestedResponse || void 0
1618
1836
  // Note: Reflector's currentTask is not used - thread metadata preserves per-thread tasks
1619
1837
  };
@@ -3109,7 +3327,24 @@ if (OM_DEBUG_LOG) {
3109
3327
  _origConsoleError.apply(console, args);
3110
3328
  };
3111
3329
  }
3330
+ function messageHasVisibleContent(msg) {
3331
+ const content = msg.content;
3332
+ if (content?.parts && Array.isArray(content.parts)) {
3333
+ return content.parts.some((p) => {
3334
+ const t = p?.type;
3335
+ return t && !t.startsWith("data-") && t !== "step-start";
3336
+ });
3337
+ }
3338
+ if (content?.content) return true;
3339
+ return false;
3340
+ }
3341
+ function buildMessageRange(messages) {
3342
+ const first = messages.find(messageHasVisibleContent) ?? messages[0];
3343
+ const last = [...messages].reverse().find(messageHasVisibleContent) ?? messages[messages.length - 1];
3344
+ return `${first.id}:${last.id}`;
3345
+ }
3112
3346
  var OBSERVATIONAL_MEMORY_DEFAULTS = {
3347
+ retrieval: false,
3113
3348
  observation: {
3114
3349
  model: "google/gemini-2.5-flash",
3115
3350
  messageTokens: 3e4,
@@ -3164,12 +3399,54 @@ KNOWLEDGE UPDATES: When asked about current state (e.g., "where do I currently..
3164
3399
  PLANNED ACTIONS: If the user stated they planned to do something (e.g., "I'm going to...", "I'm looking forward to...", "I will...") and the date they planned to do it is now in the past (check the relative time like "3 weeks ago"), assume they completed the action unless there's evidence they didn't. For example, if someone said "I'll start my new diet on Monday" and that was 2 weeks ago, assume they started the diet.
3165
3400
 
3166
3401
  MOST RECENT USER INPUT: Treat the most recent user message as the highest-priority signal for what to do next. Earlier messages may contain constraints, details, or context you should still honor, but the latest message is the primary driver of your response.`;
3402
+ var OBSERVATION_RETRIEVAL_INSTRUCTIONS = `## Recall \u2014 looking up source messages
3403
+
3404
+ 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 \u2014 use the **recall** tool to retrieve them.
3405
+
3406
+ ### When to use recall
3407
+ - The user asks you to **repeat, show, or reproduce** something from a past conversation
3408
+ - The user asks for **exact content** \u2014 code, text, quotes, error messages, URLs, file paths, specific numbers
3409
+ - 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)
3410
+ - You want to **verify or expand on** an observation before responding
3411
+
3412
+ **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.
3413
+
3414
+ ### How to use recall
3415
+ Each range has the format \`startId:endId\` where both are message IDs separated by a colon.
3416
+
3417
+ 1. Find the observation group relevant to the user's question and extract the start or end ID from its range.
3418
+ 2. Call \`recall\` with that ID as the \`cursor\`.
3419
+ 3. Use \`page: 1\` (or omit) to read forward from the cursor, \`page: -1\` to read backward.
3420
+ 4. If the first page doesn't have what you need, increment the page number to keep paginating.
3421
+ 5. Check \`hasNextPage\`/\`hasPrevPage\` in the result to know if more pages exist in each direction.
3422
+
3423
+ ### Detail levels
3424
+ By default recall returns **low** detail: truncated text and tool names only. Each message shows its ID and each part has a positional index like \`[p0]\`, \`[p1]\`, etc.
3425
+
3426
+ - Use \`detail: "high"\` to get full message content including tool arguments and results. This will only return the high detail version of a single message part at a time.
3427
+ - Use \`partIndex\` with a cursor to fetch a single part at full detail \u2014 for example, to read one specific tool result or code block without loading every part.
3428
+
3429
+ If the result says \`truncated: true\`, the output was cut to fit the token budget. You can paginate or use \`partIndex\` to target specific content.
3430
+
3431
+ ### Following up on truncated parts
3432
+ Low-detail results may include truncation hints like:
3433
+ \`[truncated \u2014 call recall cursor="..." partIndex=N detail="high" for full content]\`
3434
+
3435
+ **When you see these hints and need the full content, make the exact call described in the hint.** This is the normal workflow: first recall at low detail to scan, then drill into specific parts at high detail. Do not stop at the low-detail result if the user asked for exact content.
3436
+
3437
+ ### When recall is NOT needed
3438
+ - The user is asking for a high-level summary and your observations already cover it
3439
+ - The question is about general preferences or facts that don't require source text
3440
+ - There is no relevant range in your observations for the topic
3441
+
3442
+ Observation groups with range IDs and your recall tool allows you to think back and remember details you're fuzzy on.`;
3167
3443
  var ObservationalMemory = class _ObservationalMemory {
3168
3444
  id = "observational-memory";
3169
3445
  name = "Observational Memory";
3170
3446
  storage;
3171
3447
  tokenCounter;
3172
3448
  scope;
3449
+ retrieval = false;
3173
3450
  observationConfig;
3174
3451
  reflectionConfig;
3175
3452
  onDebugEvent;
@@ -3482,6 +3759,7 @@ var ObservationalMemory = class _ObservationalMemory {
3482
3759
  this.shouldObscureThreadIds = config.obscureThreadIds || false;
3483
3760
  this.storage = config.storage;
3484
3761
  this.scope = config.scope ?? "thread";
3762
+ this.retrieval = this.scope === "thread" && (config.retrieval ?? OBSERVATIONAL_MEMORY_DEFAULTS.retrieval);
3485
3763
  const resolveModel = (m) => m === "default" ? OBSERVATIONAL_MEMORY_DEFAULTS.observation.model : m;
3486
3764
  const observationModel = resolveModel(config.model) ?? resolveModel(config.observation?.model) ?? resolveModel(config.reflection?.model);
3487
3765
  const reflectionModel = resolveModel(config.model) ?? resolveModel(config.reflection?.model) ?? resolveModel(config.observation?.model);
@@ -3585,6 +3863,7 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
3585
3863
  get config() {
3586
3864
  return {
3587
3865
  scope: this.scope,
3866
+ retrieval: this.retrieval,
3588
3867
  observation: {
3589
3868
  messageTokens: this.observationConfig.messageTokens,
3590
3869
  previousObserverTokens: this.observationConfig.previousObserverTokens
@@ -3841,7 +4120,8 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
3841
4120
  config: {
3842
4121
  observation: this.observationConfig,
3843
4122
  reflection: this.reflectionConfig,
3844
- scope: this.scope
4123
+ scope: this.scope,
4124
+ retrieval: this.retrieval
3845
4125
  },
3846
4126
  observedTimezone
3847
4127
  });
@@ -4482,7 +4762,7 @@ ${unreflectedContent}` : bufferedReflection;
4482
4762
  totalUsage.outputTokens += usage.outputTokens ?? 0;
4483
4763
  totalUsage.totalTokens += usage.totalTokens ?? 0;
4484
4764
  }
4485
- parsed = parseReflectorOutput(result.text);
4765
+ parsed = parseReflectorOutput(result.text, observations);
4486
4766
  if (parsed.degenerate) {
4487
4767
  omDebug(
4488
4768
  `[OM:callReflector] attempt #${attemptNumber}: degenerate repetition detected, treating as compression failure`
@@ -4549,14 +4829,18 @@ ${unreflectedContent}` : bufferedReflection;
4549
4829
  * @param suggestedResponse - Thread-specific suggested response (from thread metadata)
4550
4830
  * @param unobservedContextBlocks - Formatted <unobserved-context> blocks from other threads
4551
4831
  */
4552
- formatObservationsForContext(observations, currentTask, suggestedResponse, unobservedContextBlocks, currentDate) {
4553
- let optimized = optimizeObservationsForContext(observations);
4832
+ formatObservationsForContext(observations, currentTask, suggestedResponse, unobservedContextBlocks, currentDate, retrieval = false) {
4833
+ let optimized = retrieval ? renderObservationGroupsForReflection(observations) ?? observations : optimizeObservationsForContext(observations);
4554
4834
  if (currentDate) {
4555
4835
  optimized = addRelativeTimeToObservations(optimized, currentDate);
4556
4836
  }
4557
- const messages = [`${OBSERVATION_CONTEXT_PROMPT}
4837
+ const messages = [
4838
+ `${OBSERVATION_CONTEXT_PROMPT}
4839
+
4840
+ ${OBSERVATION_CONTEXT_INSTRUCTIONS}${retrieval ? `
4558
4841
 
4559
- ${OBSERVATION_CONTEXT_INSTRUCTIONS}`];
4842
+ ${OBSERVATION_RETRIEVAL_INSTRUCTIONS}` : ""}`
4843
+ ];
4560
4844
  if (unobservedContextBlocks) {
4561
4845
  messages.push(
4562
4846
  `The following content is from OTHER conversations different from the current conversation, they're here for reference, but they're not necessarily your focus:
@@ -5041,7 +5325,8 @@ ${suggestedResponse}
5041
5325
  currentTask,
5042
5326
  suggestedResponse,
5043
5327
  unobservedContextBlocks,
5044
- currentDate
5328
+ currentDate,
5329
+ this.retrieval
5045
5330
  );
5046
5331
  messageList.clearSystemMessages("observational-memory");
5047
5332
  messageList.addSystem(observationSystemMessages, "observational-memory");
@@ -5709,11 +5994,12 @@ ${formattedMessages}
5709
5994
  * Wrap observations in a thread attribution tag.
5710
5995
  * Used in resource scope to track which thread observations came from.
5711
5996
  */
5712
- async wrapWithThreadTag(threadId, observations) {
5997
+ async wrapWithThreadTag(threadId, observations, messageRange) {
5713
5998
  const cleanObservations = this.stripThreadTags(observations);
5999
+ const groupedObservations = this.retrieval && messageRange ? wrapInObservationGroup(cleanObservations, messageRange) : cleanObservations;
5714
6000
  const obscuredId = await this.representThreadIDInContext(threadId);
5715
6001
  return `<thread id="${obscuredId}">
5716
- ${cleanObservations}
6002
+ ${groupedObservations}
5717
6003
  </thread>`;
5718
6004
  }
5719
6005
  /**
@@ -5850,9 +6136,10 @@ ${threadClose}`;
5850
6136
  });
5851
6137
  const lastObservedAt = this.getMaxMessageTimestamp(messagesToObserve);
5852
6138
  const existingObservations = freshRecord?.activeObservations ?? record.activeObservations ?? "";
6139
+ const messageRange = this.retrieval ? buildMessageRange(messagesToObserve) : void 0;
5853
6140
  let newObservations;
5854
6141
  if (this.scope === "resource") {
5855
- const threadSection = await this.wrapWithThreadTag(threadId, result.observations);
6142
+ const threadSection = await this.wrapWithThreadTag(threadId, result.observations, messageRange);
5856
6143
  newObservations = this.replaceOrAppendThreadSection(
5857
6144
  existingObservations,
5858
6145
  threadId,
@@ -5860,7 +6147,8 @@ ${threadClose}`;
5860
6147
  lastObservedAt
5861
6148
  );
5862
6149
  } else {
5863
- newObservations = existingObservations ? `${existingObservations}${_ObservationalMemory.createMessageBoundary(lastObservedAt)}${result.observations}` : result.observations;
6150
+ const groupedObservations = this.retrieval && messageRange ? wrapInObservationGroup(result.observations, messageRange) : result.observations;
6151
+ newObservations = existingObservations ? `${existingObservations}${_ObservationalMemory.createMessageBoundary(lastObservedAt)}${groupedObservations}` : groupedObservations;
5864
6152
  }
5865
6153
  let totalTokenCount = this.tokenCounter.countObservations(newObservations);
5866
6154
  const cycleObservationTokens = this.tokenCounter.countObservations(result.observations);
@@ -6168,11 +6456,12 @@ ${threadClose}`;
6168
6456
  }
6169
6457
  }
6170
6458
  }
6459
+ const messageRange = this.retrieval ? buildMessageRange(messagesToBuffer) : void 0;
6171
6460
  let newObservations;
6172
6461
  if (this.scope === "resource") {
6173
- newObservations = await this.wrapWithThreadTag(threadId, result.observations);
6462
+ newObservations = await this.wrapWithThreadTag(threadId, result.observations, messageRange);
6174
6463
  } else {
6175
- newObservations = result.observations;
6464
+ newObservations = this.retrieval && messageRange ? wrapInObservationGroup(result.observations, messageRange) : result.observations;
6176
6465
  }
6177
6466
  const newTokenCount = this.tokenCounter.countObservations(newObservations);
6178
6467
  const newMessageIds = messagesToBuffer.map((m) => m.id);
@@ -6798,7 +7087,8 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
6798
7087
  const { threadId, threadMessages, result } = obsResult;
6799
7088
  cycleObservationTokens += this.tokenCounter.countObservations(result.observations);
6800
7089
  const threadLastObservedAt = this.getMaxMessageTimestamp(threadMessages);
6801
- const threadSection = await this.wrapWithThreadTag(threadId, result.observations);
7090
+ const messageRange = this.retrieval ? buildMessageRange(threadMessages) : void 0;
7091
+ const threadSection = await this.wrapWithThreadTag(threadId, result.observations, messageRange);
6802
7092
  currentObservations = this.replaceOrAppendThreadSection(
6803
7093
  currentObservations,
6804
7094
  threadId,
@@ -7289,11 +7579,24 @@ exports.ObservationalMemory = ObservationalMemory;
7289
7579
  exports.TokenCounter = TokenCounter;
7290
7580
  exports.buildObserverPrompt = buildObserverPrompt;
7291
7581
  exports.buildObserverSystemPrompt = buildObserverSystemPrompt;
7582
+ exports.combineObservationGroupRanges = combineObservationGroupRanges;
7583
+ exports.deriveObservationGroupProvenance = deriveObservationGroupProvenance;
7292
7584
  exports.extractCurrentTask = extractCurrentTask;
7293
7585
  exports.formatMessagesForObserver = formatMessagesForObserver;
7586
+ exports.formatToolResultForObserver = formatToolResultForObserver;
7294
7587
  exports.getObservationsAsOf = getObservationsAsOf;
7295
7588
  exports.hasCurrentTaskSection = hasCurrentTaskSection;
7589
+ exports.injectAnchorIds = injectAnchorIds;
7296
7590
  exports.optimizeObservationsForContext = optimizeObservationsForContext;
7591
+ exports.parseAnchorId = parseAnchorId;
7592
+ exports.parseObservationGroups = parseObservationGroups;
7297
7593
  exports.parseObserverOutput = parseObserverOutput;
7298
- //# sourceMappingURL=chunk-AR52LM55.cjs.map
7299
- //# sourceMappingURL=chunk-AR52LM55.cjs.map
7594
+ exports.reconcileObservationGroupsFromReflection = reconcileObservationGroupsFromReflection;
7595
+ exports.renderObservationGroupsForReflection = renderObservationGroupsForReflection;
7596
+ exports.resolveToolResultValue = resolveToolResultValue;
7597
+ exports.stripEphemeralAnchorIds = stripEphemeralAnchorIds;
7598
+ exports.stripObservationGroups = stripObservationGroups;
7599
+ exports.truncateStringByTokens = truncateStringByTokens;
7600
+ exports.wrapInObservationGroup = wrapInObservationGroup;
7601
+ //# sourceMappingURL=chunk-LVV2RT42.cjs.map
7602
+ //# sourceMappingURL=chunk-LVV2RT42.cjs.map