@mastra/memory 1.30.0-alpha.4 → 1.31.0-alpha.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.
@@ -39,6 +39,7 @@ let _mastra_core_agent = require("@mastra/core/agent");
39
39
  let _mastra_core_features = require("@mastra/core/features");
40
40
  let _mastra_core_memory = require("@mastra/core/memory");
41
41
  let _mastra_core_observability = require("@mastra/core/observability");
42
+ let _mastra_core_processors = require("@mastra/core/processors");
42
43
  let _mastra_core_utils = require("@mastra/core/utils");
43
44
  let _mastra_schema_compat_schema = require("@mastra/schema-compat/schema");
44
45
  let async_mutex = require("async-mutex");
@@ -57,7 +58,6 @@ let probe_image_size_sync_js = require("probe-image-size/sync.js");
57
58
  probe_image_size_sync_js = __toESM$1(probe_image_size_sync_js, 1);
58
59
  let _mastra_core_schema = require("@mastra/core/schema");
59
60
  let _mastra_core_error = require("@mastra/core/error");
60
- let _mastra_core_processors = require("@mastra/core/processors");
61
61
  let diff = require("diff");
62
62
  let util = require("util");
63
63
  //#region ../_vendored/ai_v4/dist/dist-Cm5DZgxA.js
@@ -3735,7 +3735,7 @@ function trimStartOfStream() {
3735
3735
  };
3736
3736
  }
3737
3737
  //#endregion
3738
- //#region ../_vendored/ai_v5/dist/dist-Dqv4QeJJ.js
3738
+ //#region ../_vendored/ai_v5/dist/dist-DCHMJHX3.js
3739
3739
  var marker$1$4 = "vercel.ai.error";
3740
3740
  var symbol$1$3 = Symbol.for(marker$1$4);
3741
3741
  var _a$1$3;
@@ -18326,6 +18326,358 @@ function safeSlice(str, end) {
18326
18326
  return str.slice(0, safeEnd);
18327
18327
  }
18328
18328
  //#endregion
