@mastra/memory 1.31.0-alpha.0 → 1.31.0-alpha.2

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 (37) hide show
  1. package/dist/_types/@internal_ai-sdk-v4/package.json +1 -0
  2. package/dist/docs/SKILL.md +1 -1
  3. package/dist/docs/assets/SOURCE_MAP.json +1 -1
  4. package/dist/docs/references/docs-memory-observational-memory.md +33 -0
  5. package/dist/docs/references/reference-memory-observational-memory.md +34 -4
  6. package/dist/hooks.cjs +158 -0
  7. package/dist/hooks.cjs.map +1 -0
  8. package/dist/hooks.d.ts +25 -0
  9. package/dist/hooks.d.ts.map +1 -0
  10. package/dist/hooks.js +156 -0
  11. package/dist/hooks.js.map +1 -0
  12. package/dist/index.cjs +1 -1
  13. package/dist/index.d.ts +8 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +1 -1
  16. package/dist/processors/index.cjs +1 -1
  17. package/dist/processors/index.js +1 -1
  18. package/dist/processors/observational-memory/hooks.d.ts +63 -0
  19. package/dist/processors/observational-memory/hooks.d.ts.map +1 -0
  20. package/dist/processors/observational-memory/observation-groups.d.ts.map +1 -1
  21. package/dist/processors/observational-memory/observation-strategies/async-buffer.d.ts.map +1 -1
  22. package/dist/processors/observational-memory/observation-strategies/resource-scoped.d.ts.map +1 -1
  23. package/dist/processors/observational-memory/observation-strategies/sync.d.ts.map +1 -1
  24. package/dist/processors/observational-memory/observation-strategies/thread-title.d.ts +15 -0
  25. package/dist/processors/observational-memory/observation-strategies/thread-title.d.ts.map +1 -0
  26. package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
  27. package/dist/processors/observational-memory/processor.d.ts.map +1 -1
  28. package/dist/processors/observational-memory/types.d.ts +6 -6
  29. package/dist/{src-Da7AKXPR.cjs → src-C4niho1P.cjs} +206 -54
  30. package/dist/src-C4niho1P.cjs.map +1 -0
  31. package/dist/{src-DqLGJfSb.js → src-DquR-jTR.js} +208 -56
  32. package/dist/src-DquR-jTR.js.map +1 -0
  33. package/dist/tools/om-tools.d.ts +4 -2
  34. package/dist/tools/om-tools.d.ts.map +1 -1
  35. package/package.json +15 -5
  36. package/dist/src-Da7AKXPR.cjs.map +0 -1
  37. package/dist/src-DqLGJfSb.js.map +0 -1
@@ -5,7 +5,7 @@ import * as z4 from "zod/v4";
5
5
  import { z as z$1 } from "zod/v4";
6
6
  import { Agent, MessageList } from "@mastra/core/agent";
7
7
  import { coreFeatures } from "@mastra/core/features";
8
- import { MastraMemory, getMemoryTokenBoundary, getThreadOMMetadata, isAfterMemoryTokenBoundary, loadMessageHistory, normalizeMessageHistoryConfig, parseMemoryRequestContext, setThreadOMMetadata } from "@mastra/core/memory";
8
+ import { MastraMemory, getMemoryTokenBoundary, getThreadOMMetadata, isAfterMemoryTokenBoundary, isThreadTitlePinned, loadMessageHistory, normalizeMessageHistoryConfig, parseMemoryRequestContext, setThreadOMMetadata } from "@mastra/core/memory";
9
9
  import { EntityType, SpanType, createObservabilityContext, getOrCreateSpan } from "@mastra/core/observability";
10
10
  import { MessageHistory, MessageHistory as MessageHistory$1, SemanticRecall, TokenLimiterProcessor, WorkingMemory } from "@mastra/core/processors";
11
11
  import { generateEmptyFromSchema } from "@mastra/core/utils";
@@ -18,7 +18,7 @@ import { appendFileSync, mkdirSync, writeFileSync } from "fs";
18
18
  import { join } from "path";
19
19
  import { createTool } from "@mastra/core/tools";
20
20
  import { MASTRA_THREAD_ID_KEY, RequestContext } from "@mastra/core/request-context";
21
- import { modelSupportsAttachments, resolveModelConfig } from "@mastra/core/llm";
21
+ import { modelSupportsAttachments, modelSupportsTemperature, resolveModelConfig } from "@mastra/core/llm";
22
22
  import { estimateTokenCount } from "tokenx";
23
23
  import { AsyncLocalStorage } from "async_hooks";
24
24
  import probeImageSizeSync from "probe-image-size/sync.js";
