@mastra/memory 1.28.0-alpha.2 → 1.28.0-alpha.4
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.
- package/CHANGELOG.md +22 -0
- package/dist/docs/SKILL.md +2 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-memory-semantic-recall.md +19 -0
- package/dist/docs/references/docs-storage.md +1 -0
- package/dist/docs/references/docs-subagents.md +6 -6
- package/dist/docs/references/integrations-channels-github.md +56 -9
- package/dist/docs/references/integrations-databases-elasticsearch.md +156 -0
- package/dist/docs/references/integrations-databases-libsql.md +16 -0
- package/dist/docs/references/integrations-databases-postgresql.md +24 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/processors/index.cjs +1 -1
- package/dist/processors/index.js +1 -1
- package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
- package/dist/processors/observational-memory/processor.d.ts.map +1 -1
- package/dist/processors/observational-memory/reflector-runner.d.ts +15 -0
- package/dist/processors/observational-memory/reflector-runner.d.ts.map +1 -1
- package/dist/{src-kLYHhPqh.js → src-BATJenuZ.js} +210 -160
- package/dist/src-BATJenuZ.js.map +1 -0
- package/dist/{src-CIBCjg2A.cjs → src-C7Ozl6Pf.cjs} +209 -159
- package/dist/src-C7Ozl6Pf.cjs.map +1 -0
- package/package.json +4 -4
- package/dist/src-CIBCjg2A.cjs.map +0 -1
- package/dist/src-kLYHhPqh.js.map +0 -1
|
@@ -57,8 +57,8 @@ probe_image_size_sync_js = __toESM$1(probe_image_size_sync_js, 1);
|
|
|
57
57
|
let _mastra_core_schema = require("@mastra/core/schema");
|
|
58
58
|
let _mastra_core_error = require("@mastra/core/error");
|
|
59
59
|
let _mastra_core_processors = require("@mastra/core/processors");
|
|
60
|
-
let util = require("util");
|
|
61
60
|
let diff = require("diff");
|
|
61
|
+
let util = require("util");
|
|
62
62
|
//#region ../_vendored/ai_v4/dist/dist-Cm5DZgxA.js
|
|
63
63
|
var marker$6 = "vercel.ai.error";
|
|
64
64
|
var symbol$6 = Symbol.for(marker$6);
|
|
@@ -3734,7 +3734,7 @@ function trimStartOfStream() {
|
|
|
3734
3734
|
};
|
|
3735
3735
|
}
|
|
3736
3736
|
//#endregion
|
|
3737
|
-
//#region ../_vendored/ai_v5/dist/dist-
|
|
3737
|
+
//#region ../_vendored/ai_v5/dist/dist-nVfjvSbw.js
|
|
3738
3738
|
var marker$1$4 = "vercel.ai.error";
|
|
3739
3739
|
var symbol$1$3 = Symbol.for(marker$1$4);
|
|
3740
3740
|
var _a$1$3;
|
|
@@ -4287,6 +4287,7 @@ async function cancelResponseBody$1(response) {
|
|
|
4287
4287
|
var initialGlobalFetch$1 = globalThis.fetch;
|
|
4288
4288
|
isNodeDefaultFetch$1(initialGlobalFetch$1);
|
|
4289
4289
|
function isNodeDefaultFetch$1(fetch) {
|
|
4290
|
+
if (typeof fetch !== "function") return false;
|
|
4290
4291
|
const source = Function.prototype.toString.call(fetch);
|
|
4291
4292
|
return source.includes("internal/deps/undici") || source.includes("lazy loading of undici");
|
|
4292
4293
|
}
|
|
@@ -8622,7 +8623,7 @@ var object$1 = ({ schema: inputSchema }) => {
|
|
|
8622
8623
|
};
|
|
8623
8624
|
};
|
|
8624
8625
|
//#endregion
|
|
8625
|
-
//#region ../_vendored/ai_v6/dist/dist-
|
|
8626
|
+
//#region ../_vendored/ai_v6/dist/dist-Gd4EIxPM.js
|
|
8626
8627
|
var marker$1 = "vercel.ai.error";
|
|
8627
8628
|
var symbol$1$1 = Symbol.for(marker$1);
|
|
8628
8629
|
var _a$1$1;
|
|
@@ -9196,6 +9197,7 @@ var DownloadError = class extends (_b$2 = AISDKError, _a$2 = symbol$2, _b$2) {
|
|
|
9196
9197
|
var initialGlobalFetch = globalThis.fetch;
|
|
9197
9198
|
isNodeDefaultFetch(initialGlobalFetch);
|
|
9198
9199
|
function isNodeDefaultFetch(fetch) {
|
|
9200
|
+
if (typeof fetch !== "function") return false;
|
|
9199
9201
|
const source = Function.prototype.toString.call(fetch);
|
|
9200
9202
|
return source.includes("internal/deps/undici") || source.includes("lazy loading of undici");
|
|
9201
9203
|
}
|
|
@@ -10774,7 +10776,7 @@ function withoutTrailingSlash(url) {
|
|
|
10774
10776
|
return url == null ? void 0 : url.replace(/\/$/, "");
|
|
10775
10777
|
}
|
|
10776
10778
|
//#endregion
|
|
10777
|
-
//#region ../_vendored/ai_v6/dist/dist-
|
|
10779
|
+
//#region ../_vendored/ai_v6/dist/dist-BoeKQsDe.js
|
|
10778
10780
|
function getContext() {
|
|
10779
10781
|
return { headers: {} };
|
|
10780
10782
|
}
|
|
@@ -22434,6 +22436,151 @@ function createWorkingMemoryTool(config, options = {}) {
|
|
|
22434
22436
|
};
|
|
22435
22437
|
}
|
|
22436
22438
|
//#endregion
|
|
22439
|
+
//#region src/processors/working-memory-state/processor.ts
|
|
22440
|
+
/**
|
|
22441
|
+
* WorkingMemoryStateProcessor
|
|
22442
|
+
*
|
|
22443
|
+
* Experimental: delivers working memory to the model as a state signal instead
|
|
22444
|
+
* of folding it into the system message. Storage and the `setWorkingMemory`
|
|
22445
|
+
* tool are unchanged — this processor only changes the delivery path.
|
|
22446
|
+
*
|
|
22447
|
+
* Pattern matches `BrowserContextProcessor` in `@mastra/core/browser`:
|
|
22448
|
+
* - `stateId` namespaces the state lane on the thread.
|
|
22449
|
+
* - `cacheKey` is derived from the rendered payload so dedup is automatic.
|
|
22450
|
+
* - `contextWindow.hasSnapshot` re-injection ensures the model still sees the
|
|
22451
|
+
* current snapshot after older messages drop out of the window.
|
|
22452
|
+
*
|
|
22453
|
+
* Delta emission (markdown mode only): when a prior snapshot exists in the
|
|
22454
|
+
* context window, the processor emits a unified-diff delta against that
|
|
22455
|
+
* snapshot's contents. Schema mode and the snapshot fallback always emit a
|
|
22456
|
+
* full snapshot.
|
|
22457
|
+
*
|
|
22458
|
+
* @example
|
|
22459
|
+
* ```ts
|
|
22460
|
+
* new Memory({
|
|
22461
|
+
* options: {
|
|
22462
|
+
* workingMemory: {
|
|
22463
|
+
* enabled: true,
|
|
22464
|
+
* template: '...',
|
|
22465
|
+
* useStateSignals: true, // auto-attaches this processor
|
|
22466
|
+
* },
|
|
22467
|
+
* },
|
|
22468
|
+
* });
|
|
22469
|
+
* ```
|
|
22470
|
+
*/
|
|
22471
|
+
const WORKING_MEMORY_STATE_ID = "working-memory";
|
|
22472
|
+
const WORKING_MEMORY_STATE_PROCESSOR_ID = "working-memory-state";
|
|
22473
|
+
var WorkingMemoryStateProcessor = class {
|
|
22474
|
+
memory;
|
|
22475
|
+
memoryConfig;
|
|
22476
|
+
id = WORKING_MEMORY_STATE_PROCESSOR_ID;
|
|
22477
|
+
stateId = WORKING_MEMORY_STATE_ID;
|
|
22478
|
+
constructor(memory, memoryConfig) {
|
|
22479
|
+
this.memory = memory;
|
|
22480
|
+
this.memoryConfig = memoryConfig;
|
|
22481
|
+
}
|
|
22482
|
+
async computeStateSignal(args) {
|
|
22483
|
+
const template = await this.memory.getWorkingMemoryTemplate({ memoryConfig: this.memoryConfig });
|
|
22484
|
+
if (!template) return;
|
|
22485
|
+
const contents = (await this.memory.getWorkingMemory({
|
|
22486
|
+
threadId: args.threadId,
|
|
22487
|
+
resourceId: args.resourceId,
|
|
22488
|
+
memoryConfig: this.memoryConfig
|
|
22489
|
+
}))?.trim();
|
|
22490
|
+
if (!contents) return;
|
|
22491
|
+
const cacheKey = stableWorkingMemoryCacheKey({
|
|
22492
|
+
format: template.format,
|
|
22493
|
+
data: contents
|
|
22494
|
+
});
|
|
22495
|
+
const shouldMakeSnapshot = !args.contextWindow.hasSnapshot;
|
|
22496
|
+
if (args.tracking?.currentCacheKey === cacheKey && !shouldMakeSnapshot) return;
|
|
22497
|
+
const scope = this.memory.getMergedThreadConfig(this.memoryConfig).workingMemory?.scope ?? "resource";
|
|
22498
|
+
const deltaCandidate = template.format === "markdown" && !shouldMakeSnapshot ? buildMarkdownDelta({
|
|
22499
|
+
lastSnapshot: args.lastSnapshot,
|
|
22500
|
+
deltasSinceSnapshot: args.deltasSinceSnapshot,
|
|
22501
|
+
nextContents: contents
|
|
22502
|
+
}) : void 0;
|
|
22503
|
+
if (deltaCandidate) return {
|
|
22504
|
+
id: WORKING_MEMORY_STATE_ID,
|
|
22505
|
+
mode: "delta",
|
|
22506
|
+
cacheKey,
|
|
22507
|
+
tagName: "working-memory",
|
|
22508
|
+
contents: deltaCandidate.contents,
|
|
22509
|
+
delta: deltaCandidate.contents,
|
|
22510
|
+
value: contents,
|
|
22511
|
+
attributes: {
|
|
22512
|
+
format: template.format,
|
|
22513
|
+
scope,
|
|
22514
|
+
patch: "unified-diff"
|
|
22515
|
+
}
|
|
22516
|
+
};
|
|
22517
|
+
return {
|
|
22518
|
+
id: WORKING_MEMORY_STATE_ID,
|
|
22519
|
+
mode: "snapshot",
|
|
22520
|
+
cacheKey,
|
|
22521
|
+
tagName: "working-memory",
|
|
22522
|
+
contents,
|
|
22523
|
+
value: contents,
|
|
22524
|
+
attributes: {
|
|
22525
|
+
format: template.format,
|
|
22526
|
+
scope
|
|
22527
|
+
}
|
|
22528
|
+
};
|
|
22529
|
+
}
|
|
22530
|
+
};
|
|
22531
|
+
/**
|
|
22532
|
+
* Stable cache key for the rendered working memory payload. Returns a SHA-256
|
|
22533
|
+
* digest so dedup metadata stays compact regardless of payload size (working
|
|
22534
|
+
* memory blobs can grow arbitrarily long).
|
|
22535
|
+
*/
|
|
22536
|
+
function stableWorkingMemoryCacheKey(input) {
|
|
22537
|
+
const hash = (0, crypto$1.createHash)("sha256");
|
|
22538
|
+
hash.update(input.format);
|
|
22539
|
+
hash.update("\0");
|
|
22540
|
+
hash.update(input.data ?? "");
|
|
22541
|
+
return `sha256:${hash.digest("hex")}`;
|
|
22542
|
+
}
|
|
22543
|
+
/**
|
|
22544
|
+
* Build a unified-diff delta against the most recently emitted state. Prefers
|
|
22545
|
+
* the latest delta's `value` (the post-edit full text) when available, falling
|
|
22546
|
+
* back to the snapshot's `value` and finally the snapshot's `contents`. This
|
|
22547
|
+
* keeps deltas incremental (B→C) instead of cumulative against a stale
|
|
22548
|
+
* snapshot (A→C), which matters when many small edits land between snapshots.
|
|
22549
|
+
*
|
|
22550
|
+
* Returns undefined when:
|
|
22551
|
+
* - there's no prior state to diff against
|
|
22552
|
+
* - the prior state isn't a plain string (multimodal signal)
|
|
22553
|
+
*
|
|
22554
|
+
* In either case the caller falls back to emitting a full snapshot.
|
|
22555
|
+
*/
|
|
22556
|
+
function buildMarkdownDelta(args) {
|
|
22557
|
+
const { lastSnapshot, deltasSinceSnapshot, nextContents } = args;
|
|
22558
|
+
const prior = pickStringValue(readSignalValue(deltasSinceSnapshot.at(-1))) ?? pickStringValue(readSignalValue(lastSnapshot)) ?? (typeof lastSnapshot?.contents === "string" ? lastSnapshot.contents : void 0);
|
|
22559
|
+
if (!prior) return;
|
|
22560
|
+
return { contents: renderHunksOnly(prior, nextContents) };
|
|
22561
|
+
}
|
|
22562
|
+
function pickStringValue(value) {
|
|
22563
|
+
return typeof value === "string" ? value : void 0;
|
|
22564
|
+
}
|
|
22565
|
+
function readSignalValue(signal) {
|
|
22566
|
+
return (signal?.metadata)?.value;
|
|
22567
|
+
}
|
|
22568
|
+
/**
|
|
22569
|
+
* Render a unified-diff-style patch body containing only `@@` hunks and their
|
|
22570
|
+
* lines — dropping the filename preamble (`Index:` / `===` / `---` / `+++`)
|
|
22571
|
+
* that `createPatch` emits and the `` trailer.
|
|
22572
|
+
* The preamble exists for tooling like `patch -p1` to know which file to
|
|
22573
|
+
* apply to; we only ever diff a single working-memory blob. The newline
|
|
22574
|
+
* trailer is semantically meaningless to the model and adds noise to the
|
|
22575
|
+
* state signal.
|
|
22576
|
+
*/
|
|
22577
|
+
function renderHunksOnly(prior, next) {
|
|
22578
|
+
const { hunks } = (0, diff.structuredPatch)("", "", prior, next, "", "", { context: 0 });
|
|
22579
|
+
return hunks.map((hunk) => {
|
|
22580
|
+
return [`@@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@`, ...hunk.lines.filter((line) => !line.startsWith("\"))].join("\n");
|
|
22581
|
+
}).join("\n");
|
|
22582
|
+
}
|
|
22583
|
+
//#endregion
|
|
22437
22584
|
//#region src/processors/observational-memory/activation-ttl.ts
|
|
22438
22585
|
const MINUTE = 6e4;
|
|
22439
22586
|
const HOUR = 60 * MINUTE;
|
|
@@ -25412,6 +25559,21 @@ var ReflectorRunner = class {
|
|
|
25412
25559
|
memory;
|
|
25413
25560
|
onReflectionCommitted;
|
|
25414
25561
|
mastra;
|
|
25562
|
+
/**
|
|
25563
|
+
* Per-lock-key observation-token count of the last unproductive synchronous
|
|
25564
|
+
* reflection (failed, or committed while still over the reflection
|
|
25565
|
+
* threshold). `call()` already runs the full bounded compression ladder for
|
|
25566
|
+
* a given input, so re-running it against unchanged observations cannot
|
|
25567
|
+
* succeed — threshold-triggered sync reflection is skipped while the count
|
|
25568
|
+
* is unchanged and retried as soon as the input differs.
|
|
25569
|
+
* Keyed by lock key (thread/resource), which is stable across generations —
|
|
25570
|
+
* record ids change every time a generation is created.
|
|
25571
|
+
*
|
|
25572
|
+
* Lifecycle: an entry is deleted when a sync reflection finishes under
|
|
25573
|
+
* threshold and replaced on each unproductive attempt. Entries are one
|
|
25574
|
+
* number per active thread/resource key and live for the runner's lifetime.
|
|
25575
|
+
*/
|
|
25576
|
+
syncReflectionSuppression = /* @__PURE__ */ new Map();
|
|
25415
25577
|
constructor(opts) {
|
|
25416
25578
|
this.reflectionConfig = opts.reflectionConfig;
|
|
25417
25579
|
this.observationConfig = opts.observationConfig;
|
|
@@ -25494,6 +25656,8 @@ var ReflectorRunner = class {
|
|
|
25494
25656
|
};
|
|
25495
25657
|
let reflectedTokens = 0;
|
|
25496
25658
|
let attemptNumber = 0;
|
|
25659
|
+
/** True when the latest attempt returned an empty block for non-empty input. */
|
|
25660
|
+
let emptyOutput = false;
|
|
25497
25661
|
while (currentLevel <= maxLevel) {
|
|
25498
25662
|
attemptNumber++;
|
|
25499
25663
|
const isRetry = attemptNumber > 1;
|
|
@@ -25557,14 +25721,18 @@ var ReflectorRunner = class {
|
|
|
25557
25721
|
}
|
|
25558
25722
|
finalProviderMetadata = result.providerMetadata ?? finalProviderMetadata;
|
|
25559
25723
|
parsed = parseReflectorOutput(result.text, observations, activeExtractors);
|
|
25724
|
+
emptyOutput = !parsed.degenerate && observations.trim().length > 0 && parsed.observations.trim().length === 0;
|
|
25560
25725
|
if (parsed.degenerate) {
|
|
25561
25726
|
omDebug(`[OM:callReflector] attempt #${attemptNumber}: degenerate repetition detected, treating as compression failure. ${describeDegenerateOutput(result.text, 2e3)}`);
|
|
25562
25727
|
reflectedTokens = originalTokens;
|
|
25728
|
+
} else if (emptyOutput) {
|
|
25729
|
+
omDebug(`[OM:callReflector] attempt #${attemptNumber}: empty observations block for non-empty input, treating as compression failure`);
|
|
25730
|
+
reflectedTokens = originalTokens;
|
|
25563
25731
|
} else reflectedTokens = this.tokenCounter.countObservations(parsed.observations);
|
|
25564
25732
|
omDebug(`[OM:callReflector] attempt #${attemptNumber} parsed: reflectedTokens=${reflectedTokens}, targetThreshold=${targetThreshold}, compressionValid=${validateCompression(reflectedTokens, targetThreshold)}, parsedObsLen=${parsed.observations?.length}, degenerate=${parsed.degenerate ?? false}`);
|
|
25565
|
-
if (!parsed.degenerate && (validateCompression(reflectedTokens, targetThreshold) || currentLevel >= maxLevel)) break;
|
|
25566
|
-
if (parsed.degenerate && currentLevel >= maxLevel) {
|
|
25567
|
-
omDebug(`[OM:callReflector] degenerate output persists at maxLevel=${maxLevel}, breaking`);
|
|
25733
|
+
if (!parsed.degenerate && !emptyOutput && (validateCompression(reflectedTokens, targetThreshold) || currentLevel >= maxLevel)) break;
|
|
25734
|
+
if ((parsed.degenerate || emptyOutput) && currentLevel >= maxLevel) {
|
|
25735
|
+
omDebug(`[OM:callReflector] ${parsed.degenerate ? "degenerate" : "empty"} output persists at maxLevel=${maxLevel}, breaking`);
|
|
25568
25736
|
break;
|
|
25569
25737
|
}
|
|
25570
25738
|
if (streamContext?.writer) {
|
|
@@ -25602,6 +25770,7 @@ var ReflectorRunner = class {
|
|
|
25602
25770
|
}
|
|
25603
25771
|
currentLevel = Math.min(currentLevel + 1, maxLevel);
|
|
25604
25772
|
}
|
|
25773
|
+
if (observations.trim().length > 0 && parsed.observations.trim().length === 0) throw new Error(`Reflector produced empty output after ${attemptNumber} attempt(s)${parsed.degenerate ? " (degenerate repetition)" : ""} — refusing to commit an empty reflection over ${originalTokens} observation tokens`);
|
|
25605
25774
|
const structuredExtraction = await extractStructuredValues({
|
|
25606
25775
|
agent,
|
|
25607
25776
|
source: "reflector",
|
|
@@ -25955,6 +26124,13 @@ var ReflectorRunner = class {
|
|
|
25955
26124
|
return;
|
|
25956
26125
|
}
|
|
25957
26126
|
}
|
|
26127
|
+
if (activationTriggeredBy === "threshold") {
|
|
26128
|
+
const suppressedAtTokens = this.syncReflectionSuppression.get(lockKey);
|
|
26129
|
+
if (suppressedAtTokens !== void 0 && observationTokens === suppressedAtTokens) {
|
|
26130
|
+
omDebug(`[OM:reflect] skipping sync reflection — observations unchanged at ${observationTokens} tokens since the last unproductive attempt; retrying once they change`);
|
|
26131
|
+
return;
|
|
26132
|
+
}
|
|
26133
|
+
}
|
|
25958
26134
|
await this.storage.setReflectingFlag(record.id, true);
|
|
25959
26135
|
registerOp(record.id, "reflecting");
|
|
25960
26136
|
const cycleId = crypto.randomUUID();
|
|
@@ -26015,6 +26191,8 @@ var ReflectorRunner = class {
|
|
|
26015
26191
|
reflection: reflectResult.observations,
|
|
26016
26192
|
tokenCount: reflectionTokenCount
|
|
26017
26193
|
});
|
|
26194
|
+
if (reflectionTokenCount >= reflectThreshold) this.syncReflectionSuppression.set(lockKey, reflectionTokenCount);
|
|
26195
|
+
else this.syncReflectionSuppression.delete(lockKey);
|
|
26018
26196
|
await this.notifyReflectionCommitted({
|
|
26019
26197
|
parentThreadId: requestedThreadId ?? record.threadId ?? "",
|
|
26020
26198
|
resourceId: record.resourceId ?? "",
|
|
@@ -26074,6 +26252,7 @@ var ReflectorRunner = class {
|
|
|
26074
26252
|
}
|
|
26075
26253
|
reflectionError = error instanceof Error ? error : new Error(String(error));
|
|
26076
26254
|
if (lifecycleError !== void 0 || abortSignal?.aborted) throw error;
|
|
26255
|
+
this.syncReflectionSuppression.set(lockKey, observationTokens);
|
|
26077
26256
|
omError("[OM] Reflection failed", error);
|
|
26078
26257
|
} finally {
|
|
26079
26258
|
try {
|
|
@@ -26420,10 +26599,24 @@ function getLatestStepParts(parts) {
|
|
|
26420
26599
|
return parts;
|
|
26421
26600
|
}
|
|
26422
26601
|
/**
|
|
26423
|
-
* Returns true
|
|
26424
|
-
*
|
|
26425
|
-
*
|
|
26602
|
+
* Returns true for persisted Working Memory state signals (`role: 'signal'`,
|
|
26603
|
+
* `signal.type: 'state'`, `state.id: 'working-memory'`). OM must not observe these:
|
|
26604
|
+
* they mirror memory OM itself manages, and re-observing them creates a self-feedback
|
|
26605
|
+
* loop that can overwrite stored working memory (#21961). Only the working-memory lane
|
|
26606
|
+
* is filtered — other state lanes are outside OM's write path, so re-observing them
|
|
26607
|
+
* cannot corrupt OM-managed state; excluding them broadly is a separate decision.
|
|
26426
26608
|
*/
|
|
26609
|
+
function isWorkingMemoryStateSignal(message) {
|
|
26610
|
+
if (message.role !== "signal") return false;
|
|
26611
|
+
const signal = message.content.metadata?.signal;
|
|
26612
|
+
if (!signal || typeof signal !== "object" || Array.isArray(signal)) return false;
|
|
26613
|
+
const signalRecord = signal;
|
|
26614
|
+
if ((signalRecord.type ?? message.type) !== "state") return false;
|
|
26615
|
+
const metadata = signalRecord.metadata;
|
|
26616
|
+
if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) return false;
|
|
26617
|
+
const state = metadata.state;
|
|
26618
|
+
return !!state && typeof state === "object" && !Array.isArray(state) && state.id === "working-memory";
|
|
26619
|
+
}
|
|
26427
26620
|
function messageHasVisibleContent(msg) {
|
|
26428
26621
|
const content = msg.content;
|
|
26429
26622
|
if (content?.parts && Array.isArray(content.parts)) return content.parts.some((p) => {
|
|
@@ -27194,7 +27387,7 @@ var ObservationalMemory = class ObservationalMemory {
|
|
|
27194
27387
|
}
|
|
27195
27388
|
const result = [];
|
|
27196
27389
|
for (const msg of allMessages) {
|
|
27197
|
-
if (msg.role === "system") continue;
|
|
27390
|
+
if (msg.role === "system" || isWorkingMemoryStateSignal(msg)) continue;
|
|
27198
27391
|
if (observedMessageIds?.has(msg.id)) continue;
|
|
27199
27392
|
const endMarkerIndex = findLastCompletedObservationBoundary(msg);
|
|
27200
27393
|
if (this.hasInProgressObservation(msg)) result.push(msg);
|
|
@@ -27416,7 +27609,7 @@ var ObservationalMemory = class ObservationalMemory {
|
|
|
27416
27609
|
},
|
|
27417
27610
|
filter: startDate ? { dateRange: { start: startDate } } : void 0
|
|
27418
27611
|
});
|
|
27419
|
-
return result.messages.filter((msg) => msg.role !== "system");
|
|
27612
|
+
return result.messages.filter((msg) => msg.role !== "system" && !isWorkingMemoryStateSignal(msg));
|
|
27420
27613
|
}
|
|
27421
27614
|
/**
|
|
27422
27615
|
* Format unobserved messages from other threads as <unobserved-context> blocks.
|
|
@@ -27875,7 +28068,7 @@ ${formattedMessages}
|
|
|
27875
28068
|
direction: "ASC"
|
|
27876
28069
|
},
|
|
27877
28070
|
filter: startDate ? { dateRange: { start: startDate } } : void 0
|
|
27878
|
-
})).messages.filter((
|
|
28071
|
+
})).messages.filter((message) => !this.observedMessageIds.has(message.id) && !isWorkingMemoryStateSignal(message));
|
|
27879
28072
|
if (filtered.length > 0) messagesByThread.set(thread.id, filtered);
|
|
27880
28073
|
}
|
|
27881
28074
|
if (messagesByThread.size === 0) return void 0;
|
|
@@ -29301,151 +29494,6 @@ var observational_memory_exports = /* @__PURE__ */ __exportAll({
|
|
|
29301
29494
|
wrapInObservationGroup: () => wrapInObservationGroup
|
|
29302
29495
|
});
|
|
29303
29496
|
//#endregion
|
|
29304
|
-
//#region src/processors/working-memory-state/processor.ts
|
|
29305
|
-
/**
|
|
29306
|
-
* WorkingMemoryStateProcessor
|
|
29307
|
-
*
|
|
29308
|
-
* Experimental: delivers working memory to the model as a state signal instead
|
|
29309
|
-
* of folding it into the system message. Storage and the `setWorkingMemory`
|
|
29310
|
-
* tool are unchanged — this processor only changes the delivery path.
|
|
29311
|
-
*
|
|
29312
|
-
* Pattern matches `BrowserContextProcessor` in `@mastra/core/browser`:
|
|
29313
|
-
* - `stateId` namespaces the state lane on the thread.
|
|
29314
|
-
* - `cacheKey` is derived from the rendered payload so dedup is automatic.
|
|
29315
|
-
* - `contextWindow.hasSnapshot` re-injection ensures the model still sees the
|
|
29316
|
-
* current snapshot after older messages drop out of the window.
|
|
29317
|
-
*
|
|
29318
|
-
* Delta emission (markdown mode only): when a prior snapshot exists in the
|
|
29319
|
-
* context window, the processor emits a unified-diff delta against that
|
|
29320
|
-
* snapshot's contents. Schema mode and the snapshot fallback always emit a
|
|
29321
|
-
* full snapshot.
|
|
29322
|
-
*
|
|
29323
|
-
* @example
|
|
29324
|
-
* ```ts
|
|
29325
|
-
* new Memory({
|
|
29326
|
-
* options: {
|
|
29327
|
-
* workingMemory: {
|
|
29328
|
-
* enabled: true,
|
|
29329
|
-
* template: '...',
|
|
29330
|
-
* useStateSignals: true, // auto-attaches this processor
|
|
29331
|
-
* },
|
|
29332
|
-
* },
|
|
29333
|
-
* });
|
|
29334
|
-
* ```
|
|
29335
|
-
*/
|
|
29336
|
-
const WORKING_MEMORY_STATE_ID = "working-memory";
|
|
29337
|
-
const WORKING_MEMORY_STATE_PROCESSOR_ID = "working-memory-state";
|
|
29338
|
-
var WorkingMemoryStateProcessor = class {
|
|
29339
|
-
memory;
|
|
29340
|
-
memoryConfig;
|
|
29341
|
-
id = WORKING_MEMORY_STATE_PROCESSOR_ID;
|
|
29342
|
-
stateId = WORKING_MEMORY_STATE_ID;
|
|
29343
|
-
constructor(memory, memoryConfig) {
|
|
29344
|
-
this.memory = memory;
|
|
29345
|
-
this.memoryConfig = memoryConfig;
|
|
29346
|
-
}
|
|
29347
|
-
async computeStateSignal(args) {
|
|
29348
|
-
const template = await this.memory.getWorkingMemoryTemplate({ memoryConfig: this.memoryConfig });
|
|
29349
|
-
if (!template) return;
|
|
29350
|
-
const contents = (await this.memory.getWorkingMemory({
|
|
29351
|
-
threadId: args.threadId,
|
|
29352
|
-
resourceId: args.resourceId,
|
|
29353
|
-
memoryConfig: this.memoryConfig
|
|
29354
|
-
}))?.trim();
|
|
29355
|
-
if (!contents) return;
|
|
29356
|
-
const cacheKey = stableWorkingMemoryCacheKey({
|
|
29357
|
-
format: template.format,
|
|
29358
|
-
data: contents
|
|
29359
|
-
});
|
|
29360
|
-
const shouldMakeSnapshot = !args.contextWindow.hasSnapshot;
|
|
29361
|
-
if (args.tracking?.currentCacheKey === cacheKey && !shouldMakeSnapshot) return;
|
|
29362
|
-
const scope = this.memory.getMergedThreadConfig(this.memoryConfig).workingMemory?.scope ?? "resource";
|
|
29363
|
-
const deltaCandidate = template.format === "markdown" && !shouldMakeSnapshot ? buildMarkdownDelta({
|
|
29364
|
-
lastSnapshot: args.lastSnapshot,
|
|
29365
|
-
deltasSinceSnapshot: args.deltasSinceSnapshot,
|
|
29366
|
-
nextContents: contents
|
|
29367
|
-
}) : void 0;
|
|
29368
|
-
if (deltaCandidate) return {
|
|
29369
|
-
id: WORKING_MEMORY_STATE_ID,
|
|
29370
|
-
mode: "delta",
|
|
29371
|
-
cacheKey,
|
|
29372
|
-
tagName: "working-memory",
|
|
29373
|
-
contents: deltaCandidate.contents,
|
|
29374
|
-
delta: deltaCandidate.contents,
|
|
29375
|
-
value: contents,
|
|
29376
|
-
attributes: {
|
|
29377
|
-
format: template.format,
|
|
29378
|
-
scope,
|
|
29379
|
-
patch: "unified-diff"
|
|
29380
|
-
}
|
|
29381
|
-
};
|
|
29382
|
-
return {
|
|
29383
|
-
id: WORKING_MEMORY_STATE_ID,
|
|
29384
|
-
mode: "snapshot",
|
|
29385
|
-
cacheKey,
|
|
29386
|
-
tagName: "working-memory",
|
|
29387
|
-
contents,
|
|
29388
|
-
value: contents,
|
|
29389
|
-
attributes: {
|
|
29390
|
-
format: template.format,
|
|
29391
|
-
scope
|
|
29392
|
-
}
|
|
29393
|
-
};
|
|
29394
|
-
}
|
|
29395
|
-
};
|
|
29396
|
-
/**
|
|
29397
|
-
* Stable cache key for the rendered working memory payload. Returns a SHA-256
|
|
29398
|
-
* digest so dedup metadata stays compact regardless of payload size (working
|
|
29399
|
-
* memory blobs can grow arbitrarily long).
|
|
29400
|
-
*/
|
|
29401
|
-
function stableWorkingMemoryCacheKey(input) {
|
|
29402
|
-
const hash = (0, crypto$1.createHash)("sha256");
|
|
29403
|
-
hash.update(input.format);
|
|
29404
|
-
hash.update("\0");
|
|
29405
|
-
hash.update(input.data ?? "");
|
|
29406
|
-
return `sha256:${hash.digest("hex")}`;
|
|
29407
|
-
}
|
|
29408
|
-
/**
|
|
29409
|
-
* Build a unified-diff delta against the most recently emitted state. Prefers
|
|
29410
|
-
* the latest delta's `value` (the post-edit full text) when available, falling
|
|
29411
|
-
* back to the snapshot's `value` and finally the snapshot's `contents`. This
|
|
29412
|
-
* keeps deltas incremental (B→C) instead of cumulative against a stale
|
|
29413
|
-
* snapshot (A→C), which matters when many small edits land between snapshots.
|
|
29414
|
-
*
|
|
29415
|
-
* Returns undefined when:
|
|
29416
|
-
* - there's no prior state to diff against
|
|
29417
|
-
* - the prior state isn't a plain string (multimodal signal)
|
|
29418
|
-
*
|
|
29419
|
-
* In either case the caller falls back to emitting a full snapshot.
|
|
29420
|
-
*/
|
|
29421
|
-
function buildMarkdownDelta(args) {
|
|
29422
|
-
const { lastSnapshot, deltasSinceSnapshot, nextContents } = args;
|
|
29423
|
-
const prior = pickStringValue(readSignalValue(deltasSinceSnapshot.at(-1))) ?? pickStringValue(readSignalValue(lastSnapshot)) ?? (typeof lastSnapshot?.contents === "string" ? lastSnapshot.contents : void 0);
|
|
29424
|
-
if (!prior) return;
|
|
29425
|
-
return { contents: renderHunksOnly(prior, nextContents) };
|
|
29426
|
-
}
|
|
29427
|
-
function pickStringValue(value) {
|
|
29428
|
-
return typeof value === "string" ? value : void 0;
|
|
29429
|
-
}
|
|
29430
|
-
function readSignalValue(signal) {
|
|
29431
|
-
return (signal?.metadata)?.value;
|
|
29432
|
-
}
|
|
29433
|
-
/**
|
|
29434
|
-
* Render a unified-diff-style patch body containing only `@@` hunks and their
|
|
29435
|
-
* lines — dropping the filename preamble (`Index:` / `===` / `---` / `+++`)
|
|
29436
|
-
* that `createPatch` emits and the `` trailer.
|
|
29437
|
-
* The preamble exists for tooling like `patch -p1` to know which file to
|
|
29438
|
-
* apply to; we only ever diff a single working-memory blob. The newline
|
|
29439
|
-
* trailer is semantically meaningless to the model and adds noise to the
|
|
29440
|
-
* state signal.
|
|
29441
|
-
*/
|
|
29442
|
-
function renderHunksOnly(prior, next) {
|
|
29443
|
-
const { hunks } = (0, diff.structuredPatch)("", "", prior, next, "", "", { context: 0 });
|
|
29444
|
-
return hunks.map((hunk) => {
|
|
29445
|
-
return [`@@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@`, ...hunk.lines.filter((line) => !line.startsWith("\"))].join("\n");
|
|
29446
|
-
}).join("\n");
|
|
29447
|
-
}
|
|
29448
|
-
//#endregion
|
|
29449
29497
|
//#region src/processors/working-memory-state/index.ts
|
|
29450
29498
|
var working_memory_state_exports = /* @__PURE__ */ __exportAll({
|
|
29451
29499
|
WORKING_MEMORY_STATE_ID: () => WORKING_MEMORY_STATE_ID,
|
|
@@ -30542,6 +30590,7 @@ ${workingMemory}`;
|
|
|
30542
30590
|
instruction: omConfig.observation.instruction,
|
|
30543
30591
|
threadTitle: omConfig.observation.threadTitle,
|
|
30544
30592
|
observeAttachments: omConfig.observation.observeAttachments,
|
|
30593
|
+
continuationHints: omConfig.observation.continuationHints,
|
|
30545
30594
|
extract: omConfig.observation.extract
|
|
30546
30595
|
} : void 0,
|
|
30547
30596
|
reflection: omConfig.reflection ? {
|
|
@@ -30552,6 +30601,7 @@ ${workingMemory}`;
|
|
|
30552
30601
|
bufferActivation: omConfig.reflection.bufferActivation,
|
|
30553
30602
|
blockAfter: omConfig.reflection.blockAfter,
|
|
30554
30603
|
instruction: omConfig.reflection.instruction,
|
|
30604
|
+
continuationHints: omConfig.reflection.continuationHints,
|
|
30555
30605
|
extract: omConfig.reflection.extract
|
|
30556
30606
|
} : void 0
|
|
30557
30607
|
});
|
|
@@ -31759,4 +31809,4 @@ Object.defineProperty(exports, "wrapInObservationGroup", {
|
|
|
31759
31809
|
}
|
|
31760
31810
|
});
|
|
31761
31811
|
|
|
31762
|
-
//# sourceMappingURL=src-
|
|
31812
|
+
//# sourceMappingURL=src-C7Ozl6Pf.cjs.map
|