18329
+ //#region src/processors/observational-memory/tool-argument-helpers.ts
18330
+ const DEFAULT_OBSERVER_TOOL_ARGUMENT_MAX_TOKENS = 2e3;
18331
+ const OBSERVER_TOOL_ARGUMENT_INLINE_STRING_MAX_CHARS = 160;
18332
+ const OBSERVER_TOOL_ARGUMENT_MAX_DEPTH = 5;
18333
+ const OBSERVER_TOOL_ARGUMENT_MAX_ENTRIES_PER_CONTAINER = 20;
18334
+ const OBSERVER_TOOL_ARGUMENT_MAX_OUTLINE_ENTRIES = 100;
18335
+ const OBSERVER_TOOL_ARGUMENT_MAX_PATH_CHARS = 160;
18336
+ function isObjectLike$1(value) {
18337
+ return typeof value === "object" && value !== null;
18338
+ }
18339
+ function sanitizeSurrogates(value) {
18340
+ let sanitized = "";
18341
+ for (let index = 0; index < value.length; index++) {
18342
+ const code = value.charCodeAt(index);
18343
+ if (code >= 55296 && code <= 56319) {
18344
+ const next = value.charCodeAt(index + 1);
18345
+ if (next >= 56320 && next <= 57343) {
18346
+ sanitized += value.charAt(index) + value.charAt(index + 1);
18347
+ index++;
18348
+ } else sanitized += "�";
18349
+ continue;
18350
+ }
18351
+ sanitized += code >= 56320 && code <= 57343 ? "�" : value[index];
18352
+ }
18353
+ return sanitized;
18354
+ }
18355
+ function stablePathDigest(value) {
18356
+ let hash = 2166136261;
18357
+ for (let index = 0; index < value.length; index++) hash = Math.imul(hash ^ value.charCodeAt(index), 16777619);
18358
+ return (hash >>> 0).toString(16).padStart(8, "0");
18359
+ }
18360
+ function safeTail(value, length) {
18361
+ let start = Math.max(0, value.length - length);
18362
+ if (start > 0) {
18363
+ const code = value.charCodeAt(start);
18364
+ if (code >= 56320 && code <= 57343) start++;
18365
+ }
18366
+ return value.slice(start);
18367
+ }
18368
+ function truncatePath(path) {
18369
+ if (path.length <= OBSERVER_TOOL_ARGUMENT_MAX_PATH_CHARS) return path;
18370
+ const headLength = 50;
18371
+ const tailLength = 60;
18372
+ const omitted = path.length - headLength - tailLength;
18373
+ return `${safeSlice(path, headLength)}…[${omitted} chars; ${stablePathDigest(path)}]…${safeTail(path, tailLength)}`;
18374
+ }
18375
+ function formatPath(parent, key, isArray) {
18376
+ if (isArray) return truncatePath(`${parent}[${key}]`);
18377
+ const stringKey = String(key);
18378
+ const segment = /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(stringKey) ? stringKey : `[${JSON.stringify(stringKey)}]`;
18379
+ return truncatePath(parent ? `${parent}.${segment}` : segment);
18380
+ }
18381
+ function formatPrimitive(value) {
18382
+ if (typeof value === "string") return JSON.stringify(value);
18383
+ if (typeof value === "bigint") return `<bigint> ${value}`;
18384
+ if (typeof value === "symbol" || typeof value === "function") return JSON.stringify(String(value));
18385
+ if (value === void 0) return "<undefined>";
18386
+ if (typeof value === "number" && Object.is(value, -0)) return "-0";
18387
+ return String(value);
18388
+ }
18389
+ function containerSummary(value) {
18390
+ if (!Array.isArray(value)) return "<object>";
18391
+ try {
18392
+ return `<array, ${value.length} ${value.length === 1 ? "item" : "items"}>`;
18393
+ } catch {
18394
+ return "<array, unknown length>";
18395
+ }
18396
+ }
18397
+ function readEntries(value) {
18398
+ const entries = [];
18399
+ try {
18400
+ if (Array.isArray(value)) {
18401
+ const length = value.length;
18402
+ const visibleLength = Math.min(length, OBSERVER_TOOL_ARGUMENT_MAX_ENTRIES_PER_CONTAINER);
18403
+ for (let index = 0; index < visibleLength; index++) {
18404
+ if (!(index in value)) {
18405
+ entries.push({
18406
+ key: index,
18407
+ unavailable: "hole"
18408
+ });
18409
+ continue;
18410
+ }
18411
+ try {
18412
+ entries.push({
18413
+ key: index,
18414
+ value: value[index]
18415
+ });
18416
+ } catch {
18417
+ entries.push({
18418
+ key: index,
18419
+ unavailable: "unreadable"
18420
+ });
18421
+ }
18422
+ }
18423
+ return {
18424
+ entries,
18425
+ hasMore: length > visibleLength,
18426
+ unavailable: false
18427
+ };
18428
+ }
18429
+ let hasMore = false;
18430
+ for (const key in value) {
18431
+ if (!Object.prototype.hasOwnProperty.call(value, key)) continue;
18432
+ if (entries.length >= OBSERVER_TOOL_ARGUMENT_MAX_ENTRIES_PER_CONTAINER) {
18433
+ hasMore = true;
18434
+ break;
18435
+ }
18436
+ try {
18437
+ entries.push({
18438
+ key,
18439
+ value: value[key]
18440
+ });
18441
+ } catch {
18442
+ entries.push({
18443
+ key,
18444
+ unavailable: "unreadable"
18445
+ });
18446
+ }
18447
+ }
18448
+ return {
18449
+ entries,
18450
+ hasMore,
18451
+ unavailable: false
18452
+ };
18453
+ } catch {
18454
+ return {
18455
+ entries,
18456
+ hasMore: false,
18457
+ unavailable: true
18458
+ };
18459
+ }
18460
+ }
18461
+ function fits(text, limits) {
18462
+ return text.length <= limits.maxCharacters && (0, tokenx.estimateTokenCount)(text) <= limits.maxTokens;
18463
+ }
18464
+ function joinEntries(entries, marker) {
18465
+ const lines = [...entries].sort((a, b) => a.order - b.order).map((entry) => entry.text);
18466
+ if (marker) lines.push(marker);
18467
+ return lines.join("\n");
18468
+ }
18469
+ function selectOutlineEntries(entries, limits) {
18470
+ const all = joinEntries(entries);
18471
+ if (fits(all, limits)) return all;
18472
+ const marker = "... [additional argument fields omitted by size limit]";
18473
+ const selected = [];
18474
+ const candidates = [...entries].sort((a, b) => {
18475
+ if (a.depth !== b.depth) return a.depth - b.depth;
18476
+ return (0, tokenx.estimateTokenCount)(a.text) - (0, tokenx.estimateTokenCount)(b.text) || a.text.length - b.text.length || a.order - b.order;
18477
+ });
18478
+ for (const candidate of candidates) if (fits(joinEntries([...selected, candidate], marker), limits)) selected.push(candidate);
18479
+ const rendered = joinEntries(selected, marker);
18480
+ if (fits(rendered, limits)) return rendered;
18481
+ if (fits(marker, limits)) return marker;
18482
+ return fits("…", limits) ? "…" : "";
18483
+ }
18484
+ function indentPreview(value) {
18485
+ return value.split("\n").map((line) => ` | ${line}`).join("\n");
18486
+ }
18487
+ function formatPreview(path, value, limits, prefix = "") {
18488
+ const sanitizedValue = sanitizeSurrogates(value);
18489
+ const marker = (visible) => {
18490
+ const omitted = sanitizedValue.length - visible.length;
18491
+ return `${path}:\n${indentPreview(visible)}${omitted > 0 ? `\n | ... [${omitted} characters omitted]` : ""}`;
18492
+ };
18493
+ let low = 0;
18494
+ let high = sanitizedValue.length;
18495
+ let best = "";
18496
+ while (low <= high) {
18497
+ const mid = Math.floor((low + high) / 2);
18498
+ const candidate = marker(safeSlice(sanitizedValue, mid));
18499
+ if (fits(prefix ? `${prefix}\n${candidate}` : candidate, limits)) {
18500
+ best = candidate;
18501
+ low = mid + 1;
18502
+ } else high = mid - 1;
18503
+ }
18504
+ return best;
18505
+ }
18506
+ function appendWithinBudget(base, addition, limits) {
18507
+ if (!addition) return;
18508
+ const candidate = base ? `${base}\n${addition}` : addition;
18509
+ return fits(candidate, limits) ? candidate : void 0;
18510
+ }
18511
+ /**
18512
+ * Formats tool arguments for the Observer without allowing a large early value
18513
+ * to hide concise sibling fields. A breadth-first structural outline is selected
18514
+ * before bounded previews of large strings are added.
18515
+ */
18516
+ function formatToolArgumentsForObserver(value, options) {
18517
+ const limits = {
18518
+ maxTokens: options?.maxTokens ?? DEFAULT_OBSERVER_TOOL_ARGUMENT_MAX_TOKENS,
18519
+ maxCharacters: options?.maxCharacters ?? Number.POSITIVE_INFINITY
18520
+ };
18521
+ if (limits.maxTokens <= 0 || limits.maxCharacters <= 0) return "";
18522
+ if (!isObjectLike$1(value)) {
18523
+ if (typeof value !== "string" || value.length <= OBSERVER_TOOL_ARGUMENT_INLINE_STRING_MAX_CHARS) {
18524
+ const primitive = formatPrimitive(value);
18525
+ return fits(primitive, limits) ? primitive : fits("…", limits) ? "…" : "";
18526
+ }
18527
+ const summary = `<string, ${value.length} characters; preview size-limited>`;
18528
+ const rendered = appendWithinBudget(summary, formatPreview("preview", value, limits, summary), limits);
18529
+ if (rendered) return rendered;
18530
+ if (fits(summary, limits)) return summary;
18531
+ return fits("…", limits) ? "…" : "";
18532
+ }
18533
+ const outline = [];
18534
+ const previews = [];
18535
+ const pending = [{
18536
+ path: "",
18537
+ value,
18538
+ depth: 0,
18539
+ ancestors: /* @__PURE__ */ new Set([value])
18540
+ }];
18541
+ let outlineEntries = 0;
18542
+ let order = 0;
18543
+ let structuralLimitReached = false;
18544
+ while (pending.length > 0 && outlineEntries < OBSERVER_TOOL_ARGUMENT_MAX_OUTLINE_ENTRIES) {
18545
+ const current = pending.shift();
18546
+ const read = readEntries(current.value);
18547
+ if (read.unavailable) {
18548
+ outline.push({
18549
+ text: `${current.path || "arguments"}: [unavailable container]`,
18550
+ depth: current.depth,
18551
+ order: order++
18552
+ });
18553
+ outlineEntries++;
18554
+ continue;
18555
+ }
18556
+ if (read.entries.length === 0 && !read.hasMore) {
18557
+ outline.push({
18558
+ text: `${current.path || "arguments"}: [empty ${Array.isArray(current.value) ? "array" : "object"}]`,
18559
+ depth: current.depth,
18560
+ order: order++
18561
+ });
18562
+ outlineEntries++;
18563
+ continue;
18564
+ }
18565
+ if (read.hasMore) {
18566
+ outline.push({
18567
+ text: `${current.path || (Array.isArray(current.value) ? "items" : "fields")}: ... [additional entries omitted]`,
18568
+ depth: current.depth,
18569
+ order: order++
18570
+ });
18571
+ outlineEntries++;
18572
+ }
18573
+ for (const entry of read.entries) {
18574
+ if (outlineEntries >= OBSERVER_TOOL_ARGUMENT_MAX_OUTLINE_ENTRIES) {
18575
+ structuralLimitReached = true;
18576
+ break;
18577
+ }
18578
+ const path = formatPath(current.path, entry.key, Array.isArray(current.value));
18579
+ outlineEntries++;
18580
+ if (entry.unavailable) {
18581
+ outline.push({
18582
+ text: `${path}: [${entry.unavailable}]`,
18583
+ depth: current.depth,
18584
+ order: order++
18585
+ });
18586
+ continue;
18587
+ }
18588
+ const entryValue = entry.value;
18589
+ if (typeof entryValue === "string" && entryValue.length > OBSERVER_TOOL_ARGUMENT_INLINE_STRING_MAX_CHARS) {
18590
+ outline.push({
18591
+ text: `${path}: <string, ${entryValue.length} characters; preview size-limited>`,
18592
+ depth: current.depth,
18593
+ order: order++
18594
+ });
18595
+ previews.push({
18596
+ path,
18597
+ value: entryValue
18598
+ });
18599
+ continue;
18600
+ }
18601
+ if (!isObjectLike$1(entryValue)) {
18602
+ outline.push({
18603
+ text: `${path}: ${formatPrimitive(entryValue)}`,
18604
+ depth: current.depth,
18605
+ order: order++
18606
+ });
18607
+ continue;
18608
+ }
18609
+ if (current.ancestors.has(entryValue)) {
18610
+ outline.push({
18611
+ text: `${path}: [circular]`,
18612
+ depth: current.depth,
18613
+ order: order++
18614
+ });
18615
+ continue;
18616
+ }
18617
+ const summary = containerSummary(entryValue);
18618
+ if (current.depth >= OBSERVER_TOOL_ARGUMENT_MAX_DEPTH) {
18619
+ outline.push({
18620
+ text: `${path}: ${summary} [max depth reached]`,
18621
+ depth: current.depth,
18622
+ order: order++
18623
+ });
18624
+ continue;
18625
+ }
18626
+ outline.push({
18627
+ text: `${path}: ${summary}`,
18628
+ depth: current.depth,
18629
+ order: order++
18630
+ });
18631
+ pending.push({
18632
+ path,
18633
+ value: entryValue,
18634
+ depth: current.depth + 1,
18635
+ ancestors: /* @__PURE__ */ new Set([...current.ancestors, entryValue])
18636
+ });
18637
+ }
18638
+ }
18639
+ if (pending.length > 0 || structuralLimitReached) outline.push({
18640
+ text: "... [additional nested entries omitted by structure limit]",
18641
+ depth: Number.POSITIVE_INFINITY,
18642
+ order: order++
18643
+ });
18644
+ if (previews.length === 0) return selectOutlineEntries(outline, limits);
18645
+ const previewHeader = "Large string previews (size-limited):";
18646
+ const renderedOutline = selectOutlineEntries(outline, limits);
18647
+ const withPreviewHeader = appendWithinBudget(renderedOutline, previewHeader, limits);
18648
+ if (!withPreviewHeader) return renderedOutline;
18649
+ let rendered = withPreviewHeader;
18650
+ let renderedPreviews = 0;
18651
+ let omittedPreviews = 0;
18652
+ for (let index = 0; index < previews.length; index++) {
18653
+ const remainingCount = previews.length - index;
18654
+ const remainingTokens = Math.max(0, limits.maxTokens - (0, tokenx.estimateTokenCount)(rendered));
18655
+ const remainingCharacters = Math.max(0, limits.maxCharacters - rendered.length - 1);
18656
+ const previewLimits = {
18657
+ maxTokens: (0, tokenx.estimateTokenCount)(rendered) + Math.floor(remainingTokens / remainingCount),
18658
+ maxCharacters: rendered.length + 1 + Math.floor(remainingCharacters / remainingCount)
18659
+ };
18660
+ const preview = formatPreview(previews[index].path, previews[index].value, previewLimits, rendered);
18661
+ if (!preview) {
18662
+ omittedPreviews++;
18663
+ continue;
18664
+ }
18665
+ const withPreview = appendWithinBudget(rendered, preview, limits);
18666
+ if (!withPreview) {
18667
+ omittedPreviews++;
18668
+ continue;
18669
+ }
18670
+ rendered = withPreview;
18671
+ renderedPreviews++;
18672
+ }
18673
+ if (renderedPreviews === 0) return renderedOutline;
18674
+ if (omittedPreviews > 0) {
18675
+ const marker = `... [${omittedPreviews} large string ${omittedPreviews === 1 ? "preview" : "previews"} omitted]`;
18676
+ rendered = appendWithinBudget(rendered, marker, limits) ?? rendered;
18677
+ }
18678
+ return rendered;
18679
+ }
18680
+ //#endregion
18329
18681
  //#region src/processors/observational-memory/tool-result-helpers.ts
