@mastra/memory 1.7.0 → 1.8.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/dist/{chunk-M7RAJAZ6.js → chunk-SUU4IAZJ.js} +307 -39
- package/dist/chunk-SUU4IAZJ.js.map +1 -0
- package/dist/{chunk-SHID74TI.cjs → chunk-YPFNHFT6.cjs} +307 -39
- package/dist/chunk-YPFNHFT6.cjs.map +1 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +24 -24
- package/dist/docs/references/docs-memory-observational-memory.md +23 -0
- package/dist/docs/references/reference-memory-observational-memory.md +2 -0
- package/dist/index.cjs +64 -368
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +64 -368
- package/dist/index.js.map +1 -1
- package/dist/{observational-memory-AU6MIH4Q.cjs → observational-memory-3HFM7PY2.cjs} +17 -17
- package/dist/{observational-memory-AU6MIH4Q.cjs.map → observational-memory-3HFM7PY2.cjs.map} +1 -1
- package/dist/{observational-memory-YRWU6CY3.js → observational-memory-XXD6E2SO.js} +3 -3
- package/dist/{observational-memory-YRWU6CY3.js.map → observational-memory-XXD6E2SO.js.map} +1 -1
- package/dist/processors/index.cjs +15 -15
- package/dist/processors/index.js +1 -1
- package/dist/processors/observational-memory/observational-memory.d.ts +21 -0
- package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
- package/dist/processors/observational-memory/observer-agent.d.ts +14 -2
- package/dist/processors/observational-memory/observer-agent.d.ts.map +1 -1
- package/dist/processors/observational-memory/types.d.ts +7 -0
- package/dist/processors/observational-memory/types.d.ts.map +1 -1
- package/package.json +6 -6
- package/dist/chunk-M7RAJAZ6.js.map +0 -1
- package/dist/chunk-SHID74TI.cjs.map +0 -1
|
@@ -803,6 +803,11 @@ ${maybeTruncate(resultStr, maxLen)}`;
|
|
|
803
803
|
${maybeTruncate(argsStr, maxLen)}`;
|
|
804
804
|
}
|
|
805
805
|
const partType = part.type;
|
|
806
|
+
if (partType === "reasoning") {
|
|
807
|
+
const reasoning = part.reasoning;
|
|
808
|
+
if (reasoning) return maybeTruncate(reasoning, maxLen);
|
|
809
|
+
return "";
|
|
810
|
+
}
|
|
806
811
|
if (partType === "image" || partType === "file") {
|
|
807
812
|
const attachment = part;
|
|
808
813
|
const inputAttachment = toObserverInputAttachmentPart(attachment);
|
|
@@ -817,6 +822,9 @@ ${maybeTruncate(argsStr, maxLen)}`;
|
|
|
817
822
|
} else if (msg.content?.content) {
|
|
818
823
|
content = maybeTruncate(msg.content.content, maxLen);
|
|
819
824
|
}
|
|
825
|
+
if (!content && attachments.length === 0) {
|
|
826
|
+
return { text: "", attachments };
|
|
827
|
+
}
|
|
820
828
|
return {
|
|
821
829
|
text: `**${role}${timestampStr}:**
|
|
822
830
|
${content}`,
|
|
@@ -825,18 +833,21 @@ ${content}`,
|
|
|
825
833
|
}
|
|
826
834
|
function formatMessagesForObserver(messages, options) {
|
|
827
835
|
const counter = { nextImageId: 1, nextFileId: 1 };
|
|
828
|
-
return messages.map((msg) => formatObserverMessage(msg, counter, options).text).join("\n\n---\n\n");
|
|
836
|
+
return messages.map((msg) => formatObserverMessage(msg, counter, options).text).filter(Boolean).join("\n\n---\n\n");
|
|
829
837
|
}
|
|
830
838
|
function buildObserverHistoryMessage(messages) {
|
|
831
839
|
const counter = { nextImageId: 1, nextFileId: 1 };
|
|
832
840
|
const content = [{ type: "text", text: "## New Message History to Observe\n\n" }];
|
|
833
|
-
|
|
841
|
+
let visibleCount = 0;
|
|
842
|
+
messages.forEach((message) => {
|
|
834
843
|
const formatted = formatObserverMessage(message, counter);
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
if (index < messages.length - 1) {
|
|
844
|
+
if (!formatted.text && formatted.attachments.length === 0) return;
|
|
845
|
+
if (visibleCount > 0) {
|
|
838
846
|
content.push({ type: "text", text: "\n\n---\n\n" });
|
|
839
847
|
}
|
|
848
|
+
content.push({ type: "text", text: formatted.text });
|
|
849
|
+
content.push(...formatted.attachments);
|
|
850
|
+
visibleCount++;
|
|
840
851
|
});
|
|
841
852
|
return {
|
|
842
853
|
role: "user",
|
|
@@ -865,16 +876,22 @@ The following messages are from ${threadOrder.length} different conversation thr
|
|
|
865
876
|
threadOrder.forEach((threadId, threadIndex) => {
|
|
866
877
|
const messages = messagesByThread.get(threadId);
|
|
867
878
|
if (!messages || messages.length === 0) return;
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
messages.forEach((message
|
|
879
|
+
const threadContent = [];
|
|
880
|
+
let visibleCount = 0;
|
|
881
|
+
messages.forEach((message) => {
|
|
871
882
|
const formatted = formatObserverMessage(message, counter);
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
content.push({ type: "text", text: "\n\n---\n\n" });
|
|
883
|
+
if (!formatted.text && formatted.attachments.length === 0) return;
|
|
884
|
+
if (visibleCount > 0) {
|
|
885
|
+
threadContent.push({ type: "text", text: "\n\n---\n\n" });
|
|
876
886
|
}
|
|
887
|
+
threadContent.push({ type: "text", text: formatted.text });
|
|
888
|
+
threadContent.push(...formatted.attachments);
|
|
889
|
+
visibleCount++;
|
|
877
890
|
});
|
|
891
|
+
if (visibleCount === 0) return;
|
|
892
|
+
content.push({ type: "text", text: `<thread id="${threadId}">
|
|
893
|
+
` });
|
|
894
|
+
content.push(...threadContent);
|
|
878
895
|
content.push({ type: "text", text: "\n</thread>" });
|
|
879
896
|
if (threadIndex < threadOrder.length - 1) {
|
|
880
897
|
content.push({ type: "text", text: "\n\n" });
|
|
@@ -885,7 +902,7 @@ The following messages are from ${threadOrder.length} different conversation thr
|
|
|
885
902
|
content
|
|
886
903
|
};
|
|
887
904
|
}
|
|
888
|
-
function buildMultiThreadObserverTaskPrompt(existingObservations) {
|
|
905
|
+
function buildMultiThreadObserverTaskPrompt(existingObservations, threadOrder, priorMetadataByThread, wasTruncated) {
|
|
889
906
|
let prompt = "";
|
|
890
907
|
if (existingObservations) {
|
|
891
908
|
prompt += `## Previous Observations
|
|
@@ -897,6 +914,39 @@ ${existingObservations}
|
|
|
897
914
|
`;
|
|
898
915
|
prompt += "Do not repeat these existing observations. Your new observations will be appended to the existing observations.\n\n";
|
|
899
916
|
}
|
|
917
|
+
const hasTruncatedObservations = wasTruncated ?? false;
|
|
918
|
+
const threadMetadataLines = threadOrder?.map((threadId) => {
|
|
919
|
+
const metadata = priorMetadataByThread?.get(threadId);
|
|
920
|
+
if (!metadata?.currentTask && !metadata?.suggestedResponse) {
|
|
921
|
+
return "";
|
|
922
|
+
}
|
|
923
|
+
const lines = [`- thread ${threadId}`];
|
|
924
|
+
if (metadata.currentTask) {
|
|
925
|
+
lines.push(` - prior current-task: ${metadata.currentTask}`);
|
|
926
|
+
}
|
|
927
|
+
if (metadata.suggestedResponse) {
|
|
928
|
+
lines.push(` - prior suggested-response: ${metadata.suggestedResponse}`);
|
|
929
|
+
}
|
|
930
|
+
return lines.join("\n");
|
|
931
|
+
}).filter(Boolean).join("\n");
|
|
932
|
+
if (threadMetadataLines) {
|
|
933
|
+
prompt += `## Prior Thread Metadata
|
|
934
|
+
|
|
935
|
+
${threadMetadataLines}
|
|
936
|
+
|
|
937
|
+
`;
|
|
938
|
+
if (hasTruncatedObservations) {
|
|
939
|
+
prompt += `Previous observations were truncated for context budget reasons.
|
|
940
|
+
`;
|
|
941
|
+
prompt += `The main agent still has full memory context outside this observer window.
|
|
942
|
+
`;
|
|
943
|
+
}
|
|
944
|
+
prompt += `Use each thread's prior current-task and suggested-response as continuity hints, then update them based on that thread's new messages.
|
|
945
|
+
|
|
946
|
+
---
|
|
947
|
+
|
|
948
|
+
`;
|
|
949
|
+
}
|
|
900
950
|
prompt += `## Your Task
|
|
901
951
|
|
|
902
952
|
`;
|
|
@@ -985,6 +1035,32 @@ ${existingObservations}
|
|
|
985
1035
|
`;
|
|
986
1036
|
prompt += "Do not repeat these existing observations. Your new observations will be appended to the existing observations.\n\n";
|
|
987
1037
|
}
|
|
1038
|
+
const hasTruncatedObservations = options?.wasTruncated ?? false;
|
|
1039
|
+
const priorMetadataLines = [];
|
|
1040
|
+
if (options?.priorCurrentTask) {
|
|
1041
|
+
priorMetadataLines.push(`- prior current-task: ${options.priorCurrentTask}`);
|
|
1042
|
+
}
|
|
1043
|
+
if (options?.priorSuggestedResponse) {
|
|
1044
|
+
priorMetadataLines.push(`- prior suggested-response: ${options.priorSuggestedResponse}`);
|
|
1045
|
+
}
|
|
1046
|
+
if (priorMetadataLines.length > 0) {
|
|
1047
|
+
prompt += `## Prior Thread Metadata
|
|
1048
|
+
|
|
1049
|
+
${priorMetadataLines.join("\n")}
|
|
1050
|
+
|
|
1051
|
+
`;
|
|
1052
|
+
if (hasTruncatedObservations) {
|
|
1053
|
+
prompt += `Previous observations were truncated for context budget reasons.
|
|
1054
|
+
`;
|
|
1055
|
+
prompt += `The main agent still has full memory context outside this observer window.
|
|
1056
|
+
`;
|
|
1057
|
+
}
|
|
1058
|
+
prompt += `Use the prior current-task and suggested-response as continuity hints, then update them based on the new messages.
|
|
1059
|
+
|
|
1060
|
+
---
|
|
1061
|
+
|
|
1062
|
+
`;
|
|
1063
|
+
}
|
|
988
1064
|
prompt += `## Your Task
|
|
989
1065
|
|
|
990
1066
|
`;
|
|
@@ -3278,6 +3354,7 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
3278
3354
|
config.observation?.blockAfter ?? (config.observation?.bufferTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.bufferTokens ? 1.2 : void 0),
|
|
3279
3355
|
config.observation?.messageTokens ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.messageTokens
|
|
3280
3356
|
),
|
|
3357
|
+
previousObserverTokens: config.observation?.previousObserverTokens ?? 2e3,
|
|
3281
3358
|
instruction: config.observation?.instruction
|
|
3282
3359
|
};
|
|
3283
3360
|
this.reflectionConfig = {
|
|
@@ -3314,7 +3391,8 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
3314
3391
|
return {
|
|
3315
3392
|
scope: this.scope,
|
|
3316
3393
|
observation: {
|
|
3317
|
-
messageTokens: this.observationConfig.messageTokens
|
|
3394
|
+
messageTokens: this.observationConfig.messageTokens,
|
|
3395
|
+
previousObserverTokens: this.observationConfig.previousObserverTokens
|
|
3318
3396
|
},
|
|
3319
3397
|
reflection: {
|
|
3320
3398
|
observationTokens: this.reflectionConfig.observationTokens
|
|
@@ -3394,7 +3472,8 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
3394
3472
|
scope: this.scope,
|
|
3395
3473
|
observation: {
|
|
3396
3474
|
messageTokens: this.observationConfig.messageTokens,
|
|
3397
|
-
model: observationModelName
|
|
3475
|
+
model: observationModelName,
|
|
3476
|
+
previousObserverTokens: this.observationConfig.previousObserverTokens
|
|
3398
3477
|
},
|
|
3399
3478
|
reflection: {
|
|
3400
3479
|
observationTokens: this.reflectionConfig.observationTokens,
|
|
@@ -3459,6 +3538,13 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
3459
3538
|
);
|
|
3460
3539
|
}
|
|
3461
3540
|
}
|
|
3541
|
+
if (this.observationConfig.previousObserverTokens !== void 0 && this.observationConfig.previousObserverTokens !== false) {
|
|
3542
|
+
if (!Number.isFinite(this.observationConfig.previousObserverTokens) || this.observationConfig.previousObserverTokens < 0) {
|
|
3543
|
+
throw new Error(
|
|
3544
|
+
`observation.previousObserverTokens must be false or a finite number >= 0, got ${this.observationConfig.previousObserverTokens}`
|
|
3545
|
+
);
|
|
3546
|
+
}
|
|
3547
|
+
}
|
|
3462
3548
|
if (this.reflectionConfig.bufferActivation !== void 0) {
|
|
3463
3549
|
if (this.reflectionConfig.bufferActivation <= 0 || this.reflectionConfig.bufferActivation > 1) {
|
|
3464
3550
|
throw new Error(
|
|
@@ -3856,6 +3942,141 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
3856
3942
|
}
|
|
3857
3943
|
return result;
|
|
3858
3944
|
}
|
|
3945
|
+
/**
|
|
3946
|
+
* Prepare optimized observer context by applying truncation and buffered-reflection inclusion.
|
|
3947
|
+
*
|
|
3948
|
+
* Returns the (possibly optimized) observations string to pass as "Previous Observations"
|
|
3949
|
+
* to the observer prompt. When no optimization options are set, returns the input unchanged.
|
|
3950
|
+
*/
|
|
3951
|
+
prepareObserverContext(existingObservations, record) {
|
|
3952
|
+
const { previousObserverTokens } = this.observationConfig;
|
|
3953
|
+
const tokenBudget = previousObserverTokens === void 0 || previousObserverTokens === false ? void 0 : previousObserverTokens;
|
|
3954
|
+
if (tokenBudget === void 0) {
|
|
3955
|
+
return { context: existingObservations, wasTruncated: false };
|
|
3956
|
+
}
|
|
3957
|
+
const bufferedReflection = record?.bufferedReflection && record?.reflectedObservationLineCount ? record.bufferedReflection : void 0;
|
|
3958
|
+
if (!existingObservations) {
|
|
3959
|
+
return { context: bufferedReflection, wasTruncated: false };
|
|
3960
|
+
}
|
|
3961
|
+
let observations = existingObservations;
|
|
3962
|
+
if (bufferedReflection && record?.reflectedObservationLineCount) {
|
|
3963
|
+
const allLines = observations.split("\n");
|
|
3964
|
+
const unreflectedLines = allLines.slice(record.reflectedObservationLineCount);
|
|
3965
|
+
const unreflectedContent = unreflectedLines.join("\n").trim();
|
|
3966
|
+
observations = unreflectedContent ? `${bufferedReflection}
|
|
3967
|
+
|
|
3968
|
+
${unreflectedContent}` : bufferedReflection;
|
|
3969
|
+
}
|
|
3970
|
+
let wasTruncated = false;
|
|
3971
|
+
if (tokenBudget !== void 0) {
|
|
3972
|
+
if (tokenBudget === 0) {
|
|
3973
|
+
return { context: "", wasTruncated: true };
|
|
3974
|
+
}
|
|
3975
|
+
const currentTokens = this.tokenCounter.countObservations(observations);
|
|
3976
|
+
if (currentTokens > tokenBudget) {
|
|
3977
|
+
observations = this.truncateObservationsToTokenBudget(observations, tokenBudget);
|
|
3978
|
+
wasTruncated = true;
|
|
3979
|
+
}
|
|
3980
|
+
}
|
|
3981
|
+
return { context: observations, wasTruncated };
|
|
3982
|
+
}
|
|
3983
|
+
/**
|
|
3984
|
+
* Truncate observations to fit within a token budget.
|
|
3985
|
+
*
|
|
3986
|
+
* Strategy:
|
|
3987
|
+
* 1. Keep a raw tail of recent observations (end of block).
|
|
3988
|
+
* 2. Add a truncation marker: [X observations truncated here], placed at the hidden gap.
|
|
3989
|
+
* 3. Try to preserve important observations (🔴) from older context, newest-first.
|
|
3990
|
+
* 4. Enforce that at least 50% of kept observations remain raw tail observations.
|
|
3991
|
+
*/
|
|
3992
|
+
truncateObservationsToTokenBudget(observations, budget) {
|
|
3993
|
+
if (budget === 0) {
|
|
3994
|
+
return "";
|
|
3995
|
+
}
|
|
3996
|
+
const totalTokens = this.tokenCounter.countObservations(observations);
|
|
3997
|
+
if (totalTokens <= budget) {
|
|
3998
|
+
return observations;
|
|
3999
|
+
}
|
|
4000
|
+
const lines = observations.split("\n");
|
|
4001
|
+
const totalCount = lines.length;
|
|
4002
|
+
const lineTokens = new Array(totalCount);
|
|
4003
|
+
const isImportant = new Array(totalCount);
|
|
4004
|
+
for (let i = 0; i < totalCount; i++) {
|
|
4005
|
+
lineTokens[i] = this.tokenCounter.countString(lines[i]);
|
|
4006
|
+
isImportant[i] = lines[i].includes("\u{1F534}");
|
|
4007
|
+
}
|
|
4008
|
+
const suffixTokens = new Array(totalCount + 1);
|
|
4009
|
+
suffixTokens[totalCount] = 0;
|
|
4010
|
+
for (let i = totalCount - 1; i >= 0; i--) {
|
|
4011
|
+
suffixTokens[i] = suffixTokens[i + 1] + lineTokens[i];
|
|
4012
|
+
}
|
|
4013
|
+
const headImportantIndexes = [];
|
|
4014
|
+
const buildCandidateString = (tailStart, selectedImportantIndexes) => {
|
|
4015
|
+
const keptIndexes = [
|
|
4016
|
+
...selectedImportantIndexes,
|
|
4017
|
+
...Array.from({ length: totalCount - tailStart }, (_, i) => tailStart + i)
|
|
4018
|
+
].sort((a, b) => a - b);
|
|
4019
|
+
if (keptIndexes.length === 0) {
|
|
4020
|
+
return `[${totalCount} observations truncated here]`;
|
|
4021
|
+
}
|
|
4022
|
+
const outputLines = [];
|
|
4023
|
+
let previousKeptIndex = -1;
|
|
4024
|
+
for (const keptIndex of keptIndexes) {
|
|
4025
|
+
const hiddenCount = keptIndex - previousKeptIndex - 1;
|
|
4026
|
+
if (hiddenCount === 1) {
|
|
4027
|
+
outputLines.push(lines[previousKeptIndex + 1]);
|
|
4028
|
+
} else if (hiddenCount > 1) {
|
|
4029
|
+
outputLines.push(`[${hiddenCount} observations truncated here]`);
|
|
4030
|
+
}
|
|
4031
|
+
outputLines.push(lines[keptIndex]);
|
|
4032
|
+
previousKeptIndex = keptIndex;
|
|
4033
|
+
}
|
|
4034
|
+
const trailingHiddenCount = totalCount - previousKeptIndex - 1;
|
|
4035
|
+
if (trailingHiddenCount === 1) {
|
|
4036
|
+
outputLines.push(lines[totalCount - 1]);
|
|
4037
|
+
} else if (trailingHiddenCount > 1) {
|
|
4038
|
+
outputLines.push(`[${trailingHiddenCount} observations truncated here]`);
|
|
4039
|
+
}
|
|
4040
|
+
return outputLines.join("\n");
|
|
4041
|
+
};
|
|
4042
|
+
const estimateKeptContentCost = (tailStart, selectedImportantIndexes) => {
|
|
4043
|
+
let cost = suffixTokens[tailStart];
|
|
4044
|
+
for (const idx of selectedImportantIndexes) {
|
|
4045
|
+
cost += lineTokens[idx];
|
|
4046
|
+
}
|
|
4047
|
+
return cost;
|
|
4048
|
+
};
|
|
4049
|
+
let bestCandidate;
|
|
4050
|
+
let bestImportantCount = -1;
|
|
4051
|
+
let bestRawTailLength = -1;
|
|
4052
|
+
for (let tailStart = 1; tailStart < totalCount; tailStart++) {
|
|
4053
|
+
if (isImportant[tailStart - 1]) {
|
|
4054
|
+
headImportantIndexes.push(tailStart - 1);
|
|
4055
|
+
}
|
|
4056
|
+
const rawTailLength = totalCount - tailStart;
|
|
4057
|
+
const maxImportantByRatio = rawTailLength;
|
|
4058
|
+
let importantToKeep = Math.min(headImportantIndexes.length, maxImportantByRatio);
|
|
4059
|
+
const getSelectedImportant = (count) => count > 0 ? headImportantIndexes.slice(Math.max(0, headImportantIndexes.length - count)) : [];
|
|
4060
|
+
while (importantToKeep > 0 && estimateKeptContentCost(tailStart, getSelectedImportant(importantToKeep)) > budget) {
|
|
4061
|
+
importantToKeep -= 1;
|
|
4062
|
+
}
|
|
4063
|
+
if (estimateKeptContentCost(tailStart, getSelectedImportant(importantToKeep)) > budget) {
|
|
4064
|
+
continue;
|
|
4065
|
+
}
|
|
4066
|
+
if (importantToKeep > bestImportantCount || importantToKeep === bestImportantCount && rawTailLength > bestRawTailLength) {
|
|
4067
|
+
const candidate = buildCandidateString(tailStart, getSelectedImportant(importantToKeep));
|
|
4068
|
+
if (this.tokenCounter.countObservations(candidate) <= budget) {
|
|
4069
|
+
bestCandidate = candidate;
|
|
4070
|
+
bestImportantCount = importantToKeep;
|
|
4071
|
+
bestRawTailLength = rawTailLength;
|
|
4072
|
+
}
|
|
4073
|
+
}
|
|
4074
|
+
}
|
|
4075
|
+
if (!bestCandidate) {
|
|
4076
|
+
return `[${totalCount} observations truncated here]`;
|
|
4077
|
+
}
|
|
4078
|
+
return bestCandidate;
|
|
4079
|
+
}
|
|
3859
4080
|
/**
|
|
3860
4081
|
* Call the Observer agent to extract observations.
|
|
3861
4082
|
*/
|
|
@@ -3864,12 +4085,17 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
3864
4085
|
const observerMessages = [
|
|
3865
4086
|
{
|
|
3866
4087
|
role: "user",
|
|
3867
|
-
content: buildObserverTaskPrompt(existingObservations,
|
|
4088
|
+
content: buildObserverTaskPrompt(existingObservations, {
|
|
4089
|
+
skipContinuationHints: options?.skipContinuationHints,
|
|
4090
|
+
priorCurrentTask: options?.priorCurrentTask,
|
|
4091
|
+
priorSuggestedResponse: options?.priorSuggestedResponse,
|
|
4092
|
+
wasTruncated: options?.wasTruncated
|
|
4093
|
+
})
|
|
3868
4094
|
},
|
|
3869
4095
|
buildObserverHistoryMessage(messagesToObserve)
|
|
3870
4096
|
];
|
|
3871
4097
|
const doGenerate = async () => {
|
|
3872
|
-
|
|
4098
|
+
const result2 = await this.withAbortCheck(async () => {
|
|
3873
4099
|
const streamResult = await agent.stream(observerMessages, {
|
|
3874
4100
|
modelSettings: {
|
|
3875
4101
|
...this.observationConfig.modelSettings
|
|
@@ -3880,6 +4106,7 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
3880
4106
|
});
|
|
3881
4107
|
return streamResult.getFullOutput();
|
|
3882
4108
|
}, abortSignal);
|
|
4109
|
+
return result2;
|
|
3883
4110
|
};
|
|
3884
4111
|
let result = await doGenerate();
|
|
3885
4112
|
let parsed = parseObserverOutput(result.text);
|
|
@@ -3910,17 +4137,23 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
3910
4137
|
* Returns per-thread results with observations, currentTask, and suggestedContinuation,
|
|
3911
4138
|
* plus the total usage for the batch.
|
|
3912
4139
|
*/
|
|
3913
|
-
async callMultiThreadObserver(existingObservations, messagesByThread, threadOrder, abortSignal, requestContext) {
|
|
4140
|
+
async callMultiThreadObserver(existingObservations, messagesByThread, threadOrder, priorMetadataByThread, abortSignal, requestContext, wasTruncated) {
|
|
4141
|
+
const systemPrompt = buildObserverSystemPrompt(true, this.observationConfig.instruction);
|
|
3914
4142
|
const agent$1 = new agent.Agent({
|
|
3915
4143
|
id: "multi-thread-observer",
|
|
3916
4144
|
name: "multi-thread-observer",
|
|
3917
4145
|
model: this.observationConfig.model,
|
|
3918
|
-
instructions:
|
|
4146
|
+
instructions: systemPrompt
|
|
3919
4147
|
});
|
|
3920
4148
|
const observerMessages = [
|
|
3921
4149
|
{
|
|
3922
4150
|
role: "user",
|
|
3923
|
-
content: buildMultiThreadObserverTaskPrompt(
|
|
4151
|
+
content: buildMultiThreadObserverTaskPrompt(
|
|
4152
|
+
existingObservations,
|
|
4153
|
+
threadOrder,
|
|
4154
|
+
priorMetadataByThread,
|
|
4155
|
+
wasTruncated
|
|
4156
|
+
)
|
|
3924
4157
|
},
|
|
3925
4158
|
buildMultiThreadObserverHistoryMessage(messagesByThread, threadOrder)
|
|
3926
4159
|
];
|
|
@@ -3932,7 +4165,7 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
3932
4165
|
this.observedMessageIds.add(msg.id);
|
|
3933
4166
|
}
|
|
3934
4167
|
const doGenerate = async () => {
|
|
3935
|
-
|
|
4168
|
+
const result2 = await this.withAbortCheck(async () => {
|
|
3936
4169
|
const streamResult = await agent$1.stream(observerMessages, {
|
|
3937
4170
|
modelSettings: {
|
|
3938
4171
|
...this.observationConfig.modelSettings
|
|
@@ -3943,6 +4176,7 @@ Async buffering is enabled by default \u2014 this opt-out is only needed when us
|
|
|
3943
4176
|
});
|
|
3944
4177
|
return streamResult.getFullOutput();
|
|
3945
4178
|
}, abortSignal);
|
|
4179
|
+
return result2;
|
|
3946
4180
|
};
|
|
3947
4181
|
let result = await doGenerate();
|
|
3948
4182
|
let parsed = parseMultiThreadObserverOutput(result.text);
|
|
@@ -5376,12 +5610,18 @@ ${newThreadSection}`;
|
|
|
5376
5610
|
);
|
|
5377
5611
|
}
|
|
5378
5612
|
}
|
|
5379
|
-
const
|
|
5613
|
+
const { context: observerContext, wasTruncated } = this.prepareObserverContext(
|
|
5380
5614
|
freshRecord?.activeObservations ?? record.activeObservations,
|
|
5381
|
-
|
|
5382
|
-
abortSignal,
|
|
5383
|
-
{ requestContext }
|
|
5615
|
+
freshRecord ?? record
|
|
5384
5616
|
);
|
|
5617
|
+
const thread = await this.storage.getThreadById({ threadId });
|
|
5618
|
+
const threadOMMetadata = memory.getThreadOMMetadata(thread?.metadata);
|
|
5619
|
+
const result = await this.callObserver(observerContext, messagesToObserve, abortSignal, {
|
|
5620
|
+
requestContext,
|
|
5621
|
+
priorCurrentTask: threadOMMetadata?.currentTask,
|
|
5622
|
+
priorSuggestedResponse: threadOMMetadata?.suggestedResponse,
|
|
5623
|
+
wasTruncated
|
|
5624
|
+
});
|
|
5385
5625
|
const existingObservations = freshRecord?.activeObservations ?? record.activeObservations ?? "";
|
|
5386
5626
|
let newObservations;
|
|
5387
5627
|
if (this.scope === "resource") {
|
|
@@ -5398,16 +5638,16 @@ ${result.observations}` : result.observations;
|
|
|
5398
5638
|
const newMessageIds = messagesToObserve.map((m) => m.id);
|
|
5399
5639
|
const existingIds = freshRecord?.observedMessageIds ?? record.observedMessageIds ?? [];
|
|
5400
5640
|
const allObservedIds = [.../* @__PURE__ */ new Set([...Array.isArray(existingIds) ? existingIds : [], ...newMessageIds])];
|
|
5401
|
-
const
|
|
5402
|
-
if (
|
|
5403
|
-
const newMetadata = memory.setThreadOMMetadata(
|
|
5641
|
+
const threadForMetadata = await this.storage.getThreadById({ threadId });
|
|
5642
|
+
if (threadForMetadata) {
|
|
5643
|
+
const newMetadata = memory.setThreadOMMetadata(threadForMetadata.metadata, {
|
|
5404
5644
|
suggestedResponse: result.suggestedContinuation,
|
|
5405
5645
|
currentTask: result.currentTask,
|
|
5406
5646
|
lastObservedMessageCursor: this.getLastObservedMessageCursor(messagesToObserve)
|
|
5407
5647
|
});
|
|
5408
5648
|
await this.storage.updateThread({
|
|
5409
5649
|
id: threadId,
|
|
5410
|
-
title:
|
|
5650
|
+
title: threadForMetadata.title ?? "",
|
|
5411
5651
|
metadata: newMetadata
|
|
5412
5652
|
});
|
|
5413
5653
|
}
|
|
@@ -5641,12 +5881,21 @@ ${result.observations}` : result.observations;
|
|
|
5641
5881
|
const bufferedChunks = this.getBufferedChunks(record);
|
|
5642
5882
|
const bufferedChunksText = bufferedChunks.map((c) => c.observations).join("\n\n");
|
|
5643
5883
|
const combinedObservations = this.combineObservationsForBuffering(record.activeObservations, bufferedChunksText);
|
|
5884
|
+
const { context: observerContext, wasTruncated } = this.prepareObserverContext(combinedObservations, record);
|
|
5885
|
+
const thread = await this.storage.getThreadById({ threadId });
|
|
5886
|
+
const threadOMMetadata = memory.getThreadOMMetadata(thread?.metadata);
|
|
5644
5887
|
const result = await this.callObserver(
|
|
5645
|
-
|
|
5888
|
+
observerContext,
|
|
5646
5889
|
messagesToBuffer,
|
|
5647
5890
|
void 0,
|
|
5648
5891
|
// No abort signal for background ops
|
|
5649
|
-
{
|
|
5892
|
+
{
|
|
5893
|
+
skipContinuationHints: true,
|
|
5894
|
+
requestContext,
|
|
5895
|
+
priorCurrentTask: threadOMMetadata?.currentTask,
|
|
5896
|
+
priorSuggestedResponse: threadOMMetadata?.suggestedResponse,
|
|
5897
|
+
wasTruncated
|
|
5898
|
+
}
|
|
5650
5899
|
);
|
|
5651
5900
|
if (!result.observations) {
|
|
5652
5901
|
omDebug(`[OM:doAsyncBufferedObservation] empty observations returned, skipping buffer storage`);
|
|
@@ -5713,8 +5962,6 @@ ${result.observations}` : result.observations;
|
|
|
5713
5962
|
}
|
|
5714
5963
|
return `${activeObservations}
|
|
5715
5964
|
|
|
5716
|
-
--- BUFFERED (pending activation) ---
|
|
5717
|
-
|
|
5718
5965
|
${bufferedObservations}`;
|
|
5719
5966
|
}
|
|
5720
5967
|
/**
|
|
@@ -6074,7 +6321,11 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
|
6074
6321
|
const threadMetadataMap = /* @__PURE__ */ new Map();
|
|
6075
6322
|
for (const thread of allThreads) {
|
|
6076
6323
|
const omMetadata = memory.getThreadOMMetadata(thread.metadata);
|
|
6077
|
-
threadMetadataMap.set(thread.id, {
|
|
6324
|
+
threadMetadataMap.set(thread.id, {
|
|
6325
|
+
lastObservedAt: omMetadata?.lastObservedAt,
|
|
6326
|
+
currentTask: omMetadata?.currentTask,
|
|
6327
|
+
suggestedResponse: omMetadata?.suggestedResponse
|
|
6328
|
+
});
|
|
6078
6329
|
}
|
|
6079
6330
|
const messagesByThread = /* @__PURE__ */ new Map();
|
|
6080
6331
|
for (const thread of allThreads) {
|
|
@@ -6154,7 +6405,12 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
|
6154
6405
|
return;
|
|
6155
6406
|
}
|
|
6156
6407
|
}
|
|
6157
|
-
const
|
|
6408
|
+
const rawExistingObservations = freshRecord?.activeObservations ?? record.activeObservations ?? "";
|
|
6409
|
+
const { context: optimizedObservations, wasTruncated } = this.prepareObserverContext(
|
|
6410
|
+
rawExistingObservations,
|
|
6411
|
+
freshRecord ?? record
|
|
6412
|
+
);
|
|
6413
|
+
const existingObservations = optimizedObservations ?? rawExistingObservations;
|
|
6158
6414
|
for (const threadId of threadOrder) {
|
|
6159
6415
|
const msgs = messagesByThread.get(threadId);
|
|
6160
6416
|
if (msgs && msgs.length > 0) {
|
|
@@ -6218,12 +6474,24 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
|
6218
6474
|
batches.push(currentBatch);
|
|
6219
6475
|
}
|
|
6220
6476
|
const batchPromises = batches.map(async (batch) => {
|
|
6477
|
+
const batchPriorMetadata = /* @__PURE__ */ new Map();
|
|
6478
|
+
for (const threadId of batch.threadIds) {
|
|
6479
|
+
const metadata = threadMetadataMap.get(threadId);
|
|
6480
|
+
if (metadata?.currentTask || metadata?.suggestedResponse) {
|
|
6481
|
+
batchPriorMetadata.set(threadId, {
|
|
6482
|
+
currentTask: metadata.currentTask,
|
|
6483
|
+
suggestedResponse: metadata.suggestedResponse
|
|
6484
|
+
});
|
|
6485
|
+
}
|
|
6486
|
+
}
|
|
6221
6487
|
const batchResult = await this.callMultiThreadObserver(
|
|
6222
6488
|
existingObservations,
|
|
6223
6489
|
batch.threadMap,
|
|
6224
6490
|
batch.threadIds,
|
|
6491
|
+
batchPriorMetadata,
|
|
6225
6492
|
abortSignal,
|
|
6226
|
-
requestContext
|
|
6493
|
+
requestContext,
|
|
6494
|
+
wasTruncated
|
|
6227
6495
|
);
|
|
6228
6496
|
return batchResult;
|
|
6229
6497
|
});
|
|
@@ -6254,7 +6522,7 @@ ${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
|
6254
6522
|
result
|
|
6255
6523
|
});
|
|
6256
6524
|
}
|
|
6257
|
-
let currentObservations =
|
|
6525
|
+
let currentObservations = rawExistingObservations;
|
|
6258
6526
|
let cycleObservationTokens = 0;
|
|
6259
6527
|
for (const obsResult of observationResults) {
|
|
6260
6528
|
if (!obsResult) continue;
|
|
@@ -6721,5 +6989,5 @@ exports.formatMessagesForObserver = formatMessagesForObserver;
|
|
|
6721
6989
|
exports.hasCurrentTaskSection = hasCurrentTaskSection;
|
|
6722
6990
|
exports.optimizeObservationsForContext = optimizeObservationsForContext;
|
|
6723
6991
|
exports.parseObserverOutput = parseObserverOutput;
|
|
6724
|
-
//# sourceMappingURL=chunk-
|
|
6725
|
-
//# sourceMappingURL=chunk-
|
|
6992
|
+
//# sourceMappingURL=chunk-YPFNHFT6.cjs.map
|
|
6993
|
+
//# sourceMappingURL=chunk-YPFNHFT6.cjs.map
|