@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
|
@@ -15925,21 +15925,17 @@ Or as a standalone observation when closing out a broader task:
|
|
|
15925
15925
|
Completion observations should be terse but specific about WHAT was completed.
|
|
15926
15926
|
Prefer concrete resolved outcomes over abstract workflow status so the assistant remembers what is already done.`;
|
|
15927
15927
|
buildObserverOutputFormat();
|
|
15928
|
-
|
|
15929
|
-
|
|
15930
|
-
|
|
15931
|
-
|
|
15932
|
-
|
|
15933
|
-
|
|
15934
|
-
|
|
15935
|
-
|
|
15936
|
-
|
|
15937
|
-
|
|
15938
|
-
|
|
15939
|
-
- "I've updated the navigation model. Let me walk you through the changes..."
|
|
15940
|
-
- "The assistant should wait for the user to respond before continuing."
|
|
15941
|
-
- Call the view tool on src/example.ts to continue debugging.
|
|
15942
|
-
</suggested-response>` : "";
|
|
15928
|
+
/**
|
|
15929
|
+
* Build the Observer's output format.
|
|
15930
|
+
*
|
|
15931
|
+
* `extractors` distinguishes two cases that both look empty:
|
|
15932
|
+
* - `undefined` — the no-arg call behind the exported defaults (OBSERVER_OUTPUT_FORMAT_BASE,
|
|
15933
|
+
* OBSERVER_SYSTEM_PROMPT, REFLECTOR_SYSTEM_PROMPT), which keep describing both built-in
|
|
15934
|
+
* sections with their historical text. Runtime callers always pass the composed list.
|
|
15935
|
+
* - `[]` — the caller composed extractors and every section was disabled, so no continuation
|
|
15936
|
+
* sections are described at all.
|
|
15937
|
+
*/
|
|
15938
|
+
function buildObserverOutputFormat(extractors) {
|
|
15943
15939
|
return `Use priority levels:
|
|
15944
15940
|
- 🔴 High: explicit user facts, preferences, unresolved goals, critical context
|
|
15945
15941
|
- 🟡 Medium: project details, learned information, tool results
|
|
@@ -15965,7 +15961,19 @@ Date: Dec 5, 2025
|
|
|
15965
15961
|
* 🔴 (09:15) Continued work on feature X
|
|
15966
15962
|
</observations>
|
|
15967
15963
|
|
|
15968
|
-
${
|
|
15964
|
+
${buildExtractorOutputSections(extractors ?? []) || (extractors === void 0 ? `
|
|
15965
|
+
<current-task>
|
|
15966
|
+
State the current task(s) explicitly:
|
|
15967
|
+
- Primary: What the agent is currently working on
|
|
15968
|
+
- Secondary: Other pending tasks (mark as "waiting for user" if appropriate)
|
|
15969
|
+
</current-task>
|
|
15970
|
+
|
|
15971
|
+
<suggested-response>
|
|
15972
|
+
Hint for the agent's immediate next message. Examples:
|
|
15973
|
+
- "I've updated the navigation model. Let me walk you through the changes..."
|
|
15974
|
+
- "The assistant should wait for the user to respond before continuing."
|
|
15975
|
+
- Call the view tool on src/example.ts to continue debugging.
|
|
15976
|
+
</suggested-response>` : "")}`;
|
|
15969
15977
|
}
|
|
15970
15978
|
/**
|
|
15971
15979
|
* The guidelines for the Observer.
|
|
@@ -15992,10 +16000,22 @@ const OBSERVER_GUIDELINES = `- Be specific enough for the assistant to act on
|
|
|
15992
16000
|
* Build the complete observer system prompt.
|
|
15993
16001
|
* @param multiThread - Whether this is for multi-thread batched observation (default: false)
|
|
15994
16002
|
* @param instruction - Optional custom instructions to append to the prompt
|
|
16003
|
+
* @param includeThreadTitle - Whether the Observer should also produce a thread title
|
|
16004
|
+
* @param extractors - Active extractors, used to decide which sections the prompt describes.
|
|
16005
|
+
* Omitted only by the exported no-arg defaults; pass `[]` to describe no continuation sections at all.
|
|
15995
16006
|
*/
|
|
15996
|
-
function buildObserverSystemPrompt(multiThread = false, instruction, includeThreadTitle = false, extractors
|
|
16007
|
+
function buildObserverSystemPrompt(multiThread = false, instruction, includeThreadTitle = false, extractors) {
|
|
15997
16008
|
const outputFormat = buildObserverOutputFormat(extractors);
|
|
15998
|
-
const
|
|
16009
|
+
const customInstructions = instruction ? `\n\n=== CUSTOM INSTRUCTIONS ===\n\n${instruction}` : "";
|
|
16010
|
+
const currentTaskEnabled = extractors === void 0 || extractors.some((extractor) => extractor.slug === "current-task");
|
|
16011
|
+
const suggestedResponseEnabled = extractors === void 0 || extractors.some((extractor) => extractor.slug === "suggested-response");
|
|
16012
|
+
const multiThreadSections = [
|
|
16013
|
+
"observations",
|
|
16014
|
+
...currentTaskEnabled ? ["current-task"] : [],
|
|
16015
|
+
...suggestedResponseEnabled ? ["suggested-response"] : [],
|
|
16016
|
+
...includeThreadTitle ? ["thread-title"] : []
|
|
16017
|
+
];
|
|
16018
|
+
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>.`;
|
|
15999
16019
|
const multiThreadTitleExample = includeThreadTitle ? `
|
|
16000
16020
|
<thread-title>Feature X implementation</thread-title>` : "";
|
|
16001
16021
|
const multiThreadSecondTitleExample = includeThreadTitle ? `
|
|
@@ -16025,28 +16045,28 @@ For multi-thread output, wrap each thread's observations like this:
|
|
|
16025
16045
|
<thread id="thread_id_1">
|
|
16026
16046
|
Date: Dec 4, 2025
|
|
16027
16047
|
* 🔴 (14:30) User prefers direct answers
|
|
16028
|
-
* 🔴 (14:31) Working on feature X
|
|
16048
|
+
* 🔴 (14:31) Working on feature X${currentTaskEnabled ? `
|
|
16029
16049
|
|
|
16030
16050
|
<current-task>
|
|
16031
16051
|
What the agent is currently working on in this thread
|
|
16032
|
-
</current-task
|
|
16052
|
+
</current-task>` : ""}${suggestedResponseEnabled ? `
|
|
16033
16053
|
|
|
16034
16054
|
<suggested-response>
|
|
16035
16055
|
Hint for the agent's next message in this thread
|
|
16036
|
-
</suggested-response
|
|
16056
|
+
</suggested-response>` : ""}${multiThreadTitleExample}
|
|
16037
16057
|
</thread>
|
|
16038
16058
|
|
|
16039
16059
|
<thread id="thread_id_2">
|
|
16040
16060
|
Date: Dec 5, 2025
|
|
16041
|
-
* 🔴 (09:15) User asked about deployment
|
|
16061
|
+
* 🔴 (09:15) User asked about deployment${currentTaskEnabled ? `
|
|
16042
16062
|
|
|
16043
16063
|
<current-task>
|
|
16044
16064
|
Current task for this thread
|
|
16045
|
-
</current-task
|
|
16065
|
+
</current-task>` : ""}${suggestedResponseEnabled ? `
|
|
16046
16066
|
|
|
16047
16067
|
<suggested-response>
|
|
16048
16068
|
Suggested response for this thread
|
|
16049
|
-
</suggested-response
|
|
16069
|
+
</suggested-response>` : ""}${multiThreadSecondTitleExample}
|
|
16050
16070
|
</thread>
|
|
16051
16071
|
</observations>
|
|
16052
16072
|
|
|
@@ -16056,7 +16076,7 @@ ${OBSERVER_GUIDELINES}
|
|
|
16056
16076
|
|
|
16057
16077
|
Remember: These observations are the assistant's ONLY memory. Make them count.
|
|
16058
16078
|
|
|
16059
|
-
User messages are extremely important
|
|
16079
|
+
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}`;
|
|
16060
16080
|
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.
|
|
16061
16081
|
|
|
16062
16082
|
Extract observations that will help the assistant remember:
|
|
@@ -16081,7 +16101,7 @@ Simply output your observations without any thread-related markup.
|
|
|
16081
16101
|
|
|
16082
16102
|
Remember: These observations are the assistant's ONLY memory. Make them count.
|
|
16083
16103
|
|
|
16084
|
-
User messages are extremely important
|
|
16104
|
+
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}`;
|
|
16085
16105
|
}
|
|
16086
16106
|
/**
|
|
16087
16107
|
* Observer Agent System Prompt (default - for backwards compatibility)
|
|
@@ -16773,7 +16793,7 @@ function optimizeObservationsForContext(observations) {
|
|
|
16773
16793
|
let optimized = stripEphemeralAnchorIds(observations);
|
|
16774
16794
|
optimized = optimized.replace(/🟡\s*/g, "");
|
|
16775
16795
|
optimized = optimized.replace(/🟢\s*/g, "");
|
|
16776
|
-
optimized = optimized.replace(/\[(?![\d\s]*items collapsed)[^\]]+\]/g, "");
|
|
16796
|
+
optimized = optimized.replace(/\[(?![\d\s]*items collapsed)[^\]]+\](?!\()/g, "");
|
|
16777
16797
|
optimized = optimized.replace(/\s*->\s*/g, " ");
|
|
16778
16798
|
optimized = optimized.replace(/ +/g, " ");
|
|
16779
16799
|
optimized = optimized.replace(/\n{3,}/g, "\n\n");
|
|
@@ -18195,6 +18215,7 @@ var TokenCounter = class TokenCounter {
|
|
|
18195
18215
|
defaultModelContext;
|
|
18196
18216
|
modelContextStorage = new AsyncLocalStorage();
|
|
18197
18217
|
inFlightAttachmentCounts = /* @__PURE__ */ new Map();
|
|
18218
|
+
multimodalToolResultCounts = /* @__PURE__ */ new WeakMap();
|
|
18198
18219
|
static TOKENS_PER_MESSAGE = 3.8;
|
|
18199
18220
|
static TOKENS_PER_CONVERSATION = 24;
|
|
18200
18221
|
constructor(options) {
|
|
@@ -18257,6 +18278,9 @@ var TokenCounter = class TokenCounter {
|
|
|
18257
18278
|
}
|
|
18258
18279
|
countMultimodalToolResultContent(part, toolResult) {
|
|
18259
18280
|
if (!toolResult || typeof toolResult !== "object") return;
|
|
18281
|
+
const resultKey = buildEstimateKey("tool-result-multimodal-content-source", JSON.stringify(toolResult));
|
|
18282
|
+
const cached = this.multimodalToolResultCounts.get(part);
|
|
18283
|
+
if (cached?.resultKey === resultKey) return cached.tokens;
|
|
18260
18284
|
const output = toolResult;
|
|
18261
18285
|
const content = output.type === "content" && Array.isArray(output.value) ? output.value : output.content;
|
|
18262
18286
|
if (!Array.isArray(content)) return;
|
|
@@ -18368,10 +18392,15 @@ var TokenCounter = class TokenCounter {
|
|
|
18368
18392
|
countJsonContentPart(contentPart);
|
|
18369
18393
|
}
|
|
18370
18394
|
if (!hasAttachment) return;
|
|
18371
|
-
|
|
18395
|
+
const estimate = this.readOrPersistFixedPartEstimate(part, "tool-result-multimodal-content", JSON.stringify({
|
|
18372
18396
|
type: "content",
|
|
18373
18397
|
value: cacheParts
|
|
18374
18398
|
}), tokens);
|
|
18399
|
+
this.multimodalToolResultCounts.set(part, {
|
|
18400
|
+
resultKey,
|
|
18401
|
+
tokens: estimate
|
|
18402
|
+
});
|
|
18403
|
+
return estimate;
|
|
18375
18404
|
}
|
|
18376
18405
|
estimateImageAssetTokens(part, asset, kind) {
|
|
18377
18406
|
const modelContext = this.getModelContext();
|
|
@@ -19853,21 +19882,22 @@ const SET_WORKING_MEMORY_TOOL_NAME = "setWorkingMemory";
|
|
|
19853
19882
|
/**
|
|
19854
19883
|
* Deep merges two objects, with special handling for null values (delete) and arrays (replace).
|
|
19855
19884
|
* - Object properties are recursively merged
|
|
19856
|
-
* - null values in the update will delete the corresponding property
|
|
19885
|
+
* - null values in the update will delete the corresponding property, even when the property
|
|
19886
|
+
* or its parent object does not exist yet (so padded nulls never get stored literally)
|
|
19857
19887
|
* - Arrays are replaced entirely (not merged element-by-element)
|
|
19858
19888
|
* - Primitive values are overwritten
|
|
19889
|
+
* - The returned object is always newly constructed and never aliases `update`
|
|
19859
19890
|
*/
|
|
19860
19891
|
function deepMergeWorkingMemory(existing, update) {
|
|
19861
19892
|
if (!update || typeof update !== "object" || Object.keys(update).length === 0) return existing && typeof existing === "object" ? { ...existing } : {};
|
|
19862
|
-
|
|
19863
|
-
const result = { ...existing };
|
|
19893
|
+
const result = { ...existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {} };
|
|
19864
19894
|
for (const key of Object.keys(update)) {
|
|
19865
19895
|
const updateValue = update[key];
|
|
19866
19896
|
const existingValue = result[key];
|
|
19867
19897
|
if (updateValue === void 0) continue;
|
|
19868
19898
|
if (updateValue === null) delete result[key];
|
|
19869
19899
|
else if (Array.isArray(updateValue)) result[key] = updateValue;
|
|
19870
|
-
else if (typeof updateValue === "object"
|
|
19900
|
+
else if (typeof updateValue === "object") result[key] = deepMergeWorkingMemory(existingValue && typeof existingValue === "object" && !Array.isArray(existingValue) ? existingValue : void 0, updateValue);
|
|
19871
19901
|
else result[key] = updateValue;
|
|
19872
19902
|
}
|
|
19873
19903
|
return result;
|
|
@@ -20358,23 +20388,43 @@ function createThreadTitleExtractor() {
|
|
|
20358
20388
|
metadataKeyPath: "threadTitle"
|
|
20359
20389
|
}, true);
|
|
20360
20390
|
}
|
|
20391
|
+
/**
|
|
20392
|
+
* Normalize the user-facing `continuationHints` config into explicit per-section flags.
|
|
20393
|
+
* Both sections stay enabled unless the caller opts out, so omitting the config is a no-op.
|
|
20394
|
+
*/
|
|
20395
|
+
function resolveContinuationHints(config) {
|
|
20396
|
+
if (config === void 0 || config === true) return {
|
|
20397
|
+
currentTask: true,
|
|
20398
|
+
suggestedResponse: true
|
|
20399
|
+
};
|
|
20400
|
+
if (config === false) return {
|
|
20401
|
+
currentTask: false,
|
|
20402
|
+
suggestedResponse: false
|
|
20403
|
+
};
|
|
20404
|
+
return {
|
|
20405
|
+
currentTask: config.currentTask ?? true,
|
|
20406
|
+
suggestedResponse: config.suggestedResponse ?? true
|
|
20407
|
+
};
|
|
20408
|
+
}
|
|
20361
20409
|
function composeExtractors(options) {
|
|
20410
|
+
const continuationHints = resolveContinuationHints(options.continuationHints);
|
|
20362
20411
|
const extractors = [];
|
|
20363
|
-
if (
|
|
20412
|
+
if (continuationHints.currentTask) extractors.push(createCurrentTaskExtractor());
|
|
20413
|
+
if (continuationHints.suggestedResponse) extractors.push(createSuggestedResponseExtractor());
|
|
20364
20414
|
if (options.includeThreadTitle) extractors.push(createThreadTitleExtractor());
|
|
20365
20415
|
extractors.push(...options.userExtractors ?? []);
|
|
20366
20416
|
return validateExtractorList(extractors);
|
|
20367
20417
|
}
|
|
20368
20418
|
function composeObservationExtractors(config) {
|
|
20369
20419
|
return composeExtractors({
|
|
20370
|
-
|
|
20420
|
+
continuationHints: config.continuationHints,
|
|
20371
20421
|
includeThreadTitle: config.threadTitle,
|
|
20372
20422
|
userExtractors: config.extract
|
|
20373
20423
|
});
|
|
20374
20424
|
}
|
|
20375
20425
|
function composeReflectionExtractors(config) {
|
|
20376
20426
|
return composeExtractors({
|
|
20377
|
-
|
|
20427
|
+
continuationHints: config.continuationHints,
|
|
20378
20428
|
userExtractors: config.extract
|
|
20379
20429
|
});
|
|
20380
20430
|
}
|
|
@@ -22159,10 +22209,12 @@ var ObservationStep = class {
|
|
|
22159
22209
|
resourceId,
|
|
22160
22210
|
checkThreshold: true,
|
|
22161
22211
|
messages: step0Messages,
|
|
22212
|
+
record: this.turn.record,
|
|
22162
22213
|
currentModel: this.turn.actorModelContext,
|
|
22163
22214
|
writer: this.turn.writer,
|
|
22164
22215
|
messageList
|
|
22165
22216
|
});
|
|
22217
|
+
this.turn.setRecord(activation.record);
|
|
22166
22218
|
if (activation.activated) {
|
|
22167
22219
|
activated = true;
|
|
22168
22220
|
if (activation.activatedMessageIds?.length) messageList.removeByIds(activation.activatedMessageIds);
|
|
@@ -22204,6 +22256,7 @@ var ObservationStep = class {
|
|
|
22204
22256
|
let statusSnapshot = await om.getStatus({
|
|
22205
22257
|
threadId,
|
|
22206
22258
|
resourceId,
|
|
22259
|
+
record: this.turn.record,
|
|
22207
22260
|
messages: getObservableMessages(messageList)
|
|
22208
22261
|
});
|
|
22209
22262
|
if (statusSnapshot.shouldBuffer && !hasIncompleteToolCalls) {
|
|
@@ -22299,6 +22352,7 @@ var ObservationStep = class {
|
|
|
22299
22352
|
statusSnapshot = await om.getStatus({
|
|
22300
22353
|
threadId,
|
|
22301
22354
|
resourceId,
|
|
22355
|
+
record: this.turn.record,
|
|
22302
22356
|
messages: getObservableMessages(messageList)
|
|
22303
22357
|
});
|
|
22304
22358
|
}
|
|
@@ -22349,10 +22403,12 @@ var ObservationStep = class {
|
|
|
22349
22403
|
const { threadId, resourceId, messageList } = this.turn;
|
|
22350
22404
|
const om = this.turn.om;
|
|
22351
22405
|
await om.waitForBuffering(threadId, resourceId);
|
|
22406
|
+
await this.turn.refreshRecord();
|
|
22352
22407
|
const observableMessages = this.seededResponseMessage ? getObservableMessages(messageList).filter((msg) => msg.id !== this.turn.responseMessageId) : getObservableMessages(messageList);
|
|
22353
22408
|
const freshStatus = await om.getStatus({
|
|
22354
22409
|
threadId,
|
|
22355
22410
|
resourceId,
|
|
22411
|
+
record: this.turn.record,
|
|
22356
22412
|
messages: observableMessages
|
|
22357
22413
|
});
|
|
22358
22414
|
if (!freshStatus.shouldObserve) return {
|
|
@@ -22363,11 +22419,13 @@ var ObservationStep = class {
|
|
|
22363
22419
|
const activation = await om.activate({
|
|
22364
22420
|
threadId,
|
|
22365
22421
|
resourceId,
|
|
22422
|
+
record: this.turn.record,
|
|
22366
22423
|
messages: observableMessages,
|
|
22367
22424
|
currentModel: this.turn.actorModelContext,
|
|
22368
22425
|
writer: this.turn.writer,
|
|
22369
22426
|
messageList
|
|
22370
22427
|
});
|
|
22428
|
+
this.turn.setRecord(activation.record);
|
|
22371
22429
|
if (activation.activated) {
|
|
22372
22430
|
const postActivationRecord = activation.record;
|
|
22373
22431
|
await om.reflector.maybeReflect({
|
|
@@ -22552,6 +22610,18 @@ var ObservationTurn = class {
|
|
|
22552
22610
|
};
|
|
22553
22611
|
return this._context;
|
|
22554
22612
|
}
|
|
22613
|
+
/** Replace the cached turn record with a specific instance. */
|
|
22614
|
+
setRecord(record) {
|
|
22615
|
+
this._record = record;
|
|
22616
|
+
if (this._context) this._context.record = record;
|
|
22617
|
+
}
|
|
22618
|
+
/** Patch the cached turn record with merged fields. */
|
|
22619
|
+
patchRecord(patch) {
|
|
22620
|
+
this.setRecord({
|
|
22621
|
+
...this.record,
|
|
22622
|
+
...patch
|
|
22623
|
+
});
|
|
22624
|
+
}
|
|
22555
22625
|
/**
|
|
22556
22626
|
* Create a step handle. If a previous step exists, it is finalized
|
|
22557
22627
|
* (its output messages will be saved at the start of the new step's prepare()).
|
|
@@ -22606,7 +22676,7 @@ var ObservationTurn = class {
|
|
|
22606
22676
|
* @internal
|
|
22607
22677
|
*/
|
|
22608
22678
|
async refreshRecord() {
|
|
22609
|
-
this.
|
|
22679
|
+
this.setRecord(await this.om.getOrCreateRecord(this.threadId, this.resourceId));
|
|
22610
22680
|
}
|
|
22611
22681
|
/**
|
|
22612
22682
|
* Refresh cross-thread context for resource scope. Called per-step.
|
|
@@ -22661,9 +22731,13 @@ var ObservationTurn = class {
|
|
|
22661
22731
|
* - Preserving ALL important information (reflections become the ENTIRE memory)
|
|
22662
22732
|
*
|
|
22663
22733
|
* @param instruction - Optional custom instructions to append to the prompt
|
|
22734
|
+
* @param extractors - Active extractors, used to decide which sections the prompt describes
|
|
22664
22735
|
*/
|
|
22665
|
-
function buildReflectorSystemPrompt(instruction, extractors
|
|
22736
|
+
function buildReflectorSystemPrompt(instruction, extractors) {
|
|
22666
22737
|
const outputFormat = buildObserverOutputFormat(extractors);
|
|
22738
|
+
const customInstructions = instruction ? `\n\n=== CUSTOM INSTRUCTIONS ===\n\n${instruction}` : "";
|
|
22739
|
+
const currentTaskEnabled = extractors === void 0 || extractors.some((extractor) => extractor.slug === "current-task");
|
|
22740
|
+
const suggestedResponseEnabled = extractors === void 0 || extractors.some((extractor) => extractor.slug === "suggested-response");
|
|
22667
22741
|
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.
|
|
22668
22742
|
|
|
22669
22743
|
The following instructions were given to another part of your psyche (the observer) to create memories.
|
|
@@ -22740,7 +22814,7 @@ Date: Dec 4, 2025
|
|
|
22740
22814
|
|
|
22741
22815
|
${outputFormat}
|
|
22742
22816
|
|
|
22743
|
-
User messages are extremely important
|
|
22817
|
+
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}`;
|
|
22744
22818
|
}
|
|
22745
22819
|
buildReflectorSystemPrompt();
|
|
22746
22820
|
/**
|
|
@@ -24204,7 +24278,8 @@ var ObservationalMemory = class ObservationalMemory {
|
|
|
24204
24278
|
observeAttachments: config.observation?.observeAttachments ?? true,
|
|
24205
24279
|
extractors: composeObservationExtractors({
|
|
24206
24280
|
threadTitle: config.observation?.threadTitle ?? false,
|
|
24207
|
-
extract: config.observation?.extract
|
|
24281
|
+
extract: config.observation?.extract,
|
|
24282
|
+
continuationHints: config.observation?.continuationHints
|
|
24208
24283
|
})
|
|
24209
24284
|
};
|
|
24210
24285
|
this.reflectionConfig = {
|
|
@@ -24221,7 +24296,10 @@ var ObservationalMemory = class ObservationalMemory {
|
|
|
24221
24296
|
activateOnProviderChange: config.reflection?.activateOnProviderChange ?? false,
|
|
24222
24297
|
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),
|
|
24223
24298
|
instruction: config.reflection?.instruction,
|
|
24224
|
-
extractors: composeReflectionExtractors({
|
|
24299
|
+
extractors: composeReflectionExtractors({
|
|
24300
|
+
extract: config.reflection?.extract,
|
|
24301
|
+
continuationHints: config.reflection?.continuationHints
|
|
24302
|
+
})
|
|
24225
24303
|
};
|
|
24226
24304
|
this.tokenCounter = new TokenCounter({ model: typeof observationModel === "string" ? observationModel : void 0 });
|
|
24227
24305
|
this.onDebugEvent = config.onDebugEvent;
|
|
@@ -25336,8 +25414,9 @@ ${formattedMessages}
|
|
|
25336
25414
|
return;
|
|
25337
25415
|
}
|
|
25338
25416
|
const omMetadata = getThreadOMMetadata((await this.storage.getThreadById({ threadId }))?.metadata);
|
|
25339
|
-
const
|
|
25340
|
-
const
|
|
25417
|
+
const activeExtractors = [...this.observationConfig.extractors, ...this.reflectionConfig.extractors];
|
|
25418
|
+
const currentTask = activeExtractors.some((extractor) => extractor.slug === "current-task") ? omMetadata?.currentTask : void 0;
|
|
25419
|
+
const suggestedResponse = activeExtractors.some((extractor) => extractor.slug === "suggested-response") ? omMetadata?.suggestedResponse : void 0;
|
|
25341
25420
|
const currentDate = opts.currentDate ?? /* @__PURE__ */ new Date();
|
|
25342
25421
|
return this.formatObservationsForContext(record.activeObservations, currentTask, suggestedResponse, omMetadata?.extracted, unobservedContextBlocks, currentDate, this.retrieval);
|
|
25343
25422
|
}
|
|
@@ -25436,7 +25515,10 @@ ${formattedMessages}
|
|
|
25436
25515
|
}
|
|
25437
25516
|
};
|
|
25438
25517
|
omDebug(`[OM:status] step=${stepNumber} msgs=${pendingTokens}/${threshold} obs=${currentObservationTokens}/${effectiveObservationTokensThreshold} gen=${record.generationCount}`);
|
|
25439
|
-
await writer.custom(
|
|
25518
|
+
await writer.custom({
|
|
25519
|
+
...statusPart,
|
|
25520
|
+
transient: true
|
|
25521
|
+
}).catch(() => {});
|
|
25440
25522
|
}
|
|
25441
25523
|
}
|
|
25442
25524
|
/**
|
|
@@ -25462,11 +25544,11 @@ ${formattedMessages}
|
|
|
25462
25544
|
* ```
|
|
25463
25545
|
*/
|
|
25464
25546
|
async getStatus(opts) {
|
|
25465
|
-
const { threadId, resourceId } = opts;
|
|
25466
|
-
const record = await this.getOrCreateRecord(threadId, resourceId);
|
|
25547
|
+
const { threadId, resourceId, record: providedRecord, messages } = opts;
|
|
25548
|
+
const record = providedRecord ?? await this.getOrCreateRecord(threadId, resourceId);
|
|
25467
25549
|
const currentObservationTokens = record.observationTokenCount ?? 0;
|
|
25468
25550
|
let unobservedMessages;
|
|
25469
|
-
if (
|
|
25551
|
+
if (messages) unobservedMessages = this.getUnobservedMessages(messages, record);
|
|
25470
25552
|
else {
|
|
25471
25553
|
const rawMessages = await this.loadMessagesFromStorage(threadId, resourceId, record.lastObservedAt ? new Date(record.lastObservedAt) : void 0);
|
|
25472
25554
|
unobservedMessages = this.getUnobservedMessages(rawMessages, record);
|
|
@@ -25623,6 +25705,7 @@ ${formattedMessages}
|
|
|
25623
25705
|
async buffer(opts) {
|
|
25624
25706
|
const { threadId, resourceId, requestContext, observabilityContext } = opts;
|
|
25625
25707
|
let record = opts.record ?? await this.getOrCreateRecord(threadId, resourceId);
|
|
25708
|
+
const inMemoryRecord = record;
|
|
25626
25709
|
if (!this.buffering.isAsyncObservationEnabled()) return {
|
|
25627
25710
|
buffered: false,
|
|
25628
25711
|
record
|
|
@@ -25641,6 +25724,8 @@ ${formattedMessages}
|
|
|
25641
25724
|
await existingOp;
|
|
25642
25725
|
} catch {}
|
|
25643
25726
|
registerOp(record.id, "bufferingObservation");
|
|
25727
|
+
inMemoryRecord.isBufferingObservation = true;
|
|
25728
|
+
inMemoryRecord.lastBufferedAtTokens = currentTokens;
|
|
25644
25729
|
this.storage.setBufferingObservationFlag(record.id, true, currentTokens).catch((err) => {
|
|
25645
25730
|
omError("[OM] Failed to set buffering observation flag", err);
|
|
25646
25731
|
});
|
|
@@ -25650,6 +25735,14 @@ ${formattedMessages}
|
|
|
25650
25735
|
});
|
|
25651
25736
|
BufferingCoordinator.asyncBufferingOps.set(bufferKey, opPromise);
|
|
25652
25737
|
record = await this.storage.getObservationalMemory(record.threadId, record.resourceId) ?? record;
|
|
25738
|
+
const setBufferingState = (isBufferingObservation, lastBufferedAtTokens) => {
|
|
25739
|
+
inMemoryRecord.isBufferingObservation = isBufferingObservation;
|
|
25740
|
+
record.isBufferingObservation = isBufferingObservation;
|
|
25741
|
+
if (lastBufferedAtTokens !== void 0) {
|
|
25742
|
+
inMemoryRecord.lastBufferedAtTokens = lastBufferedAtTokens;
|
|
25743
|
+
record.lastBufferedAtTokens = lastBufferedAtTokens;
|
|
25744
|
+
}
|
|
25745
|
+
};
|
|
25653
25746
|
let flagCleared = false;
|
|
25654
25747
|
try {
|
|
25655
25748
|
let candidateMessages;
|
|
@@ -25671,10 +25764,13 @@ ${formattedMessages}
|
|
|
25671
25764
|
}
|
|
25672
25765
|
const minNewTokens = (this.observationConfig.bufferTokens ?? 5e3) / 2;
|
|
25673
25766
|
const newTokens = await this.tokenCounter.countMessagesAsync(candidateMessages);
|
|
25674
|
-
if (candidateMessages.length === 0 || !opts.skipMinimumTokenCheck && newTokens < minNewTokens)
|
|
25675
|
-
|
|
25676
|
-
|
|
25677
|
-
|
|
25767
|
+
if (candidateMessages.length === 0 || !opts.skipMinimumTokenCheck && newTokens < minNewTokens) {
|
|
25768
|
+
setBufferingState(false);
|
|
25769
|
+
return {
|
|
25770
|
+
buffered: false,
|
|
25771
|
+
record
|
|
25772
|
+
};
|
|
25773
|
+
}
|
|
25678
25774
|
if (opts.beforeBuffer) await opts.beforeBuffer(candidateMessages);
|
|
25679
25775
|
else if (opts.messages) this.sealMessagesForBuffering(candidateMessages);
|
|
25680
25776
|
const cycleId = `buffer-obs-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
@@ -25729,13 +25825,14 @@ ${formattedMessages}
|
|
|
25729
25825
|
});
|
|
25730
25826
|
await this.storage.setBufferingObservationFlag(record.id, false, newTokens).catch(() => {});
|
|
25731
25827
|
flagCleared = true;
|
|
25828
|
+
setBufferingState(false, newTokens);
|
|
25732
25829
|
BufferingCoordinator.lastBufferedBoundary.set(bufferKey, newTokens);
|
|
25733
25830
|
const maxTimestamp = this.getMaxMessageTimestamp(candidateMessages);
|
|
25734
25831
|
const cursor = new Date(maxTimestamp.getTime() + 1);
|
|
25735
25832
|
BufferingCoordinator.lastBufferedAtTime.set(bufferKey, cursor);
|
|
25736
25833
|
return {
|
|
25737
25834
|
buffered: true,
|
|
25738
|
-
record: await this.
|
|
25835
|
+
record: await this.storage.getObservationalMemory(record.threadId, record.resourceId) ?? record
|
|
25739
25836
|
};
|
|
25740
25837
|
} catch (error) {
|
|
25741
25838
|
omError("[OM] buffer() failed", error);
|
|
@@ -25747,7 +25844,10 @@ ${formattedMessages}
|
|
|
25747
25844
|
unregisterOp(record.id, "bufferingObservation");
|
|
25748
25845
|
BufferingCoordinator.asyncBufferingOps.delete(bufferKey);
|
|
25749
25846
|
resolveOp();
|
|
25750
|
-
if (!flagCleared)
|
|
25847
|
+
if (!flagCleared) {
|
|
25848
|
+
setBufferingState(false);
|
|
25849
|
+
await this.storage.setBufferingObservationFlag(record.id, false).catch(() => {});
|
|
25850
|
+
}
|
|
25751
25851
|
}
|
|
25752
25852
|
}
|
|
25753
25853
|
/**
|
|
@@ -25773,7 +25873,7 @@ ${formattedMessages}
|
|
|
25773
25873
|
/** @internal Used by ObservationStep. */
|
|
25774
25874
|
async activate(opts) {
|
|
25775
25875
|
const { threadId, resourceId } = opts;
|
|
25776
|
-
const record = await this.getOrCreateRecord(threadId, resourceId);
|
|
25876
|
+
const record = opts.record ?? await this.getOrCreateRecord(threadId, resourceId);
|
|
25777
25877
|
if (this.buffering.isAsyncObservationEnabled()) {
|
|
25778
25878
|
const lockKey = this.buffering.getLockKey(threadId, resourceId);
|
|
25779
25879
|
const bufKey = this.buffering.getObservationBufferKey(lockKey);
|
|
@@ -25819,6 +25919,7 @@ ${formattedMessages}
|
|
|
25819
25919
|
const status = await this.getStatus({
|
|
25820
25920
|
threadId,
|
|
25821
25921
|
resourceId,
|
|
25922
|
+
record,
|
|
25822
25923
|
messages: thresholdMessages
|
|
25823
25924
|
});
|
|
25824
25925
|
if (status.pendingTokens < status.threshold) return {
|
|
@@ -26538,31 +26639,30 @@ var ObservationalMemoryProcessor = class {
|
|
|
26538
26639
|
threadId,
|
|
26539
26640
|
resourceId
|
|
26540
26641
|
});
|
|
26541
|
-
const
|
|
26642
|
+
const turnRecord = this.turn.record;
|
|
26542
26643
|
await this.engine.emitProgress({
|
|
26543
|
-
record:
|
|
26644
|
+
record: turnRecord,
|
|
26544
26645
|
stepNumber,
|
|
26545
26646
|
pendingTokens: ctx.status.pendingTokens,
|
|
26546
26647
|
threshold: ctx.status.threshold,
|
|
26547
26648
|
effectiveObservationTokensThreshold: ctx.status.effectiveObservationTokensThreshold,
|
|
26548
|
-
currentObservationTokens:
|
|
26649
|
+
currentObservationTokens: turnRecord.observationTokenCount ?? 0,
|
|
26549
26650
|
writer,
|
|
26550
26651
|
threadId,
|
|
26551
26652
|
resourceId
|
|
26552
26653
|
});
|
|
26553
|
-
const
|
|
26554
|
-
|
|
26555
|
-
|
|
26556
|
-
|
|
26557
|
-
|
|
26558
|
-
await this.engine.getStorage().setPendingMessageTokens(freshRecord.id, finalTotalPending).catch(() => {});
|
|
26654
|
+
const finalTotalPending = ctx.status.pendingTokens;
|
|
26655
|
+
try {
|
|
26656
|
+
await this.engine.getStorage().setPendingMessageTokens(turnRecord.id, finalTotalPending);
|
|
26657
|
+
this.turn.patchRecord({ pendingMessageTokens: finalTotalPending });
|
|
26658
|
+
} catch {}
|
|
26559
26659
|
if (reproCaptureEnabled) writeProcessInputStepReproCapture({
|
|
26560
26660
|
threadId,
|
|
26561
26661
|
resourceId,
|
|
26562
26662
|
stepNumber,
|
|
26563
26663
|
args,
|
|
26564
26664
|
preRecord: preRecordSnapshot,
|
|
26565
|
-
postRecord: safeCaptureJson(
|
|
26665
|
+
postRecord: safeCaptureJson(turnRecord),
|
|
26566
26666
|
preMessages: preMessagesSnapshot,
|
|
26567
26667
|
preBufferedChunks: [],
|
|
26568
26668
|
preContextTokenCount: 0,
|
|
@@ -28696,4 +28796,4 @@ Notes:
|
|
|
28696
28796
|
//#endregion
|
|
28697
28797
|
export { extractCurrentTask as A, OBSERVATION_CONTEXT_INSTRUCTIONS as B, WorkingMemoryExtractor as C, OBSERVER_SYSTEM_PROMPT as D, TokenCounter as E, injectAnchorIds as F, OBSERVATION_CONTINUATION_HINT as H, parseAnchorId as I, stripEphemeralAnchorIds as L, hasCurrentTaskSection as M, optimizeObservationsForContext as N, buildObserverPrompt as O, parseObserverOutput as P, Extractor as R, deepMergeWorkingMemory as S, summarizeConversation as T, OBSERVATION_CONTEXT_PROMPT as V, reconcileObservationGroupsFromReflection as _, extractWorkingMemoryContent as a, wrapInObservationGroup as b, WORKING_MEMORY_STATE_ID as c, getObservationsAsOf as d, ObservationalMemoryProcessor as f, parseObservationGroups as g, deriveObservationGroupProvenance as h, WorkingMemory as i, formatMessagesForObserver as j, buildObserverSystemPrompt as k, WORKING_MEMORY_STATE_PROCESSOR_ID as l, combineObservationGroupRanges as m, MessageHistory$1 as n, extractWorkingMemoryTags as o, ObservationalMemory as p, SemanticRecall as r, removeWorkingMemoryTags as s, Memory as t, WorkingMemoryStateProcessor as u, renderObservationGroupsForReflection as v, SUMMARIZE_THREAD_DEFAULTS as w, ModelByInputTokens as x, stripObservationGroups as y, OBSERVATIONAL_MEMORY_DEFAULTS as z };
|
|
28698
28798
|
|
|
28699
|
-
//# sourceMappingURL=src-
|
|
28799
|
+
//# sourceMappingURL=src-BKRU-0Fx.js.map
|