18330
18682
  const ENCRYPTED_CONTENT_KEY = "encryptedContent";
18331
18683
  const ENCRYPTED_CONTENT_REDACTION_THRESHOLD = 256;
@@ -18404,7 +18756,7 @@ function truncateStringByTokens(text, maxTokens) {
18404
18756
  return best;
18405
18757
  }
18406
18758
  function formatToolResultForObserver(value, options) {
18407
- return truncateStringByTokens(stringifyToolResult(value), options?.maxTokens ?? 1e4);
18759
+ return truncateStringByTokens(stringifyToolResult(value), options?.maxTokens ?? 5e3);
18408
18760
  }
18409
18761
  //#endregion
18410
18762
  //#region src/processors/observational-memory/observer-agent.ts
@@ -19091,9 +19443,52 @@ function getTemporalGapMarkerText(msg) {
19091
19443
  if (metadata?.reminderType === "temporal-gap" && typeof metadata.gapText === "string") return metadata.gapText;
19092
19444
  if (typeof metadata?.systemReminder === "object" && metadata.systemReminder && "type" in metadata.systemReminder && metadata.systemReminder.type === "temporal-gap" && "gapText" in metadata.systemReminder && typeof metadata.systemReminder.gapText === "string") return metadata.systemReminder.gapText;
19093
19445
  }
