@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
|
@@ -18542,33 +18542,62 @@ var TokenCounter = class TokenCounter {
|
|
|
18542
18542
|
if (isImageAttachment) await resolveImageDimensionsAsync(part);
|
|
18543
18543
|
return this.countAttachmentPartSync(part);
|
|
18544
18544
|
}
|
|
18545
|
+
/**
|
|
18546
|
+
* Count the name and the arguments of a tool call. Every state before the tool produces an
|
|
18547
|
+
* output holds the same call signature in the context window, so all of those states share
|
|
18548
|
+
* these cache kinds. `buildEstimateKey` hashes the text, so a shared kind stays correct and
|
|
18549
|
+
* keeps the estimate warm while the invocation moves from one state to the next.
|
|
18550
|
+
*/
|
|
18551
|
+
countToolCallSignature(part, invocation) {
|
|
18552
|
+
let tokens = 0;
|
|
18553
|
+
let overheadDelta = 0;
|
|
18554
|
+
if (invocation.toolName) tokens += this.readOrPersistPartEstimate(part, "tool-call-name", invocation.toolName);
|
|
18555
|
+
if (invocation.args) if (typeof invocation.args === "string") tokens += this.readOrPersistPartEstimate(part, "tool-call-args", invocation.args);
|
|
18556
|
+
else {
|
|
18557
|
+
const argsJson = JSON.stringify(invocation.args);
|
|
18558
|
+
tokens += this.readOrPersistPartEstimate(part, "tool-call-args-json", argsJson);
|
|
18559
|
+
overheadDelta -= 12;
|
|
18560
|
+
}
|
|
18561
|
+
return {
|
|
18562
|
+
tokens,
|
|
18563
|
+
overheadDelta
|
|
18564
|
+
};
|
|
18565
|
+
}
|
|
18545
18566
|
countNonAttachmentPart(part) {
|
|
18546
18567
|
let overheadDelta = 0;
|
|
18547
|
-
let
|
|
18568
|
+
let extraMessageDelta = 0;
|
|
18548
18569
|
if (part.type === "text") return {
|
|
18549
18570
|
tokens: this.readOrPersistPartEstimate(part, "text", part.text),
|
|
18550
18571
|
overheadDelta,
|
|
18551
|
-
|
|
18572
|
+
extraMessageDelta
|
|
18552
18573
|
};
|
|
18553
18574
|
if (part.type === "tool-invocation") {
|
|
18554
18575
|
const invocation = part.toolInvocation;
|
|
18576
|
+
const state = invocation.state;
|
|
18555
18577
|
let tokens = 0;
|
|
18556
|
-
if (
|
|
18557
|
-
|
|
18558
|
-
|
|
18559
|
-
|
|
18560
|
-
|
|
18561
|
-
|
|
18562
|
-
|
|
18563
|
-
|
|
18578
|
+
if (state === "call" || state === "partial-call" || state === "approval-requested") {
|
|
18579
|
+
const signature = this.countToolCallSignature(part, invocation);
|
|
18580
|
+
return {
|
|
18581
|
+
tokens: signature.tokens,
|
|
18582
|
+
overheadDelta: overheadDelta + signature.overheadDelta,
|
|
18583
|
+
extraMessageDelta
|
|
18584
|
+
};
|
|
18585
|
+
}
|
|
18586
|
+
if (state === "approval-responded") {
|
|
18587
|
+
extraMessageDelta++;
|
|
18588
|
+
const signature = this.countToolCallSignature(part, invocation);
|
|
18589
|
+
tokens += signature.tokens;
|
|
18590
|
+
overheadDelta += signature.overheadDelta;
|
|
18591
|
+
const reason = invocation.approval?.reason;
|
|
18592
|
+
if (reason) tokens += this.readOrPersistPartEstimate(part, "tool-approval-reason", reason);
|
|
18564
18593
|
return {
|
|
18565
18594
|
tokens,
|
|
18566
18595
|
overheadDelta,
|
|
18567
|
-
|
|
18596
|
+
extraMessageDelta
|
|
18568
18597
|
};
|
|
18569
18598
|
}
|
|
18570
|
-
if (
|
|
18571
|
-
|
|
18599
|
+
if (state === "result") {
|
|
18600
|
+
extraMessageDelta++;
|
|
18572
18601
|
const { value: resultForCounting, usingStoredModelOutput } = this.resolveToolResultForTokenCounting(part, invocation.result);
|
|
18573
18602
|
if (resultForCounting !== void 0) {
|
|
18574
18603
|
const contentTokens = this.countMultimodalToolResultContent(part, resultForCounting);
|
|
@@ -18582,47 +18611,45 @@ var TokenCounter = class TokenCounter {
|
|
|
18582
18611
|
return {
|
|
18583
18612
|
tokens,
|
|
18584
18613
|
overheadDelta,
|
|
18585
|
-
|
|
18614
|
+
extraMessageDelta
|
|
18586
18615
|
};
|
|
18587
18616
|
}
|
|
18588
|
-
if (
|
|
18589
|
-
|
|
18617
|
+
if (state === "output-denied") {
|
|
18618
|
+
extraMessageDelta++;
|
|
18590
18619
|
const reason = invocation.approval?.reason ?? "Tool call was not approved by the user";
|
|
18591
18620
|
tokens += this.readOrPersistPartEstimate(part, "tool-result-denied", reason);
|
|
18592
18621
|
return {
|
|
18593
18622
|
tokens,
|
|
18594
18623
|
overheadDelta,
|
|
18595
|
-
|
|
18624
|
+
extraMessageDelta
|
|
18596
18625
|
};
|
|
18597
18626
|
}
|
|
18598
|
-
if (
|
|
18599
|
-
|
|
18600
|
-
const
|
|
18601
|
-
const errorMessage = typeof errorText === "string" ? errorText : "Tool execution failed";
|
|
18627
|
+
if (state === "output-error") {
|
|
18628
|
+
extraMessageDelta++;
|
|
18629
|
+
const errorMessage = typeof invocation.errorText === "string" ? invocation.errorText : "Tool execution failed";
|
|
18602
18630
|
tokens += this.readOrPersistPartEstimate(part, "tool-result-error", errorMessage);
|
|
18603
18631
|
return {
|
|
18604
18632
|
tokens,
|
|
18605
18633
|
overheadDelta,
|
|
18606
|
-
|
|
18634
|
+
extraMessageDelta
|
|
18607
18635
|
};
|
|
18608
18636
|
}
|
|
18609
|
-
throw new Error(`Unhandled tool-invocation state '${part.toolInvocation?.state}' in token counting for part type '${part.type}'`);
|
|
18610
18637
|
}
|
|
18611
18638
|
if (typeof part.type === "string" && part.type.startsWith("data-")) return {
|
|
18612
18639
|
tokens: 0,
|
|
18613
18640
|
overheadDelta,
|
|
18614
|
-
|
|
18641
|
+
extraMessageDelta
|
|
18615
18642
|
};
|
|
18616
18643
|
if (part.type === "reasoning") return {
|
|
18617
18644
|
tokens: 0,
|
|
18618
18645
|
overheadDelta,
|
|
18619
|
-
|
|
18646
|
+
extraMessageDelta
|
|
18620
18647
|
};
|
|
18621
18648
|
const serialized = serializePartForTokenCounting(part);
|
|
18622
18649
|
return {
|
|
18623
18650
|
tokens: this.readOrPersistPartEstimate(part, `part-${part.type}`, serialized),
|
|
18624
18651
|
overheadDelta,
|
|
18625
|
-
|
|
18652
|
+
extraMessageDelta
|
|
18626
18653
|
};
|
|
18627
18654
|
}
|
|
18628
18655
|
/**
|
|
@@ -18631,7 +18658,7 @@ var TokenCounter = class TokenCounter {
|
|
|
18631
18658
|
countMessage(message) {
|
|
18632
18659
|
let payloadTokens = this.countString(message.role);
|
|
18633
18660
|
let overhead = TokenCounter.TOKENS_PER_MESSAGE;
|
|
18634
|
-
let
|
|
18661
|
+
let extraMessageCount = 0;
|
|
18635
18662
|
if (typeof message.content === "string") payloadTokens += this.readOrPersistMessageEstimate(message, "message-content", message.content);
|
|
18636
18663
|
else if (message.content && typeof message.content === "object") {
|
|
18637
18664
|
if (message.content.content && !Array.isArray(message.content.parts)) payloadTokens += this.readOrPersistMessageEstimate(message, "content-content", message.content.content);
|
|
@@ -18644,16 +18671,16 @@ var TokenCounter = class TokenCounter {
|
|
|
18644
18671
|
const result = this.countNonAttachmentPart(part);
|
|
18645
18672
|
payloadTokens += result.tokens;
|
|
18646
18673
|
overhead += result.overheadDelta;
|
|
18647
|
-
|
|
18674
|
+
extraMessageCount += result.extraMessageDelta;
|
|
18648
18675
|
}
|
|
18649
18676
|
}
|
|
18650
|
-
if (
|
|
18677
|
+
if (extraMessageCount > 0) overhead += extraMessageCount * TokenCounter.TOKENS_PER_MESSAGE;
|
|
18651
18678
|
return Math.round(payloadTokens + overhead);
|
|
18652
18679
|
}
|
|
18653
18680
|
async countMessageAsync(message) {
|
|
18654
18681
|
let payloadTokens = this.countString(message.role);
|
|
18655
18682
|
let overhead = TokenCounter.TOKENS_PER_MESSAGE;
|
|
18656
|
-
let
|
|
18683
|
+
let extraMessageCount = 0;
|
|
18657
18684
|
if (typeof message.content === "string") payloadTokens += this.readOrPersistMessageEstimate(message, "message-content", message.content);
|
|
18658
18685
|
else if (message.content && typeof message.content === "object") {
|
|
18659
18686
|
if (message.content.content && !Array.isArray(message.content.parts)) payloadTokens += this.readOrPersistMessageEstimate(message, "content-content", message.content.content);
|
|
@@ -18666,10 +18693,10 @@ var TokenCounter = class TokenCounter {
|
|
|
18666
18693
|
const result = this.countNonAttachmentPart(part);
|
|
18667
18694
|
payloadTokens += result.tokens;
|
|
18668
18695
|
overhead += result.overheadDelta;
|
|
18669
|
-
|
|
18696
|
+
extraMessageCount += result.extraMessageDelta;
|
|
18670
18697
|
}
|
|
18671
18698
|
}
|
|
18672
|
-
if (
|
|
18699
|
+
if (extraMessageCount > 0) overhead += extraMessageCount * TokenCounter.TOKENS_PER_MESSAGE;
|
|
18673
18700
|
return Math.round(payloadTokens + overhead);
|
|
18674
18701
|
}
|
|
18675
18702
|
/**
|
|
@@ -18980,9 +19007,10 @@ async function listThreadsForResource({ memory, resourceId, currentThreadId, pag
|
|
|
18980
19007
|
hasMore
|
|
18981
19008
|
};
|
|
18982
19009
|
}
|
|
19010
|
+
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.";
|
|
18983
19011
|
async function searchMessagesForResource({ memory, resourceId, currentThreadId, query, topK = 10, maxTokens = DEFAULT_MAX_RESULT_TOKENS, before, after, threadScope }) {
|
|
18984
19012
|
if (!memory.searchMessages) return {
|
|
18985
|
-
results:
|
|
19013
|
+
results: SEARCH_NOT_CONFIGURED_MESSAGE,
|
|
18986
19014
|
count: 0
|
|
18987
19015
|
};
|
|
18988
19016
|
const MAX_TOPK = 20;
|
|
@@ -19528,9 +19556,16 @@ async function recallThreadFromStart({ memory, threadId, resourceId, page = 1, l
|
|
|
19528
19556
|
}
|
|
19529
19557
|
const recallTool = (_memoryConfig, options) => {
|
|
19530
19558
|
const isResourceScope = (options?.retrievalScope ?? "thread") === "resource";
|
|
19559
|
+
const searchEnabled = options?.searchEnabled ?? true;
|
|
19560
|
+
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.`;
|
|
19561
|
+
const modeEnum = searchEnabled ? [
|
|
19562
|
+
"messages",
|
|
19563
|
+
"threads",
|
|
19564
|
+
"search"
|
|
19565
|
+
] : ["messages", "threads"];
|
|
19531
19566
|
return (0, _mastra_core_tools.createTool)({
|
|
19532
19567
|
id: "recall",
|
|
19533
|
-
description
|
|
19568
|
+
description,
|
|
19534
19569
|
inputSchema: {
|
|
19535
19570
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
19536
19571
|
type: "object",
|
|
@@ -19538,12 +19573,8 @@ const recallTool = (_memoryConfig, options) => {
|
|
|
19538
19573
|
...isResourceScope ? {
|
|
19539
19574
|
mode: {
|
|
19540
19575
|
type: "string",
|
|
19541
|
-
enum:
|
|
19542
|
-
|
|
19543
|
-
"threads",
|
|
19544
|
-
"search"
|
|
19545
|
-
],
|
|
19546
|
-
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."
|
|
19576
|
+
enum: modeEnum,
|
|
19577
|
+
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." : ""}`
|
|
19547
19578
|
},
|
|
19548
19579
|
threadId: {
|
|
19549
19580
|
type: "string",
|
|
@@ -19560,18 +19591,14 @@ const recallTool = (_memoryConfig, options) => {
|
|
|
19560
19591
|
}
|
|
19561
19592
|
} : { mode: {
|
|
19562
19593
|
type: "string",
|
|
19563
|
-
enum:
|
|
19564
|
-
|
|
19565
|
-
"threads",
|
|
19566
|
-
"search"
|
|
19567
|
-
],
|
|
19568
|
-
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."
|
|
19594
|
+
enum: modeEnum,
|
|
19595
|
+
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." : ""}`
|
|
19569
19596
|
} },
|
|
19570
|
-
query: {
|
|
19597
|
+
...searchEnabled ? { query: {
|
|
19571
19598
|
type: "string",
|
|
19572
19599
|
minLength: 1,
|
|
19573
19600
|
description: "Search query for mode=\"search\". Finds messages semantically similar to this text."
|
|
19574
|
-
},
|
|
19601
|
+
} } : {},
|
|
19575
19602
|
cursor: {
|
|
19576
19603
|
type: "string",
|
|
19577
19604
|
minLength: 1,
|
|
@@ -19632,6 +19659,10 @@ const recallTool = (_memoryConfig, options) => {
|
|
|
19632
19659
|
if (!memory) throw new Error("Memory instance is required for recall");
|
|
19633
19660
|
if (explicitThreadId === "current" && !currentThreadId) throw new Error("Could not resolve current thread.");
|
|
19634
19661
|
if (mode === "search") {
|
|
19662
|
+
if (!searchEnabled) return {
|
|
19663
|
+
results: SEARCH_NOT_CONFIGURED_MESSAGE,
|
|
19664
|
+
count: 0
|
|
19665
|
+
};
|
|
19635
19666
|
if (!query) throw new Error("query is required for mode=\"search\"");
|
|
19636
19667
|
if (!resourceId) throw new Error("Resource ID is required for recall");
|
|
19637
19668
|
return searchMessagesForResource({
|
|
@@ -19768,6 +19799,7 @@ function deepMergeWorkingMemory(existing, update) {
|
|
|
19768
19799
|
for (const key of Object.keys(update)) {
|
|
19769
19800
|
const updateValue = update[key];
|
|
19770
19801
|
const existingValue = result[key];
|
|
19802
|
+
if (updateValue === void 0) continue;
|
|
19771
19803
|
if (updateValue === null) delete result[key];
|
|
19772
19804
|
else if (Array.isArray(updateValue)) result[key] = updateValue;
|
|
19773
19805
|
else if (typeof updateValue === "object" && updateValue !== null && typeof existingValue === "object" && existingValue !== null && !Array.isArray(existingValue)) result[key] = deepMergeWorkingMemory(existingValue, updateValue);
|
|
@@ -19820,7 +19852,7 @@ const updateWorkingMemoryTool = (memoryConfig) => {
|
|
|
19820
19852
|
version: 1,
|
|
19821
19853
|
vendor: "mastra",
|
|
19822
19854
|
validate: (value) => {
|
|
19823
|
-
const memoryValue = !!value && typeof value === "object" && !Array.isArray(value) && "memory" in value ? value.memory :
|
|
19855
|
+
const memoryValue = stripNullsFromOptional(!!value && typeof value === "object" && !Array.isArray(value) && "memory" in value ? value.memory : value, jsonSchema);
|
|
19824
19856
|
const result = validateMemory(memoryValue);
|
|
19825
19857
|
return result instanceof Promise ? result.then(toWrappedResult) : toWrappedResult(result);
|
|
19826
19858
|
},
|
|
@@ -19837,6 +19869,7 @@ const updateWorkingMemoryTool = (memoryConfig) => {
|
|
|
19837
19869
|
id: "update-working-memory",
|
|
19838
19870
|
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.`,
|
|
19839
19871
|
inputSchema,
|
|
19872
|
+
...usesMergeSemantics ? { strict: false } : {},
|
|
19840
19873
|
execute: async (inputData, context) => {
|
|
19841
19874
|
const workingMemoryInput = inputData;
|
|
19842
19875
|
const threadId = context?.agent?.threadId;
|
|
@@ -20593,6 +20626,24 @@ function getUnobservedPartsPreservingToolCallPairs(message) {
|
|
|
20593
20626
|
return preservedCalls.length > 0 ? [...preservedCalls, ...unobservedParts] : unobservedParts;
|
|
20594
20627
|
}
|
|
20595
20628
|
/**
|
|
20629
|
+
* Get the messages Observational Memory is allowed to work with.
|
|
20630
|
+
*
|
|
20631
|
+
* Messages supplied through the `context` option are per-run ephemeral input. Core's
|
|
20632
|
+
* persistence contract already treats them as never-persist: `MessageStateManager` routes
|
|
20633
|
+
* them into `userContextMessages`, and `drainUnsavedMessages` only drains input/response.
|
|
20634
|
+
*
|
|
20635
|
+
* OM builds its windows from `get.all.db()`, which includes context messages, and then
|
|
20636
|
+
* seals and persists candidates directly — turning ephemeral context into durable user
|
|
20637
|
+
* messages. Excluding them here keeps OM's window, sealing, persistence and token
|
|
20638
|
+
* accounting consistent with that contract.
|
|
20639
|
+
*/
|
|
20640
|
+
function getObservableMessages(messageList) {
|
|
20641
|
+
const allMessages = messageList.get.all.db();
|
|
20642
|
+
const contextMessageIds = messageList.makeMessageSourceChecker().context;
|
|
20643
|
+
if (contextMessageIds.size === 0) return allMessages;
|
|
20644
|
+
return allMessages.filter((message) => !contextMessageIds.has(message.id));
|
|
20645
|
+
}
|
|
20646
|
+
/**
|
|
20596
20647
|
* Safely extract buffered observation chunks from a record.
|
|
20597
20648
|
* Handles both array and JSON-string formats, returning empty array if malformed.
|
|
20598
20649
|
*/
|
|
@@ -20605,7 +20656,7 @@ function getUnobservedPartsPreservingToolCallPairs(message) {
|
|
|
20605
20656
|
*/
|
|
20606
20657
|
function filterObservedMessages(opts) {
|
|
20607
20658
|
const { messageList, record } = opts;
|
|
20608
|
-
const allMessages = messageList
|
|
20659
|
+
const allMessages = getObservableMessages(messageList);
|
|
20609
20660
|
const useMarkerBoundaryPruning = opts.useMarkerBoundaryPruning ?? true;
|
|
20610
20661
|
const preserveMessageIds = opts.preserveMessageIds ?? /* @__PURE__ */ new Set();
|
|
20611
20662
|
const observedIds = new Set(Array.isArray(record?.observedMessageIds) ? record.observedMessageIds : []);
|
|
@@ -21158,7 +21209,7 @@ var ObservationStrategy = class ObservationStrategy {
|
|
|
21158
21209
|
*/
|
|
21159
21210
|
async persistMarkerToMessage(marker, messageList, threadId, resourceId) {
|
|
21160
21211
|
if (!messageList) return false;
|
|
21161
|
-
const allMsgs = messageList
|
|
21212
|
+
const allMsgs = getObservableMessages(messageList);
|
|
21162
21213
|
for (let i = allMsgs.length - 1; i >= 0; i--) {
|
|
21163
21214
|
const msg = allMsgs[i];
|
|
21164
21215
|
if (msg?.role === "assistant" && msg.content?.parts && Array.isArray(msg.content.parts)) {
|
|
@@ -22037,7 +22088,7 @@ var ObservationStep = class {
|
|
|
22037
22088
|
let didThresholdCleanup = false;
|
|
22038
22089
|
let observerExchange;
|
|
22039
22090
|
if (this.stepNumber === 0) {
|
|
22040
|
-
const step0Messages = messageList
|
|
22091
|
+
const step0Messages = getObservableMessages(messageList);
|
|
22041
22092
|
const activation = await om.activate({
|
|
22042
22093
|
threadId,
|
|
22043
22094
|
resourceId,
|
|
@@ -22069,7 +22120,7 @@ var ObservationStep = class {
|
|
|
22069
22120
|
currentModel: this.turn.actorModelContext,
|
|
22070
22121
|
requestContext: this.turn.requestContext,
|
|
22071
22122
|
observabilityContext: this.turn.observabilityContext,
|
|
22072
|
-
lastActivityAt: getLastActivityFromMessages(messageList
|
|
22123
|
+
lastActivityAt: getLastActivityFromMessages(getObservableMessages(messageList)),
|
|
22073
22124
|
reflectionHooks: om.composeHooks(void 0, {
|
|
22074
22125
|
threadId,
|
|
22075
22126
|
resourceId,
|
|
@@ -22079,7 +22130,7 @@ var ObservationStep = class {
|
|
|
22079
22130
|
await this.turn.refreshRecord();
|
|
22080
22131
|
if (this.turn.record.generationCount > preReflectGeneration) reflected = true;
|
|
22081
22132
|
}
|
|
22082
|
-
const allMsgsForToolCheck = messageList
|
|
22133
|
+
const allMsgsForToolCheck = getObservableMessages(messageList);
|
|
22083
22134
|
const lastMessage = allMsgsForToolCheck[allMsgsForToolCheck.length - 1];
|
|
22084
22135
|
const pendingStepMessages = [...messageList.get.input.db(), ...messageList.get.response.db()];
|
|
22085
22136
|
const latestStepParts = [...getLatestStepParts(lastMessage?.content?.parts ?? []), ...pendingStepMessages.flatMap((msg) => getLatestStepParts(msg.content?.parts ?? []))];
|
|
@@ -22088,10 +22139,10 @@ var ObservationStep = class {
|
|
|
22088
22139
|
let statusSnapshot = await om.getStatus({
|
|
22089
22140
|
threadId,
|
|
22090
22141
|
resourceId,
|
|
22091
|
-
messages: messageList
|
|
22142
|
+
messages: getObservableMessages(messageList)
|
|
22092
22143
|
});
|
|
22093
22144
|
if (statusSnapshot.shouldBuffer && !hasIncompleteToolCalls) {
|
|
22094
|
-
const allMessages = messageList
|
|
22145
|
+
const allMessages = getObservableMessages(messageList);
|
|
22095
22146
|
const unobservedMessages = om.getUnobservedMessages(allMessages, statusSnapshot.record);
|
|
22096
22147
|
const candidates = om.getUnobservedMessages(unobservedMessages, statusSnapshot.record, { excludeBuffered: true });
|
|
22097
22148
|
if (candidates.length > 0) {
|
|
@@ -22183,7 +22234,7 @@ var ObservationStep = class {
|
|
|
22183
22234
|
statusSnapshot = await om.getStatus({
|
|
22184
22235
|
threadId,
|
|
22185
22236
|
resourceId,
|
|
22186
|
-
messages: messageList
|
|
22237
|
+
messages: getObservableMessages(messageList)
|
|
22187
22238
|
});
|
|
22188
22239
|
}
|
|
22189
22240
|
const otherThreadsContext = await this.turn.refreshOtherThreadsContext();
|
|
@@ -22232,7 +22283,7 @@ var ObservationStep = class {
|
|
|
22232
22283
|
const { threadId, resourceId, messageList } = this.turn;
|
|
22233
22284
|
const om = this.turn.om;
|
|
22234
22285
|
await om.waitForBuffering(threadId, resourceId);
|
|
22235
|
-
const observableMessages = this.seededResponseMessage ? messageList
|
|
22286
|
+
const observableMessages = this.seededResponseMessage ? getObservableMessages(messageList).filter((msg) => msg.id !== this.turn.responseMessageId) : getObservableMessages(messageList);
|
|
22236
22287
|
const freshStatus = await om.getStatus({
|
|
22237
22288
|
threadId,
|
|
22238
22289
|
resourceId,
|
|
@@ -22262,7 +22313,7 @@ var ObservationStep = class {
|
|
|
22262
22313
|
currentModel: this.turn.actorModelContext,
|
|
22263
22314
|
requestContext: this.turn.requestContext,
|
|
22264
22315
|
observabilityContext: this.turn.observabilityContext,
|
|
22265
|
-
lastActivityAt: getLastActivityFromMessages(messageList
|
|
22316
|
+
lastActivityAt: getLastActivityFromMessages(getObservableMessages(messageList)),
|
|
22266
22317
|
reflectionHooks: om.composeHooks(void 0, {
|
|
22267
22318
|
threadId,
|
|
22268
22319
|
resourceId,
|
|
@@ -22288,7 +22339,7 @@ var ObservationStep = class {
|
|
|
22288
22339
|
});
|
|
22289
22340
|
if (obsResult.observed) {
|
|
22290
22341
|
const observedMessageIds = new Set(obsResult.record.observedMessageIds ?? []);
|
|
22291
|
-
const liveMessages = messageList
|
|
22342
|
+
const liveMessages = getObservableMessages(messageList);
|
|
22292
22343
|
let latestObservedIndex = -1;
|
|
22293
22344
|
for (let i = liveMessages.length - 1; i >= 0; i--) {
|
|
22294
22345
|
const message = liveMessages[i];
|
|
@@ -22463,7 +22514,7 @@ var ObservationTurn = class {
|
|
|
22463
22514
|
const asyncObservationEnabled = this.om.buffering.isAsyncObservationEnabled();
|
|
22464
22515
|
const bufferOnIdle = this.om.getObservationConfig().bufferOnIdle;
|
|
22465
22516
|
if (asyncObservationEnabled && bufferOnIdle) {
|
|
22466
|
-
const allMessages = this.messageList
|
|
22517
|
+
const allMessages = getObservableMessages(this.messageList);
|
|
22467
22518
|
const record = this._record;
|
|
22468
22519
|
const unobservedMessages = this.om.getUnobservedMessages(allMessages, record);
|
|
22469
22520
|
if (unobservedMessages.length > 0) this.om.buffer({
|
|
@@ -22833,7 +22884,7 @@ function getCurrentModel$1(model) {
|
|
|
22833
22884
|
return formatModelContext$1(model?.provider, model?.modelId);
|
|
22834
22885
|
}
|
|
22835
22886
|
function getLastModelFromMessageList(messageList) {
|
|
22836
|
-
const messages = messageList
|
|
22887
|
+
const messages = messageList ? getObservableMessages(messageList) : void 0;
|
|
22837
22888
|
if (!messages) return void 0;
|
|
22838
22889
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
22839
22890
|
const message = messages[i];
|
|
@@ -24417,7 +24468,7 @@ var ObservationalMemory = class ObservationalMemory {
|
|
|
24417
24468
|
*/
|
|
24418
24469
|
async persistMarkerToMessage(marker, messageList, threadId, resourceId) {
|
|
24419
24470
|
if (!messageList) return;
|
|
24420
|
-
const allMsgs = messageList
|
|
24471
|
+
const allMsgs = getObservableMessages(messageList);
|
|
24421
24472
|
for (let i = allMsgs.length - 1; i >= 0; i--) {
|
|
24422
24473
|
const msg = allMsgs[i];
|
|
24423
24474
|
if (msg?.role === "assistant" && msg.content?.parts && Array.isArray(msg.content.parts)) {
|
|
@@ -25095,7 +25146,7 @@ ${formattedMessages}
|
|
|
25095
25146
|
async cleanupMessages(opts) {
|
|
25096
25147
|
const { threadId, resourceId, observedMessageIds, retentionFloor, preserveMessageIds } = opts;
|
|
25097
25148
|
const messageList = this.isMessageList(opts.messages) ? opts.messages : void 0;
|
|
25098
|
-
const allMsgs = messageList ? messageList
|
|
25149
|
+
const allMsgs = messageList ? getObservableMessages(messageList) : opts.messages;
|
|
25099
25150
|
let markerIdx = -1;
|
|
25100
25151
|
let markerMsg = null;
|
|
25101
25152
|
for (let i = allMsgs.length - 1; i >= 0; i--) {
|
|
@@ -26211,7 +26262,7 @@ function isTemporalGapMarkerForMessage(message, targetMessageId) {
|
|
|
26211
26262
|
async function insertTemporalGapMarkers({ messageList, sendSignal }) {
|
|
26212
26263
|
const latestInputMessage = messageList.get.input.db().filter((message) => Boolean(message)).at(-1);
|
|
26213
26264
|
if (!latestInputMessage || isTemporalGapMarker(latestInputMessage)) return;
|
|
26214
|
-
const allMessages = messageList
|
|
26265
|
+
const allMessages = getObservableMessages(messageList).filter((message) => Boolean(message));
|
|
26215
26266
|
const latestInputIndex = allMessages.findIndex((message) => message.id === latestInputMessage.id);
|
|
26216
26267
|
if (latestInputIndex <= 0) return;
|
|
26217
26268
|
if (allMessages.some((message) => isTemporalGapMarkerForMessage(message, latestInputMessage.id))) return;
|
|
@@ -26435,7 +26486,7 @@ var ObservationalMemoryProcessor = class {
|
|
|
26435
26486
|
threadId,
|
|
26436
26487
|
resourceId
|
|
26437
26488
|
});
|
|
26438
|
-
const allDbMsgs = messageList
|
|
26489
|
+
const allDbMsgs = getObservableMessages(messageList);
|
|
26439
26490
|
const tokenCounter = this.engine.getTokenCounter();
|
|
26440
26491
|
const contextTokens = await tokenCounter.countMessagesAsync(allDbMsgs);
|
|
26441
26492
|
const otherThreadsContext = this.turn.context.otherThreadsContext;
|
|
@@ -26805,6 +26856,18 @@ var Memory = class extends _mastra_core_memory.MastraMemory {
|
|
|
26805
26856
|
_omEngine;
|
|
26806
26857
|
_omEngineInstance;
|
|
26807
26858
|
_mastraInstance;
|
|
26859
|
+
/**
|
|
26860
|
+
* Every vector cleanup that deleteThread or deleteMessages started in the background.
|
|
26861
|
+
* Callers do not wait for the cleanup, so this handle is the only join point.
|
|
26862
|
+
*/
|
|
26863
|
+
pendingVectorCleanup = Promise.resolve();
|
|
26864
|
+
/**
|
|
26865
|
+
* Adds a background vector cleanup to the join handle.
|
|
26866
|
+
* The handle keeps the earlier cleanups, so it settles only after all of them end.
|
|
26867
|
+
*/
|
|
26868
|
+
trackVectorCleanup(cleanup) {
|
|
26869
|
+
this.pendingVectorCleanup = Promise.allSettled([this.pendingVectorCleanup, cleanup]).then(() => void 0);
|
|
26870
|
+
}
|
|
26808
26871
|
/** The shared ObservationalMemory engine. Lazily created on first access. */
|
|
26809
26872
|
get omEngine() {
|
|
26810
26873
|
if (!this._omEngine) this._omEngine = this._initOMEngine().then((engine) => {
|
|
@@ -27069,26 +27132,40 @@ var Memory = class extends _mastra_core_memory.MastraMemory {
|
|
|
27069
27132
|
const thread = await memoryStore.getThreadById({ threadId });
|
|
27070
27133
|
await memoryStore.deleteThread({ threadId });
|
|
27071
27134
|
if (thread?.resourceId && memoryStore.supportsObservationalMemory) await memoryStore.clearObservationalMemory(threadId, thread.resourceId);
|
|
27072
|
-
if (this.vector) this.deleteThreadVectors(threadId);
|
|
27135
|
+
if (this.vector) this.trackVectorCleanup(this.deleteThreadVectors(threadId));
|
|
27136
|
+
}
|
|
27137
|
+
/**
|
|
27138
|
+
* Prefix shared by every message index. The index for the default embedding
|
|
27139
|
+
* dimension is named with the bare prefix; other dimensions add a suffix.
|
|
27140
|
+
*/
|
|
27141
|
+
get messageIndexPrefix() {
|
|
27142
|
+
return this.getEmbeddingIndexName();
|
|
27073
27143
|
}
|
|
27074
27144
|
/**
|
|
27075
|
-
*
|
|
27076
|
-
* Handles separator differences across vector store backends (e.g. '_' vs '-').
|
|
27145
|
+
* Prefix shared by every observation index. Each observation index adds a dimension suffix.
|
|
27077
27146
|
*/
|
|
27078
|
-
|
|
27147
|
+
get observationIndexPrefix() {
|
|
27148
|
+
return `memory${this.vector?.indexSeparator ?? "_"}observations`;
|
|
27149
|
+
}
|
|
27150
|
+
/**
|
|
27151
|
+
* Lists the vector indexes whose name starts with one of the given prefixes.
|
|
27152
|
+
* Index names can carry a dimension suffix, so discovery matches on the prefix.
|
|
27153
|
+
*/
|
|
27154
|
+
async getMemoryVectorIndexes(prefixes) {
|
|
27079
27155
|
if (!this.vector) return [];
|
|
27080
|
-
|
|
27081
|
-
return (await this.vector.listIndexes()).filter((name) => name.startsWith(prefix));
|
|
27156
|
+
return (await this.vector.listIndexes()).filter((name) => prefixes.some((prefix) => name.startsWith(prefix)));
|
|
27082
27157
|
}
|
|
27083
27158
|
/**
|
|
27084
27159
|
* Deletes all vector embeddings associated with a thread.
|
|
27085
27160
|
* This is called internally by deleteThread to clean up orphaned vectors.
|
|
27161
|
+
* Both message and observation vectors are removed, so no text of the deleted
|
|
27162
|
+
* thread stays reachable through resource-scoped retrieval.
|
|
27086
27163
|
*
|
|
27087
27164
|
* @param threadId - The ID of the thread whose vectors should be deleted
|
|
27088
27165
|
*/
|
|
27089
27166
|
async deleteThreadVectors(threadId) {
|
|
27090
27167
|
try {
|
|
27091
|
-
const memoryIndexes = await this.getMemoryVectorIndexes();
|
|
27168
|
+
const memoryIndexes = await this.getMemoryVectorIndexes([this.messageIndexPrefix, this.observationIndexPrefix]);
|
|
27092
27169
|
await Promise.all(memoryIndexes.map(async (indexName) => {
|
|
27093
27170
|
try {
|
|
27094
27171
|
await this.vector.deleteVectors({
|
|
@@ -27096,14 +27173,14 @@ var Memory = class extends _mastra_core_memory.MastraMemory {
|
|
|
27096
27173
|
filter: { thread_id: threadId }
|
|
27097
27174
|
});
|
|
27098
27175
|
} catch {
|
|
27099
|
-
this.logger.
|
|
27176
|
+
this.logger.warn("Failed to delete vectors of the deleted thread from index", {
|
|
27100
27177
|
threadId,
|
|
27101
27178
|
indexName
|
|
27102
27179
|
});
|
|
27103
27180
|
}
|
|
27104
27181
|
}));
|
|
27105
27182
|
} catch {
|
|
27106
|
-
this.logger.
|
|
27183
|
+
this.logger.warn("Failed to clean up vectors of the deleted thread", { threadId });
|
|
27107
27184
|
}
|
|
27108
27185
|
}
|
|
27109
27186
|
async updateWorkingMemory({ threadId, resourceId, workingMemory, memoryConfig, observabilityContext }) {
|
|
@@ -27776,7 +27853,7 @@ Notes:
|
|
|
27776
27853
|
getObservationEmbeddingIndexName(dimensions) {
|
|
27777
27854
|
const usedDimensions = dimensions ?? 384;
|
|
27778
27855
|
const separator = this.vector?.indexSeparator ?? "_";
|
|
27779
|
-
return
|
|
27856
|
+
return `${this.observationIndexPrefix}${separator}${usedDimensions}`;
|
|
27780
27857
|
}
|
|
27781
27858
|
async createObservationEmbeddingIndex(dimensions) {
|
|
27782
27859
|
const usedDimensions = dimensions ?? 384;
|
|
@@ -28022,7 +28099,10 @@ Notes:
|
|
|
28022
28099
|
tools[name] = tool;
|
|
28023
28100
|
}
|
|
28024
28101
|
const omConfig = normalizeObservationalMemoryConfig(mergedConfig.observationalMemory);
|
|
28025
|
-
if (omConfig?.retrieval) tools.recall = recallTool(mergedConfig, {
|
|
28102
|
+
if (omConfig?.retrieval) tools.recall = recallTool(mergedConfig, {
|
|
28103
|
+
retrievalScope: typeof omConfig.retrieval === "object" ? omConfig.retrieval.scope ?? "resource" : "resource",
|
|
28104
|
+
searchEnabled: this.hasRetrievalSearch(omConfig.retrieval)
|
|
28105
|
+
});
|
|
28026
28106
|
return tools;
|
|
28027
28107
|
}
|
|
28028
28108
|
/**
|
|
@@ -28078,7 +28158,7 @@ Notes:
|
|
|
28078
28158
|
}));
|
|
28079
28159
|
const messageIdsNeedingDeletion = /* @__PURE__ */ new Set([...messageIdsWithClearedContent, ...messageIdsWithNewEmbeddings]);
|
|
28080
28160
|
if (messageIdsNeedingDeletion.size > 0) try {
|
|
28081
|
-
const memoryIndexes = await this.getMemoryVectorIndexes();
|
|
28161
|
+
const memoryIndexes = await this.getMemoryVectorIndexes([this.messageIndexPrefix]);
|
|
28082
28162
|
const idsToDelete = [...messageIdsNeedingDeletion];
|
|
28083
28163
|
await Promise.all(memoryIndexes.map(async (indexName) => {
|
|
28084
28164
|
for (let i = 0; i < idsToDelete.length; i += VECTOR_DELETE_BATCH_SIZE) {
|
|
@@ -28137,7 +28217,7 @@ Notes:
|
|
|
28137
28217
|
const span = this.createMemorySpan("delete", observabilityContext, void 0, { messageCount: messageIds.length });
|
|
28138
28218
|
try {
|
|
28139
28219
|
await (await this.getMemoryStore()).deleteMessages(messageIds);
|
|
28140
|
-
if (this.vector) this.deleteMessageVectors(messageIds);
|
|
28220
|
+
if (this.vector) this.trackVectorCleanup(this.deleteMessageVectors(messageIds));
|
|
28141
28221
|
span?.end({
|
|
28142
28222
|
output: { success: true },
|
|
28143
28223
|
attributes: { messageCount: messageIds.length }
|
|
@@ -28153,12 +28233,14 @@ Notes:
|
|
|
28153
28233
|
/**
|
|
28154
28234
|
* Deletes vector embeddings for specific messages.
|
|
28155
28235
|
* This is called internally by deleteMessages to clean up orphaned vectors.
|
|
28236
|
+
* Only the message indexes are touched, because observation vectors can hold
|
|
28237
|
+
* text of other messages of the thread.
|
|
28156
28238
|
*
|
|
28157
28239
|
* @param messageIds - The IDs of the messages whose vectors should be deleted
|
|
28158
28240
|
*/
|
|
28159
28241
|
async deleteMessageVectors(messageIds) {
|
|
28160
28242
|
try {
|
|
28161
|
-
const memoryIndexes = await this.getMemoryVectorIndexes();
|
|
28243
|
+
const memoryIndexes = await this.getMemoryVectorIndexes([this.messageIndexPrefix]);
|
|
28162
28244
|
await Promise.all(memoryIndexes.map(async (indexName) => {
|
|
28163
28245
|
for (let i = 0; i < messageIds.length; i += VECTOR_DELETE_BATCH_SIZE) {
|
|
28164
28246
|
const batch = messageIds.slice(i, i + VECTOR_DELETE_BATCH_SIZE);
|
|
@@ -28785,4 +28867,4 @@ Object.defineProperty(exports, "wrapInObservationGroup", {
|
|
|
28785
28867
|
}
|
|
28786
28868
|
});
|
|
28787
28869
|
|
|
28788
|
-
//# sourceMappingURL=src-
|
|
28870
|
+
//# sourceMappingURL=src-CTQrRb5X.cjs.map
|