@mastra/memory 1.26.1-alpha.0 → 1.26.1-alpha.3
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 +50 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +25 -2
- 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/message-utils.d.ts +13 -0
- package/dist/processors/observational-memory/message-utils.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-turn/turn.d.ts.map +1 -1
- package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
- package/dist/processors/observational-memory/processor.d.ts.map +1 -1
- package/dist/processors/observational-memory/reflector-runner.d.ts.map +1 -1
- package/dist/processors/observational-memory/temporal-markers.d.ts.map +1 -1
- package/dist/processors/observational-memory/token-counter.d.ts +7 -0
- package/dist/processors/observational-memory/token-counter.d.ts.map +1 -1
- package/dist/{src-x5iu_K3X.cjs → src-CTQrRb5X.cjs} +163 -81
- package/dist/{src-x5iu_K3X.cjs.map → src-CTQrRb5X.cjs.map} +1 -1
- package/dist/{src-Iw-V5CfD.js → src-MScpLVRh.js} +163 -81
- package/dist/{src-Iw-V5CfD.js.map → src-MScpLVRh.js.map} +1 -1
- package/dist/tools/om-tools.d.ts +2 -0
- package/dist/tools/om-tools.d.ts.map +1 -1
- package/dist/tools/working-memory.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -18521,33 +18521,62 @@ var TokenCounter = class TokenCounter {
|
|
|
18521
18521
|
if (isImageAttachment) await resolveImageDimensionsAsync(part);
|
|
18522
18522
|
return this.countAttachmentPartSync(part);
|
|
18523
18523
|
}
|
|
18524
|
+
/**
|
|
18525
|
+
* Count the name and the arguments of a tool call. Every state before the tool produces an
|
|
18526
|
+
* output holds the same call signature in the context window, so all of those states share
|
|
18527
|
+
* these cache kinds. `buildEstimateKey` hashes the text, so a shared kind stays correct and
|
|
18528
|
+
* keeps the estimate warm while the invocation moves from one state to the next.
|
|
18529
|
+
*/
|
|
18530
|
+
countToolCallSignature(part, invocation) {
|
|
18531
|
+
let tokens = 0;
|
|
18532
|
+
let overheadDelta = 0;
|
|
18533
|
+
if (invocation.toolName) tokens += this.readOrPersistPartEstimate(part, "tool-call-name", invocation.toolName);
|
|
18534
|
+
if (invocation.args) if (typeof invocation.args === "string") tokens += this.readOrPersistPartEstimate(part, "tool-call-args", invocation.args);
|
|
18535
|
+
else {
|
|
18536
|
+
const argsJson = JSON.stringify(invocation.args);
|
|
18537
|
+
tokens += this.readOrPersistPartEstimate(part, "tool-call-args-json", argsJson);
|
|
18538
|
+
overheadDelta -= 12;
|
|
18539
|
+
}
|
|
18540
|
+
return {
|
|
18541
|
+
tokens,
|
|
18542
|
+
overheadDelta
|
|
18543
|
+
};
|
|
18544
|
+
}
|
|
18524
18545
|
countNonAttachmentPart(part) {
|
|
18525
18546
|
let overheadDelta = 0;
|
|
18526
|
-
let
|
|
18547
|
+
let extraMessageDelta = 0;
|
|
18527
18548
|
if (part.type === "text") return {
|
|
18528
18549
|
tokens: this.readOrPersistPartEstimate(part, "text", part.text),
|
|
18529
18550
|
overheadDelta,
|
|
18530
|
-
|
|
18551
|
+
extraMessageDelta
|
|
18531
18552
|
};
|
|
18532
18553
|
if (part.type === "tool-invocation") {
|
|
18533
18554
|
const invocation = part.toolInvocation;
|
|
18555
|
+
const state = invocation.state;
|
|
18534
18556
|
let tokens = 0;
|
|
18535
|
-
if (
|
|
18536
|
-
|
|
18537
|
-
|
|
18538
|
-
|
|
18539
|
-
|
|
18540
|
-
|
|
18541
|
-
|
|
18542
|
-
|
|
18557
|
+
if (state === "call" || state === "partial-call" || state === "approval-requested") {
|
|
18558
|
+
const signature = this.countToolCallSignature(part, invocation);
|
|
18559
|
+
return {
|
|
18560
|
+
tokens: signature.tokens,
|
|
18561
|
+
overheadDelta: overheadDelta + signature.overheadDelta,
|
|
18562
|
+
extraMessageDelta
|
|
18563
|
+
};
|
|
18564
|
+
}
|
|
18565
|
+
if (state === "approval-responded") {
|
|
18566
|
+
extraMessageDelta++;
|
|
18567
|
+
const signature = this.countToolCallSignature(part, invocation);
|
|
18568
|
+
tokens += signature.tokens;
|
|
18569
|
+
overheadDelta += signature.overheadDelta;
|
|
18570
|
+
const reason = invocation.approval?.reason;
|
|
18571
|
+
if (reason) tokens += this.readOrPersistPartEstimate(part, "tool-approval-reason", reason);
|
|
18543
18572
|
return {
|
|
18544
18573
|
tokens,
|
|
18545
18574
|
overheadDelta,
|
|
18546
|
-
|
|
18575
|
+
extraMessageDelta
|
|
18547
18576
|
};
|
|
18548
18577
|
}
|
|
18549
|
-
if (
|
|
18550
|
-
|
|
18578
|
+
if (state === "result") {
|
|
18579
|
+
extraMessageDelta++;
|
|
18551
18580
|
const { value: resultForCounting, usingStoredModelOutput } = this.resolveToolResultForTokenCounting(part, invocation.result);
|
|
18552
18581
|
if (resultForCounting !== void 0) {
|
|
18553
18582
|
const contentTokens = this.countMultimodalToolResultContent(part, resultForCounting);
|
|
@@ -18561,47 +18590,45 @@ var TokenCounter = class TokenCounter {
|
|
|
18561
18590
|
return {
|
|
18562
18591
|
tokens,
|
|
18563
18592
|
overheadDelta,
|
|
18564
|
-
|
|
18593
|
+
extraMessageDelta
|
|
18565
18594
|
};
|
|
18566
18595
|
}
|
|
18567
|
-
if (
|
|
18568
|
-
|
|
18596
|
+
if (state === "output-denied") {
|
|
18597
|
+
extraMessageDelta++;
|
|
18569
18598
|
const reason = invocation.approval?.reason ?? "Tool call was not approved by the user";
|
|
18570
18599
|
tokens += this.readOrPersistPartEstimate(part, "tool-result-denied", reason);
|
|
18571
18600
|
return {
|
|
18572
18601
|
tokens,
|
|
18573
18602
|
overheadDelta,
|
|
18574
|
-
|
|
18603
|
+
extraMessageDelta
|
|
18575
18604
|
};
|
|
18576
18605
|
}
|
|
18577
|
-
if (
|
|
18578
|
-
|
|
18579
|
-
const
|
|
18580
|
-
const errorMessage = typeof errorText === "string" ? errorText : "Tool execution failed";
|
|
18606
|
+
if (state === "output-error") {
|
|
18607
|
+
extraMessageDelta++;
|
|
18608
|
+
const errorMessage = typeof invocation.errorText === "string" ? invocation.errorText : "Tool execution failed";
|
|
18581
18609
|
tokens += this.readOrPersistPartEstimate(part, "tool-result-error", errorMessage);
|
|
18582
18610
|
return {
|
|
18583
18611
|
tokens,
|
|
18584
18612
|
overheadDelta,
|
|
18585
|
-
|
|
18613
|
+
extraMessageDelta
|
|
18586
18614
|
};
|
|
18587
18615
|
}
|
|
18588
|
-
throw new Error(`Unhandled tool-invocation state '${part.toolInvocation?.state}' in token counting for part type '${part.type}'`);
|
|
18589
18616
|
}
|
|
18590
18617
|
if (typeof part.type === "string" && part.type.startsWith("data-")) return {
|
|
18591
18618
|
tokens: 0,
|
|
18592
18619
|
overheadDelta,
|
|
18593
|
-
|
|
18620
|
+
extraMessageDelta
|
|
18594
18621
|
};
|
|
18595
18622
|
if (part.type === "reasoning") return {
|
|
18596
18623
|
tokens: 0,
|
|
18597
18624
|
overheadDelta,
|
|
18598
|
-
|
|
18625
|
+
extraMessageDelta
|
|
18599
18626
|
};
|
|
18600
18627
|
const serialized = serializePartForTokenCounting(part);
|
|
18601
18628
|
return {
|
|
18602
18629
|
tokens: this.readOrPersistPartEstimate(part, `part-${part.type}`, serialized),
|
|
18603
18630
|
overheadDelta,
|
|
18604
|
-
|
|
18631
|
+
extraMessageDelta
|
|
18605
18632
|
};
|
|
18606
18633
|
}
|
|
18607
18634
|
/**
|
|
@@ -18610,7 +18637,7 @@ var TokenCounter = class TokenCounter {
|
|
|
18610
18637
|
countMessage(message) {
|
|
18611
18638
|
let payloadTokens = this.countString(message.role);
|
|
18612
18639
|
let overhead = TokenCounter.TOKENS_PER_MESSAGE;
|
|
18613
|
-
let
|
|
18640
|
+
let extraMessageCount = 0;
|
|
18614
18641
|
if (typeof message.content === "string") payloadTokens += this.readOrPersistMessageEstimate(message, "message-content", message.content);
|
|
18615
18642
|
else if (message.content && typeof message.content === "object") {
|
|
18616
18643
|
if (message.content.content && !Array.isArray(message.content.parts)) payloadTokens += this.readOrPersistMessageEstimate(message, "content-content", message.content.content);
|
|
@@ -18623,16 +18650,16 @@ var TokenCounter = class TokenCounter {
|
|
|
18623
18650
|
const result = this.countNonAttachmentPart(part);
|
|
18624
18651
|
payloadTokens += result.tokens;
|
|
18625
18652
|
overhead += result.overheadDelta;
|
|
18626
|
-
|
|
18653
|
+
extraMessageCount += result.extraMessageDelta;
|
|
18627
18654
|
}
|
|
18628
18655
|
}
|
|
18629
|
-
if (
|
|
18656
|
+
if (extraMessageCount > 0) overhead += extraMessageCount * TokenCounter.TOKENS_PER_MESSAGE;
|
|
18630
18657
|
return Math.round(payloadTokens + overhead);
|
|
18631
18658
|
}
|
|
18632
18659
|
async countMessageAsync(message) {
|
|
18633
18660
|
let payloadTokens = this.countString(message.role);
|
|
18634
18661
|
let overhead = TokenCounter.TOKENS_PER_MESSAGE;
|
|
18635
|
-
let
|
|
18662
|
+
let extraMessageCount = 0;
|
|
18636
18663
|
if (typeof message.content === "string") payloadTokens += this.readOrPersistMessageEstimate(message, "message-content", message.content);
|
|
18637
18664
|
else if (message.content && typeof message.content === "object") {
|
|
18638
18665
|
if (message.content.content && !Array.isArray(message.content.parts)) payloadTokens += this.readOrPersistMessageEstimate(message, "content-content", message.content.content);
|
|
@@ -18645,10 +18672,10 @@ var TokenCounter = class TokenCounter {
|
|
|
18645
18672
|
const result = this.countNonAttachmentPart(part);
|
|
18646
18673
|
payloadTokens += result.tokens;
|
|
18647
18674
|
overhead += result.overheadDelta;
|
|
18648
|
-
|
|
18675
|
+
extraMessageCount += result.extraMessageDelta;
|
|
18649
18676
|
}
|
|
18650
18677
|
}
|
|
18651
|
-
if (
|
|
18678
|
+
if (extraMessageCount > 0) overhead += extraMessageCount * TokenCounter.TOKENS_PER_MESSAGE;
|
|
18652
18679
|
return Math.round(payloadTokens + overhead);
|
|
18653
18680
|
}
|
|
18654
18681
|
/**
|
|
@@ -18959,9 +18986,10 @@ async function listThreadsForResource({ memory, resourceId, currentThreadId, pag
|
|
|
18959
18986
|
hasMore
|
|
18960
18987
|
};
|
|
18961
18988
|
}
|
|
18989
|
+
const SEARCH_NOT_CONFIGURED_MESSAGE = "Search is not configured. Enable it with `retrieval: { vector: true }` and configure a vector store and embedder on your Memory instance.";
|
|
18962
18990
|
async function searchMessagesForResource({ memory, resourceId, currentThreadId, query, topK = 10, maxTokens = DEFAULT_MAX_RESULT_TOKENS, before, after, threadScope }) {
|
|
18963
18991
|
if (!memory.searchMessages) return {
|
|
18964
|
-
results:
|
|
18992
|
+
results: SEARCH_NOT_CONFIGURED_MESSAGE,
|
|
18965
18993
|
count: 0
|
|
18966
18994
|
};
|
|
18967
18995
|
const MAX_TOPK = 20;
|
|
@@ -19507,9 +19535,16 @@ async function recallThreadFromStart({ memory, threadId, resourceId, page = 1, l
|
|
|
19507
19535
|
}
|
|
19508
19536
|
const recallTool = (_memoryConfig, options) => {
|
|
19509
19537
|
const isResourceScope = (options?.retrievalScope ?? "thread") === "resource";
|
|
19538
|
+
const searchEnabled = options?.searchEnabled ?? true;
|
|
19539
|
+
const description = isResourceScope ? `Browse conversation history. Use mode="threads" to list all threads for the current user. Use mode="messages" (default) to browse messages in the current thread or pass threadId to browse another thread in the active resource. When mode="messages" has no cursor or threadId, it defaults to the current thread and says so at the top of the result. If you pass only a cursor, it must belong to the current thread.${searchEnabled ? " Use mode=\"search\" to find messages by content across all threads." : ""}` : `Browse conversation history in the current thread. Use mode="messages" (default) to page through messages near a cursor.${searchEnabled ? " Use mode=\"search\" to find messages by content in this thread." : ""} Use mode="threads" to get the current thread's ID and title.`;
|
|
19540
|
+
const modeEnum = searchEnabled ? [
|
|
19541
|
+
"messages",
|
|
19542
|
+
"threads",
|
|
19543
|
+
"search"
|
|
19544
|
+
] : ["messages", "threads"];
|
|
19510
19545
|
return createTool({
|
|
19511
19546
|
id: "recall",
|
|
19512
|
-
description
|
|
19547
|
+
description,
|
|
19513
19548
|
inputSchema: {
|
|
19514
19549
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
19515
19550
|
type: "object",
|
|
@@ -19517,12 +19552,8 @@ const recallTool = (_memoryConfig, options) => {
|
|
|
19517
19552
|
...isResourceScope ? {
|
|
19518
19553
|
mode: {
|
|
19519
19554
|
type: "string",
|
|
19520
|
-
enum:
|
|
19521
|
-
|
|
19522
|
-
"threads",
|
|
19523
|
-
"search"
|
|
19524
|
-
],
|
|
19525
|
-
description: "What to retrieve. \"messages\" (default) pages through message history. \"threads\" lists all threads for the current user. \"search\" finds messages by semantic similarity across all threads."
|
|
19555
|
+
enum: modeEnum,
|
|
19556
|
+
description: `What to retrieve. "messages" (default) pages through message history. "threads" lists all threads for the current user.${searchEnabled ? " \"search\" finds messages by semantic similarity across all threads." : ""}`
|
|
19526
19557
|
},
|
|
19527
19558
|
threadId: {
|
|
19528
19559
|
type: "string",
|
|
@@ -19539,18 +19570,14 @@ const recallTool = (_memoryConfig, options) => {
|
|
|
19539
19570
|
}
|
|
19540
19571
|
} : { mode: {
|
|
19541
19572
|
type: "string",
|
|
19542
|
-
enum:
|
|
19543
|
-
|
|
19544
|
-
"threads",
|
|
19545
|
-
"search"
|
|
19546
|
-
],
|
|
19547
|
-
description: "What to retrieve. \"messages\" (default) pages through message history. \"threads\" returns info about the current thread. \"search\" finds messages by semantic similarity in this thread."
|
|
19573
|
+
enum: modeEnum,
|
|
19574
|
+
description: `What to retrieve. "messages" (default) pages through message history. "threads" returns info about the current thread.${searchEnabled ? " \"search\" finds messages by semantic similarity in this thread." : ""}`
|
|
19548
19575
|
} },
|
|
19549
|
-
query: {
|
|
19576
|
+
...searchEnabled ? { query: {
|
|
19550
19577
|
type: "string",
|
|
19551
19578
|
minLength: 1,
|
|
19552
19579
|
description: "Search query for mode=\"search\". Finds messages semantically similar to this text."
|
|
19553
|
-
},
|
|
19580
|
+
} } : {},
|
|
19554
19581
|
cursor: {
|
|
19555
19582
|
type: "string",
|
|
19556
19583
|
minLength: 1,
|
|
@@ -19611,6 +19638,10 @@ const recallTool = (_memoryConfig, options) => {
|
|
|
19611
19638
|
if (!memory) throw new Error("Memory instance is required for recall");
|
|
19612
19639
|
if (explicitThreadId === "current" && !currentThreadId) throw new Error("Could not resolve current thread.");
|
|
19613
19640
|
if (mode === "search") {
|
|
19641
|
+
if (!searchEnabled) return {
|
|
19642
|
+
results: SEARCH_NOT_CONFIGURED_MESSAGE,
|
|
19643
|
+
count: 0
|
|
19644
|
+
};
|
|
19614
19645
|
if (!query) throw new Error("query is required for mode=\"search\"");
|
|
19615
19646
|
if (!resourceId) throw new Error("Resource ID is required for recall");
|
|
19616
19647
|
return searchMessagesForResource({
|
|
@@ -19747,6 +19778,7 @@ function deepMergeWorkingMemory(existing, update) {
|
|
|
19747
19778
|
for (const key of Object.keys(update)) {
|
|
19748
19779
|
const updateValue = update[key];
|
|
19749
19780
|
const existingValue = result[key];
|
|
19781
|
+
if (updateValue === void 0) continue;
|
|
19750
19782
|
if (updateValue === null) delete result[key];
|
|
19751
19783
|
else if (Array.isArray(updateValue)) result[key] = updateValue;
|
|
19752
19784
|
else if (typeof updateValue === "object" && updateValue !== null && typeof existingValue === "object" && existingValue !== null && !Array.isArray(existingValue)) result[key] = deepMergeWorkingMemory(existingValue, updateValue);
|
|
@@ -19799,7 +19831,7 @@ const updateWorkingMemoryTool = (memoryConfig) => {
|
|
|
19799
19831
|
version: 1,
|
|
19800
19832
|
vendor: "mastra",
|
|
19801
19833
|
validate: (value) => {
|
|
19802
|
-
const memoryValue = !!value && typeof value === "object" && !Array.isArray(value) && "memory" in value ? value.memory :
|
|
19834
|
+
const memoryValue = stripNullsFromOptional(!!value && typeof value === "object" && !Array.isArray(value) && "memory" in value ? value.memory : value, jsonSchema);
|
|
19803
19835
|
const result = validateMemory(memoryValue);
|
|
19804
19836
|
return result instanceof Promise ? result.then(toWrappedResult) : toWrappedResult(result);
|
|
19805
19837
|
},
|
|
@@ -19816,6 +19848,7 @@ const updateWorkingMemoryTool = (memoryConfig) => {
|
|
|
19816
19848
|
id: "update-working-memory",
|
|
19817
19849
|
description: schema ? useStateSignals ? `${stateSignalsPreamble} Data is merged with existing memory — only include fields you want to add or update.` : `Update the working memory with new information. Data is merged with existing memory - only include fields you want to add or update. To preserve existing data, omit the field entirely. Arrays are replaced entirely when provided, so pass the complete array or omit it to keep the existing values.` : useStateSignals ? `${stateSignalsPreamble} Pass the full updated Markdown blob as a string in the memory field.` : `Update the working memory with new information. Any data not included will be overwritten. Always pass data as string to the memory field. Never pass an object.`,
|
|
19818
19850
|
inputSchema,
|
|
19851
|
+
...usesMergeSemantics ? { strict: false } : {},
|
|
19819
19852
|
execute: async (inputData, context) => {
|
|
19820
19853
|
const workingMemoryInput = inputData;
|
|
19821
19854
|
const threadId = context?.agent?.threadId;
|
|
@@ -20572,6 +20605,24 @@ function getUnobservedPartsPreservingToolCallPairs(message) {
|
|
|
20572
20605
|
return preservedCalls.length > 0 ? [...preservedCalls, ...unobservedParts] : unobservedParts;
|
|
20573
20606
|
}
|
|
20574
20607
|
/**
|
|
20608
|
+
* Get the messages Observational Memory is allowed to work with.
|
|
20609
|
+
*
|
|
20610
|
+
* Messages supplied through the `context` option are per-run ephemeral input. Core's
|
|
20611
|
+
* persistence contract already treats them as never-persist: `MessageStateManager` routes
|
|
20612
|
+
* them into `userContextMessages`, and `drainUnsavedMessages` only drains input/response.
|
|
20613
|
+
*
|
|
20614
|
+
* OM builds its windows from `get.all.db()`, which includes context messages, and then
|
|
20615
|
+
* seals and persists candidates directly — turning ephemeral context into durable user
|
|
20616
|
+
* messages. Excluding them here keeps OM's window, sealing, persistence and token
|
|
20617
|
+
* accounting consistent with that contract.
|
|
20618
|
+
*/
|
|
20619
|
+
function getObservableMessages(messageList) {
|
|
20620
|
+
const allMessages = messageList.get.all.db();
|
|
20621
|
+
const contextMessageIds = messageList.makeMessageSourceChecker().context;
|
|
20622
|
+
if (contextMessageIds.size === 0) return allMessages;
|
|
20623
|
+
return allMessages.filter((message) => !contextMessageIds.has(message.id));
|
|
20624
|
+
}
|
|
20625
|
+
/**
|
|
20575
20626
|
* Safely extract buffered observation chunks from a record.
|
|
20576
20627
|
* Handles both array and JSON-string formats, returning empty array if malformed.
|
|
20577
20628
|
*/
|
|
@@ -20584,7 +20635,7 @@ function getUnobservedPartsPreservingToolCallPairs(message) {
|
|
|
20584
20635
|
*/
|
|
20585
20636
|
function filterObservedMessages(opts) {
|
|
20586
20637
|
const { messageList, record } = opts;
|
|
20587
|
-
const allMessages = messageList
|
|
20638
|
+
const allMessages = getObservableMessages(messageList);
|
|
20588
20639
|
const useMarkerBoundaryPruning = opts.useMarkerBoundaryPruning ?? true;
|
|
20589
20640
|
const preserveMessageIds = opts.preserveMessageIds ?? /* @__PURE__ */ new Set();
|
|
20590
20641
|
const observedIds = new Set(Array.isArray(record?.observedMessageIds) ? record.observedMessageIds : []);
|
|
@@ -21137,7 +21188,7 @@ var ObservationStrategy = class ObservationStrategy {
|
|
|
21137
21188
|
*/
|
|
21138
21189
|
async persistMarkerToMessage(marker, messageList, threadId, resourceId) {
|
|
21139
21190
|
if (!messageList) return false;
|
|
21140
|
-
const allMsgs = messageList
|
|
21191
|
+
const allMsgs = getObservableMessages(messageList);
|
|
21141
21192
|
for (let i = allMsgs.length - 1; i >= 0; i--) {
|
|
21142
21193
|
const msg = allMsgs[i];
|
|
21143
21194
|
if (msg?.role === "assistant" && msg.content?.parts && Array.isArray(msg.content.parts)) {
|
|
@@ -22016,7 +22067,7 @@ var ObservationStep = class {
|
|
|
22016
22067
|
let didThresholdCleanup = false;
|
|
22017
22068
|
let observerExchange;
|
|
22018
22069
|
if (this.stepNumber === 0) {
|
|
22019
|
-
const step0Messages = messageList
|
|
22070
|
+
const step0Messages = getObservableMessages(messageList);
|
|
22020
22071
|
const activation = await om.activate({
|
|
22021
22072
|
threadId,
|
|
22022
22073
|
resourceId,
|
|
@@ -22048,7 +22099,7 @@ var ObservationStep = class {
|
|
|
22048
22099
|
currentModel: this.turn.actorModelContext,
|
|
22049
22100
|
requestContext: this.turn.requestContext,
|
|
22050
22101
|
observabilityContext: this.turn.observabilityContext,
|
|
22051
|
-
lastActivityAt: getLastActivityFromMessages(messageList
|
|
22102
|
+
lastActivityAt: getLastActivityFromMessages(getObservableMessages(messageList)),
|
|
22052
22103
|
reflectionHooks: om.composeHooks(void 0, {
|
|
22053
22104
|
threadId,
|
|
22054
22105
|
resourceId,
|
|
@@ -22058,7 +22109,7 @@ var ObservationStep = class {
|
|
|
22058
22109
|
await this.turn.refreshRecord();
|
|
22059
22110
|
if (this.turn.record.generationCount > preReflectGeneration) reflected = true;
|
|
22060
22111
|
}
|
|
22061
|
-
const allMsgsForToolCheck = messageList
|
|
22112
|
+
const allMsgsForToolCheck = getObservableMessages(messageList);
|
|
22062
22113
|
const lastMessage = allMsgsForToolCheck[allMsgsForToolCheck.length - 1];
|
|
22063
22114
|
const pendingStepMessages = [...messageList.get.input.db(), ...messageList.get.response.db()];
|
|
22064
22115
|
const latestStepParts = [...getLatestStepParts(lastMessage?.content?.parts ?? []), ...pendingStepMessages.flatMap((msg) => getLatestStepParts(msg.content?.parts ?? []))];
|
|
@@ -22067,10 +22118,10 @@ var ObservationStep = class {
|
|
|
22067
22118
|
let statusSnapshot = await om.getStatus({
|
|
22068
22119
|
threadId,
|
|
22069
22120
|
resourceId,
|
|
22070
|
-
messages: messageList
|
|
22121
|
+
messages: getObservableMessages(messageList)
|
|
22071
22122
|
});
|
|
22072
22123
|
if (statusSnapshot.shouldBuffer && !hasIncompleteToolCalls) {
|
|
22073
|
-
const allMessages = messageList
|
|
22124
|
+
const allMessages = getObservableMessages(messageList);
|
|
22074
22125
|
const unobservedMessages = om.getUnobservedMessages(allMessages, statusSnapshot.record);
|
|
22075
22126
|
const candidates = om.getUnobservedMessages(unobservedMessages, statusSnapshot.record, { excludeBuffered: true });
|
|
22076
22127
|
if (candidates.length > 0) {
|
|
@@ -22162,7 +22213,7 @@ var ObservationStep = class {
|
|
|
22162
22213
|
statusSnapshot = await om.getStatus({
|
|
22163
22214
|
threadId,
|
|
22164
22215
|
resourceId,
|
|
22165
|
-
messages: messageList
|
|
22216
|
+
messages: getObservableMessages(messageList)
|
|
22166
22217
|
});
|
|
22167
22218
|
}
|
|
22168
22219
|
const otherThreadsContext = await this.turn.refreshOtherThreadsContext();
|
|
@@ -22211,7 +22262,7 @@ var ObservationStep = class {
|
|
|
22211
22262
|
const { threadId, resourceId, messageList } = this.turn;
|
|
22212
22263
|
const om = this.turn.om;
|
|
22213
22264
|
await om.waitForBuffering(threadId, resourceId);
|
|
22214
|
-
const observableMessages = this.seededResponseMessage ? messageList
|
|
22265
|
+
const observableMessages = this.seededResponseMessage ? getObservableMessages(messageList).filter((msg) => msg.id !== this.turn.responseMessageId) : getObservableMessages(messageList);
|
|
22215
22266
|
const freshStatus = await om.getStatus({
|
|
22216
22267
|
threadId,
|
|
22217
22268
|
resourceId,
|
|
@@ -22241,7 +22292,7 @@ var ObservationStep = class {
|
|
|
22241
22292
|
currentModel: this.turn.actorModelContext,
|
|
22242
22293
|
requestContext: this.turn.requestContext,
|
|
22243
22294
|
observabilityContext: this.turn.observabilityContext,
|
|
22244
|
-
lastActivityAt: getLastActivityFromMessages(messageList
|
|
22295
|
+
lastActivityAt: getLastActivityFromMessages(getObservableMessages(messageList)),
|
|
22245
22296
|
reflectionHooks: om.composeHooks(void 0, {
|
|
22246
22297
|
threadId,
|
|
22247
22298
|
resourceId,
|
|
@@ -22267,7 +22318,7 @@ var ObservationStep = class {
|
|
|
22267
22318
|
});
|
|
22268
22319
|
if (obsResult.observed) {
|
|
22269
22320
|
const observedMessageIds = new Set(obsResult.record.observedMessageIds ?? []);
|
|
22270
|
-
const liveMessages = messageList
|
|
22321
|
+
const liveMessages = getObservableMessages(messageList);
|
|
22271
22322
|
let latestObservedIndex = -1;
|
|
22272
22323
|
for (let i = liveMessages.length - 1; i >= 0; i--) {
|
|
22273
22324
|
const message = liveMessages[i];
|
|
@@ -22442,7 +22493,7 @@ var ObservationTurn = class {
|
|
|
22442
22493
|
const asyncObservationEnabled = this.om.buffering.isAsyncObservationEnabled();
|
|
22443
22494
|
const bufferOnIdle = this.om.getObservationConfig().bufferOnIdle;
|
|
22444
22495
|
if (asyncObservationEnabled && bufferOnIdle) {
|
|
22445
|
-
const allMessages = this.messageList
|
|
22496
|
+
const allMessages = getObservableMessages(this.messageList);
|
|
22446
22497
|
const record = this._record;
|
|
22447
22498
|
const unobservedMessages = this.om.getUnobservedMessages(allMessages, record);
|
|
22448
22499
|
if (unobservedMessages.length > 0) this.om.buffer({
|
|
@@ -22812,7 +22863,7 @@ function getCurrentModel$1(model) {
|
|
|
22812
22863
|
return formatModelContext$1(model?.provider, model?.modelId);
|
|
22813
22864
|
}
|
|
22814
22865
|
function getLastModelFromMessageList(messageList) {
|
|
22815
|
-
const messages = messageList
|
|
22866
|
+
const messages = messageList ? getObservableMessages(messageList) : void 0;
|
|
22816
22867
|
if (!messages) return void 0;
|
|
22817
22868
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
22818
22869
|
const message = messages[i];
|
|
@@ -24396,7 +24447,7 @@ var ObservationalMemory = class ObservationalMemory {
|
|
|
24396
24447
|
*/
|
|
24397
24448
|
async persistMarkerToMessage(marker, messageList, threadId, resourceId) {
|
|
24398
24449
|
if (!messageList) return;
|
|
24399
|
-
const allMsgs = messageList
|
|
24450
|
+
const allMsgs = getObservableMessages(messageList);
|
|
24400
24451
|
for (let i = allMsgs.length - 1; i >= 0; i--) {
|
|
24401
24452
|
const msg = allMsgs[i];
|
|
24402
24453
|
if (msg?.role === "assistant" && msg.content?.parts && Array.isArray(msg.content.parts)) {
|
|
@@ -25074,7 +25125,7 @@ ${formattedMessages}
|
|
|
25074
25125
|
async cleanupMessages(opts) {
|
|
25075
25126
|
const { threadId, resourceId, observedMessageIds, retentionFloor, preserveMessageIds } = opts;
|
|
25076
25127
|
const messageList = this.isMessageList(opts.messages) ? opts.messages : void 0;
|
|
25077
|
-
const allMsgs = messageList ? messageList
|
|
25128
|
+
const allMsgs = messageList ? getObservableMessages(messageList) : opts.messages;
|
|
25078
25129
|
let markerIdx = -1;
|
|
25079
25130
|
let markerMsg = null;
|
|
25080
25131
|
for (let i = allMsgs.length - 1; i >= 0; i--) {
|
|
@@ -26190,7 +26241,7 @@ function isTemporalGapMarkerForMessage(message, targetMessageId) {
|
|
|
26190
26241
|
async function insertTemporalGapMarkers({ messageList, sendSignal }) {
|
|
26191
26242
|
const latestInputMessage = messageList.get.input.db().filter((message) => Boolean(message)).at(-1);
|
|
26192
26243
|
if (!latestInputMessage || isTemporalGapMarker(latestInputMessage)) return;
|
|
26193
|
-
const allMessages = messageList
|
|
26244
|
+
const allMessages = getObservableMessages(messageList).filter((message) => Boolean(message));
|
|
26194
26245
|
const latestInputIndex = allMessages.findIndex((message) => message.id === latestInputMessage.id);
|
|
26195
26246
|
if (latestInputIndex <= 0) return;
|
|
26196
26247
|
if (allMessages.some((message) => isTemporalGapMarkerForMessage(message, latestInputMessage.id))) return;
|
|
@@ -26414,7 +26465,7 @@ var ObservationalMemoryProcessor = class {
|
|
|
26414
26465
|
threadId,
|
|
26415
26466
|
resourceId
|
|
26416
26467
|
});
|
|
26417
|
-
const allDbMsgs = messageList
|
|
26468
|
+
const allDbMsgs = getObservableMessages(messageList);
|
|
26418
26469
|
const tokenCounter = this.engine.getTokenCounter();
|
|
26419
26470
|
const contextTokens = await tokenCounter.countMessagesAsync(allDbMsgs);
|
|
26420
26471
|
const otherThreadsContext = this.turn.context.otherThreadsContext;
|
|
@@ -26784,6 +26835,18 @@ var Memory = class extends MastraMemory {
|
|
|
26784
26835
|
_omEngine;
|
|
26785
26836
|
_omEngineInstance;
|
|
26786
26837
|
_mastraInstance;
|
|
26838
|
+
/**
|
|
26839
|
+
* Every vector cleanup that deleteThread or deleteMessages started in the background.
|
|
26840
|
+
* Callers do not wait for the cleanup, so this handle is the only join point.
|
|
26841
|
+
*/
|
|
26842
|
+
pendingVectorCleanup = Promise.resolve();
|
|
26843
|
+
/**
|
|
26844
|
+
* Adds a background vector cleanup to the join handle.
|
|
26845
|
+
* The handle keeps the earlier cleanups, so it settles only after all of them end.
|
|
26846
|
+
*/
|
|
26847
|
+
trackVectorCleanup(cleanup) {
|
|
26848
|
+
this.pendingVectorCleanup = Promise.allSettled([this.pendingVectorCleanup, cleanup]).then(() => void 0);
|
|
26849
|
+
}
|
|
26787
26850
|
/** The shared ObservationalMemory engine. Lazily created on first access. */
|
|
26788
26851
|
get omEngine() {
|
|
26789
26852
|
if (!this._omEngine) this._omEngine = this._initOMEngine().then((engine) => {
|
|
@@ -27048,26 +27111,40 @@ var Memory = class extends MastraMemory {
|
|
|
27048
27111
|
const thread = await memoryStore.getThreadById({ threadId });
|
|
27049
27112
|
await memoryStore.deleteThread({ threadId });
|
|
27050
27113
|
if (thread?.resourceId && memoryStore.supportsObservationalMemory) await memoryStore.clearObservationalMemory(threadId, thread.resourceId);
|
|
27051
|
-
if (this.vector) this.deleteThreadVectors(threadId);
|
|
27114
|
+
if (this.vector) this.trackVectorCleanup(this.deleteThreadVectors(threadId));
|
|
27115
|
+
}
|
|
27116
|
+
/**
|
|
27117
|
+
* Prefix shared by every message index. The index for the default embedding
|
|
27118
|
+
* dimension is named with the bare prefix; other dimensions add a suffix.
|
|
27119
|
+
*/
|
|
27120
|
+
get messageIndexPrefix() {
|
|
27121
|
+
return this.getEmbeddingIndexName();
|
|
27052
27122
|
}
|
|
27053
27123
|
/**
|
|
27054
|
-
*
|
|
27055
|
-
* Handles separator differences across vector store backends (e.g. '_' vs '-').
|
|
27124
|
+
* Prefix shared by every observation index. Each observation index adds a dimension suffix.
|
|
27056
27125
|
*/
|
|
27057
|
-
|
|
27126
|
+
get observationIndexPrefix() {
|
|
27127
|
+
return `memory${this.vector?.indexSeparator ?? "_"}observations`;
|
|
27128
|
+
}
|
|
27129
|
+
/**
|
|
27130
|
+
* Lists the vector indexes whose name starts with one of the given prefixes.
|
|
27131
|
+
* Index names can carry a dimension suffix, so discovery matches on the prefix.
|
|
27132
|
+
*/
|
|
27133
|
+
async getMemoryVectorIndexes(prefixes) {
|
|
27058
27134
|
if (!this.vector) return [];
|
|
27059
|
-
|
|
27060
|
-
return (await this.vector.listIndexes()).filter((name) => name.startsWith(prefix));
|
|
27135
|
+
return (await this.vector.listIndexes()).filter((name) => prefixes.some((prefix) => name.startsWith(prefix)));
|
|
27061
27136
|
}
|
|
27062
27137
|
/**
|
|
27063
27138
|
* Deletes all vector embeddings associated with a thread.
|
|
27064
27139
|
* This is called internally by deleteThread to clean up orphaned vectors.
|
|
27140
|
+
* Both message and observation vectors are removed, so no text of the deleted
|
|
27141
|
+
* thread stays reachable through resource-scoped retrieval.
|
|
27065
27142
|
*
|
|
27066
27143
|
* @param threadId - The ID of the thread whose vectors should be deleted
|
|
27067
27144
|
*/
|
|
27068
27145
|
async deleteThreadVectors(threadId) {
|
|
27069
27146
|
try {
|
|
27070
|
-
const memoryIndexes = await this.getMemoryVectorIndexes();
|
|
27147
|
+
const memoryIndexes = await this.getMemoryVectorIndexes([this.messageIndexPrefix, this.observationIndexPrefix]);
|
|
27071
27148
|
await Promise.all(memoryIndexes.map(async (indexName) => {
|
|
27072
27149
|
try {
|
|
27073
27150
|
await this.vector.deleteVectors({
|
|
@@ -27075,14 +27152,14 @@ var Memory = class extends MastraMemory {
|
|
|
27075
27152
|
filter: { thread_id: threadId }
|
|
27076
27153
|
});
|
|
27077
27154
|
} catch {
|
|
27078
|
-
this.logger.
|
|
27155
|
+
this.logger.warn("Failed to delete vectors of the deleted thread from index", {
|
|
27079
27156
|
threadId,
|
|
27080
27157
|
indexName
|
|
27081
27158
|
});
|
|
27082
27159
|
}
|
|
27083
27160
|
}));
|
|
27084
27161
|
} catch {
|
|
27085
|
-
this.logger.
|
|
27162
|
+
this.logger.warn("Failed to clean up vectors of the deleted thread", { threadId });
|
|
27086
27163
|
}
|
|
27087
27164
|
}
|
|
27088
27165
|
async updateWorkingMemory({ threadId, resourceId, workingMemory, memoryConfig, observabilityContext }) {
|
|
@@ -27755,7 +27832,7 @@ Notes:
|
|
|
27755
27832
|
getObservationEmbeddingIndexName(dimensions) {
|
|
27756
27833
|
const usedDimensions = dimensions ?? 384;
|
|
27757
27834
|
const separator = this.vector?.indexSeparator ?? "_";
|
|
27758
|
-
return
|
|
27835
|
+
return `${this.observationIndexPrefix}${separator}${usedDimensions}`;
|
|
27759
27836
|
}
|
|
27760
27837
|
async createObservationEmbeddingIndex(dimensions) {
|
|
27761
27838
|
const usedDimensions = dimensions ?? 384;
|
|
@@ -28001,7 +28078,10 @@ Notes:
|
|
|
28001
28078
|
tools[name] = tool;
|
|
28002
28079
|
}
|
|
28003
28080
|
const omConfig = normalizeObservationalMemoryConfig(mergedConfig.observationalMemory);
|
|
28004
|
-
if (omConfig?.retrieval) tools.recall = recallTool(mergedConfig, {
|
|
28081
|
+
if (omConfig?.retrieval) tools.recall = recallTool(mergedConfig, {
|
|
28082
|
+
retrievalScope: typeof omConfig.retrieval === "object" ? omConfig.retrieval.scope ?? "resource" : "resource",
|
|
28083
|
+
searchEnabled: this.hasRetrievalSearch(omConfig.retrieval)
|
|
28084
|
+
});
|
|
28005
28085
|
return tools;
|
|
28006
28086
|
}
|
|
28007
28087
|
/**
|
|
@@ -28057,7 +28137,7 @@ Notes:
|
|
|
28057
28137
|
}));
|
|
28058
28138
|
const messageIdsNeedingDeletion = /* @__PURE__ */ new Set([...messageIdsWithClearedContent, ...messageIdsWithNewEmbeddings]);
|
|
28059
28139
|
if (messageIdsNeedingDeletion.size > 0) try {
|
|
28060
|
-
const memoryIndexes = await this.getMemoryVectorIndexes();
|
|
28140
|
+
const memoryIndexes = await this.getMemoryVectorIndexes([this.messageIndexPrefix]);
|
|
28061
28141
|
const idsToDelete = [...messageIdsNeedingDeletion];
|
|
28062
28142
|
await Promise.all(memoryIndexes.map(async (indexName) => {
|
|
28063
28143
|
for (let i = 0; i < idsToDelete.length; i += VECTOR_DELETE_BATCH_SIZE) {
|
|
@@ -28116,7 +28196,7 @@ Notes:
|
|
|
28116
28196
|
const span = this.createMemorySpan("delete", observabilityContext, void 0, { messageCount: messageIds.length });
|
|
28117
28197
|
try {
|
|
28118
28198
|
await (await this.getMemoryStore()).deleteMessages(messageIds);
|
|
28119
|
-
if (this.vector) this.deleteMessageVectors(messageIds);
|
|
28199
|
+
if (this.vector) this.trackVectorCleanup(this.deleteMessageVectors(messageIds));
|
|
28120
28200
|
span?.end({
|
|
28121
28201
|
output: { success: true },
|
|
28122
28202
|
attributes: { messageCount: messageIds.length }
|
|
@@ -28132,12 +28212,14 @@ Notes:
|
|
|
28132
28212
|
/**
|
|
28133
28213
|
* Deletes vector embeddings for specific messages.
|
|
28134
28214
|
* This is called internally by deleteMessages to clean up orphaned vectors.
|
|
28215
|
+
* Only the message indexes are touched, because observation vectors can hold
|
|
28216
|
+
* text of other messages of the thread.
|
|
28135
28217
|
*
|
|
28136
28218
|
* @param messageIds - The IDs of the messages whose vectors should be deleted
|
|
28137
28219
|
*/
|
|
28138
28220
|
async deleteMessageVectors(messageIds) {
|
|
28139
28221
|
try {
|
|
28140
|
-
const memoryIndexes = await this.getMemoryVectorIndexes();
|
|
28222
|
+
const memoryIndexes = await this.getMemoryVectorIndexes([this.messageIndexPrefix]);
|
|
28141
28223
|
await Promise.all(memoryIndexes.map(async (indexName) => {
|
|
28142
28224
|
for (let i = 0; i < messageIds.length; i += VECTOR_DELETE_BATCH_SIZE) {
|
|
28143
28225
|
const batch = messageIds.slice(i, i + VECTOR_DELETE_BATCH_SIZE);
|
|
@@ -28531,4 +28613,4 @@ Notes:
|
|
|
28531
28613
|
//#endregion
|
|
28532
28614
|
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 };
|
|
28533
28615
|
|
|
28534
|
-
//# sourceMappingURL=src-
|
|
28616
|
+
//# sourceMappingURL=src-MScpLVRh.js.map
|