19094
- function formatObserverMessage(msg, counter, options) {
19446
+ function isCallLikeToolInvocation(invocation) {
19447
+ return invocation.state === "call" || invocation.state === "partial-call" || invocation.state === "approval-requested" || invocation.state === "approval-responded";
19448
+ }
19449
+ function isTerminalToolInvocation(invocation) {
19450
+ return invocation.state === "result" || invocation.state === "output-error" || invocation.state === "output-denied";
19451
+ }
19452
+ function createObserverToolFormattingState(messages) {
19453
+ const exchanges = /* @__PURE__ */ new Map();
19454
+ const occurrences = /* @__PURE__ */ new Map();
19455
+ let occurrence = 0;
19456
+ for (const message of messages) {
19457
+ if (typeof message.content === "string" || !Array.isArray(message.content?.parts)) continue;
19458
+ for (const part of message.content.parts) {
19459
+ if (part.type !== "tool-invocation") continue;
19460
+ const invocation = part.toolInvocation;
19461
+ occurrences.set(part, occurrence);
19462
+ if (!isCallLikeToolInvocation(invocation) && !isTerminalToolInvocation(invocation)) {
19463
+ occurrence++;
19464
+ continue;
19465
+ }
19466
+ const exchange = exchanges.get(invocation.toolCallId) ?? { firstOccurrence: occurrence };
19467
+ if (isCallLikeToolInvocation(invocation) && (invocation.args !== void 0 || exchange.signature === void 0)) exchange.signature = invocation;
19468
+ if (isTerminalToolInvocation(invocation)) exchange.terminal = {
19469
+ ...invocation,
19470
+ occurrence
19471
+ };
19472
+ exchanges.set(invocation.toolCallId, exchange);
19473
+ occurrence++;
19474
+ }
19475
+ }
19476
+ for (const exchange of exchanges.values()) if (exchange.terminal?.args !== void 0) exchange.signature = exchange.terminal;
19477
+ else if (!exchange.signature && exchange.terminal) exchange.signature = exchange.terminal;
19478
+ return {
19479
+ exchanges,
19480
+ occurrences,
19481
+ emittedCalls: /* @__PURE__ */ new Set(),
19482
+ emittedOutcomes: /* @__PURE__ */ new Set()
19483
+ };
19484
+ }
19485
+ function formatObserverToolArguments(args, maxCharacters) {
19486
+ if (args === void 0) return maybeTruncate("[arguments unavailable]", maxCharacters);
19487
+ return formatToolArgumentsForObserver(args, { maxCharacters: maxCharacters || void 0 });
19488
+ }
19489
+ function formatObserverMessage(msg, counter, toolFormatting, options) {
19095
19490
  const maxLen = options?.maxPartLength;
19096
- const maxToolResultTokens = options?.maxToolResultTokens ?? 1e4;
19491
+ const maxToolResultTokens = options?.maxToolResultTokens ?? 5e3;
19097
19492
  const attachmentFilter = options?.attachmentFilter;
19098
19493
  const role = msg.role.charAt(0).toUpperCase() + msg.role.slice(1);
19099
19494
  const attachments = [];
@@ -19120,14 +19515,31 @@ function formatObserverMessage(msg, counter, options) {
19120
19515
  }
19121
19516
  if (part.type === "tool-invocation") {
19122
19517
  const inv = part.toolInvocation;
19518
+ const occurrence = toolFormatting.occurrences.get(part);
19519
+ const exchange = toolFormatting.exchanges.get(inv.toolCallId);
19520
+ if (exchange && occurrence === exchange.firstOccurrence && exchange.signature && !toolFormatting.emittedCalls.has(inv.toolCallId)) {
19521
+ toolFormatting.emittedCalls.add(inv.toolCallId);
19522
+ pushLine(`Tool Call ${exchange.signature.toolName}`, formatObserverToolArguments(exchange.signature.args, maxLen), partCreatedAt);
19523
+ }
19123
19524
  if (inv.state === "result") {
19124
19525
  const { value: resultForObserver } = resolveToolResultValue(part, inv.result);
19125
19526
  const { resultWithoutAttachments, attachments: extractedAttachments } = extractToolResultAttachments(resultForObserver, counter, attachmentFilter);
19126
19527
  if (extractedAttachments.length > 0) attachments.push(...extractedAttachments);
19127
- pushLine(`Tool Result ${inv.toolName}`, maybeTruncate(formatToolResultForObserver(resultWithoutAttachments, { maxTokens: maxToolResultTokens }), maxLen), partCreatedAt);
19528
+ if (exchange?.terminal?.occurrence === occurrence && !toolFormatting.emittedOutcomes.has(inv.toolCallId)) {
19529
+ toolFormatting.emittedOutcomes.add(inv.toolCallId);
19530
+ const hasResult = resultWithoutAttachments !== void 0 && (typeof resultWithoutAttachments !== "string" || resultWithoutAttachments.trim().length > 0);
19531
+ const body = inv.isError ? hasResult ? formatToolResultForObserver(resultWithoutAttachments, { maxTokens: maxToolResultTokens }) : inv.errorText?.trim() ? inv.errorText : "Tool execution failed" : hasResult ? formatToolResultForObserver(resultWithoutAttachments, { maxTokens: maxToolResultTokens }) : "[empty result]";
19532
+ pushLine(`${inv.isError ? "Tool Error" : "Tool Result"} ${inv.toolName}`, maybeTruncate(body, maxLen), partCreatedAt);
19533
+ }
19534
+ return;
19535
+ }
19536
+ if (exchange?.terminal?.occurrence === occurrence && !toolFormatting.emittedOutcomes.has(inv.toolCallId)) {
19537
+ toolFormatting.emittedOutcomes.add(inv.toolCallId);
19538
+ if (inv.state === "output-error") pushLine(`Tool Error ${inv.toolName}`, maybeTruncate(inv.errorText?.trim() ? inv.errorText : "Tool execution failed", maxLen), partCreatedAt);
19539
+ else if (inv.state === "output-denied") pushLine(`Tool Denied ${inv.toolName}`, maybeTruncate(inv.approval?.reason?.trim() ? inv.approval.reason : "Tool call was not approved by the user", maxLen), partCreatedAt);
19128
19540
  return;
19129
19541
  }
19130
- pushLine(`Tool Call ${inv.toolName}`, maybeTruncate(JSON.stringify(inv.args, null, 2), maxLen), partCreatedAt);
19542
+ if (!exchange) pushLine(`Tool Call ${inv.toolName}`, formatObserverToolArguments(inv.args, maxLen), partCreatedAt);
19131
19543
  return;
19132
19544
  }
19133
19545
  const partType = part.type;
@@ -19161,10 +19573,11 @@ function formatMessagesForObserver(messages, options) {
19161
19573
  nextImageId: 1,
19162
19574
  nextFileId: 1
19163
19575
  };
19576
+ const toolFormatting = createObserverToolFormattingState(messages);
19164
19577
  const sections = [];
19165
19578
  let context = {};
19166
19579
  for (const message of messages) {
19167
- const formatted = formatObserverMessage(message, counter, options);
19580
+ const formatted = formatObserverMessage(message, counter, toolFormatting, options);
19168
19581
  if (formatted.lines.length === 0) continue;
19169
19582
  const rendered = formatObserverLines(formatted.lines, context);
19170
19583
  if (!rendered.text) continue;
@@ -19187,13 +19600,14 @@ function buildObserverHistoryMessage(messages, options) {
19187
19600
  nextImageId: 1,
19188
19601
  nextFileId: 1
19189
19602
  };
19603
+ const toolFormatting = createObserverToolFormattingState(messages);
19190
19604
  const content = [{
19191
19605
  type: "text",
19192
19606
  text: "## New Message History to Observe\n\n"
19193
19607
  }];
19194
19608
  let context = {};
19195
19609
  messages.forEach((message) => {
19196
- const formatted = formatObserverMessage(message, counter, options);
19610
+ const formatted = formatObserverMessage(message, counter, toolFormatting, options);
19197
19611
  if (formatted.lines.length === 0 && formatted.attachments.length === 0) return;
19198
19612
  context = appendFormattedObserverMessage(content, formatted, context);
19199
19613
  });
@@ -19221,10 +19635,11 @@ function buildMultiThreadObserverHistoryMessage(messagesByThread, threadOrder, o
19221
19635
  const messages = messagesByThread.get(threadId);
19222
19636
  if (!messages || messages.length === 0) return;
19223
19637
  const threadContent = [];
19638
+ const toolFormatting = createObserverToolFormattingState(messages);
19224
19639
  let context = {};
19225
19640
  let hasVisibleContent = false;
19226
19641
  messages.forEach((message) => {
19227
- const formatted = formatObserverMessage(message, counter, options);
19642
+ const formatted = formatObserverMessage(message, counter, toolFormatting, options);
19228
19643
  if (formatted.lines.length === 0 && formatted.attachments.length === 0) return;
19229
19644
  context = appendFormattedObserverMessage(threadContent, formatted, context);
19230
19645
  hasVisibleContent = true;
@@ -19920,15 +20335,14 @@ var ObserverRunner = class {
19920
20335
  this.mastra = mastra;
19921
20336
  }
19922
20337
  createAgent(model, isMultiThread = false, memory, extractors = this.observationConfig.extractors ?? []) {
19923
- const agent = new _mastra_core_agent.Agent({
20338
+ return new _mastra_core_agent.Agent({
19924
20339
  id: isMultiThread ? "multi-thread-observer" : "observational-memory-observer",
19925
20340
  name: isMultiThread ? "multi-thread-observer" : "Observer",
19926
20341
  instructions: buildObserverSystemPrompt(isMultiThread, this.observationConfig.instruction, this.observationConfig.threadTitle, extractors),
19927
20342
  model,
19928
- ...memory ? { memory } : {}
20343
+ ...memory ? { memory } : {},
20344
+ ...this.mastra ? { mastra: this.mastra } : {}
19929
20345
  });
19930
- if (this.mastra) agent.__registerMastra(this.mastra);
19931
- return agent;
19932
20346
  }
19933
20347
  /**
19934
20348
  * Extract a router-style model ID (`provider/model`) from a model config.
@@ -21574,7 +21988,7 @@ var TokenCounter = class TokenCounter {
21574
21988
  let tokens = 0;
21575
21989
  let overheadDelta = 0;
21576
21990
  if (invocation.toolName) tokens += this.readOrPersistPartEstimate(part, "tool-call-name", invocation.toolName);
21577
- if (invocation.args) if (typeof invocation.args === "string") tokens += this.readOrPersistPartEstimate(part, "tool-call-args", invocation.args);
21991
+ if (invocation.args !== void 0) if (typeof invocation.args === "string") tokens += this.readOrPersistPartEstimate(part, "tool-call-args", invocation.args);
21578
21992
  else {
21579
21993
  const argsJson = JSON.stringify(invocation.args);
21580
21994
  tokens += this.readOrPersistPartEstimate(part, "tool-call-args-json", argsJson);
@@ -21620,8 +22034,11 @@ var TokenCounter = class TokenCounter {
21620
22034
  }
21621
22035
  if (state === "result") {
21622
22036
  extraMessageDelta++;
22037
+ const signature = this.countToolCallSignature(part, invocation);
22038
+ tokens += signature.tokens;
22039
+ overheadDelta += signature.overheadDelta;
21623
22040
  const { value: resultForCounting, usingStoredModelOutput } = this.resolveToolResultForTokenCounting(part, invocation.result);
21624
- if (resultForCounting !== void 0) {
22041
+ if (resultForCounting !== void 0 && (typeof resultForCounting !== "string" || resultForCounting.trim().length > 0)) {
21625
22042
  const contentTokens = this.countMultimodalToolResultContent(part, resultForCounting);
21626
22043
  if (contentTokens !== void 0) tokens += contentTokens;
21627
22044
  else {
@@ -21629,6 +22046,9 @@ var TokenCounter = class TokenCounter {
21629
22046
  tokens += this.readOrPersistPartEstimate(part, usingStoredModelOutput ? "tool-result-model-output-json" : "tool-result-json", formattedResult);
21630
22047
  }
21631
22048
  if (typeof resultForCounting !== "string") overheadDelta -= 12;
22049
+ } else {
22050
+ const fallback = invocation.isError ? invocation.errorText?.trim() ? invocation.errorText : "Tool execution failed" : "[empty result]";
22051
+ tokens += this.readOrPersistPartEstimate(part, invocation.isError ? "tool-result-error" : "tool-result-json", fallback);
21632
22052
  }
21633
22053
  return {
21634
22054
  tokens,
@@ -21638,7 +22058,10 @@ var TokenCounter = class TokenCounter {
21638
22058
  }
21639
22059
  if (state === "output-denied") {
21640
22060
  extraMessageDelta++;
21641
- const reason = invocation.approval?.reason ?? "Tool call was not approved by the user";
22061
+ const signature = this.countToolCallSignature(part, invocation);
22062
+ tokens += signature.tokens;
22063
+ overheadDelta += signature.overheadDelta;
22064
+ const reason = invocation.approval?.reason?.trim() ? invocation.approval.reason : "Tool call was not approved by the user";
21642
22065
  tokens += this.readOrPersistPartEstimate(part, "tool-result-denied", reason);
21643
22066
  return {
21644
22067
  tokens,
@@ -21648,7 +22071,10 @@ var TokenCounter = class TokenCounter {
21648
22071
  }
21649
22072
  if (state === "output-error") {
21650
22073
  extraMessageDelta++;
21651
- const errorMessage = typeof invocation.errorText === "string" ? invocation.errorText : "Tool execution failed";
22074
+ const signature = this.countToolCallSignature(part, invocation);
22075
+ tokens += signature.tokens;
22076
+ overheadDelta += signature.overheadDelta;
22077
+ const errorMessage = invocation.errorText?.trim() ? invocation.errorText : "Tool execution failed";
21652
22078
  tokens += this.readOrPersistPartEstimate(part, "tool-result-error", errorMessage);
21653
22079
  return {
21654
22080
  tokens,
@@ -21675,7 +22101,12 @@ var TokenCounter = class TokenCounter {
21675
22101
  };
21676
22102
  }
21677
22103
  /**
21678
- * Count tokens in a single message
22104
+ * Count tokens in a single message.
22105
+ *
22106
+ * Canonical terminal invocations carry their call signature and outcome in one part. Legacy or
22107
+ * foreign histories may instead repeat the same signature across separate call and result
22108
+ * messages; those signatures are intentionally counted once per message because this API has no
22109
+ * sequence context. The conservative overcount can activate observation earlier, never later.
21679
22110
  */
21680
22111
  countMessage(message) {
21681
22112
  let payloadTokens = this.countString(message.role);
@@ -26331,15 +26762,14 @@ var ReflectorRunner = class {
26331
26762
  this.mastra = mastra;
26332
26763
  }
26333
26764
  createAgent(model, memory, extractors = this.reflectionConfig.extractors) {
26334
- const agent = new _mastra_core_agent.Agent({
26765
+ return new _mastra_core_agent.Agent({
26335
26766
  id: "observational-memory-reflector",
26336
26767
  name: "Reflector",
26337
26768
  instructions: buildReflectorSystemPrompt(this.reflectionConfig.instruction, extractors),
26338
26769
  model,
26339
- ...memory ? { memory } : {}
26770
+ ...memory ? { memory } : {},
26771
+ ...this.mastra ? { mastra: this.mastra } : {}
26340
26772
  });
26341
- if (this.mastra) agent.__registerMastra(this.mastra);
26342
- return agent;
26343
26773
  }
26344
26774
  getObservationMarkerConfig(record) {
26345
26775
  return {
@@ -30390,6 +30820,9 @@ const DEFAULT_EMBEDDING_CACHE_MAX_SIZE = 1e3;
30390
30820
  * if packaged docs are unavailable.
30391
30821
  */
30392
30822
  var Memory = class Memory extends _mastra_core_memory.MastraMemory {
30823
+ createMemoryTokenCounter() {
30824
+ return new TokenCounter();
30825
+ }
30393
30826
  _omEngine;
30394
30827
  _omEngineInstance;
30395
30828
  _mastraInstance;
@@ -30560,6 +30993,7 @@ var Memory = class Memory extends _mastra_core_memory.MastraMemory {
30560
30993
  const thread = await this.getThreadById({ threadId });
30561
30994
  if (!thread && !resourceScope) throw new Error(`No thread found with id ${threadId}`);
30562
30995
  if (thread && thread.resourceId !== resourceId) throw new Error(`Thread with id ${threadId} is for resource with id ${thread.resourceId} but resource ${resourceId} was queried.`);
30996
+ return thread;
30563
30997
  }
30564
30998
  createMemorySpan(operationType, observabilityContext, input, attributes) {
30565
30999
  const currentSpan = observabilityContext?.tracingContext?.currentSpan;
@@ -30580,6 +31014,9 @@ var Memory = class Memory extends _mastra_core_memory.MastraMemory {
30580
31014
  const { threadId, resourceId, perPage: perPageArg, page, orderBy, threadConfig, vectorSearchString, includeSystemReminders, hideSignals, filter, includeTotal } = args;
30581
31015
  const config = this.getMergedThreadConfig(threadConfig || {});
30582
31016
  const semanticRecallEnabled = Boolean(config.semanticRecall);
31017
+ const history = (0, _mastra_core_memory.normalizeMessageHistoryConfig)(config.lastMessages, config.messageHistory);
31018
+ const historyDisabledByConfig = !history.enabled && perPageArg === void 0;
31019
+ const shouldUseTokenLoader = perPageArg === void 0 && history.enabled && history.maxTokens !== void 0;
30583
31020
  const span = this.createMemorySpan("recall", args.observabilityContext, {
30584
31021
  threadId,
30585
31022
  resourceId,
@@ -30589,9 +31026,23 @@ var Memory = class Memory extends _mastra_core_memory.MastraMemory {
30589
31026
  lastMessages: config.lastMessages
30590
31027
  });
30591
31028
  try {
30592
- if (resourceId) await this.validateThreadIsOwnedByResource(threadId, resourceId, config);
30593
- const perPage = perPageArg !== void 0 ? perPageArg : config.lastMessages;
30594
- const historyDisabledByConfig = config.lastMessages === false && perPageArg === void 0;
31029
+ if (historyDisabledByConfig && (!config.semanticRecall || !vectorSearchString || !this.vector)) {
31030
+ const result = {
31031
+ messages: [],
31032
+ usage: void 0,
31033
+ total: 0,
31034
+ page: page ?? 0,
31035
+ perPage: 0,
31036
+ hasMore: false
31037
+ };
31038
+ span?.end({
31039
+ output: { success: true },
31040
+ attributes: { messageCount: 0 }
31041
+ });
31042
+ return result;
31043
+ }
31044
+ const validatedThread = resourceId ? await this.validateThreadIsOwnedByResource(threadId, resourceId, config) : void 0;
31045
+ const perPage = perPageArg !== void 0 ? perPageArg : history.maxMessages ?? 0;
30595
31046
  const shouldGetNewestAndReverse = !orderBy && perPage !== false;
30596
31047
  const effectiveOrderBy = shouldGetNewestAndReverse ? {
30597
31048
  field: "createdAt",
@@ -30620,21 +31071,6 @@ var Memory = class Memory extends _mastra_core_memory.MastraMemory {
30620
31071
  const resourceScope = typeof config?.semanticRecall === "object" && config?.semanticRecall?.scope !== `thread` || config.semanticRecall === true;
30621
31072
  if (resourceScope && !resourceId && config?.semanticRecall && vectorSearchString) throw new Error("Memory error: Resource-scoped semantic recall is enabled but no resourceId was provided. Either provide a resourceId or explicitly set semanticRecall.scope to 'thread'.");
30622
31073
  let usage;
30623
- if (historyDisabledByConfig && (!config.semanticRecall || !vectorSearchString || !this.vector)) {
30624
- const result = {
30625
- messages: [],
30626
- usage: void 0,
30627
- total: 0,
30628
- page: page ?? 0,
30629
- perPage: 0,
30630
- hasMore: false
30631
- };
30632
- span?.end({
30633
- output: { success: true },
30634
- attributes: { messageCount: 0 }
30635
- });
30636
- return result;
30637
- }
30638
31074
  if (config?.semanticRecall && vectorSearchString && this.vector) {
30639
31075
  const result = await this.embedMessageContent(vectorSearchString);
30640
31076
  usage = result.usage;
@@ -30656,28 +31092,71 @@ var Memory = class Memory extends _mastra_core_memory.MastraMemory {
30656
31092
  const threshold = (typeof config.semanticRecall === "object" ? config.semanticRecall : void 0)?.threshold;
30657
31093
  const filteredVectorResults = threshold !== void 0 ? vectorResults.filter((r) => r.score >= threshold) : vectorResults;
30658
31094
  const memoryStore = await this.getMemoryStore();
30659
- const effectivePerPage = historyDisabledByConfig ? 0 : perPage;
30660
- const paginatedResult = await memoryStore.listMessages({
30661
- threadId,
30662
- resourceId,
30663
- perPage: effectivePerPage,
30664
- page,
30665
- orderBy: effectiveOrderBy,
30666
- filter,
30667
- ...includeTotal !== void 0 ? { includeTotal } : {},
30668
- ...filteredVectorResults?.length ? { include: filteredVectorResults.map((r) => ({
30669
- id: r.metadata?.message_id,
30670
- threadId: r.metadata?.thread_id,
30671
- withNextMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.after,
30672
- withPreviousMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.before
30673
- })) } : {}
30674
- });
30675
- const rawMessages = shouldGetNewestAndReverse ? paginatedResult.messages.reverse() : paginatedResult.messages;
31095
+ const include = filteredVectorResults.map((r) => ({
31096
+ id: r.metadata?.message_id,
31097
+ threadId: r.metadata?.thread_id,
31098
+ withNextMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.after,
31099
+ withPreviousMessages: typeof vectorConfig.messageRange === "number" ? vectorConfig.messageRange : vectorConfig.messageRange.before
31100
+ }));
31101
+ let rawMessages;
31102
+ let resultPage;
31103
+ let resultPerPage;
31104
+ let total;
31105
+ let hasMore;
31106
+ if (shouldUseTokenLoader) {
31107
+ const storedBoundary = (0, _mastra_core_memory.getMemoryTokenBoundary)(validatedThread ?? await memoryStore.getThreadById({
31108
+ threadId,
31109
+ resourceId
31110
+ }));
31111
+ const boundary = storedBoundary !== void 0 && storedBoundary.maxTokens === history.maxTokens && storedBoundary.atMaxRemoveTokens === history.atMaxRemoveTokens ? storedBoundary : void 0;
31112
+ rawMessages = (await (0, _mastra_core_memory.loadMessageHistory)({
31113
+ storage: memoryStore,
31114
+ threadId,
31115
+ resourceId,
31116
+ boundary,
31117
+ filter,
31118
+ maxMessages: history.maxMessages,
31119
+ maxTokens: history.maxTokens,
31120
+ atMaxRemoveTokens: history.atMaxRemoveTokens,
31121
+ tokenCounter: new TokenCounter(),
31122
+ initialTokens: 24
31123
+ })).messages;
31124
+ if (include.length) {
31125
+ const semanticMessages = await memoryStore.listMessages({
31126
+ threadId,
31127
+ resourceId,
31128
+ perPage: 0,
31129
+ include,
31130
+ includeTotal: false
31131
+ });
31132
+ rawMessages = new _mastra_core_agent.MessageList({
31133
+ threadId,
31134
+ resourceId
31135
+ }).add(rawMessages, "memory").add(semanticMessages.messages.filter((message) => !boundary || (0, _mastra_core_memory.isAfterMemoryTokenBoundary)(message, boundary)), "memory").get.all.db();
31136
+ }
31137
+ resultPage = 0;
31138
+ resultPerPage = history.maxMessages ?? false;
31139
+ total = rawMessages.length;
31140
+ hasMore = false;
31141
+ } else {
31142
+ const effectivePerPage = historyDisabledByConfig ? 0 : perPage;
31143
+ const paginatedResult = await memoryStore.listMessages({
31144
+ threadId,
31145
+ resourceId,
31146
+ perPage: effectivePerPage,
31147
+ page,
31148
+ orderBy: effectiveOrderBy,
31149
+ filter,
31150
+ ...includeTotal !== void 0 ? { includeTotal } : {},
31151
+ ...include.length ? { include } : {}
31152
+ });
31153
+ rawMessages = shouldGetNewestAndReverse ? paginatedResult.messages.reverse() : paginatedResult.messages;
31154
+ ({total, page: resultPage, perPage: resultPerPage, hasMore} = paginatedResult);
31155
+ }
30676
31156
  const messages = filterSystemReminderMessages(new _mastra_core_agent.MessageList({
30677
31157
  threadId,
30678
31158
  resourceId
30679
31159
  }).add(rawMessages, "memory").get.all.db(), includeSystemReminders, hideSignals);
30680
- const { total, page: resultPage, perPage: resultPerPage, hasMore } = paginatedResult;
30681
31160
  const recallResult = {
30682
31161
  messages,
30683
31162
  usage,
@@ -31298,16 +31777,52 @@ ${workingMemory}`;
31298
31777
  messages = runState ? await runState.load(`observational-memory:messages:thread:${threadId}:${boundary}`, loadMessages) : await loadMessages();
31299
31778
  }
31300
31779
  } else {
31301
- const lastMessages = config.lastMessages;
31302
- if (lastMessages === false) messages = [];
31303
- else messages = (await memoryStore.listMessages({
31780
+ const lastMessages = (0, _mastra_core_memory.normalizeMessageHistoryConfig)(config.lastMessages, config.messageHistory);
31781
+ if (!lastMessages.enabled) messages = [];
31782
+ else if (lastMessages.maxTokens !== void 0) {
31783
+ const storedBoundary = (0, _mastra_core_memory.getMemoryTokenBoundary)(await memoryStore.getThreadById({
31784
+ threadId,
31785
+ resourceId
31786
+ }));
31787
+ const boundary = storedBoundary?.maxTokens === lastMessages.maxTokens && storedBoundary.atMaxRemoveTokens === lastMessages.atMaxRemoveTokens ? storedBoundary : void 0;
31788
+ const tokenCounter = this.createMemoryTokenCounter();
31789
+ const loaded = await (0, _mastra_core_memory.loadMessageHistory)({
31790
+ storage: memoryStore,
31791
+ threadId,
31792
+ resourceId,
31793
+ boundary,
31794
+ maxMessages: lastMessages.maxMessages,
31795
+ maxTokens: lastMessages.maxTokens,
31796
+ tokenCounter,
31797
+ initialTokens: 24
31798
+ });
31799
+ const messageList = new _mastra_core_agent.MessageList();
31800
+ messageList.add(loaded.messages, "memory");
31801
+ if (systemParts.length) messageList.addSystem(systemParts.join("\n\n"));
31802
+ await new _mastra_core_processors.TokenLimiterProcessor({
31803
+ limit: lastMessages.maxTokens,
31804
+ atMaxRemoveTokens: lastMessages.atMaxRemoveTokens,
31805
+ trimMode: "memory-only",
31806
+ tokenCounter
31807
+ }).processInput({
31808
+ messageList,
31809
+ messages: messageList.get.all.db(),
31810
+ systemMessages: messageList.getAllSystemMessages(),
31811
+ state: {},
31812
+ retryCount: 0,
31813
+ abort: (reason) => {
31814
+ throw new Error(reason);
31815
+ }
31816
+ });
31817
+ messages = messageList.get.all.db();
31818
+ } else messages = (await memoryStore.listMessages({
31304
31819
  threadId,
31305
31820
  resourceId,
31306
31821
  orderBy: {
31307
31822
  field: "createdAt",
31308
31823
  direction: "DESC"
31309
31824
  },
31310
- perPage: typeof lastMessages === "number" ? lastMessages : void 0,
31825
+ perPage: lastMessages.maxMessages,
31311
31826
  includeTotal: false
31312
31827
  })).messages.reverse();
31313
31828
  }
@@ -32730,4 +33245,4 @@ Object.defineProperty(exports, "wrapInObservationGroup", {
32730
33245
  }
32731
33246
  });
32732
33247
 
32733
- //# sourceMappingURL=src-oL_dDHN9.cjs.map
33248
+ //# sourceMappingURL=src-Da7AKXPR.cjs.map