@@ -22778,13 +22778,13 @@ function renderFormattedParts(parts, timestamps, options) {
22778
22778
  tokenOffset: expandedTokens - options.maxTokens
22779
22779
  };
22780
22780
  }
22781
- async function recallPart({ memory, threadId, resourceId, cursor, partIndex, charOffset, threadScope, maxTokens = DEFAULT_MAX_RESULT_TOKENS }) {
22781
+ async function recallPart({ memory, threadId, resourceId, cursor, partIndex, charOffset, threadScope, retrievalScope = "thread", maxTokens = DEFAULT_MAX_RESULT_TOKENS }) {
22782
22782
  if (!memory || typeof memory.getMemoryStore !== "function") throw new Error("Memory instance is required for recall");
22783
22783
  if (!threadId) throw new Error("Thread ID is required for recall");
22784
22784
  const resolved = await resolveCursorMessage(memory, cursor, {
22785
22785
  resourceId,
22786
22786
  threadScope,
22787
- enforceThreadScope: false
22787
+ enforceThreadScope: retrievalScope !== "resource"
22788
22788
  });
22789
22789
  if ("hint" in resolved) throw new Error(resolved.hint);
22790
22790
  const allParts = formatMessageParts(resolved, "high");
@@ -22795,7 +22795,7 @@ async function recallPart({ memory, threadId, resourceId, cursor, partIndex, cha
22795
22795
  if (partIndex > Math.max(...allParts.map((p) => p.partIndex))) {
22796
22796
  const nextMessage = await getNextVisibleMessage({
22797
22797
  memory,
22798
- threadId,
22798
+ threadId: resolved.threadId ?? threadId,
22799
22799
  resourceId,
22800
22800
  after: resolved.createdAt
22801
22801
  });
@@ -22834,7 +22834,7 @@ async function recallPart({ memory, threadId, resourceId, cursor, partIndex, cha
22834
22834
  note
22835
22835
  };
22836
22836
  }
22837
- async function recallMessages({ memory, threadId, resourceId, cursor, page = 1, limit = 20, detail = "low", partType, toolName, threadScope, maxTokens = DEFAULT_MAX_RESULT_TOKENS }) {
22837
+ async function recallMessages({ memory, threadId, resourceId, cursor, page = 1, limit = 20, detail = "low", partType, toolName, threadScope, retrievalScope = "thread", maxTokens = DEFAULT_MAX_RESULT_TOKENS }) {
22838
22838
  if (!memory) throw new Error("Memory instance is required for recall");
22839
22839
  if (!threadId) throw new Error("Thread ID is required for recall");
22840
22840
  if (typeof memory.getMemoryStore !== "function") throw new Error("recall requires a Memory instance with storage access");
@@ -22845,7 +22845,7 @@ async function recallMessages({ memory, threadId, resourceId, cursor, page = 1,
22845
22845
  const resolved = await resolveCursorMessage(memory, cursor, {
22846
22846
  resourceId,
22847
22847
  threadScope,
22848
- enforceThreadScope: false
22848
+ enforceThreadScope: retrievalScope === "thread"
22849
22849
  });
22850
22850
  if ("hint" in resolved) return {
22851
22851
  messages: resolved.hint,
@@ -22862,7 +22862,7 @@ async function recallMessages({ memory, threadId, resourceId, cursor, page = 1,
22862
22862
  const anchor = resolved;
22863
22863
  const crossThreadId = anchor.threadId && anchor.threadId !== threadId ? anchor.threadId : void 0;
22864
22864
  if (crossThreadId && threadScope) return {
22865
- messages: `Cursor does not belong to the active thread. Expected thread "${threadId}" but cursor "${cursor}" belongs to "${anchor.threadId}". Pass threadId="${anchor.threadId}" to browse that thread, or omit threadId and use this cursor directly in resource scope.`,
22865
+ messages: `Cursor does not belong to the active thread. Expected thread "${threadId}" but cursor "${cursor}" belongs to "${anchor.threadId}". Pass threadId="${anchor.threadId}" to browse that thread.`,
22866
22866
  count: 0,
22867
22867
  cursor,
22868
22868
  page: normalizedPage,
@@ -23021,7 +23021,8 @@ async function recallThreadFromStart({ memory, threadId, resourceId, page = 1, l
23021
23021
  };
23022
23022
  }
23023
23023
  const recallTool = (_memoryConfig, options) => {
23024
- const isResourceScope = (options?.retrievalScope ?? "thread") === "resource";
23024
+ const retrievalScope = options?.retrievalScope ?? "thread";
23025
+ const isResourceScope = retrievalScope === "resource";
23025
23026
  const searchEnabled = options?.searchEnabled ?? true;
23026
23027
  const description = isResourceScope ? `Browse conversation history. Use mode="threads" to list all threads for the current user. Use mode="messages" (default) to browse messages in the current thread or pass threadId to browse another thread in the active resource. When mode="messages" has no cursor or threadId, it defaults to the current thread and says so at the top of the result. If you pass only a cursor, it must belong to the current thread.${searchEnabled ? " Use mode=\"search\" to find messages by content across all threads." : ""}` : `Browse conversation history in the current thread. Use mode="messages" (default) to page through messages near a cursor.${searchEnabled ? " Use mode=\"search\" to find messages by content in this thread." : ""} Use mode="threads" to get the current thread's ID and title.`;
23027
23028
  const modeEnum = searchEnabled ? [
@@ -23232,23 +23233,25 @@ const recallTool = (_memoryConfig, options) => {
23232
23233
  if (partIndex !== void 0 && partIndex !== null) return recallPart({
23233
23234
  memory,
23234
23235
  threadId: targetThreadId,
23235
- resourceId: isResourceScope ? resourceId : void 0,
23236
+ resourceId,
23236
23237
  cursor,
23237
23238
  partIndex,
23238
23239
  charOffset,
23239
- threadScope
23240
+ threadScope,
23241
+ retrievalScope
23240
23242
  });
23241
23243
  return recallMessages({
23242
23244
  memory,
23243
23245
  threadId: targetThreadId,
23244
- resourceId: isResourceScope ? resourceId : void 0,
23246
+ resourceId,
23245
23247
  cursor,
23246
23248
  page,
23247
23249
  limit,
23248
23250
  detail: detail ?? "low",
23249
23251
  partType,
23250
23252
  toolName,
23251
- threadScope
23253
+ threadScope,
23254
+ retrievalScope
23252
23255
  });
23253
23256
  }
23254
23257
  });
@@ -24354,7 +24357,8 @@ function stripThreadTags(observations) {
24354
24357
  }
24355
24358
  //#endregion
24356
24359
  //#region src/processors/observational-memory/observation-groups.ts
24357
- const OBSERVATION_GROUP_PATTERN = /<observation-group\s([^>]*)>([\s\S]*?)<\/observation-group>/g;
24360
+ const OBSERVATION_GROUP_OPEN = "<observation-group";
24361
+ const OBSERVATION_GROUP_CLOSE = "</observation-group>";
24358
24362
  const ATTRIBUTE_PATTERN = /([\w][\w-]*)="([^"]*)"/g;
24359
24363
  const REFLECTION_GROUP_SPLIT_PATTERN = /^##\s+Group\s+/m;
24360
24364
  function parseObservationGroupAttributes(attributeString) {
@@ -24365,6 +24369,81 @@ function parseObservationGroupAttributes(attributeString) {
24365
24369
  }
24366
24370
  return attributes;
24367
24371
  }
24372
+ function isLineStart(observations, index) {
24373
+ return index === 0 || observations[index - 1] === "\n";
24374
+ }
24375
+ function scanObservationGroupTags(observations) {
24376
+ const tags = [];
24377
+ const incompleteOpenings = [];
24378
+ let cursor = 0;
24379
+ let closeFloor = 0;
24380
+ while (cursor < observations.length) {
24381
+ const start = observations.indexOf(OBSERVATION_GROUP_OPEN, cursor);
24382
+ if (start === -1) break;
24383
+ const attributesStart = start + 18;
24384
+ if (!/\s/.test(observations[attributesStart] ?? "")) {
24385
+ cursor = attributesStart;
24386
+ continue;
24387
+ }
24388
+ const openEnd = observations.indexOf(">", attributesStart);
24389
+ if (openEnd === -1) break;
24390
+ const closeStart = observations.indexOf(OBSERVATION_GROUP_CLOSE, Math.max(openEnd + 1, closeFloor));
24391
+ if (closeStart === -1) {
24392
+ if (isLineStart(observations, start)) incompleteOpenings.push({
24393
+ start,
24394
+ end: openEnd + 1
24395
+ });
24396
+ closeFloor = observations.length;
24397
+ cursor = openEnd + 1;
24398
+ continue;
24399
+ }
24400
+ const nestedStart = observations.indexOf(OBSERVATION_GROUP_OPEN, openEnd + 1);
24401
+ if (nestedStart !== -1 && nestedStart < closeStart && isLineStart(observations, nestedStart)) {
24402
+ incompleteOpenings.push({
24403
+ start,
24404
+ end: openEnd + 1
24405
+ });
24406
+ closeFloor = closeStart;
24407
+ cursor = nestedStart;
24408
+ continue;
24409
+ }
24410
+ tags.push({
24411
+ start,
24412
+ end: closeStart + 20,
24413
+ attributeString: observations.slice(attributesStart, openEnd),
24414
+ content: observations.slice(openEnd + 1, closeStart)
24415
+ });
24416
+ closeFloor = closeStart;
24417
+ cursor = closeStart + 20;
24418
+ }
24419
+ return {
24420
+ tags,
24421
+ incompleteOpenings
24422
+ };
24423
+ }
24424
+ function replaceObservationGroupTags(observations, replace) {
24425
+ const { tags, incompleteOpenings } = scanObservationGroupTags(observations);
24426
+ const parts = [];
24427
+ let cursor = 0;
24428
+ let openingIndex = 0;
24429
+ const skipIncompleteOpeningsBefore = (limit) => {
24430
+ while (openingIndex < incompleteOpenings.length && incompleteOpenings[openingIndex].start < limit) {
24431
+ const opening = incompleteOpenings[openingIndex];
24432
+ openingIndex++;
24433
+ if (opening.start < cursor) continue;
24434
+ parts.push(observations.slice(cursor, opening.start));
24435
+ cursor = opening.end;
24436
+ }
24437
+ };
24438
+ for (const tag of tags) {
24439
+ skipIncompleteOpeningsBefore(tag.start);
24440
+ parts.push(observations.slice(cursor, tag.start), replace(tag));
24441
+ cursor = tag.end;
24442
+ }
24443
+ skipIncompleteOpeningsBefore(Number.POSITIVE_INFINITY);
24444
+ parts.push(observations.slice(cursor));
24445
+ return parts.join("");
24446
+ }
24368
24447
  function parseReflectionObservationGroupSections(content) {
24369
24448
  const normalizedContent = content.trim();
24370
24449
  if (!normalizedContent || !REFLECTION_GROUP_SPLIT_PATTERN.test(normalizedContent)) return [];
@@ -24389,9 +24468,8 @@ function wrapInObservationGroup(observations, range, id = generateAnchorId(), _s
24389
24468
  function parseObservationGroups(observations) {
24390
24469
  if (!observations) return [];
24391
24470
  const groups = [];
24392
- let match;
24393
- while ((match = OBSERVATION_GROUP_PATTERN.exec(observations)) !== null) {
24394
- const attributes = parseObservationGroupAttributes(match[1] ?? "");
24471
+ for (const tag of scanObservationGroupTags(observations).tags) {
24472
+ const attributes = parseObservationGroupAttributes(tag.attributeString);
24395
24473
  const id = attributes.id;
24396
24474
  const range = attributes.range;
24397
24475
  if (!id || !range) continue;
@@ -24399,54 +24477,96 @@ function parseObservationGroups(observations) {
24399
24477
  id,
24400
24478
  range,
24401
24479
  kind: attributes.kind,
24402
- content: match[2].trim()
24480
+ content: tag.content.trim()
24403
24481
  });
24404
24482
  }
24405
24483
  return groups;
24406
24484
  }
24407
24485
  function stripObservationGroups(observations) {
24408
24486
  if (!observations) return observations;
24409
- return observations.replace(OBSERVATION_GROUP_PATTERN, (_match, _attributes, content) => content.trim()).replace(/\n{3,}/g, "\n\n").trim();
24487
+ return replaceObservationGroupTags(observations, (tag) => tag.content.trim()).replace(/\n{3,}/g, "\n\n").trim();
24410
24488
  }
24411
24489
  function getRangeSegments(range) {
24412
24490
  return range.split(",").map((segment) => segment.trim()).filter(Boolean);
24413
24491
  }
24492
+ function getRangeEndpoints(segment) {
24493
+ const parts = segment.split(":").map((part) => part.trim());
24494
+ if (parts.length !== 2 || !parts[0] || !parts[1]) return null;
24495
+ return {
24496
+ start: parts[0],
24497
+ end: parts[1]
24498
+ };
24499
+ }
24500
+ /**
24501
+ * `buildMessageRange` produces opaque UUID endpoints, so those segments cannot be ordered by value.
24502
+ * Spanning from the first start to the last end keeps reflected metadata bounded — the full segment
24503
+ * list is deliberately not preserved (#14791). Segments that are not `start:end` pairs are left as
24504
+ * they are rather than being joined into a fabricated span.
24505
+ */
24506
+ function spanRangeSegments(segments) {
24507
+ const endpoints = segments.map(getRangeEndpoints);
24508
+ if (endpoints.some((endpoint) => endpoint === null)) return segments.join(",");
24509
+ const first = endpoints[0];
24510
+ const last = endpoints.at(-1);
24511
+ return `${first.start}:${last.end}`;
24512
+ }
24414
24513
  function combineObservationGroupRanges(groups) {
24415
- const segments = groups.flatMap((group) => getRangeSegments(group.range));
24514
+ const segments = Array.from(new Set(groups.flatMap((group) => getRangeSegments(group.range))));
24416
24515
  if (segments.length === 0) return "";
24417
- const firstSegment = segments[0];
24418
- const lastSegment = segments[segments.length - 1];
24419
- const firstStart = firstSegment?.split(":")[0]?.trim();
24420
- const lastEnd = lastSegment?.split(":").at(-1)?.trim();
24421
- if (firstStart && lastEnd) return `${firstStart}:${lastEnd}`;
24422
- return Array.from(new Set(segments)).join(",");
24516
+ const numericEndpoints = [];
24517
+ if (!segments.every((segment) => {
24518
+ const endpoints = getRangeEndpoints(segment);
24519
+ if (!endpoints || !/^\d+$/.test(endpoints.start) || !/^\d+$/.test(endpoints.end)) return false;
24520
+ const start = {
24521
+ label: endpoints.start,
24522
+ value: Number(endpoints.start)
24523
+ };
24524
+ const end = {
24525
+ label: endpoints.end,
24526
+ value: Number(endpoints.end)
24527
+ };
24528
+ if (!Number.isSafeInteger(start.value) || !Number.isSafeInteger(end.value)) return false;
24529
+ numericEndpoints.push(start.value <= end.value ? {
24530
+ start,
24531
+ end
24532
+ } : {
24533
+ start: end,
24534
+ end: start
24535
+ });
24536
+ return true;
24537
+ })) return spanRangeSegments(segments);
24538
+ const first = numericEndpoints.reduce((lowest, pair) => pair.start.value < lowest.start.value ? pair : lowest);
24539
+ const last = numericEndpoints.reduce((highest, pair) => pair.end.value > highest.end.value ? pair : highest);
24540
+ return `${first.start.label}:${last.end.label}`;
24423
24541
  }
24424
24542
  function renderObservationGroupsForReflection(observations) {
24425
- const groups = parseObservationGroups(observations);
24426
- if (groups.length === 0) return null;
24427
- const groupsByContent = new Map(groups.map((g) => [g.content.trim(), g]));
24428
- return observations.replace(OBSERVATION_GROUP_PATTERN, (_match, _attrs, content) => {
24429
- const group = groupsByContent.get(content.trim());
24430
- if (!group) return content.trim();
24431
- return `## Group \`${group.id}\`\n_range: \`${group.range}\`_\n\n${group.content}`;
24543
+ if (parseObservationGroups(observations).length === 0) return null;
24544
+ return replaceObservationGroupTags(observations, (tag) => {
24545
+ const attributes = parseObservationGroupAttributes(tag.attributeString);
24546
+ if (!attributes.id || !attributes.range) return tag.content.trim();
24547
+ return `## Group \`${attributes.id}\`\n_range: \`${attributes.range}\`_\n\n${tag.content.trim()}`;
24432
24548
  }).replace(/\n{3,}/g, "\n\n").trim();
24433
24549
  }
24434
24550
  function getCanonicalGroupId(sectionHeading, fallbackIndex) {
24435
24551
  return sectionHeading.match(/`([^`]+)`/)?.[1]?.trim() || `derived-group-${fallbackIndex + 1}`;
24436
24552
  }
24553
+ function getContentLines(content) {
24554
+ return content.split("\n").map((line) => line.trim()).filter(Boolean);
24555
+ }
24437
24556
  function deriveObservationGroupProvenance(content, groups) {
24438
24557
  const sections = parseReflectionObservationGroupSections(content);
24439
24558
  if (sections.length === 0 || groups.length === 0) return [];
24440
24559
  return sections.map((section, index) => {
24441
- const bodyLines = new Set(section.body.split("\n").map((line) => line.trim()).filter(Boolean));
24442
- const matchingGroups = groups.filter((group) => {
24443
- return group.content.split("\n").map((line) => line.trim()).filter(Boolean).some((line) => bodyLines.has(line));
24444
- });
24560
+ const canonicalGroupId = getCanonicalGroupId(section.heading, index);
24561
+ const identifiedGroup = groups.find((group) => group.id === canonicalGroupId);
24562
+ const bodyLines = new Set(getContentLines(section.body));
24563
+ const matchingGroups = groups.filter((group) => getContentLines(group.content).some((line) => bodyLines.has(line)));
24445
24564
  const fallbackGroup = groups[Math.min(index, groups.length - 1)];
24446
- const resolvedGroups = matchingGroups.length > 0 ? matchingGroups : fallbackGroup ? [fallbackGroup] : [];
24565
+ const identifiedLines = new Set(getContentLines(identifiedGroup?.content ?? ""));
24566
+ const contributingGroups = identifiedGroup ? matchingGroups.filter((group) => group.id !== identifiedGroup.id && getContentLines(group.content).some((line) => bodyLines.has(line) && !identifiedLines.has(line))) : [];
24447
24567
  return {
24448
- id: getCanonicalGroupId(section.heading, index),
24449
- range: combineObservationGroupRanges(resolvedGroups),
24568
+ id: canonicalGroupId,
24569
+ range: combineObservationGroupRanges(identifiedGroup ? groups.filter((group) => group === identifiedGroup || contributingGroups.includes(group)) : matchingGroups.length > 0 ? matchingGroups : fallbackGroup ? [fallbackGroup] : []),
24450
24570
  kind: "reflection",
24451
24571
  content: section.body
24452
24572
  };
@@ -24874,6 +24994,23 @@ var ObservationStrategy = class ObservationStrategy {
24874
24994
  }
24875
24995
  };
24876
24996
  //#endregion
24997
+ //#region src/processors/observational-memory/observation-strategies/thread-title.ts
24998
+ /**
24999
+ * Resolve the thread title an Observational Memory cycle should persist.
25000
+ *
25001
+ * Returns the trimmed candidate when it is a new, long-enough title, or
25002
+ * `undefined` when the current title must stay — including when the user
25003
+ * pinned it via `session.thread.rename()`, which sets the
25004
+ * `titlePinned` thread metadata flag.
25005
+ */
25006
+ function resolveThreadTitleUpdate(thread, generatedTitle) {
25007
+ const candidate = generatedTitle?.trim();
25008
+ if (!candidate || candidate.length < 3) return void 0;
25009
+ if (isThreadTitlePinned(thread?.metadata)) return void 0;
25010
+ if (candidate === thread?.title?.trim()) return void 0;
25011
+ return candidate;
25012
+ }
25013
+ //#endregion
24877
25014
  //#region src/processors/observational-memory/observation-strategies/sync.ts
24878
25015
  var SyncObservationStrategy = class extends ObservationStrategy {
24879
25016
  startedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -25026,8 +25163,8 @@ var SyncObservationStrategy = class extends ObservationStrategy {
25026
25163
  let threadUpdateMarker;
25027
25164
  if (thread) {
25028
25165
  const oldTitle = thread.title?.trim();
25029
- const newTitle = processed.threadTitle?.trim();
25030
- const shouldUpdateThreadTitle = !!newTitle && newTitle.length >= 3 && newTitle !== oldTitle;
25166
+ const newTitle = resolveThreadTitleUpdate(thread, processed.threadTitle);
25167
+ const shouldUpdateThreadTitle = newTitle !== void 0;
25031
25168
  const previousOmMetadata = getThreadOMMetadata(thread.metadata);
25032
25169
  const metadataUpdate = buildThreadMetadataFromExtractedValues(processed.extractors ?? this.observationConfig.extractors, processed.extractedValues);
25033
25170
  const newMetadata = setThreadOMMetadata(thread.metadata, {
@@ -25226,13 +25363,14 @@ var AsyncBufferObservationStrategy = class extends ObservationStrategy {
25226
25363
  abortSignal: this.opts.abortSignal
25227
25364
  });
25228
25365
  await this.indexObservationGroups(processed.observations, threadId, resourceId, processed.lastObservedAt);
25229
- const newTitle = processed.threadTitle?.trim();
25230
- const hasValidThreadTitle = !!newTitle && newTitle.length >= 3;
25366
+ const candidateTitle = processed.threadTitle?.trim();
25367
+ const hasValidThreadTitle = !!candidateTitle && candidateTitle.length >= 3;
25231
25368
  if (hasValidThreadTitle || processed.extractedValues) {
25232
25369
  const thread = await this.storage.getThreadById({ threadId });
25233
25370
  if (thread) {
25234
25371
  const oldTitle = thread.title?.trim();
25235
- const shouldUpdateThreadTitle = hasValidThreadTitle && newTitle !== oldTitle;
25372
+ const newTitle = resolveThreadTitleUpdate(thread, candidateTitle);
25373
+ const shouldUpdateThreadTitle = newTitle !== void 0;
25236
25374
  const previousOmMetadata = getThreadOMMetadata(thread.metadata);
25237
25375
  const metadataUpdate = buildThreadMetadataFromExtractedValues(processed.extractors ?? this.observationConfig.extractors, processed.extractedValues);
25238
25376
  const newMetadata = setThreadOMMetadata(thread.metadata, {
@@ -25589,8 +25727,8 @@ var ResourceScopedObservationStrategy = class extends ObservationStrategy {
25589
25727
  const thread = await this.storage.getThreadById({ threadId: update.threadId });
25590
25728
  if (thread) {
25591
25729
  const oldTitle = thread.title?.trim();
25592
- const newTitle = update.threadTitle?.trim();
25593
- const shouldUpdateThreadTitle = !!newTitle && newTitle.length >= 3 && newTitle !== oldTitle;
25730
+ const newTitle = resolveThreadTitleUpdate(thread, update.threadTitle);
25731
+ const shouldUpdateThreadTitle = newTitle !== void 0;
25594
25732
  const previousOmMetadata = getThreadOMMetadata(thread.metadata);
25595
25733
  const metadataUpdate = buildThreadMetadataFromExtractedValues(update.extractors ?? this.observationConfig.extractors, update.extracted);
25596
25734
  const newMetadata = setThreadOMMetadata(thread.metadata, {
@@ -28023,11 +28161,19 @@ var ObservationalMemory = class ObservationalMemory {
28023
28161
  const messageTokens = config.observation?.messageTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.messageTokens;
28024
28162
  const observationTokens = config.reflection?.observationTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.observationTokens;
28025
28163
  const isSharedBudget = config.shareTokenBudget ?? false;
28026
- const isDefaultModelSelection = (model) => model === void 0 || model === "default" || model instanceof ModelByInputTokens;
28164
+ const supportsDefaultTemperature = (model) => {
28165
+ if (model instanceof ModelByInputTokens || typeof model === "function") return false;
28166
+ if (typeof model === "string") return modelSupportsTemperature(model) === true;
28167
+ if (model && typeof model === "object" && "provider" in model && "modelId" in model && typeof model.provider === "string" && typeof model.modelId === "string") return modelSupportsTemperature(`${model.provider.split(".")[0]}/${model.modelId}`) === true;
28168
+ return false;
28169
+ };
28170
+ const usesDefaultOutputTokenBudget = (model) => model === void 0 || model === "default" || model instanceof ModelByInputTokens;
28027
28171
  const observationSelectedModel = topLevelModel ?? observationConfigModel ?? reflectionConfigModel;
28028
28172
  const reflectionSelectedModel = topLevelModel ?? reflectionConfigModel ?? observationConfigModel;
28029
- const observationDefaultMaxOutputTokens = config.observation?.modelSettings?.maxOutputTokens ?? (isDefaultModelSelection(observationSelectedModel) ? OBSERVATIONAL_MEMORY_DEFAULTS.observation.modelSettings.maxOutputTokens : void 0);
28030
- const reflectionDefaultMaxOutputTokens = config.reflection?.modelSettings?.maxOutputTokens ?? (isDefaultModelSelection(reflectionSelectedModel) ? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.modelSettings.maxOutputTokens : void 0);
28173
+ const observationTemperature = config.observation?.modelSettings?.temperature ?? (supportsDefaultTemperature(observationModel) ? OBSERVATIONAL_MEMORY_DEFAULTS.observation.modelSettings.temperature : void 0);
28174
+ const observationDefaultMaxOutputTokens = config.observation?.modelSettings?.maxOutputTokens ?? (usesDefaultOutputTokenBudget(observationSelectedModel) ? OBSERVATIONAL_MEMORY_DEFAULTS.observation.modelSettings.maxOutputTokens : void 0);
28175
+ const reflectionTemperature = config.reflection?.modelSettings?.temperature ?? (supportsDefaultTemperature(reflectionModel) ? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.modelSettings.temperature : void 0);
28176
+ const reflectionDefaultMaxOutputTokens = config.reflection?.modelSettings?.maxOutputTokens ?? (usesDefaultOutputTokenBudget(reflectionSelectedModel) ? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.modelSettings.maxOutputTokens : void 0);
28031
28177
  const totalBudget = messageTokens + observationTokens;
28032
28178
  const userExplicitlyConfiguredAsync = config.observation?.bufferTokens !== void 0 || config.observation?.bufferActivation !== void 0 || config.reflection?.bufferActivation !== void 0;
28033
28179
  const asyncBufferingDisabled = config.observation?.bufferTokens === false || config.scope === "resource" && !userExplicitlyConfiguredAsync;
@@ -28043,7 +28189,7 @@ var ObservationalMemory = class ObservationalMemory {
28043
28189
  } : messageTokens,
28044
28190
  shareTokenBudget: isSharedBudget,
28045
28191
  modelSettings: {
28046
- temperature: config.observation?.modelSettings?.temperature ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.modelSettings.temperature,
28192
+ ...observationTemperature !== void 0 ? { temperature: observationTemperature } : {},
28047
28193
  ...observationDefaultMaxOutputTokens !== void 0 ? { maxOutputTokens: observationDefaultMaxOutputTokens } : {}
28048
28194
  },
28049
28195
  providerOptions: config.observation?.providerOptions ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.providerOptions,
@@ -28069,7 +28215,7 @@ var ObservationalMemory = class ObservationalMemory {
28069
28215
  observationTokens,
28070
28216
  shareTokenBudget: isSharedBudget,
28071
28217
  modelSettings: {
28072
- temperature: config.reflection?.modelSettings?.temperature ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.modelSettings.temperature,
28218
+ ...reflectionTemperature !== void 0 ? { temperature: reflectionTemperature } : {},
28073
28219
  ...reflectionDefaultMaxOutputTokens !== void 0 ? { maxOutputTokens: reflectionDefaultMaxOutputTokens } : {}
28074
28220
  },
28075
28221
  providerOptions: config.reflection?.providerOptions ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.providerOptions,
@@ -29793,9 +29939,8 @@ ${formattedMessages}
29793
29939
  currentTask: lastActivated.currentTask,
29794
29940
  threadTitle: chunkThreadTitle
29795
29941
  });
29796
- const oldTitle = thread.title?.trim();
29797
- const newTitle = chunkThreadTitle?.trim();
29798
- const shouldUpdateThreadTitle = !!newTitle && newTitle.length >= 3 && newTitle !== oldTitle;
29942
+ const newTitle = resolveThreadTitleUpdate(thread, chunkThreadTitle);
29943
+ const shouldUpdateThreadTitle = newTitle !== void 0;
29799
29944
  await this.storage.patchThread({
29800
29945
  id: threadId,
29801
29946
  ...shouldUpdateThreadTitle ? { title: newTitle } : {},
@@ -31187,6 +31332,13 @@ var Memory = class Memory extends MastraMemory {
31187
31332
  });
31188
31333
  return savedThread;
31189
31334
  }
31335
+ /**
31336
+ * Update a thread's title or metadata.
31337
+ *
31338
+ * Unlike `session.thread.rename()`, this does not pin the title, so
31339
+ * Observational Memory may still replace it with an extracted title. To
31340
+ * protect a manual rename, set `metadata.titlePinned` to `true`.
31341
+ */
31190
31342
  async updateThread({ id, title, metadata, memoryConfig }) {
31191
31343
  const updatedThread = await (await this.getMemoryStore()).patchThread({
31192
31344
  id,
@@ -32942,4 +33094,4 @@ Notes:
32942
33094
  //#endregion
32943
33095
  export { formatMessagesForObserver as A, OBSERVATION_CONTINUATION_HINT as B, SUMMARIZE_THREAD_DEFAULTS as C, buildObserverPrompt as D, OBSERVER_SYSTEM_PROMPT as E, parseAnchorId as F, ModelByInputTokens as G, KnowledgeSemanticIndexCoordinator as H, stripEphemeralAnchorIds as I, publishSubconsciousActivity as J, SUBCONSCIOUS_ACTIVITY_STATE_ID as K, OBSERVATIONAL_MEMORY_DEFAULTS as L, optimizeObservationsForContext as M, parseObserverOutput as N, buildObserverSystemPrompt as O, injectAnchorIds as P, OBSERVATION_CONTEXT_INSTRUCTIONS as R, WorkingMemoryExtractor as S, TokenCounter as T, StaleKnowledgeSemanticIndexError as U, Subconscious as V, SubconsciousRemindExtractor as W, Extractor as X, renderSubconsciousActivity as Y, wrapInObservationGroup as _, extractWorkingMemoryContent as a, WorkingMemoryStateProcessor as b, getObservationsAsOf as c, combineObservationGroupRanges as d, deriveObservationGroupProvenance as f, stripObservationGroups as g, renderObservationGroupsForReflection as h, WorkingMemory as i, hasCurrentTaskSection as j, extractCurrentTask as k, ObservationalMemoryProcessor as l, reconcileObservationGroupsFromReflection as m, MessageHistory$1 as n, extractWorkingMemoryTags as o, parseObservationGroups as p, buildSubconsciousActivitySnapshot as q, SemanticRecall as r, removeWorkingMemoryTags as s, Memory as t, ObservationalMemory as u, WORKING_MEMORY_STATE_ID as v, summarizeConversation as w, deepMergeWorkingMemory as x, WORKING_MEMORY_STATE_PROCESSOR_ID as y, OBSERVATION_CONTEXT_PROMPT as z };
32944
33096
 
32945
- //# sourceMappingURL=src-DqLGJfSb.js.map
33097
+ //# sourceMappingURL=src-DquR-jTR.js.map