@mastra/memory 1.26.2 → 1.27.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +62 -0
- package/dist/docs/SKILL.md +6 -6
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/{docs-agents-agent-approval.md → docs-agents-human-in-the-loop.md} +7 -5
- package/dist/docs/references/docs-agents-networks.md +3 -3
- package/dist/docs/references/{docs-long-running-agents-background-tasks.md → docs-harness-background-tasks.md} +5 -5
- package/dist/docs/references/{docs-long-running-agents-goals.md → docs-harness-goals.md} +6 -6
- package/dist/docs/references/docs-memory-message-history.md +1 -1
- package/dist/docs/references/docs-memory-overview.md +4 -4
- package/dist/docs/references/docs-memory-working-memory.md +1 -1
- package/dist/docs/references/{docs-storage-overview.md → docs-storage.md} +1 -1
- package/dist/docs/references/{docs-capabilities-subagents.md → docs-subagents.md} +35 -5
- package/dist/docs/references/integrations-channels-github.md +1 -1
- package/dist/docs/references/integrations-databases-postgresql.md +3 -1
- package/dist/docs/references/reference-file-based-agents-memory.md +2 -2
- package/dist/docs/references/reference-memory-observational-memory.md +4 -0
- package/dist/index.cjs +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/built-in-extractors.d.ts +13 -4
- package/dist/processors/observational-memory/built-in-extractors.d.ts.map +1 -1
- package/dist/processors/observational-memory/index.d.ts +1 -1
- package/dist/processors/observational-memory/index.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-turn/step.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-turn/turn.d.ts +4 -0
- package/dist/processors/observational-memory/observation-turn/turn.d.ts.map +1 -1
- package/dist/processors/observational-memory/observational-memory.d.ts +5 -1
- package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
- package/dist/processors/observational-memory/observer-agent.d.ts +13 -0
- package/dist/processors/observational-memory/observer-agent.d.ts.map +1 -1
- package/dist/processors/observational-memory/processor.d.ts.map +1 -1
- package/dist/processors/observational-memory/reflector-agent.d.ts +1 -0
- package/dist/processors/observational-memory/reflector-agent.d.ts.map +1 -1
- package/dist/processors/observational-memory/token-counter.d.ts +1 -0
- package/dist/processors/observational-memory/token-counter.d.ts.map +1 -1
- package/dist/processors/observational-memory/types.d.ts +31 -0
- package/dist/processors/observational-memory/types.d.ts.map +1 -1
- package/dist/{src-BYD6Wp5m.js → src-BKRU-0Fx.js} +164 -64
- package/dist/{src-BYD6Wp5m.js.map → src-BKRU-0Fx.js.map} +1 -1
- package/dist/{src-b5E69E65.cjs → src-_7ADtEwc.cjs} +164 -64
- package/dist/{src-b5E69E65.cjs.map → src-_7ADtEwc.cjs.map} +1 -1
- package/dist/tools/working-memory.d.ts +3 -1
- package/dist/tools/working-memory.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -15946,21 +15946,17 @@ Or as a standalone observation when closing out a broader task:
|
|
|
15946
15946
|
Completion observations should be terse but specific about WHAT was completed.
|
|
15947
15947
|
Prefer concrete resolved outcomes over abstract workflow status so the assistant remembers what is already done.`;
|
|
15948
15948
|
buildObserverOutputFormat();
|
|
15949
|
-
|
|
15950
|
-
|
|
15951
|
-
|
|
15952
|
-
|
|
15953
|
-
|
|
15954
|
-
|
|
15955
|
-
|
|
15956
|
-
|
|
15957
|
-
|
|
15958
|
-
|
|
15959
|
-
|
|
15960
|
-
- "I've updated the navigation model. Let me walk you through the changes..."
|
|
15961
|
-
- "The assistant should wait for the user to respond before continuing."
|
|
15962
|
-
- Call the view tool on src/example.ts to continue debugging.
|
|
15963
|
-
</suggested-response>` : "";
|
|
15949
|
+
/**
|
|
15950
|
+
* Build the Observer's output format.
|
|
15951
|
+
*
|
|
15952
|
+
* `extractors` distinguishes two cases that both look empty:
|
|
15953
|
+
* - `undefined` — the no-arg call behind the exported defaults (OBSERVER_OUTPUT_FORMAT_BASE,
|
|
15954
|
+
* OBSERVER_SYSTEM_PROMPT, REFLECTOR_SYSTEM_PROMPT), which keep describing both built-in
|
|
15955
|
+
* sections with their historical text. Runtime callers always pass the composed list.
|
|
15956
|
+
* - `[]` — the caller composed extractors and every section was disabled, so no continuation
|
|
15957
|
+
* sections are described at all.
|
|
15958
|
+
*/
|
|
15959
|
+
function buildObserverOutputFormat(extractors) {
|
|
15964
15960
|
return `Use priority levels:
|
|
15965
15961
|
- 🔴 High: explicit user facts, preferences, unresolved goals, critical context
|
|
15966
15962
|
- 🟡 Medium: project details, learned information, tool results
|
|
@@ -15986,7 +15982,19 @@ Date: Dec 5, 2025
|
|
|
15986
15982
|
* 🔴 (09:15) Continued work on feature X
|
|
15987
15983
|
</observations>
|
|
15988
15984
|
|
|
15989
|
-
${
|
|
15985
|
+
${buildExtractorOutputSections(extractors ?? []) || (extractors === void 0 ? `
|
|
15986
|
+
<current-task>
|
|
15987
|
+
State the current task(s) explicitly:
|
|
15988
|
+
- Primary: What the agent is currently working on
|
|
15989
|
+
- Secondary: Other pending tasks (mark as "waiting for user" if appropriate)
|
|
15990
|
+
</current-task>
|
|
15991
|
+
|
|
15992
|
+
<suggested-response>
|
|
15993
|
+
Hint for the agent's immediate next message. Examples:
|
|
15994
|
+
- "I've updated the navigation model. Let me walk you through the changes..."
|
|
15995
|
+
- "The assistant should wait for the user to respond before continuing."
|
|
15996
|
+
- Call the view tool on src/example.ts to continue debugging.
|
|
15997
|
+
</suggested-response>` : "")}`;
|
|
15990
15998
|
}
|
|
15991
15999
|
/**
|
|
15992
16000
|
* The guidelines for the Observer.
|
|
@@ -16013,10 +16021,22 @@ const OBSERVER_GUIDELINES = `- Be specific enough for the assistant to act on
|
|
|
16013
16021
|
* Build the complete observer system prompt.
|
|
16014
16022
|
* @param multiThread - Whether this is for multi-thread batched observation (default: false)
|
|
16015
16023
|
* @param instruction - Optional custom instructions to append to the prompt
|
|
16024
|
+
* @param includeThreadTitle - Whether the Observer should also produce a thread title
|
|
16025
|
+
* @param extractors - Active extractors, used to decide which sections the prompt describes.
|
|
16026
|
+
* Omitted only by the exported no-arg defaults; pass `[]` to describe no continuation sections at all.
|
|
16016
16027
|
*/
|
|
16017
|
-
function buildObserverSystemPrompt(multiThread = false, instruction, includeThreadTitle = false, extractors
|
|
16028
|
+
function buildObserverSystemPrompt(multiThread = false, instruction, includeThreadTitle = false, extractors) {
|
|
16018
16029
|
const outputFormat = buildObserverOutputFormat(extractors);
|
|
16019
|
-
const
|
|
16030
|
+
const customInstructions = instruction ? `\n\n=== CUSTOM INSTRUCTIONS ===\n\n${instruction}` : "";
|
|
16031
|
+
const currentTaskEnabled = extractors === void 0 || extractors.some((extractor) => extractor.slug === "current-task");
|
|
16032
|
+
const suggestedResponseEnabled = extractors === void 0 || extractors.some((extractor) => extractor.slug === "suggested-response");
|
|
16033
|
+
const multiThreadSections = [
|
|
16034
|
+
"observations",
|
|
16035
|
+
...currentTaskEnabled ? ["current-task"] : [],
|
|
16036
|
+
...suggestedResponseEnabled ? ["suggested-response"] : [],
|
|
16037
|
+
...includeThreadTitle ? ["thread-title"] : []
|
|
16038
|
+
];
|
|
16039
|
+
const multiThreadTitleInstruction = ` Each thread's ${multiThreadSections.length <= 2 ? multiThreadSections.join(" and ") : `${multiThreadSections.slice(0, -1).join(", ")}, and ${multiThreadSections[multiThreadSections.length - 1]}`} should be nested inside a <thread id="..."> block within <observations>.`;
|
|
16020
16040
|
const multiThreadTitleExample = includeThreadTitle ? `
|
|
16021
16041
|
<thread-title>Feature X implementation</thread-title>` : "";
|
|
16022
16042
|
const multiThreadSecondTitleExample = includeThreadTitle ? `
|
|
@@ -16046,28 +16066,28 @@ For multi-thread output, wrap each thread's observations like this:
|
|
|
16046
16066
|
<thread id="thread_id_1">
|
|
16047
16067
|
Date: Dec 4, 2025
|
|
16048
16068
|
* 🔴 (14:30) User prefers direct answers
|
|
16049
|
-
* 🔴 (14:31) Working on feature X
|
|
16069
|
+
* 🔴 (14:31) Working on feature X${currentTaskEnabled ? `
|
|
16050
16070
|
|
|
16051
16071
|
<current-task>
|
|
16052
16072
|
What the agent is currently working on in this thread
|
|
16053
|
-
</current-task
|
|
16073
|
+
</current-task>` : ""}${suggestedResponseEnabled ? `
|
|
16054
16074
|
|
|
16055
16075
|
<suggested-response>
|
|
16056
16076
|
Hint for the agent's next message in this thread
|
|
16057
|
-
</suggested-response
|
|
16077
|
+
</suggested-response>` : ""}${multiThreadTitleExample}
|
|
16058
16078
|
</thread>
|
|
16059
16079
|
|
|
16060
16080
|
<thread id="thread_id_2">
|
|
16061
16081
|
Date: Dec 5, 2025
|
|
16062
|
-
* 🔴 (09:15) User asked about deployment
|
|
16082
|
+
* 🔴 (09:15) User asked about deployment${currentTaskEnabled ? `
|
|
16063
16083
|
|
|
16064
16084
|
<current-task>
|
|
16065
16085
|
Current task for this thread
|
|
16066
|
-
</current-task
|
|
16086
|
+
</current-task>` : ""}${suggestedResponseEnabled ? `
|
|
16067
16087
|
|
|
16068
16088
|
<suggested-response>
|
|
16069
16089
|
Suggested response for this thread
|
|
16070
|
-
</suggested-response
|
|
16090
|
+
</suggested-response>` : ""}${multiThreadSecondTitleExample}
|
|
16071
16091
|
</thread>
|
|
16072
16092
|
</observations>
|
|
16073
16093
|
|
|
@@ -16077,7 +16097,7 @@ ${OBSERVER_GUIDELINES}
|
|
|
16077
16097
|
|
|
16078
16098
|
Remember: These observations are the assistant's ONLY memory. Make them count.
|
|
16079
16099
|
|
|
16080
|
-
User messages are extremely important
|
|
16100
|
+
User messages are extremely important.${currentTaskEnabled ? " If the user asks a question or gives a new task, make it clear in <current-task> that this is the priority." : ""}${customInstructions}`;
|
|
16081
16101
|
return `You are the memory consciousness of an AI assistant. Your observations will be the ONLY information the assistant has about past interactions with this user.
|
|
16082
16102
|
|
|
16083
16103
|
Extract observations that will help the assistant remember:
|
|
@@ -16102,7 +16122,7 @@ Simply output your observations without any thread-related markup.
|
|
|
16102
16122
|
|
|
16103
16123
|
Remember: These observations are the assistant's ONLY memory. Make them count.
|
|
16104
16124
|
|
|
16105
|
-
User messages are extremely important
|
|
16125
|
+
User messages are extremely important.${currentTaskEnabled ? " If the user asks a question or gives a new task, make it clear in <current-task> that this is the priority." : ""}${suggestedResponseEnabled ? " If the assistant needs to respond to the user, indicate in <suggested-response> that it should pause for user reply before continuing other tasks." : ""}${customInstructions}`;
|
|
16106
16126
|
}
|
|
16107
16127
|
/**
|
|
16108
16128
|
* Observer Agent System Prompt (default - for backwards compatibility)
|
|
@@ -16794,7 +16814,7 @@ function optimizeObservationsForContext(observations) {
|
|
|
16794
16814
|
let optimized = stripEphemeralAnchorIds(observations);
|
|
16795
16815
|
optimized = optimized.replace(/🟡\s*/g, "");
|
|
16796
16816
|
optimized = optimized.replace(/🟢\s*/g, "");
|
|
16797
|
-
optimized = optimized.replace(/\[(?![\d\s]*items collapsed)[^\]]+\]/g, "");
|
|
16817
|
+
optimized = optimized.replace(/\[(?![\d\s]*items collapsed)[^\]]+\](?!\()/g, "");
|
|
16798
16818
|
optimized = optimized.replace(/\s*->\s*/g, " ");
|
|
16799
16819
|
optimized = optimized.replace(/ +/g, " ");
|
|
16800
16820
|
optimized = optimized.replace(/\n{3,}/g, "\n\n");
|
|
@@ -18216,6 +18236,7 @@ var TokenCounter = class TokenCounter {
|
|
|
18216
18236
|
defaultModelContext;
|
|
18217
18237
|
modelContextStorage = new async_hooks.AsyncLocalStorage();
|
|
18218
18238
|
inFlightAttachmentCounts = /* @__PURE__ */ new Map();
|
|
18239
|
+
multimodalToolResultCounts = /* @__PURE__ */ new WeakMap();
|
|
18219
18240
|
static TOKENS_PER_MESSAGE = 3.8;
|
|
18220
18241
|
static TOKENS_PER_CONVERSATION = 24;
|
|
18221
18242
|
constructor(options) {
|
|
@@ -18278,6 +18299,9 @@ var TokenCounter = class TokenCounter {
|
|
|
18278
18299
|
}
|
|
18279
18300
|
countMultimodalToolResultContent(part, toolResult) {
|
|
18280
18301
|
if (!toolResult || typeof toolResult !== "object") return;
|
|
18302
|
+
const resultKey = buildEstimateKey("tool-result-multimodal-content-source", JSON.stringify(toolResult));
|
|
18303
|
+
const cached = this.multimodalToolResultCounts.get(part);
|
|
18304
|
+
if (cached?.resultKey === resultKey) return cached.tokens;
|
|
18281
18305
|
const output = toolResult;
|
|
18282
18306
|
const content = output.type === "content" && Array.isArray(output.value) ? output.value : output.content;
|
|
18283
18307
|
if (!Array.isArray(content)) return;
|
|
@@ -18389,10 +18413,15 @@ var TokenCounter = class TokenCounter {
|
|
|
18389
18413
|
countJsonContentPart(contentPart);
|
|
18390
18414
|
}
|
|
18391
18415
|
if (!hasAttachment) return;
|
|
18392
|
-
|
|
18416
|
+
const estimate = this.readOrPersistFixedPartEstimate(part, "tool-result-multimodal-content", JSON.stringify({
|
|
18393
18417
|
type: "content",
|
|
18394
18418
|
value: cacheParts
|
|
18395
18419
|
}), tokens);
|
|
18420
|
+
this.multimodalToolResultCounts.set(part, {
|
|
18421
|
+
resultKey,
|
|
18422
|
+
tokens: estimate
|
|
18423
|
+
});
|
|
18424
|
+
return estimate;
|
|
18396
18425
|
}
|
|
18397
18426
|
estimateImageAssetTokens(part, asset, kind) {
|
|
18398
18427
|
const modelContext = this.getModelContext();
|
|
@@ -19874,21 +19903,22 @@ const SET_WORKING_MEMORY_TOOL_NAME = "setWorkingMemory";
|
|
|
19874
19903
|
/**
|
|
19875
19904
|
* Deep merges two objects, with special handling for null values (delete) and arrays (replace).
|
|
19876
19905
|
* - Object properties are recursively merged
|
|
19877
|
-
* - null values in the update will delete the corresponding property
|
|
19906
|
+
* - null values in the update will delete the corresponding property, even when the property
|
|
19907
|
+
* or its parent object does not exist yet (so padded nulls never get stored literally)
|
|
19878
19908
|
* - Arrays are replaced entirely (not merged element-by-element)
|
|
19879
19909
|
* - Primitive values are overwritten
|
|
19910
|
+
* - The returned object is always newly constructed and never aliases `update`
|
|
19880
19911
|
*/
|
|
19881
19912
|
function deepMergeWorkingMemory(existing, update) {
|
|
19882
19913
|
if (!update || typeof update !== "object" || Object.keys(update).length === 0) return existing && typeof existing === "object" ? { ...existing } : {};
|
|
19883
|
-
|
|
19884
|
-
const result = { ...existing };
|
|
19914
|
+
const result = { ...existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {} };
|
|
19885
19915
|
for (const key of Object.keys(update)) {
|
|
19886
19916
|
const updateValue = update[key];
|
|
19887
19917
|
const existingValue = result[key];
|
|
19888
19918
|
if (updateValue === void 0) continue;
|
|
19889
19919
|
if (updateValue === null) delete result[key];
|
|
19890
19920
|
else if (Array.isArray(updateValue)) result[key] = updateValue;
|
|
19891
|
-
else if (typeof updateValue === "object"
|
|
19921
|
+
else if (typeof updateValue === "object") result[key] = deepMergeWorkingMemory(existingValue && typeof existingValue === "object" && !Array.isArray(existingValue) ? existingValue : void 0, updateValue);
|
|
19892
19922
|
else result[key] = updateValue;
|
|
19893
19923
|
}
|
|
19894
19924
|
return result;
|
|
@@ -20379,23 +20409,43 @@ function createThreadTitleExtractor() {
|
|
|
20379
20409
|
metadataKeyPath: "threadTitle"
|
|
20380
20410
|
}, true);
|
|
20381
20411
|
}
|
|
20412
|
+
/**
|
|
20413
|
+
* Normalize the user-facing `continuationHints` config into explicit per-section flags.
|
|
20414
|
+
* Both sections stay enabled unless the caller opts out, so omitting the config is a no-op.
|
|
20415
|
+
*/
|
|
20416
|
+
function resolveContinuationHints(config) {
|
|
20417
|
+
if (config === void 0 || config === true) return {
|
|
20418
|
+
currentTask: true,
|
|
20419
|
+
suggestedResponse: true
|
|
20420
|
+
};
|
|
20421
|
+
if (config === false) return {
|
|
20422
|
+
currentTask: false,
|
|
20423
|
+
suggestedResponse: false
|
|
20424
|
+
};
|
|
20425
|
+
return {
|
|
20426
|
+
currentTask: config.currentTask ?? true,
|
|
20427
|
+
suggestedResponse: config.suggestedResponse ?? true
|
|
20428
|
+
};
|
|
20429
|
+
}
|
|
20382
20430
|
function composeExtractors(options) {
|
|
20431
|
+
const continuationHints = resolveContinuationHints(options.continuationHints);
|
|
20383
20432
|
const extractors = [];
|
|
20384
|
-
if (
|
|
20433
|
+
if (continuationHints.currentTask) extractors.push(createCurrentTaskExtractor());
|
|
20434
|
+
if (continuationHints.suggestedResponse) extractors.push(createSuggestedResponseExtractor());
|
|
20385
20435
|
if (options.includeThreadTitle) extractors.push(createThreadTitleExtractor());
|
|
20386
20436
|
extractors.push(...options.userExtractors ?? []);
|
|
20387
20437
|
return validateExtractorList(extractors);
|
|
20388
20438
|
}
|
|
20389
20439
|
function composeObservationExtractors(config) {
|
|
20390
20440
|
return composeExtractors({
|
|
20391
|
-
|
|
20441
|
+
continuationHints: config.continuationHints,
|
|
20392
20442
|
includeThreadTitle: config.threadTitle,
|
|
20393
20443
|
userExtractors: config.extract
|
|
20394
20444
|
});
|
|
20395
20445
|
}
|
|
20396
20446
|
function composeReflectionExtractors(config) {
|
|
20397
20447
|
return composeExtractors({
|
|
20398
|
-
|
|
20448
|
+
continuationHints: config.continuationHints,
|
|
20399
20449
|
userExtractors: config.extract
|
|
20400
20450
|
});
|
|
20401
20451
|
}
|
|
@@ -22180,10 +22230,12 @@ var ObservationStep = class {
|
|
|
22180
22230
|
resourceId,
|
|
22181
22231
|
checkThreshold: true,
|
|
22182
22232
|
messages: step0Messages,
|
|
22233
|
+
record: this.turn.record,
|
|
22183
22234
|
currentModel: this.turn.actorModelContext,
|
|
22184
22235
|
writer: this.turn.writer,
|
|
22185
22236
|
messageList
|
|
22186
22237
|
});
|
|
22238
|
+
this.turn.setRecord(activation.record);
|
|
22187
22239
|
if (activation.activated) {
|
|
22188
22240
|
activated = true;
|
|
22189
22241
|
if (activation.activatedMessageIds?.length) messageList.removeByIds(activation.activatedMessageIds);
|
|
@@ -22225,6 +22277,7 @@ var ObservationStep = class {
|
|
|
22225
22277
|
let statusSnapshot = await om.getStatus({
|
|
22226
22278
|
threadId,
|
|
22227
22279
|
resourceId,
|
|
22280
|
+
record: this.turn.record,
|
|
22228
22281
|
messages: getObservableMessages(messageList)
|
|
22229
22282
|
});
|
|
22230
22283
|
if (statusSnapshot.shouldBuffer && !hasIncompleteToolCalls) {
|
|
@@ -22320,6 +22373,7 @@ var ObservationStep = class {
|
|
|
22320
22373
|
statusSnapshot = await om.getStatus({
|
|
22321
22374
|
threadId,
|
|
22322
22375
|
resourceId,
|
|
22376
|
+
record: this.turn.record,
|
|
22323
22377
|
messages: getObservableMessages(messageList)
|
|
22324
22378
|
});
|
|
22325
22379
|
}
|
|
@@ -22370,10 +22424,12 @@ var ObservationStep = class {
|
|
|
22370
22424
|
const { threadId, resourceId, messageList } = this.turn;
|
|
22371
22425
|
const om = this.turn.om;
|
|
22372
22426
|
await om.waitForBuffering(threadId, resourceId);
|
|
22427
|
+
await this.turn.refreshRecord();
|
|
22373
22428
|
const observableMessages = this.seededResponseMessage ? getObservableMessages(messageList).filter((msg) => msg.id !== this.turn.responseMessageId) : getObservableMessages(messageList);
|
|
22374
22429
|
const freshStatus = await om.getStatus({
|
|
22375
22430
|
threadId,
|
|
22376
22431
|
resourceId,
|
|
22432
|
+
record: this.turn.record,
|
|
22377
22433
|
messages: observableMessages
|
|
22378
22434
|
});
|
|
22379
22435
|
if (!freshStatus.shouldObserve) return {
|
|
@@ -22384,11 +22440,13 @@ var ObservationStep = class {
|
|
|
22384
22440
|
const activation = await om.activate({
|
|
22385
22441
|
threadId,
|
|
22386
22442
|
resourceId,
|
|
22443
|
+
record: this.turn.record,
|
|
22387
22444
|
messages: observableMessages,
|
|
22388
22445
|
currentModel: this.turn.actorModelContext,
|
|
22389
22446
|
writer: this.turn.writer,
|
|
22390
22447
|
messageList
|
|
22391
22448
|
});
|
|
22449
|
+
this.turn.setRecord(activation.record);
|
|
22392
22450
|
if (activation.activated) {
|
|
22393
22451
|
const postActivationRecord = activation.record;
|
|
22394
22452
|
await om.reflector.maybeReflect({
|
|
@@ -22573,6 +22631,18 @@ var ObservationTurn = class {
|
|
|
22573
22631
|
};
|
|
22574
22632
|
return this._context;
|
|
22575
22633
|
}
|
|
22634
|
+
/** Replace the cached turn record with a specific instance. */
|
|
22635
|
+
setRecord(record) {
|
|
22636
|
+
this._record = record;
|
|
22637
|
+
if (this._context) this._context.record = record;
|
|
22638
|
+
}
|
|
22639
|
+
/** Patch the cached turn record with merged fields. */
|
|
22640
|
+
patchRecord(patch) {
|
|
22641
|
+
this.setRecord({
|
|
22642
|
+
...this.record,
|
|
22643
|
+
...patch
|
|
22644
|
+
});
|
|
22645
|
+
}
|
|
22576
22646
|
/**
|
|
22577
22647
|
* Create a step handle. If a previous step exists, it is finalized
|
|
22578
22648
|
* (its output messages will be saved at the start of the new step's prepare()).
|
|
@@ -22627,7 +22697,7 @@ var ObservationTurn = class {
|
|
|
22627
22697
|
* @internal
|
|
22628
22698
|
*/
|
|
22629
22699
|
async refreshRecord() {
|
|
22630
|
-
this.
|
|
22700
|
+
this.setRecord(await this.om.getOrCreateRecord(this.threadId, this.resourceId));
|
|
22631
22701
|
}
|
|
22632
22702
|
/**
|
|
22633
22703
|
* Refresh cross-thread context for resource scope. Called per-step.
|
|
@@ -22682,9 +22752,13 @@ var ObservationTurn = class {
|
|
|
22682
22752
|
* - Preserving ALL important information (reflections become the ENTIRE memory)
|
|
22683
22753
|
*
|
|
22684
22754
|
* @param instruction - Optional custom instructions to append to the prompt
|
|
22755
|
+
* @param extractors - Active extractors, used to decide which sections the prompt describes
|
|
22685
22756
|
*/
|
|
22686
|
-
function buildReflectorSystemPrompt(instruction, extractors
|
|
22757
|
+
function buildReflectorSystemPrompt(instruction, extractors) {
|
|
22687
22758
|
const outputFormat = buildObserverOutputFormat(extractors);
|
|
22759
|
+
const customInstructions = instruction ? `\n\n=== CUSTOM INSTRUCTIONS ===\n\n${instruction}` : "";
|
|
22760
|
+
const currentTaskEnabled = extractors === void 0 || extractors.some((extractor) => extractor.slug === "current-task");
|
|
22761
|
+
const suggestedResponseEnabled = extractors === void 0 || extractors.some((extractor) => extractor.slug === "suggested-response");
|
|
22688
22762
|
return `You are the memory consciousness of an AI assistant. Your memory observation reflections will be the ONLY information the assistant has about past interactions with this user.
|
|
22689
22763
|
|
|
22690
22764
|
The following instructions were given to another part of your psyche (the observer) to create memories.
|
|
@@ -22761,7 +22835,7 @@ Date: Dec 4, 2025
|
|
|
22761
22835
|
|
|
22762
22836
|
${outputFormat}
|
|
22763
22837
|
|
|
22764
|
-
User messages are extremely important
|
|
22838
|
+
User messages are extremely important.${currentTaskEnabled ? " If the user asks a question or gives a new task, make it clear in <current-task> that this is the priority." : ""}${suggestedResponseEnabled ? " If the assistant needs to respond to the user, indicate in <suggested-response> that it should pause for user reply before continuing other tasks." : ""}${customInstructions}`;
|
|
22765
22839
|
}
|
|
22766
22840
|
buildReflectorSystemPrompt();
|
|
22767
22841
|
/**
|
|
@@ -24225,7 +24299,8 @@ var ObservationalMemory = class ObservationalMemory {
|
|
|
24225
24299
|
observeAttachments: config.observation?.observeAttachments ?? true,
|
|
24226
24300
|
extractors: composeObservationExtractors({
|
|
24227
24301
|
threadTitle: config.observation?.threadTitle ?? false,
|
|
24228
|
-
extract: config.observation?.extract
|
|
24302
|
+
extract: config.observation?.extract,
|
|
24303
|
+
continuationHints: config.observation?.continuationHints
|
|
24229
24304
|
})
|
|
24230
24305
|
};
|
|
24231
24306
|
this.reflectionConfig = {
|
|
@@ -24242,7 +24317,10 @@ var ObservationalMemory = class ObservationalMemory {
|
|
|
24242
24317
|
activateOnProviderChange: config.reflection?.activateOnProviderChange ?? false,
|
|
24243
24318
|
blockAfter: asyncBufferingDisabled ? void 0 : resolveBlockAfter(config.reflection?.blockAfter ?? (config.reflection?.bufferActivation ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.bufferActivation ? 1.2 : void 0), config.reflection?.observationTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.observationTokens),
|
|
24244
24319
|
instruction: config.reflection?.instruction,
|
|
24245
|
-
extractors: composeReflectionExtractors({
|
|
24320
|
+
extractors: composeReflectionExtractors({
|
|
24321
|
+
extract: config.reflection?.extract,
|
|
24322
|
+
continuationHints: config.reflection?.continuationHints
|
|
24323
|
+
})
|
|
24246
24324
|
};
|
|
24247
24325
|
this.tokenCounter = new TokenCounter({ model: typeof observationModel === "string" ? observationModel : void 0 });
|
|
24248
24326
|
this.onDebugEvent = config.onDebugEvent;
|
|
@@ -25357,8 +25435,9 @@ ${formattedMessages}
|
|
|
25357
25435
|
return;
|
|
25358
25436
|
}
|
|
25359
25437
|
const omMetadata = (0, _mastra_core_memory.getThreadOMMetadata)((await this.storage.getThreadById({ threadId }))?.metadata);
|
|
25360
|
-
const
|
|
25361
|
-
const
|
|
25438
|
+
const activeExtractors = [...this.observationConfig.extractors, ...this.reflectionConfig.extractors];
|
|
25439
|
+
const currentTask = activeExtractors.some((extractor) => extractor.slug === "current-task") ? omMetadata?.currentTask : void 0;
|
|
25440
|
+
const suggestedResponse = activeExtractors.some((extractor) => extractor.slug === "suggested-response") ? omMetadata?.suggestedResponse : void 0;
|
|
25362
25441
|
const currentDate = opts.currentDate ?? /* @__PURE__ */ new Date();
|
|
25363
25442
|
return this.formatObservationsForContext(record.activeObservations, currentTask, suggestedResponse, omMetadata?.extracted, unobservedContextBlocks, currentDate, this.retrieval);
|
|
25364
25443
|
}
|
|
@@ -25457,7 +25536,10 @@ ${formattedMessages}
|
|
|
25457
25536
|
}
|
|
25458
25537
|
};
|
|
25459
25538
|
omDebug(`[OM:status] step=${stepNumber} msgs=${pendingTokens}/${threshold} obs=${currentObservationTokens}/${effectiveObservationTokensThreshold} gen=${record.generationCount}`);
|
|
25460
|
-
await writer.custom(
|
|
25539
|
+
await writer.custom({
|
|
25540
|
+
...statusPart,
|
|
25541
|
+
transient: true
|
|
25542
|
+
}).catch(() => {});
|
|
25461
25543
|
}
|
|
25462
25544
|
}
|
|
25463
25545
|
/**
|
|
@@ -25483,11 +25565,11 @@ ${formattedMessages}
|
|
|
25483
25565
|
* ```
|
|
25484
25566
|
*/
|
|
25485
25567
|
async getStatus(opts) {
|
|
25486
|
-
const { threadId, resourceId } = opts;
|
|
25487
|
-
const record = await this.getOrCreateRecord(threadId, resourceId);
|
|
25568
|
+
const { threadId, resourceId, record: providedRecord, messages } = opts;
|
|
25569
|
+
const record = providedRecord ?? await this.getOrCreateRecord(threadId, resourceId);
|
|
25488
25570
|
const currentObservationTokens = record.observationTokenCount ?? 0;
|
|
25489
25571
|
let unobservedMessages;
|
|
25490
|
-
if (
|
|
25572
|
+
if (messages) unobservedMessages = this.getUnobservedMessages(messages, record);
|
|
25491
25573
|
else {
|
|
25492
25574
|
const rawMessages = await this.loadMessagesFromStorage(threadId, resourceId, record.lastObservedAt ? new Date(record.lastObservedAt) : void 0);
|
|
25493
25575
|
unobservedMessages = this.getUnobservedMessages(rawMessages, record);
|
|
@@ -25644,6 +25726,7 @@ ${formattedMessages}
|
|
|
25644
25726
|
async buffer(opts) {
|
|
25645
25727
|
const { threadId, resourceId, requestContext, observabilityContext } = opts;
|
|
25646
25728
|
let record = opts.record ?? await this.getOrCreateRecord(threadId, resourceId);
|
|
25729
|
+
const inMemoryRecord = record;
|
|
25647
25730
|
if (!this.buffering.isAsyncObservationEnabled()) return {
|
|
25648
25731
|
buffered: false,
|
|
25649
25732
|
record
|
|
@@ -25662,6 +25745,8 @@ ${formattedMessages}
|
|
|
25662
25745
|
await existingOp;
|
|
25663
25746
|
} catch {}
|
|
25664
25747
|
registerOp(record.id, "bufferingObservation");
|
|
25748
|
+
inMemoryRecord.isBufferingObservation = true;
|
|
25749
|
+
inMemoryRecord.lastBufferedAtTokens = currentTokens;
|
|
25665
25750
|
this.storage.setBufferingObservationFlag(record.id, true, currentTokens).catch((err) => {
|
|
25666
25751
|
omError("[OM] Failed to set buffering observation flag", err);
|
|
25667
25752
|
});
|
|
@@ -25671,6 +25756,14 @@ ${formattedMessages}
|
|
|
25671
25756
|
});
|
|
25672
25757
|
BufferingCoordinator.asyncBufferingOps.set(bufferKey, opPromise);
|
|
25673
25758
|
record = await this.storage.getObservationalMemory(record.threadId, record.resourceId) ?? record;
|
|
25759
|
+
const setBufferingState = (isBufferingObservation, lastBufferedAtTokens) => {
|
|
25760
|
+
inMemoryRecord.isBufferingObservation = isBufferingObservation;
|
|
25761
|
+
record.isBufferingObservation = isBufferingObservation;
|
|
25762
|
+
if (lastBufferedAtTokens !== void 0) {
|
|
25763
|
+
inMemoryRecord.lastBufferedAtTokens = lastBufferedAtTokens;
|
|
25764
|
+
record.lastBufferedAtTokens = lastBufferedAtTokens;
|
|
25765
|
+
}
|
|
25766
|
+
};
|
|
25674
25767
|
let flagCleared = false;
|
|
25675
25768
|
try {
|
|
25676
25769
|
let candidateMessages;
|
|
@@ -25692,10 +25785,13 @@ ${formattedMessages}
|
|
|
25692
25785
|
}
|
|
25693
25786
|
const minNewTokens = (this.observationConfig.bufferTokens ?? 5e3) / 2;
|
|
25694
25787
|
const newTokens = await this.tokenCounter.countMessagesAsync(candidateMessages);
|
|
25695
|
-
if (candidateMessages.length === 0 || !opts.skipMinimumTokenCheck && newTokens < minNewTokens)
|
|
25696
|
-
|
|
25697
|
-
|
|
25698
|
-
|
|
25788
|
+
if (candidateMessages.length === 0 || !opts.skipMinimumTokenCheck && newTokens < minNewTokens) {
|
|
25789
|
+
setBufferingState(false);
|
|
25790
|
+
return {
|
|
25791
|
+
buffered: false,
|
|
25792
|
+
record
|
|
25793
|
+
};
|
|
25794
|
+
}
|
|
25699
25795
|
if (opts.beforeBuffer) await opts.beforeBuffer(candidateMessages);
|
|
25700
25796
|
else if (opts.messages) this.sealMessagesForBuffering(candidateMessages);
|
|
25701
25797
|
const cycleId = `buffer-obs-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
@@ -25750,13 +25846,14 @@ ${formattedMessages}
|
|
|
25750
25846
|
});
|
|
25751
25847
|
await this.storage.setBufferingObservationFlag(record.id, false, newTokens).catch(() => {});
|
|
25752
25848
|
flagCleared = true;
|
|
25849
|
+
setBufferingState(false, newTokens);
|
|
25753
25850
|
BufferingCoordinator.lastBufferedBoundary.set(bufferKey, newTokens);
|
|
25754
25851
|
const maxTimestamp = this.getMaxMessageTimestamp(candidateMessages);
|
|
25755
25852
|
const cursor = new Date(maxTimestamp.getTime() + 1);
|
|
25756
25853
|
BufferingCoordinator.lastBufferedAtTime.set(bufferKey, cursor);
|
|
25757
25854
|
return {
|
|
25758
25855
|
buffered: true,
|
|
25759
|
-
record: await this.
|
|
25856
|
+
record: await this.storage.getObservationalMemory(record.threadId, record.resourceId) ?? record
|
|
25760
25857
|
};
|
|
25761
25858
|
} catch (error) {
|
|
25762
25859
|
omError("[OM] buffer() failed", error);
|
|
@@ -25768,7 +25865,10 @@ ${formattedMessages}
|
|
|
25768
25865
|
unregisterOp(record.id, "bufferingObservation");
|
|
25769
25866
|
BufferingCoordinator.asyncBufferingOps.delete(bufferKey);
|
|
25770
25867
|
resolveOp();
|
|
25771
|
-
if (!flagCleared)
|
|
25868
|
+
if (!flagCleared) {
|
|
25869
|
+
setBufferingState(false);
|
|
25870
|
+
await this.storage.setBufferingObservationFlag(record.id, false).catch(() => {});
|
|
25871
|
+
}
|
|
25772
25872
|
}
|
|
25773
25873
|
}
|
|
25774
25874
|
/**
|
|
@@ -25794,7 +25894,7 @@ ${formattedMessages}
|
|
|
25794
25894
|
/** @internal Used by ObservationStep. */
|
|
25795
25895
|
async activate(opts) {
|
|
25796
25896
|
const { threadId, resourceId } = opts;
|
|
25797
|
-
const record = await this.getOrCreateRecord(threadId, resourceId);
|
|
25897
|
+
const record = opts.record ?? await this.getOrCreateRecord(threadId, resourceId);
|
|
25798
25898
|
if (this.buffering.isAsyncObservationEnabled()) {
|
|
25799
25899
|
const lockKey = this.buffering.getLockKey(threadId, resourceId);
|
|
25800
25900
|
const bufKey = this.buffering.getObservationBufferKey(lockKey);
|
|
@@ -25840,6 +25940,7 @@ ${formattedMessages}
|
|
|
25840
25940
|
const status = await this.getStatus({
|
|
25841
25941
|
threadId,
|
|
25842
25942
|
resourceId,
|
|
25943
|
+
record,
|
|
25843
25944
|
messages: thresholdMessages
|
|
25844
25945
|
});
|
|
25845
25946
|
if (status.pendingTokens < status.threshold) return {
|
|
@@ -26559,31 +26660,30 @@ var ObservationalMemoryProcessor = class {
|
|
|
26559
26660
|
threadId,
|
|
26560
26661
|
resourceId
|
|
26561
26662
|
});
|
|
26562
|
-
const
|
|
26663
|
+
const turnRecord = this.turn.record;
|
|
26563
26664
|
await this.engine.emitProgress({
|
|
26564
|
-
record:
|
|
26665
|
+
record: turnRecord,
|
|
26565
26666
|
stepNumber,
|
|
26566
26667
|
pendingTokens: ctx.status.pendingTokens,
|
|
26567
26668
|
threshold: ctx.status.threshold,
|
|
26568
26669
|
effectiveObservationTokensThreshold: ctx.status.effectiveObservationTokensThreshold,
|
|
26569
|
-
currentObservationTokens:
|
|
26670
|
+
currentObservationTokens: turnRecord.observationTokenCount ?? 0,
|
|
26570
26671
|
writer,
|
|
26571
26672
|
threadId,
|
|
26572
26673
|
resourceId
|
|
26573
26674
|
});
|
|
26574
|
-
const
|
|
26575
|
-
|
|
26576
|
-
|
|
26577
|
-
|
|
26578
|
-
|
|
26579
|
-
await this.engine.getStorage().setPendingMessageTokens(freshRecord.id, finalTotalPending).catch(() => {});
|
|
26675
|
+
const finalTotalPending = ctx.status.pendingTokens;
|
|
26676
|
+
try {
|
|
26677
|
+
await this.engine.getStorage().setPendingMessageTokens(turnRecord.id, finalTotalPending);
|
|
26678
|
+
this.turn.patchRecord({ pendingMessageTokens: finalTotalPending });
|
|
26679
|
+
} catch {}
|
|
26580
26680
|
if (reproCaptureEnabled) writeProcessInputStepReproCapture({
|
|
26581
26681
|
threadId,
|
|
26582
26682
|
resourceId,
|
|
26583
26683
|
stepNumber,
|
|
26584
26684
|
args,
|
|
26585
26685
|
preRecord: preRecordSnapshot,
|
|
26586
|
-
postRecord: safeCaptureJson(
|
|
26686
|
+
postRecord: safeCaptureJson(turnRecord),
|
|
26587
26687
|
preMessages: preMessagesSnapshot,
|
|
26588
26688
|
preBufferedChunks: [],
|
|
26589
26689
|
preContextTokenCount: 0,
|
|
@@ -28950,4 +29050,4 @@ Object.defineProperty(exports, "wrapInObservationGroup", {
|
|
|
28950
29050
|
}
|
|
28951
29051
|
});
|
|
28952
29052
|
|
|
28953
|
-
//# sourceMappingURL=src-
|
|
29053
|
+
//# sourceMappingURL=src-_7ADtEwc.cjs.map
|