@mastra/memory 1.39.0-alpha.2 → 1.39.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/reference-memory-settled.md +13 -5
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/processors/index.cjs +1 -1
- package/dist/processors/index.js +1 -1
- package/dist/processors/observational-memory/extraction-runner.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-strategies/async-buffer.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-strategies/sync.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-turn/step.d.ts +2 -0
- package/dist/processors/observational-memory/observation-turn/step.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-turn/turn.d.ts +13 -0
- package/dist/processors/observational-memory/observation-turn/turn.d.ts.map +1 -1
- package/dist/processors/observational-memory/observational-memory.d.ts +17 -3
- package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
- package/dist/processors/observational-memory/observer-runner.d.ts.map +1 -1
- package/dist/processors/observational-memory/processor.d.ts.map +1 -1
- package/dist/processors/observational-memory/reflector-runner.d.ts +3 -0
- package/dist/processors/observational-memory/reflector-runner.d.ts.map +1 -1
- package/dist/processors/observational-memory/retry.d.ts +28 -1
- package/dist/processors/observational-memory/retry.d.ts.map +1 -1
- package/dist/{src-BDhP0_OK.js → src--zkaCof1.js} +224 -44
- package/dist/{src-BDhP0_OK.js.map → src--zkaCof1.js.map} +1 -1
- package/dist/{src-CJiR-m2F.cjs → src-BGgY5kgl.cjs} +224 -44
- package/dist/{src-CJiR-m2F.cjs.map → src-BGgY5kgl.cjs.map} +1 -1
- package/package.json +4 -3
|
@@ -18664,7 +18664,15 @@ const RETRY_CONFIG = {
|
|
|
18664
18664
|
/** Cap on per-attempt delay (ms). */
|
|
18665
18665
|
maxDelayMs: 12e4,
|
|
18666
18666
|
/** Random jitter as a fraction of the computed delay (e.g. 0.2 = ±20%). */
|
|
18667
|
-
jitter: .2
|
|
18667
|
+
jitter: .2,
|
|
18668
|
+
/**
|
|
18669
|
+
* How long one observer, reflector, or extraction model call may go without streaming any
|
|
18670
|
+
* output before it is aborted and retried. Without it a provider that accepts the request but
|
|
18671
|
+
* never answers stalls the call forever, and the retry schedule above never gets a chance to run.
|
|
18672
|
+
* It measures inactivity, not total duration, so a long reply that keeps streaming is never cut
|
|
18673
|
+
* off. It is generous because reasoning models can think silently before their first token.
|
|
18674
|
+
*/
|
|
18675
|
+
modelCallIdleTimeoutMs: 3e5
|
|
18668
18676
|
};
|
|
18669
18677
|
const TRANSIENT_MESSAGE_SUBSTRINGS = [
|
|
18670
18678
|
"terminated",
|
|
@@ -18683,6 +18691,19 @@ const TRANSIENT_MESSAGE_SUBSTRINGS = [
|
|
|
18683
18691
|
];
|
|
18684
18692
|
const INCOMPLETE_FINISH_REASONS = /* @__PURE__ */ new Set(["other", "unknown"]);
|
|
18685
18693
|
/**
|
|
18694
|
+
* A model call that streamed nothing for `RETRY_CONFIG.modelCallIdleTimeoutMs`. Retryable, and
|
|
18695
|
+
* deliberately not an AbortError so `withRetry` doesn't treat it as cancellation.
|
|
18696
|
+
*
|
|
18697
|
+
* @internal
|
|
18698
|
+
*/
|
|
18699
|
+
var OmModelCallTimeoutError = class extends Error {
|
|
18700
|
+
isRetryable = true;
|
|
18701
|
+
constructor(label, idleTimeoutMs) {
|
|
18702
|
+
super(`${label} call produced no output for ${idleTimeoutMs}ms`);
|
|
18703
|
+
this.name = "OmModelCallTimeoutError";
|
|
18704
|
+
}
|
|
18705
|
+
};
|
|
18706
|
+
/**
|
|
18686
18707
|
* A model reply that ended before the model finished. Carries the AI SDK's
|
|
18687
18708
|
* `isRetryable` flag, which `isTransientLLMError` and core's error processors
|
|
18688
18709
|
* already recognize.
|
|
@@ -18825,6 +18846,51 @@ function sleep(ms, abortSignal) {
|
|
|
18825
18846
|
});
|
|
18826
18847
|
}
|
|
18827
18848
|
/**
|
|
18849
|
+
* Run one attempt, failing with a retryable `OmModelCallTimeoutError` if it
|
|
18850
|
+
* goes `idleTimeoutMs` without calling `onActivity`. `fn` gets a signal that
|
|
18851
|
+
* aborts on timeout or on the caller's signal, so the underlying request is
|
|
18852
|
+
* cancelled too.
|
|
18853
|
+
*/
|
|
18854
|
+
async function attemptWithIdleTimeout(fn, label, idleTimeoutMs, abortSignal) {
|
|
18855
|
+
const controller = new AbortController();
|
|
18856
|
+
let rejectOnAbort;
|
|
18857
|
+
const callerAborted = new Promise((_, reject) => {
|
|
18858
|
+
rejectOnAbort = reject;
|
|
18859
|
+
});
|
|
18860
|
+
const onAbort = () => {
|
|
18861
|
+
controller.abort(abortSignal?.reason);
|
|
18862
|
+
rejectOnAbort(abortSignal?.reason ?? /* @__PURE__ */ new Error("The operation was aborted."));
|
|
18863
|
+
};
|
|
18864
|
+
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
18865
|
+
let timer;
|
|
18866
|
+
let rejectOnIdle;
|
|
18867
|
+
const idle = new Promise((_, reject) => {
|
|
18868
|
+
rejectOnIdle = reject;
|
|
18869
|
+
});
|
|
18870
|
+
const armIdleTimer = () => {
|
|
18871
|
+
clearTimeout(timer);
|
|
18872
|
+
timer = setTimeout(() => {
|
|
18873
|
+
const error = new OmModelCallTimeoutError(label, idleTimeoutMs);
|
|
18874
|
+
rejectOnIdle(error);
|
|
18875
|
+
controller.abort(error);
|
|
18876
|
+
}, idleTimeoutMs);
|
|
18877
|
+
};
|
|
18878
|
+
const onActivity = () => {
|
|
18879
|
+
if (!controller.signal.aborted) armIdleTimer();
|
|
18880
|
+
};
|
|
18881
|
+
armIdleTimer();
|
|
18882
|
+
try {
|
|
18883
|
+
return await Promise.race([
|
|
18884
|
+
fn(controller.signal, onActivity),
|
|
18885
|
+
idle,
|
|
18886
|
+
callerAborted
|
|
18887
|
+
]);
|
|
18888
|
+
} finally {
|
|
18889
|
+
clearTimeout(timer);
|
|
18890
|
+
abortSignal?.removeEventListener("abort", onAbort);
|
|
18891
|
+
}
|
|
18892
|
+
}
|
|
18893
|
+
/**
|
|
18828
18894
|
* Run `fn` with retries on transient transport-class errors.
|
|
18829
18895
|
*
|
|
18830
18896
|
* Non-transient errors (auth, validation, schema, etc.) are rethrown
|
|
@@ -18833,14 +18899,16 @@ function sleep(ms, abortSignal) {
|
|
|
18833
18899
|
* @internal
|
|
18834
18900
|
*/
|
|
18835
18901
|
async function withRetry(fn, opts) {
|
|
18836
|
-
const { label, abortSignal, maxRetries = RETRY_CONFIG.maxRetries } = opts;
|
|
18902
|
+
const { label, abortSignal, maxRetries = RETRY_CONFIG.maxRetries, idleTimeoutMs } = opts;
|
|
18837
18903
|
let attempt = 0;
|
|
18838
18904
|
while (true) {
|
|
18839
18905
|
if (abortSignal?.aborted) throw new Error("The operation was aborted.");
|
|
18840
18906
|
try {
|
|
18841
|
-
return await fn();
|
|
18907
|
+
if (idleTimeoutMs === void 0) return await fn(abortSignal ?? new AbortController().signal, () => {});
|
|
18908
|
+
return await attemptWithIdleTimeout(fn, label, idleTimeoutMs, abortSignal);
|
|
18842
18909
|
} catch (error) {
|
|
18843
|
-
if (
|
|
18910
|
+
if (abortSignal?.aborted) throw error;
|
|
18911
|
+
if (!(error instanceof OmModelCallTimeoutError) && hasAbortInChain(error)) throw error;
|
|
18844
18912
|
if (attempt >= maxRetries || !isTransientLLMError(error)) {
|
|
18845
18913
|
if (attempt > 0) omDebug(`[OM:retry:${label}] giving up after ${attempt} retry/retries: ${error instanceof Error ? error.message : String(error)}`);
|
|
18846
18914
|
throw error;
|
|
@@ -18960,19 +19028,21 @@ If a prior value is still applicable and carry-forward is enabled, return that p
|
|
|
18960
19028
|
${extractorInstructions}${priorLines.length > 0 ? `\n\n## Prior Extracted Values\n\n${priorLines.join("\n\n")}` : ""}`;
|
|
18961
19029
|
const values = {};
|
|
18962
19030
|
const failures = [];
|
|
18963
|
-
const streamWithStructuredOutput = async (jsonPromptInjection) => withRetry(() => streamOnce(jsonPromptInjection), {
|
|
19031
|
+
const streamWithStructuredOutput = async (jsonPromptInjection) => withRetry((attemptSignal, onActivity) => streamOnce(jsonPromptInjection, attemptSignal, onActivity), {
|
|
18964
19032
|
label: `om-${opts.source}-structured-extraction`,
|
|
18965
19033
|
abortSignal: opts.abortSignal,
|
|
18966
|
-
maxRetries: 1
|
|
19034
|
+
maxRetries: 1,
|
|
19035
|
+
idleTimeoutMs: RETRY_CONFIG.modelCallIdleTimeoutMs
|
|
18967
19036
|
});
|
|
18968
|
-
const streamOnce = async (jsonPromptInjection) => {
|
|
19037
|
+
const streamOnce = async (jsonPromptInjection, abortSignal, onActivity) => {
|
|
18969
19038
|
const object = await (await opts.agent.stream(prompt, {
|
|
18970
19039
|
structuredOutput: {
|
|
18971
19040
|
schema,
|
|
18972
19041
|
...jsonPromptInjection ? { jsonPromptInjection } : {}
|
|
18973
19042
|
},
|
|
18974
19043
|
...opts.memory ? { memory: opts.memory } : {},
|
|
18975
|
-
|
|
19044
|
+
abortSignal,
|
|
19045
|
+
onChunk: onActivity,
|
|
18976
19046
|
...opts.requestContext ? { requestContext: opts.requestContext } : {},
|
|
18977
19047
|
...opts.observabilityContext
|
|
18978
19048
|
})).object;
|
|
@@ -21740,7 +21810,7 @@ var ObserverRunner = class {
|
|
|
21740
21810
|
timeZone: options?.timeZone
|
|
21741
21811
|
})];
|
|
21742
21812
|
const doGenerate = async () => {
|
|
21743
|
-
return withRetry(() => withOmTracingSpan({
|
|
21813
|
+
return withRetry((attemptSignal, onActivity) => withOmTracingSpan({
|
|
21744
21814
|
phase: "observer",
|
|
21745
21815
|
model: resolvedModel.model,
|
|
21746
21816
|
inputTokens,
|
|
@@ -21763,7 +21833,8 @@ var ObserverRunner = class {
|
|
|
21763
21833
|
modelSettings: { ...this.observationConfig.modelSettings },
|
|
21764
21834
|
providerOptions: this.observationConfig.providerOptions,
|
|
21765
21835
|
...attemptMemory ? { memory: attemptMemory } : {},
|
|
21766
|
-
|
|
21836
|
+
abortSignal: attemptSignal,
|
|
21837
|
+
onChunk: onActivity,
|
|
21767
21838
|
...internalRequestContext ? { requestContext: internalRequestContext } : {},
|
|
21768
21839
|
...childObservabilityContext
|
|
21769
21840
|
})).getFullOutput(), "OM observer");
|
|
@@ -21785,6 +21856,7 @@ var ObserverRunner = class {
|
|
|
21785
21856
|
}), {
|
|
21786
21857
|
label: "observer",
|
|
21787
21858
|
abortSignal,
|
|
21859
|
+
idleTimeoutMs: RETRY_CONFIG.modelCallIdleTimeoutMs,
|
|
21788
21860
|
maxRetries: this.observationConfig.maxRetries
|
|
21789
21861
|
});
|
|
21790
21862
|
};
|
|
@@ -21953,7 +22025,7 @@ var ObserverRunner = class {
|
|
|
21953
22025
|
timeZone
|
|
21954
22026
|
})];
|
|
21955
22027
|
const doGenerate = async () => {
|
|
21956
|
-
return withRetry(() => withOmTracingSpan({
|
|
22028
|
+
return withRetry((attemptSignal, onActivity) => withOmTracingSpan({
|
|
21957
22029
|
phase: "observer-multi-thread",
|
|
21958
22030
|
model: resolvedModel.model,
|
|
21959
22031
|
inputTokens,
|
|
@@ -21974,7 +22046,8 @@ var ObserverRunner = class {
|
|
|
21974
22046
|
maxSteps: 1,
|
|
21975
22047
|
modelSettings: { ...this.observationConfig.modelSettings },
|
|
21976
22048
|
providerOptions: this.observationConfig.providerOptions,
|
|
21977
|
-
|
|
22049
|
+
abortSignal: attemptSignal,
|
|
22050
|
+
onChunk: onActivity,
|
|
21978
22051
|
...internalRequestContext ? { requestContext: internalRequestContext } : {},
|
|
21979
22052
|
...childObservabilityContext
|
|
21980
22053
|
})).getFullOutput(), "OM multi-thread observer");
|
|
@@ -21998,6 +22071,7 @@ var ObserverRunner = class {
|
|
|
21998
22071
|
}), {
|
|
21999
22072
|
label: "observer-multi-thread",
|
|
22000
22073
|
abortSignal,
|
|
22074
|
+
idleTimeoutMs: RETRY_CONFIG.modelCallIdleTimeoutMs,
|
|
22001
22075
|
maxRetries: this.observationConfig.maxRetries
|
|
22002
22076
|
});
|
|
22003
22077
|
};
|
|
@@ -28577,6 +28651,7 @@ var ObservationStep = class {
|
|
|
28577
28651
|
let observerExchange;
|
|
28578
28652
|
const step0Messages = this.stepNumber === 0 ? getObservableMessages(messageList) : [];
|
|
28579
28653
|
if (this.stepNumber === 0) {
|
|
28654
|
+
this.turn.inputMessageIds = messageList.get.input.db().map((msg) => msg.id);
|
|
28580
28655
|
const activation = await om.activate({
|
|
28581
28656
|
threadId,
|
|
28582
28657
|
resourceId,
|
|
@@ -28678,19 +28753,36 @@ var ObservationStep = class {
|
|
|
28678
28753
|
observabilityContext: this.turn.observabilityContext
|
|
28679
28754
|
}).catch((err) => {
|
|
28680
28755
|
omDebug(`[OM:buffer] fire-and-forget buffer failed: ${err?.message}`);
|
|
28681
|
-
})
|
|
28756
|
+
}), {
|
|
28757
|
+
threadId,
|
|
28758
|
+
resourceId
|
|
28759
|
+
});
|
|
28682
28760
|
buffered = true;
|
|
28683
28761
|
}
|
|
28684
28762
|
}
|
|
28685
28763
|
const bandDefersObservation = statusSnapshot.inAsyncObservationBand && !statusSnapshot.canActivate;
|
|
28686
28764
|
const willObserveNow = statusSnapshot.shouldObserve && !hasIncompleteToolCalls && !bandDefersObservation;
|
|
28687
|
-
/**
|
|
28688
|
-
|
|
28765
|
+
/**
|
|
28766
|
+
* In-flight message ids cleanup must never remove from live context: the turn's own
|
|
28767
|
+
* request, plus whatever the model has not read yet (the pending messages at step 0, the
|
|
28768
|
+
* previous step's output — e.g. a tool result — at step > 0).
|
|
28769
|
+
*/
|
|
28770
|
+
let inFlightIds;
|
|
28689
28771
|
if (this.stepNumber > 0 || willObserveNow) {
|
|
28690
28772
|
if (this.stepNumber > 0) {
|
|
28691
28773
|
const newInput = messageList.clear.input.db();
|
|
28692
28774
|
const newOutput = messageList.clear.response.db();
|
|
28693
28775
|
const messagesToSave = [...newInput, ...newOutput];
|
|
28776
|
+
const drainedIds = new Set(messagesToSave.map((msg) => msg.id));
|
|
28777
|
+
const updatedEarlier = messageList.get.all.db().filter((msg) => !drainedIds.has(msg.id) && this.turn.drainedPartKeys.has(msg.id));
|
|
28778
|
+
const drainedKeys = /* @__PURE__ */ new Map();
|
|
28779
|
+
const unreadIds = [...messagesToSave, ...updatedEarlier].filter((msg) => {
|
|
28780
|
+
const keys = getPartKeys(msg);
|
|
28781
|
+
const seen = this.turn.drainedPartKeys.get(msg.id);
|
|
28782
|
+
drainedKeys.set(msg.id, /* @__PURE__ */ new Set([...seen ?? [], ...keys]));
|
|
28783
|
+
return !seen || keys.some((key) => !seen.has(key));
|
|
28784
|
+
}).map((msg) => msg.id);
|
|
28785
|
+
inFlightIds = [.../* @__PURE__ */ new Set([...this.turn.inputMessageIds, ...unreadIds])];
|
|
28694
28786
|
if (messagesToSave.length > 0) {
|
|
28695
28787
|
for (const msg of messagesToSave) messageList.add(msg, "memory");
|
|
28696
28788
|
try {
|
|
@@ -28701,10 +28793,11 @@ var ObservationStep = class {
|
|
|
28701
28793
|
throw error;
|
|
28702
28794
|
}
|
|
28703
28795
|
}
|
|
28796
|
+
for (const [id, keys] of drainedKeys) this.turn.drainedPartKeys.set(id, keys);
|
|
28704
28797
|
} else {
|
|
28705
28798
|
const pending = [...messageList.get.input.db(), ...messageList.get.response.db()];
|
|
28706
28799
|
if (pending.length > 0) await om.persistMessages(pending, threadId, resourceId);
|
|
28707
|
-
|
|
28800
|
+
inFlightIds = pending.map((msg) => msg.id);
|
|
28708
28801
|
}
|
|
28709
28802
|
if (this.stepNumber === 0 && willObserveNow && this.turn.responseMessageId) {
|
|
28710
28803
|
const seed = {
|
|
@@ -28738,7 +28831,7 @@ var ObservationStep = class {
|
|
|
28738
28831
|
messages: messageList,
|
|
28739
28832
|
observedMessageIds: observedIds,
|
|
28740
28833
|
retentionFloor: minRemaining,
|
|
28741
|
-
preserveMessageIds:
|
|
28834
|
+
preserveMessageIds: [...inFlightIds ?? [], ...this.changedSinceDrain(messageList)]
|
|
28742
28835
|
});
|
|
28743
28836
|
if (statusSnapshot.asyncObservationEnabled) await om.resetBufferingState({
|
|
28744
28837
|
threadId,
|
|
@@ -28766,7 +28859,7 @@ var ObservationStep = class {
|
|
|
28766
28859
|
});
|
|
28767
28860
|
if (!didThresholdCleanup) {
|
|
28768
28861
|
const fallbackCursor = this.turn.record.threadId ? getThreadOMMetadata((await om.getStorage().getThreadById({ threadId: this.turn.record.threadId }))?.metadata)?.lastObservedMessageCursor : void 0;
|
|
28769
|
-
const pendingMessageIds = new Set([...messageList.get.input.db(), ...messageList.get.response.db()].map((msg) => msg.id).filter(Boolean));
|
|
28862
|
+
const pendingMessageIds = new Set([...messageList.get.input.db(), ...messageList.get.response.db()].map((msg) => msg.id).concat(inFlightIds ?? [], this.turn.inputMessageIds, this.changedSinceDrain(messageList)).filter(Boolean));
|
|
28770
28863
|
filterObservedMessages({
|
|
28771
28864
|
messageList,
|
|
28772
28865
|
record: this.turn.record,
|
|
@@ -28795,6 +28888,13 @@ var ObservationStep = class {
|
|
|
28795
28888
|
this._prepared = true;
|
|
28796
28889
|
return this._context;
|
|
28797
28890
|
}
|
|
28891
|
+
/** Ids of already-drained messages that now hold parts the model has not been sent. */
|
|
28892
|
+
changedSinceDrain(messageList) {
|
|
28893
|
+
return messageList.get.all.db().filter((msg) => {
|
|
28894
|
+
const seen = this.turn.drainedPartKeys.get(msg.id);
|
|
28895
|
+
return seen !== void 0 && getPartKeys(msg).some((key) => !seen.has(key));
|
|
28896
|
+
}).map((msg) => msg.id);
|
|
28897
|
+
}
|
|
28798
28898
|
/**
|
|
28799
28899
|
* Run the full threshold observation pipeline:
|
|
28800
28900
|
* waitForBuffering → re-check → activate buffered chunks → reflect → observe
|
|
@@ -28967,6 +29067,49 @@ function restoreDrainedMessages(messageList, drained, source) {
|
|
|
28967
29067
|
const ids = drained.map((msg) => msg.id).filter((id) => !stillQueued.has(id));
|
|
28968
29068
|
for (const msg of messageList.removeByIds(ids)) messageList.add(msg, source, { merge: false });
|
|
28969
29069
|
}
|
|
29070
|
+
/**
|
|
29071
|
+
* Identity keys of a message's non-marker parts. Tool parts are keyed by call id, state and result,
|
|
29072
|
+
* so a result merged in place into an existing tool-invocation part yields a new key. Bookkeeping
|
|
29073
|
+
* fields that change when a part is re-stamped are not part of the identity.
|
|
29074
|
+
*/
|
|
29075
|
+
function getPartKeys(msg) {
|
|
29076
|
+
const seen = /* @__PURE__ */ new Map();
|
|
29077
|
+
return (msg.content.parts ?? []).flatMap((part) => {
|
|
29078
|
+
if (part.type.startsWith("data-om-")) return [];
|
|
29079
|
+
let identity;
|
|
29080
|
+
if (part.type === "tool-invocation") identity = toolPartIdentity(part.toolInvocation);
|
|
29081
|
+
else {
|
|
29082
|
+
const { providerMetadata: _providerMetadata, createdAt: _createdAt, updatedAt: _updatedAt, ...rest } = part;
|
|
29083
|
+
identity = JSON.stringify(rest);
|
|
29084
|
+
}
|
|
29085
|
+
const ordinal = seen.get(identity) ?? 0;
|
|
29086
|
+
seen.set(identity, ordinal + 1);
|
|
29087
|
+
return [`${identity}#${ordinal}`];
|
|
29088
|
+
});
|
|
29089
|
+
}
|
|
29090
|
+
/**
|
|
29091
|
+
* Serializing a tool result on every step is quadratic in turn length (each step rescans every drained
|
|
29092
|
+
* message), so the identity is cached per invocation object and reused while its state and result
|
|
29093
|
+
* reference are unchanged. A result merged in place replaces that reference and is re-serialized.
|
|
29094
|
+
*/
|
|
29095
|
+
const toolPartIdentityCache = /* @__PURE__ */ new WeakMap();
|
|
29096
|
+
function toolPartIdentity(invocation) {
|
|
29097
|
+
const result = invocation.state === "result" ? invocation.result : null;
|
|
29098
|
+
const cached = toolPartIdentityCache.get(invocation);
|
|
29099
|
+
if (cached && cached.state === invocation.state && cached.result === result) return cached.identity;
|
|
29100
|
+
const identity = JSON.stringify([
|
|
29101
|
+
"tool-invocation",
|
|
29102
|
+
invocation.toolCallId,
|
|
29103
|
+
invocation.state,
|
|
29104
|
+
result
|
|
29105
|
+
]);
|
|
29106
|
+
toolPartIdentityCache.set(invocation, {
|
|
29107
|
+
state: invocation.state,
|
|
29108
|
+
result,
|
|
29109
|
+
identity
|
|
29110
|
+
});
|
|
29111
|
+
return identity;
|
|
29112
|
+
}
|
|
28970
29113
|
//#endregion
|
|
28971
29114
|
//#region src/processors/observational-memory/observation-turn/turn.ts
|
|
28972
29115
|
/**
|
|
@@ -29000,6 +29143,19 @@ var ObservationTurn = class {
|
|
|
29000
29143
|
_ended = false;
|
|
29001
29144
|
/** Generation count at turn start — used to detect if reflection happened during the turn. */
|
|
29002
29145
|
_generationCountAtStart = -1;
|
|
29146
|
+
/**
|
|
29147
|
+
* Ids of the messages this turn was started with (the user's request). Mid-turn
|
|
29148
|
+
* observation may record them, but they stay in the live prompt until the turn ends.
|
|
29149
|
+
* @internal Set by step 0.
|
|
29150
|
+
*/
|
|
29151
|
+
inputMessageIds = [];
|
|
29152
|
+
/**
|
|
29153
|
+
* Fingerprints of the non-marker parts each message had when a step last drained it. A message
|
|
29154
|
+
* is unread step output only if it gained a part the model has not seen — including a tool result
|
|
29155
|
+
* merged in place into an existing tool-invocation part — not when it only gained OM markers.
|
|
29156
|
+
* @internal
|
|
29157
|
+
*/
|
|
29158
|
+
drainedPartKeys = /* @__PURE__ */ new Map();
|
|
29003
29159
|
/** Memory context provider — set via start(). Used by steps for beforeBuffer persistence. */
|
|
29004
29160
|
memory;
|
|
29005
29161
|
/** Optional stream writer for emitting markers. */
|
|
@@ -29153,7 +29309,10 @@ var ObservationTurn = class {
|
|
|
29153
29309
|
skipMinimumTokenCheck: true
|
|
29154
29310
|
}).catch((err) => {
|
|
29155
29311
|
omDebug(`[OM:turn.end] idle buffer failed: ${err?.message}`);
|
|
29156
|
-
})
|
|
29312
|
+
}), {
|
|
29313
|
+
threadId: this.threadId,
|
|
29314
|
+
resourceId: this.resourceId
|
|
29315
|
+
});
|
|
29157
29316
|
}
|
|
29158
29317
|
return { record: this._record };
|
|
29159
29318
|
}
|
|
@@ -29597,6 +29756,7 @@ var ReflectorRunner = class {
|
|
|
29597
29756
|
* number per active thread/resource key and live for the runner's lifetime.
|
|
29598
29757
|
*/
|
|
29599
29758
|
syncReflectionSuppression = /* @__PURE__ */ new Map();
|
|
29759
|
+
trackBackgroundWork;
|
|
29600
29760
|
constructor(opts) {
|
|
29601
29761
|
this.reflectionConfig = opts.reflectionConfig;
|
|
29602
29762
|
this.observationConfig = opts.observationConfig;
|
|
@@ -29613,6 +29773,7 @@ var ReflectorRunner = class {
|
|
|
29613
29773
|
this.memory = opts.memory;
|
|
29614
29774
|
this.onReflectionCommitted = opts.onReflectionCommitted;
|
|
29615
29775
|
this.hooks = opts.hooks;
|
|
29776
|
+
this.trackBackgroundWork = opts.trackBackgroundWork;
|
|
29616
29777
|
}
|
|
29617
29778
|
__registerMastra(mastra) {
|
|
29618
29779
|
this.mastra = mastra;
|
|
@@ -29709,7 +29870,7 @@ var ReflectorRunner = class {
|
|
|
29709
29870
|
const prompt = buildReflectorPrompt(observations, manualPrompt, currentLevel, skipContinuationHints, activeExtractors, priorExtractedValues);
|
|
29710
29871
|
omDebug(`[OM:callReflector] ${isRetry ? `retry #${attemptNumber - 1}` : "first attempt"}: level=${currentLevel}, originalTokens=${originalTokens}, targetThreshold=${targetThreshold}, promptLen=${prompt.length}, skipContinuationHints=${skipContinuationHints}`);
|
|
29711
29872
|
let chunkCount = 0;
|
|
29712
|
-
const result = await withRetry(() => withOmTracingSpan({
|
|
29873
|
+
const result = await withRetry((attemptSignal, onActivity) => withOmTracingSpan({
|
|
29713
29874
|
phase: "reflector",
|
|
29714
29875
|
model: resolvedModel.model,
|
|
29715
29876
|
inputTokens: originalTokens,
|
|
@@ -29733,17 +29894,19 @@ var ReflectorRunner = class {
|
|
|
29733
29894
|
modelSettings: { ...this.reflectionConfig.modelSettings },
|
|
29734
29895
|
providerOptions: this.reflectionConfig.providerOptions,
|
|
29735
29896
|
...attemptMemory ? { memory: attemptMemory } : {},
|
|
29736
|
-
|
|
29897
|
+
abortSignal: attemptSignal,
|
|
29737
29898
|
...internalRequestContext ? { requestContext: internalRequestContext } : {},
|
|
29738
29899
|
...childObservabilityContext,
|
|
29900
|
+
onChunk(chunk) {
|
|
29901
|
+
onActivity();
|
|
29902
|
+
if (attemptNumber !== 1) return;
|
|
29903
|
+
chunkCount++;
|
|
29904
|
+
if (chunkCount === 1 || chunkCount % 50 === 0) {
|
|
29905
|
+
const preview = chunk.type === "text-delta" ? ` text="${chunk.textDelta?.slice(0, 80)}..."` : chunk.type === "tool-call" ? ` tool=${chunk.toolName}` : "";
|
|
29906
|
+
omDebug(`[OM:callReflector] chunk#${chunkCount}: type=${chunk.type}${preview}`);
|
|
29907
|
+
}
|
|
29908
|
+
},
|
|
29739
29909
|
...attemptNumber === 1 ? {
|
|
29740
|
-
onChunk(chunk) {
|
|
29741
|
-
chunkCount++;
|
|
29742
|
-
if (chunkCount === 1 || chunkCount % 50 === 0) {
|
|
29743
|
-
const preview = chunk.type === "text-delta" ? ` text="${chunk.textDelta?.slice(0, 80)}..."` : chunk.type === "tool-call" ? ` tool=${chunk.toolName}` : "";
|
|
29744
|
-
omDebug(`[OM:callReflector] chunk#${chunkCount}: type=${chunk.type}${preview}`);
|
|
29745
|
-
}
|
|
29746
|
-
},
|
|
29747
29910
|
onFinish(event) {
|
|
29748
29911
|
omDebug(`[OM:callReflector] onFinish: chunks=${chunkCount}, finishReason=${event.finishReason}, inputTokens=${event.usage?.inputTokens}, outputTokens=${event.usage?.outputTokens}, textLen=${event.text?.length}`);
|
|
29749
29912
|
},
|
|
@@ -29763,6 +29926,7 @@ var ReflectorRunner = class {
|
|
|
29763
29926
|
}), {
|
|
29764
29927
|
label: "reflector",
|
|
29765
29928
|
abortSignal,
|
|
29929
|
+
idleTimeoutMs: RETRY_CONFIG.modelCallIdleTimeoutMs,
|
|
29766
29930
|
maxRetries: this.reflectionConfig.maxRetries
|
|
29767
29931
|
});
|
|
29768
29932
|
omDebug(`[OM:callReflector] attempt #${attemptNumber} returned: textLen=${result.text?.length}, textPreview="${result.text?.slice(0, 120)}...", inputTokens=${result.usage?.inputTokens ?? result.totalUsage?.inputTokens}, outputTokens=${result.usage?.outputTokens ?? result.totalUsage?.outputTokens}`);
|
|
@@ -29870,10 +30034,11 @@ var ReflectorRunner = class {
|
|
|
29870
30034
|
if (this.buffering.isAsyncBufferingInProgress(bufferKey)) return;
|
|
29871
30035
|
BufferingCoordinator.lastBufferedBoundary.set(bufferKey, observationTokens);
|
|
29872
30036
|
registerOp(record.id, "bufferingReflection");
|
|
29873
|
-
this.storage.setBufferingReflectionFlag(record.id, true).catch((err) => {
|
|
30037
|
+
const flagSet = this.storage.setBufferingReflectionFlag(record.id, true).catch((err) => {
|
|
29874
30038
|
omError("[OM] Failed to set buffering reflection flag", err);
|
|
29875
30039
|
});
|
|
29876
30040
|
const asyncOp = (async () => {
|
|
30041
|
+
await flagSet;
|
|
29877
30042
|
let outcome;
|
|
29878
30043
|
let reflectionError;
|
|
29879
30044
|
try {
|
|
@@ -29914,12 +30079,13 @@ var ReflectorRunner = class {
|
|
|
29914
30079
|
}
|
|
29915
30080
|
BufferingCoordinator.asyncBufferingOps.delete(bufferKey);
|
|
29916
30081
|
unregisterOp(record.id, "bufferingReflection");
|
|
29917
|
-
this.storage.setBufferingReflectionFlag(record.id, false).catch((err) => {
|
|
30082
|
+
await this.storage.setBufferingReflectionFlag(record.id, false).catch((err) => {
|
|
29918
30083
|
omError("[OM] Failed to clear buffering reflection flag", err);
|
|
29919
30084
|
});
|
|
29920
30085
|
}
|
|
29921
30086
|
})();
|
|
29922
30087
|
BufferingCoordinator.asyncBufferingOps.set(bufferKey, asyncOp);
|
|
30088
|
+
this.trackBackgroundWork?.(asyncOp, lockKey);
|
|
29923
30089
|
}
|
|
29924
30090
|
/**
|
|
29925
30091
|
* Perform async buffered reflection — reflects observations and stores to bufferedReflection.
|
|
@@ -30947,32 +31113,44 @@ var ObservationalMemory = class ObservationalMemory {
|
|
|
30947
31113
|
* Tracked so callers can join them via `settled()` before closing a storage
|
|
30948
31114
|
* connection they own — otherwise a background cycle's tail statements race the close.
|
|
30949
31115
|
*/
|
|
30950
|
-
pendingBackgroundWork = /* @__PURE__ */ new
|
|
31116
|
+
pendingBackgroundWork = /* @__PURE__ */ new Map();
|
|
30951
31117
|
/**
|
|
30952
31118
|
* Register fire-and-forget background work so `settled()` can join it.
|
|
31119
|
+
* `scope` is the conversation the work belongs to (thread/resource ids, or a lock key from
|
|
31120
|
+
* `buffering.getLockKey`),
|
|
31121
|
+
* so a scoped `settled()` can wait for one conversation without waiting for every other.
|
|
30953
31122
|
* Returns the original promise so callers keep their own rejection handling.
|
|
30954
31123
|
*/
|
|
30955
|
-
trackBackgroundWork(work) {
|
|
31124
|
+
trackBackgroundWork(work, scope) {
|
|
31125
|
+
const lockKey = typeof scope === "string" ? scope : this.buffering.getLockKey(scope.threadId, scope.resourceId);
|
|
30956
31126
|
const tracked = work.catch(() => {}).finally(() => {
|
|
30957
31127
|
this.pendingBackgroundWork.delete(tracked);
|
|
30958
31128
|
});
|
|
30959
|
-
this.pendingBackgroundWork.
|
|
31129
|
+
this.pendingBackgroundWork.set(tracked, lockKey);
|
|
30960
31130
|
return work;
|
|
30961
31131
|
}
|
|
30962
31132
|
/**
|
|
30963
|
-
* Resolve once
|
|
31133
|
+
* Resolve once background observational-memory work started so far has finished.
|
|
31134
|
+
*
|
|
31135
|
+
* Pass `threadId`/`resourceId` to wait only for that conversation's work. An engine shared by
|
|
31136
|
+
* many busy threads may never be fully idle, so an unscoped wait can last indefinitely there.
|
|
31137
|
+
* A scope without the id this engine keys work on (`resourceId` for resource scope, `threadId`
|
|
31138
|
+
* for thread scope) can't be matched to its work, so it falls back to waiting for all work.
|
|
30964
31139
|
*
|
|
30965
31140
|
* Background cycles enqueue further background work (a buffered observation can
|
|
30966
31141
|
* trigger a reflection, which runs nested agent streams), so this drains repeatedly
|
|
30967
31142
|
* until nothing is left rather than joining a single snapshot.
|
|
30968
31143
|
*/
|
|
30969
|
-
async settled() {
|
|
31144
|
+
async settled(scope) {
|
|
31145
|
+
const lockKey = (this.scope === "resource" ? scope?.resourceId : scope?.threadId) ? this.buffering.getLockKey(scope.threadId, scope.resourceId) : void 0;
|
|
31146
|
+
const pending = () => [...this.pendingBackgroundWork].filter(([, key]) => lockKey === void 0 || key === lockKey).map(([w]) => w);
|
|
30970
31147
|
const maxDrainRounds = 100;
|
|
30971
31148
|
for (let round = 0; round < maxDrainRounds; round++) {
|
|
30972
|
-
|
|
30973
|
-
|
|
31149
|
+
const work = pending();
|
|
31150
|
+
if (work.length === 0) return;
|
|
31151
|
+
await Promise.allSettled(work);
|
|
30974
31152
|
}
|
|
30975
|
-
if (
|
|
31153
|
+
if (pending().length === 0) return;
|
|
30976
31154
|
omError(`[OM:settled] background work still pending after ${maxDrainRounds} drain rounds; giving up waiting`);
|
|
30977
31155
|
}
|
|
30978
31156
|
/**
|
|
@@ -31128,7 +31306,8 @@ var ObservationalMemory = class ObservationalMemory {
|
|
|
31128
31306
|
mastra: config.mastra,
|
|
31129
31307
|
memory: this.memory,
|
|
31130
31308
|
onReflectionCommitted: config.onReflectionCommitted,
|
|
31131
|
-
hooks: this.hooks
|
|
31309
|
+
hooks: this.hooks,
|
|
31310
|
+
trackBackgroundWork: (work, lockKey) => this.trackBackgroundWork(work, lockKey)
|
|
31132
31311
|
});
|
|
31133
31312
|
this.validateBufferConfig();
|
|
31134
31313
|
if (this.scope === "resource" && !hasWarnedResourceScopeDeprecation) {
|
|
@@ -31984,11 +32163,12 @@ ${formattedMessages}
|
|
|
31984
32163
|
}).finally(() => {
|
|
31985
32164
|
if (BufferingCoordinator.asyncBufferingOps.get(bufferKey) === asyncOp) BufferingCoordinator.asyncBufferingOps.delete(bufferKey);
|
|
31986
32165
|
unregisterOp(record.id, "bufferingObservation");
|
|
31987
|
-
runOMCommit(lockKey, () => this.storage.setBufferingObservationFlag(record.id, false)).catch((err) => {
|
|
32166
|
+
return runOMCommit(lockKey, () => this.storage.setBufferingObservationFlag(record.id, false)).catch((err) => {
|
|
31988
32167
|
omError("[OM] Failed to clear buffering observation flag", err);
|
|
31989
32168
|
});
|
|
31990
32169
|
});
|
|
31991
32170
|
BufferingCoordinator.asyncBufferingOps.set(bufferKey, asyncOp);
|
|
32171
|
+
return { op: asyncOp };
|
|
31992
32172
|
}
|
|
31993
32173
|
/**
|
|
31994
32174
|
* Internal method that waits for existing buffering operation and then runs new buffering.
|
|
@@ -32088,7 +32268,7 @@ ${formattedMessages}
|
|
|
32088
32268
|
if (!this.buffering.isAsyncObservationEnabled()) return false;
|
|
32089
32269
|
const lockKey = this.buffering.getLockKey(opts.threadId, opts.resourceId);
|
|
32090
32270
|
const shouldTrigger = this.buffering.shouldTriggerAsyncObservation(opts.pendingTokens, lockKey, opts.record, this.storage, opts.threshold);
|
|
32091
|
-
if (shouldTrigger) this.trackBackgroundWork(this.startAsyncBufferedObservation(opts.record, opts.threadId, opts.unobservedMessages, lockKey, opts.writer, opts.unbufferedPendingTokens, opts.requestContext, opts.observabilityContext));
|
|
32271
|
+
if (shouldTrigger) this.trackBackgroundWork(this.startAsyncBufferedObservation(opts.record, opts.threadId, opts.unobservedMessages, lockKey, opts.writer, opts.unbufferedPendingTokens, opts.requestContext, opts.observabilityContext).then(({ op }) => op), lockKey);
|
|
32092
32272
|
return shouldTrigger;
|
|
32093
32273
|
}
|
|
32094
32274
|
isMessageList(value) {
|
|
@@ -34140,9 +34320,9 @@ var Memory = class Memory extends MastraMemory {
|
|
|
34140
34320
|
* await store.close();
|
|
34141
34321
|
* ```
|
|
34142
34322
|
*/
|
|
34143
|
-
async settled() {
|
|
34323
|
+
async settled(scope) {
|
|
34144
34324
|
await this.pendingVectorCleanup;
|
|
34145
|
-
await (this._omEngine ? await this._omEngine : this._omEngineInstance)?.settled();
|
|
34325
|
+
await (this._omEngine ? await this._omEngine : this._omEngineInstance)?.settled(scope);
|
|
34146
34326
|
await this.pendingVectorCleanup;
|
|
34147
34327
|
}
|
|
34148
34328
|
/** The shared ObservationalMemory engine. Lazily created on first access. */
|
|
@@ -36431,4 +36611,4 @@ Notes:
|
|
|
36431
36611
|
//#endregion
|
|
36432
36612
|
export { renderSubconsciousActivity as $, buildObserverSystemPrompt as A, OBSERVATION_CONTEXT_INSTRUCTIONS as B, WorkingMemoryExtractor as C, TokenCounter as D, summarizeConversation as E, parseObserverOutput as F, Subconscious as G, OBSERVATION_CONTEXT_PROMPT_THREAD as H, injectAnchorIds as I, SubconsciousRemindExtractor as J, KnowledgeSemanticIndexCoordinator as K, parseAnchorId as L, formatMessagesForObserver as M, hasCurrentTaskSection as N, OBSERVER_SYSTEM_PROMPT as O, optimizeObservationsForContext as P, publishSubconsciousActivity as Q, stripEphemeralAnchorIds as R, wrapInObservationGroup as S, SUMMARIZE_THREAD_DEFAULTS as T, OBSERVATION_CONTINUATION_HINT as U, OBSERVATION_CONTEXT_PROMPT as V, getObservationContextPrompt as W, SUBCONSCIOUS_ACTIVITY_STATE_ID as X, ModelByInputTokens as Y, buildSubconsciousActivitySnapshot as Z, deriveObservationGroupProvenance as _, extractWorkingMemoryContent as a, renderObservationGroupsForReflection as b, getObservationsAsOf as c, AUTO_MODEL_BY_PROVIDER as d, Extractor as et, resolveAutoModelId as f, combineObservationGroupRanges as g, WorkingMemoryStateProcessor as h, WorkingMemory as i, extractCurrentTask as j, buildObserverPrompt as k, ObservationalMemoryProcessor as l, WORKING_MEMORY_STATE_PROCESSOR_ID as m, MessageHistory$1 as n, extractWorkingMemoryTags as o, WORKING_MEMORY_STATE_ID as p, StaleKnowledgeSemanticIndexError as q, SemanticRecall as r, removeWorkingMemoryTags as s, Memory as t, ObservationalMemory as u, parseObservationGroups as v, deepMergeWorkingMemory as w, stripObservationGroups as x, reconcileObservationGroupsFromReflection as y, OBSERVATIONAL_MEMORY_DEFAULTS as z };
|
|
36433
36613
|
|
|
36434
|
-
//# sourceMappingURL=src
|
|
36614
|
+
//# sourceMappingURL=src--zkaCof1.js.map
|