@mastra/memory 1.10.1-alpha.3 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +66 -0
- package/dist/{chunk-SKRONGCV.js → chunk-D4D6ZFBQ.js} +355 -105
- package/dist/chunk-D4D6ZFBQ.js.map +1 -0
- package/dist/{chunk-DTAZSLVU.cjs → chunk-VINRPDYQ.cjs} +355 -105
- package/dist/chunk-VINRPDYQ.cjs.map +1 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +47 -47
- package/dist/docs/references/docs-memory-observational-memory.md +49 -4
- package/dist/docs/references/reference-memory-observational-memory.md +32 -6
- package/dist/index.cjs +577 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +46 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +570 -29
- package/dist/index.js.map +1 -1
- package/dist/{observational-memory-XIZTJN3S.cjs → observational-memory-FATH657E.cjs} +26 -26
- package/dist/{observational-memory-XIZTJN3S.cjs.map → observational-memory-FATH657E.cjs.map} +1 -1
- package/dist/{observational-memory-UGDENJPE.js → observational-memory-SN7GKMHZ.js} +3 -3
- package/dist/{observational-memory-UGDENJPE.js.map → observational-memory-SN7GKMHZ.js.map} +1 -1
- package/dist/processors/index.cjs +24 -24
- package/dist/processors/index.js +1 -1
- package/dist/processors/observational-memory/observation-strategies/async-buffer.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-strategies/base.d.ts +9 -0
- package/dist/processors/observational-memory/observation-strategies/base.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-strategies/resource-scoped.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-strategies/sync.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-strategies/types.d.ts +2 -0
- package/dist/processors/observational-memory/observation-strategies/types.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-turn/step.d.ts.map +1 -1
- package/dist/processors/observational-memory/observation-turn/turn.d.ts +4 -0
- package/dist/processors/observational-memory/observation-turn/turn.d.ts.map +1 -1
- package/dist/processors/observational-memory/observational-memory.d.ts +27 -2
- package/dist/processors/observational-memory/observational-memory.d.ts.map +1 -1
- package/dist/processors/observational-memory/observer-runner.d.ts +14 -3
- package/dist/processors/observational-memory/observer-runner.d.ts.map +1 -1
- package/dist/processors/observational-memory/processor.d.ts +8 -12
- package/dist/processors/observational-memory/processor.d.ts.map +1 -1
- package/dist/processors/observational-memory/reflector-runner.d.ts +11 -1
- package/dist/processors/observational-memory/reflector-runner.d.ts.map +1 -1
- package/dist/processors/observational-memory/tracing.d.ts +17 -0
- package/dist/processors/observational-memory/tracing.d.ts.map +1 -0
- package/dist/processors/observational-memory/types.d.ts +19 -1
- package/dist/processors/observational-memory/types.d.ts.map +1 -1
- package/dist/tools/om-tools.d.ts +96 -4
- package/dist/tools/om-tools.d.ts.map +1 -1
- package/package.json +7 -7
- package/dist/chunk-DTAZSLVU.cjs.map +0 -1
- package/dist/chunk-SKRONGCV.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var chunkCK4U3AYR_cjs = require('./chunk-CK4U3AYR.cjs');
|
|
4
4
|
var chunkIDRQZVB4_cjs = require('./chunk-IDRQZVB4.cjs');
|
|
5
|
-
var
|
|
5
|
+
var chunkVINRPDYQ_cjs = require('./chunk-VINRPDYQ.cjs');
|
|
6
6
|
var v3 = require('zod/v3');
|
|
7
7
|
var zod = require('zod');
|
|
8
8
|
var z4 = require('zod/v4');
|
|
@@ -15473,7 +15473,7 @@ function parseRangeFormat(cursor) {
|
|
|
15473
15473
|
}
|
|
15474
15474
|
return null;
|
|
15475
15475
|
}
|
|
15476
|
-
async function resolveCursorMessage(memory, cursor) {
|
|
15476
|
+
async function resolveCursorMessage(memory, cursor, access) {
|
|
15477
15477
|
const normalized = cursor.trim();
|
|
15478
15478
|
if (!normalized) {
|
|
15479
15479
|
throw new Error("Cursor is required");
|
|
@@ -15491,8 +15491,171 @@ async function resolveCursorMessage(memory, cursor) {
|
|
|
15491
15491
|
if (!message) {
|
|
15492
15492
|
throw new Error(`Could not resolve cursor message: ${cursor}`);
|
|
15493
15493
|
}
|
|
15494
|
+
if (access?.resourceId && message.resourceId !== access.resourceId) {
|
|
15495
|
+
throw new Error(`Could not resolve cursor message: ${cursor}`);
|
|
15496
|
+
}
|
|
15497
|
+
if (access?.threadScope && message.threadId !== access.threadScope) {
|
|
15498
|
+
throw new Error(`Could not resolve cursor message: ${cursor}`);
|
|
15499
|
+
}
|
|
15494
15500
|
return message;
|
|
15495
15501
|
}
|
|
15502
|
+
async function listThreadsForResource({
|
|
15503
|
+
memory,
|
|
15504
|
+
resourceId,
|
|
15505
|
+
currentThreadId,
|
|
15506
|
+
page = 0,
|
|
15507
|
+
limit = 20,
|
|
15508
|
+
before,
|
|
15509
|
+
after
|
|
15510
|
+
}) {
|
|
15511
|
+
if (!resourceId) {
|
|
15512
|
+
throw new Error("Resource ID is required to list threads");
|
|
15513
|
+
}
|
|
15514
|
+
const MAX_LIMIT = 50;
|
|
15515
|
+
const normalizedLimit = Math.min(Math.max(limit, 1), MAX_LIMIT);
|
|
15516
|
+
const hasDateFilter = !!(before || after);
|
|
15517
|
+
const beforeDate = before ? new Date(before) : null;
|
|
15518
|
+
const afterDate = after ? new Date(after) : null;
|
|
15519
|
+
const result = await memory.listThreads({
|
|
15520
|
+
filter: { resourceId },
|
|
15521
|
+
page: hasDateFilter ? 0 : page,
|
|
15522
|
+
perPage: hasDateFilter ? false : normalizedLimit,
|
|
15523
|
+
orderBy: { field: "updatedAt", direction: "DESC" }
|
|
15524
|
+
});
|
|
15525
|
+
let threads = result.threads;
|
|
15526
|
+
if (beforeDate) {
|
|
15527
|
+
threads = threads.filter((t) => t.createdAt < beforeDate);
|
|
15528
|
+
}
|
|
15529
|
+
if (afterDate) {
|
|
15530
|
+
threads = threads.filter((t) => t.createdAt > afterDate);
|
|
15531
|
+
}
|
|
15532
|
+
let hasMore;
|
|
15533
|
+
if (hasDateFilter) {
|
|
15534
|
+
const offset = page * normalizedLimit;
|
|
15535
|
+
hasMore = offset + normalizedLimit < threads.length;
|
|
15536
|
+
threads = threads.slice(offset, offset + normalizedLimit);
|
|
15537
|
+
} else {
|
|
15538
|
+
hasMore = result.hasMore;
|
|
15539
|
+
}
|
|
15540
|
+
if (threads.length === 0) {
|
|
15541
|
+
return {
|
|
15542
|
+
threads: "No threads found matching the criteria.",
|
|
15543
|
+
count: 0,
|
|
15544
|
+
page,
|
|
15545
|
+
hasMore: false
|
|
15546
|
+
};
|
|
15547
|
+
}
|
|
15548
|
+
const lines = [];
|
|
15549
|
+
for (const thread of threads) {
|
|
15550
|
+
const isCurrent = thread.id === currentThreadId;
|
|
15551
|
+
const title = thread.title || "(untitled)";
|
|
15552
|
+
const updated = formatTimestamp(thread.updatedAt);
|
|
15553
|
+
const created = formatTimestamp(thread.createdAt);
|
|
15554
|
+
const marker21 = isCurrent ? " \u2190 current" : "";
|
|
15555
|
+
lines.push(`- **${title}**${marker21}`);
|
|
15556
|
+
lines.push(` id: ${thread.id}`);
|
|
15557
|
+
lines.push(` updated: ${updated} | created: ${created}`);
|
|
15558
|
+
}
|
|
15559
|
+
return {
|
|
15560
|
+
threads: lines.join("\n"),
|
|
15561
|
+
count: threads.length,
|
|
15562
|
+
page,
|
|
15563
|
+
hasMore
|
|
15564
|
+
};
|
|
15565
|
+
}
|
|
15566
|
+
async function searchMessagesForResource({
|
|
15567
|
+
memory,
|
|
15568
|
+
resourceId,
|
|
15569
|
+
currentThreadId,
|
|
15570
|
+
query,
|
|
15571
|
+
topK = 10,
|
|
15572
|
+
maxTokens = DEFAULT_MAX_RESULT_TOKENS,
|
|
15573
|
+
before,
|
|
15574
|
+
after,
|
|
15575
|
+
threadScope
|
|
15576
|
+
}) {
|
|
15577
|
+
if (!memory.searchMessages) {
|
|
15578
|
+
return {
|
|
15579
|
+
results: "Search is not configured. Enable it with `retrieval: { vector: true }` and configure a vector store and embedder on your Memory instance.",
|
|
15580
|
+
count: 0
|
|
15581
|
+
};
|
|
15582
|
+
}
|
|
15583
|
+
const MAX_TOPK = 20;
|
|
15584
|
+
const clampedTopK = Math.min(Math.max(topK, 1), MAX_TOPK);
|
|
15585
|
+
const effectiveTopK = threadScope || before || after ? Math.max(clampedTopK * 3, clampedTopK + 10) : clampedTopK;
|
|
15586
|
+
const searchTopK = Math.min(MAX_TOPK, effectiveTopK);
|
|
15587
|
+
const beforeDate = before ? new Date(before) : void 0;
|
|
15588
|
+
const afterDate = after ? new Date(after) : void 0;
|
|
15589
|
+
const { results } = await memory.searchMessages({
|
|
15590
|
+
query,
|
|
15591
|
+
resourceId,
|
|
15592
|
+
topK: searchTopK,
|
|
15593
|
+
filter: {
|
|
15594
|
+
...threadScope ? { threadId: threadScope } : {},
|
|
15595
|
+
...afterDate ? { observedAfter: afterDate } : {},
|
|
15596
|
+
...beforeDate ? { observedBefore: beforeDate } : {}
|
|
15597
|
+
}
|
|
15598
|
+
});
|
|
15599
|
+
if (results.length === 0) {
|
|
15600
|
+
return {
|
|
15601
|
+
results: "No matching messages found.",
|
|
15602
|
+
count: 0
|
|
15603
|
+
};
|
|
15604
|
+
}
|
|
15605
|
+
const threadIds = [...new Set(results.map((r) => r.threadId))];
|
|
15606
|
+
const threadMap = /* @__PURE__ */ new Map();
|
|
15607
|
+
if (memory.getThreadById) {
|
|
15608
|
+
await Promise.all(
|
|
15609
|
+
threadIds.map(async (id) => {
|
|
15610
|
+
const thread = await memory.getThreadById({ threadId: id });
|
|
15611
|
+
if (thread) threadMap.set(id, thread);
|
|
15612
|
+
})
|
|
15613
|
+
);
|
|
15614
|
+
}
|
|
15615
|
+
const filteredMatches = results.filter((match) => {
|
|
15616
|
+
if (threadScope && match.threadId !== threadScope) return false;
|
|
15617
|
+
if (beforeDate && match.observedAt && match.observedAt >= beforeDate) return false;
|
|
15618
|
+
if (afterDate && match.observedAt && match.observedAt <= afterDate) return false;
|
|
15619
|
+
return true;
|
|
15620
|
+
});
|
|
15621
|
+
if (filteredMatches.length === 0) {
|
|
15622
|
+
return { results: "No matching messages found.", count: 0 };
|
|
15623
|
+
}
|
|
15624
|
+
const limitedMatches = filteredMatches.slice(0, clampedTopK);
|
|
15625
|
+
const sections = limitedMatches.map((match) => {
|
|
15626
|
+
const thread = threadMap.get(match.threadId);
|
|
15627
|
+
const title = thread?.title || "(untitled)";
|
|
15628
|
+
const isCurrentThread = match.threadId === currentThreadId;
|
|
15629
|
+
const generationLabel = isCurrentThread ? "Current thread memory" : "Older memory from another thread";
|
|
15630
|
+
const generationDetail = isCurrentThread ? "This result came from the current thread." : "This result came from an older memory generation in another thread.";
|
|
15631
|
+
const threadLine = `- thread: ${match.threadId}${thread ? ` (${title})` : ""}`;
|
|
15632
|
+
const sourceLine = match.range ? `- source: raw messages from ID ${match.range.split(":")[0] ?? "(unknown)"} through ID ${match.range.split(":")[1] ?? "(unknown)"}` : "- source: raw message range unavailable";
|
|
15633
|
+
const updatedLine = thread ? `- thread updated: ${formatTimestamp(thread.updatedAt)}` : void 0;
|
|
15634
|
+
const groupLine = match.groupId ? `- observation group: ${match.groupId}` : void 0;
|
|
15635
|
+
const scoreLine = `- score: ${match.score.toFixed(2)}`;
|
|
15636
|
+
const body = (match.text || "").trim() || "_Observation text unavailable._";
|
|
15637
|
+
return [
|
|
15638
|
+
`### ${generationLabel}`,
|
|
15639
|
+
"",
|
|
15640
|
+
generationDetail,
|
|
15641
|
+
threadLine,
|
|
15642
|
+
sourceLine,
|
|
15643
|
+
updatedLine,
|
|
15644
|
+
groupLine,
|
|
15645
|
+
scoreLine,
|
|
15646
|
+
"",
|
|
15647
|
+
"```text",
|
|
15648
|
+
body,
|
|
15649
|
+
"```"
|
|
15650
|
+
].filter(Boolean).join("\n");
|
|
15651
|
+
});
|
|
15652
|
+
const assembled = sections.join("\n\n");
|
|
15653
|
+
const { text: limited } = truncateByTokens(assembled, maxTokens);
|
|
15654
|
+
return {
|
|
15655
|
+
results: limited,
|
|
15656
|
+
count: limitedMatches.length
|
|
15657
|
+
};
|
|
15658
|
+
}
|
|
15496
15659
|
var LOW_DETAIL_PART_TOKENS = 30;
|
|
15497
15660
|
var AUTO_EXPAND_TEXT_TOKENS = 100;
|
|
15498
15661
|
var AUTO_EXPAND_TOOL_TOKENS = 20;
|
|
@@ -15503,7 +15666,7 @@ function formatTimestamp(date) {
|
|
|
15503
15666
|
}
|
|
15504
15667
|
function truncateByTokens(text4, maxTokens, hint) {
|
|
15505
15668
|
if (tokenx.estimateTokenCount(text4) <= maxTokens) return { text: text4, wasTruncated: false };
|
|
15506
|
-
const truncated =
|
|
15669
|
+
const truncated = chunkVINRPDYQ_cjs.truncateStringByTokens(text4, maxTokens);
|
|
15507
15670
|
const suffix = hint ? ` [${hint} for more]` : "";
|
|
15508
15671
|
return { text: truncated + suffix, wasTruncated: true };
|
|
15509
15672
|
}
|
|
@@ -15536,11 +15699,11 @@ function formatMessageParts(msg, detail) {
|
|
|
15536
15699
|
} else if (partType === "tool-invocation") {
|
|
15537
15700
|
const inv = part.toolInvocation;
|
|
15538
15701
|
if (inv.state === "result") {
|
|
15539
|
-
const { value: resultValue } =
|
|
15702
|
+
const { value: resultValue } = chunkVINRPDYQ_cjs.resolveToolResultValue(
|
|
15540
15703
|
part,
|
|
15541
15704
|
inv.result
|
|
15542
15705
|
);
|
|
15543
|
-
const resultStr =
|
|
15706
|
+
const resultStr = chunkVINRPDYQ_cjs.formatToolResultForObserver(resultValue, { maxTokens: HIGH_DETAIL_TOOL_RESULT_TOKENS });
|
|
15544
15707
|
const fullText = `[Tool Result: ${inv.toolName}]
|
|
15545
15708
|
${resultStr}`;
|
|
15546
15709
|
parts.push(makePart(msg, i, "tool-result", fullText, detail));
|
|
@@ -15603,7 +15766,7 @@ function renderFormattedParts(parts, timestamps, options) {
|
|
|
15603
15766
|
const text4 = buildRenderedText(parts, timestamps);
|
|
15604
15767
|
let totalTokens = tokenx.estimateTokenCount(text4);
|
|
15605
15768
|
if (totalTokens > options.maxTokens) {
|
|
15606
|
-
const truncated =
|
|
15769
|
+
const truncated = chunkVINRPDYQ_cjs.truncateStringByTokens(text4, options.maxTokens);
|
|
15607
15770
|
return { text: truncated, truncated: true, tokenOffset: totalTokens - options.maxTokens };
|
|
15608
15771
|
}
|
|
15609
15772
|
const truncatedIndices = parts.map((p, i) => ({ part: p, index: i })).filter(({ part }) => part.text !== part.fullText).sort((a, b) => expandPriority(a.part) - expandPriority(b.part));
|
|
@@ -15636,14 +15799,16 @@ function renderFormattedParts(parts, timestamps, options) {
|
|
|
15636
15799
|
if (expandedTokens <= options.maxTokens) {
|
|
15637
15800
|
return { text: expanded, truncated: false, tokenOffset: 0 };
|
|
15638
15801
|
}
|
|
15639
|
-
const hardTruncated =
|
|
15802
|
+
const hardTruncated = chunkVINRPDYQ_cjs.truncateStringByTokens(expanded, options.maxTokens);
|
|
15640
15803
|
return { text: hardTruncated, truncated: true, tokenOffset: expandedTokens - options.maxTokens };
|
|
15641
15804
|
}
|
|
15642
15805
|
async function recallPart({
|
|
15643
15806
|
memory,
|
|
15644
15807
|
threadId,
|
|
15808
|
+
resourceId,
|
|
15645
15809
|
cursor,
|
|
15646
15810
|
partIndex,
|
|
15811
|
+
threadScope,
|
|
15647
15812
|
maxTokens = DEFAULT_MAX_RESULT_TOKENS
|
|
15648
15813
|
}) {
|
|
15649
15814
|
if (!memory || typeof memory.getMemoryStore !== "function") {
|
|
@@ -15652,13 +15817,10 @@ async function recallPart({
|
|
|
15652
15817
|
if (!threadId) {
|
|
15653
15818
|
throw new Error("Thread ID is required for recall");
|
|
15654
15819
|
}
|
|
15655
|
-
const resolved = await resolveCursorMessage(memory, cursor);
|
|
15820
|
+
const resolved = await resolveCursorMessage(memory, cursor, { resourceId, threadScope });
|
|
15656
15821
|
if ("hint" in resolved) {
|
|
15657
15822
|
throw new Error(resolved.hint);
|
|
15658
15823
|
}
|
|
15659
|
-
if (resolved.threadId !== threadId) {
|
|
15660
|
-
throw new Error("The requested cursor does not belong to the current thread");
|
|
15661
|
-
}
|
|
15662
15824
|
const allParts = formatMessageParts(resolved, "high");
|
|
15663
15825
|
if (allParts.length === 0) {
|
|
15664
15826
|
throw new Error(
|
|
@@ -15671,7 +15833,7 @@ async function recallPart({
|
|
|
15671
15833
|
`Part index ${partIndex} not found in message ${cursor}. Available indices: ${allParts.map((p) => p.partIndex).join(", ")}`
|
|
15672
15834
|
);
|
|
15673
15835
|
}
|
|
15674
|
-
const truncatedText =
|
|
15836
|
+
const truncatedText = chunkVINRPDYQ_cjs.truncateStringByTokens(target.text, maxTokens);
|
|
15675
15837
|
const wasTruncated = truncatedText !== target.text;
|
|
15676
15838
|
return {
|
|
15677
15839
|
text: truncatedText,
|
|
@@ -15690,6 +15852,7 @@ async function recallMessages({
|
|
|
15690
15852
|
page = 1,
|
|
15691
15853
|
limit = 20,
|
|
15692
15854
|
detail = "low",
|
|
15855
|
+
threadScope,
|
|
15693
15856
|
maxTokens = DEFAULT_MAX_RESULT_TOKENS
|
|
15694
15857
|
}) {
|
|
15695
15858
|
if (!memory) {
|
|
@@ -15706,7 +15869,7 @@ async function recallMessages({
|
|
|
15706
15869
|
const rawPage = page === 0 ? 1 : page;
|
|
15707
15870
|
const normalizedPage = Math.max(Math.min(rawPage, MAX_PAGE), -MAX_PAGE);
|
|
15708
15871
|
const normalizedLimit = Math.min(limit, MAX_LIMIT);
|
|
15709
|
-
const resolved = await resolveCursorMessage(memory, cursor);
|
|
15872
|
+
const resolved = await resolveCursorMessage(memory, cursor, { resourceId, threadScope });
|
|
15710
15873
|
if ("hint" in resolved) {
|
|
15711
15874
|
return {
|
|
15712
15875
|
messages: resolved.hint,
|
|
@@ -15722,15 +15885,27 @@ async function recallMessages({
|
|
|
15722
15885
|
};
|
|
15723
15886
|
}
|
|
15724
15887
|
const anchor = resolved;
|
|
15725
|
-
if (anchor.threadId !== threadId) {
|
|
15726
|
-
|
|
15888
|
+
if (anchor.threadId && anchor.threadId !== threadId) {
|
|
15889
|
+
return {
|
|
15890
|
+
messages: `Cursor does not belong to the active thread. Expected thread "${threadId}" but cursor "${cursor}" belongs to "${anchor.threadId}".`,
|
|
15891
|
+
count: 0,
|
|
15892
|
+
cursor,
|
|
15893
|
+
page: normalizedPage,
|
|
15894
|
+
limit: normalizedLimit,
|
|
15895
|
+
detail,
|
|
15896
|
+
hasNextPage: false,
|
|
15897
|
+
hasPrevPage: false,
|
|
15898
|
+
truncated: false,
|
|
15899
|
+
tokenOffset: 0
|
|
15900
|
+
};
|
|
15727
15901
|
}
|
|
15902
|
+
const resolvedThreadId = threadId;
|
|
15728
15903
|
const isForward = normalizedPage > 0;
|
|
15729
15904
|
const pageIndex = Math.max(Math.abs(normalizedPage), 1) - 1;
|
|
15730
15905
|
const skip = pageIndex * normalizedLimit;
|
|
15731
15906
|
const fetchCount = skip + normalizedLimit + 1;
|
|
15732
15907
|
const result = await memory.recall({
|
|
15733
|
-
threadId,
|
|
15908
|
+
threadId: resolvedThreadId,
|
|
15734
15909
|
resourceId,
|
|
15735
15910
|
page: 0,
|
|
15736
15911
|
perPage: fetchCount,
|
|
@@ -15813,55 +15988,233 @@ High detail returns 1 part at a time. To continue: ${hints.join(", or ")}.`;
|
|
|
15813
15988
|
tokenOffset: rendered.tokenOffset
|
|
15814
15989
|
};
|
|
15815
15990
|
}
|
|
15816
|
-
|
|
15991
|
+
async function recallThreadFromStart({
|
|
15992
|
+
memory,
|
|
15993
|
+
threadId,
|
|
15994
|
+
resourceId,
|
|
15995
|
+
page = 1,
|
|
15996
|
+
limit = 20,
|
|
15997
|
+
detail = "low",
|
|
15998
|
+
maxTokens = DEFAULT_MAX_RESULT_TOKENS
|
|
15999
|
+
}) {
|
|
16000
|
+
if (!memory) {
|
|
16001
|
+
throw new Error("Memory instance is required for recall");
|
|
16002
|
+
}
|
|
16003
|
+
if (!threadId) {
|
|
16004
|
+
throw new Error("Thread ID is required for recall");
|
|
16005
|
+
}
|
|
16006
|
+
if (resourceId && memory.getThreadById) {
|
|
16007
|
+
const thread = await memory.getThreadById({ threadId });
|
|
16008
|
+
if (!thread || thread.resourceId !== resourceId) {
|
|
16009
|
+
throw new Error("Thread not found");
|
|
16010
|
+
}
|
|
16011
|
+
}
|
|
16012
|
+
const MAX_PAGE = 50;
|
|
16013
|
+
const MAX_LIMIT = 20;
|
|
16014
|
+
const normalizedPage = Math.max(Math.min(page, MAX_PAGE), 1);
|
|
16015
|
+
const normalizedLimit = Math.min(Math.max(limit, 1), MAX_LIMIT);
|
|
16016
|
+
const pageIndex = normalizedPage - 1;
|
|
16017
|
+
const fetchCount = pageIndex * normalizedLimit + normalizedLimit + 1;
|
|
16018
|
+
const result = await memory.recall({
|
|
16019
|
+
threadId,
|
|
16020
|
+
resourceId,
|
|
16021
|
+
page: 0,
|
|
16022
|
+
perPage: fetchCount,
|
|
16023
|
+
orderBy: { field: "createdAt", direction: "ASC" }
|
|
16024
|
+
});
|
|
16025
|
+
const visibleMessages = result.messages.filter(hasVisibleParts);
|
|
16026
|
+
const total = visibleMessages.length;
|
|
16027
|
+
const skip = pageIndex * normalizedLimit;
|
|
16028
|
+
const hasMore = total > skip + normalizedLimit;
|
|
16029
|
+
const messages = visibleMessages.slice(skip, skip + normalizedLimit);
|
|
16030
|
+
const allParts = [];
|
|
16031
|
+
const timestamps = /* @__PURE__ */ new Map();
|
|
16032
|
+
for (const msg of messages) {
|
|
16033
|
+
timestamps.set(msg.id, msg.createdAt);
|
|
16034
|
+
allParts.push(...formatMessageParts(msg, detail));
|
|
16035
|
+
}
|
|
16036
|
+
const rendered = renderFormattedParts(allParts, timestamps, { maxTokens });
|
|
16037
|
+
return {
|
|
16038
|
+
messages: rendered.text || "(no messages in this thread)",
|
|
16039
|
+
count: messages.length,
|
|
16040
|
+
cursor: messages[0]?.id || "",
|
|
16041
|
+
page: normalizedPage,
|
|
16042
|
+
limit: normalizedLimit,
|
|
16043
|
+
detail,
|
|
16044
|
+
hasNextPage: hasMore,
|
|
16045
|
+
hasPrevPage: pageIndex > 0,
|
|
16046
|
+
truncated: rendered.truncated,
|
|
16047
|
+
tokenOffset: rendered.tokenOffset
|
|
16048
|
+
};
|
|
16049
|
+
}
|
|
16050
|
+
var recallTool = (_memoryConfig, options) => {
|
|
16051
|
+
const retrievalScope = options?.retrievalScope ?? "thread";
|
|
16052
|
+
const isResourceScope = retrievalScope === "resource";
|
|
16053
|
+
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. If you pass only a cursor, it must belong to the current thread. 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. Use mode="search" to find messages by content in this thread. Use mode="threads" to get the current thread's ID and title.`;
|
|
15817
16054
|
return tools.createTool({
|
|
15818
16055
|
id: "recall",
|
|
15819
|
-
description
|
|
16056
|
+
description,
|
|
15820
16057
|
inputSchema: zod.z.object({
|
|
15821
|
-
|
|
16058
|
+
...isResourceScope ? {
|
|
16059
|
+
mode: zod.z.enum(["messages", "threads", "search"]).optional().describe(
|
|
16060
|
+
'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.'
|
|
16061
|
+
),
|
|
16062
|
+
threadId: zod.z.string().min(1).optional().describe('Browse a different thread. Use mode="threads" first to discover thread IDs.'),
|
|
16063
|
+
before: zod.z.string().optional().describe(
|
|
16064
|
+
'For mode="threads": only show threads created before this date. ISO 8601 or natural date string (e.g. "2026-03-15", "2026-03-10T00:00:00Z").'
|
|
16065
|
+
),
|
|
16066
|
+
after: zod.z.string().optional().describe(
|
|
16067
|
+
'For mode="threads": only show threads created after this date. ISO 8601 or natural date string (e.g. "2026-03-01", "2026-03-10T00:00:00Z").'
|
|
16068
|
+
)
|
|
16069
|
+
} : {
|
|
16070
|
+
mode: zod.z.enum(["messages", "threads", "search"]).optional().describe(
|
|
16071
|
+
'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.'
|
|
16072
|
+
)
|
|
16073
|
+
},
|
|
16074
|
+
query: zod.z.string().min(1).optional().describe('Search query for mode="search". Finds messages semantically similar to this text.'),
|
|
16075
|
+
cursor: zod.z.string().min(1).optional().describe(
|
|
16076
|
+
'A message ID to use as the pagination cursor. For mode="messages", provide either cursor or threadId. If only cursor is provided, it must belong to the current thread. Extract it from the start or end of an observation group range.'
|
|
16077
|
+
),
|
|
15822
16078
|
page: zod.z.number().int().min(-50).max(50).optional().describe(
|
|
15823
|
-
"Pagination offset
|
|
16079
|
+
"Pagination offset. For messages: positive pages move forward from cursor, negative move backward. For threads: page number (0-indexed). 0 is treated as 1 for messages."
|
|
15824
16080
|
),
|
|
15825
|
-
limit: zod.z.number().int().positive().max(20).optional().describe("Maximum number of
|
|
16081
|
+
limit: zod.z.number().int().positive().max(20).optional().describe("Maximum number of items to return per page. Defaults to 20."),
|
|
15826
16082
|
detail: zod.z.enum(["low", "high"]).optional().describe(
|
|
15827
|
-
'Detail level. "low" (default) returns truncated text and tool names. "high" returns full content with tool args/results.'
|
|
16083
|
+
'Detail level for messages. "low" (default) returns truncated text and tool names. "high" returns full content with tool args/results.'
|
|
15828
16084
|
),
|
|
15829
16085
|
partIndex: zod.z.number().int().min(0).optional().describe(
|
|
15830
16086
|
"Fetch a single part from the cursor message by its positional index. When provided, returns only that part at high detail. Indices are shown as [p0], [p1], etc. in recall results."
|
|
15831
16087
|
)
|
|
15832
16088
|
}),
|
|
15833
16089
|
execute: async ({
|
|
16090
|
+
mode,
|
|
16091
|
+
query,
|
|
15834
16092
|
cursor,
|
|
16093
|
+
threadId: explicitThreadId,
|
|
15835
16094
|
page,
|
|
15836
16095
|
limit,
|
|
15837
16096
|
detail,
|
|
15838
|
-
partIndex
|
|
16097
|
+
partIndex,
|
|
16098
|
+
before,
|
|
16099
|
+
after
|
|
15839
16100
|
}, context2) => {
|
|
15840
16101
|
const memory = context2?.memory;
|
|
15841
|
-
const
|
|
16102
|
+
const currentThreadId = context2?.agent?.threadId;
|
|
15842
16103
|
const resourceId = context2?.agent?.resourceId;
|
|
15843
16104
|
if (!memory) {
|
|
15844
16105
|
throw new Error("Memory instance is required for recall");
|
|
15845
16106
|
}
|
|
15846
|
-
if (
|
|
16107
|
+
if (mode === "search") {
|
|
16108
|
+
if (!query) {
|
|
16109
|
+
throw new Error('query is required for mode="search"');
|
|
16110
|
+
}
|
|
16111
|
+
if (!resourceId) {
|
|
16112
|
+
throw new Error("Resource ID is required for recall");
|
|
16113
|
+
}
|
|
16114
|
+
return searchMessagesForResource({
|
|
16115
|
+
memory,
|
|
16116
|
+
resourceId,
|
|
16117
|
+
currentThreadId: currentThreadId || void 0,
|
|
16118
|
+
query,
|
|
16119
|
+
topK: limit ?? 10,
|
|
16120
|
+
before,
|
|
16121
|
+
after,
|
|
16122
|
+
threadScope: !isResourceScope ? currentThreadId || void 0 : void 0
|
|
16123
|
+
});
|
|
16124
|
+
}
|
|
16125
|
+
if (mode === "threads") {
|
|
16126
|
+
if (!isResourceScope) {
|
|
16127
|
+
if (!currentThreadId || !memory.getThreadById) {
|
|
16128
|
+
return { error: "Could not resolve current thread." };
|
|
16129
|
+
}
|
|
16130
|
+
const thread = await memory.getThreadById({ threadId: currentThreadId });
|
|
16131
|
+
if (!thread) {
|
|
16132
|
+
return { error: "Could not resolve current thread." };
|
|
16133
|
+
}
|
|
16134
|
+
return {
|
|
16135
|
+
threads: `- **${thread.title || "(untitled)"}** \u2190 current
|
|
16136
|
+
id: ${thread.id}
|
|
16137
|
+
updated: ${formatTimestamp(thread.updatedAt)} | created: ${formatTimestamp(thread.createdAt)}`,
|
|
16138
|
+
count: 1,
|
|
16139
|
+
page: 0,
|
|
16140
|
+
hasMore: false
|
|
16141
|
+
};
|
|
16142
|
+
}
|
|
16143
|
+
if (!resourceId) {
|
|
16144
|
+
throw new Error("Resource ID is required for recall");
|
|
16145
|
+
}
|
|
16146
|
+
return listThreadsForResource({
|
|
16147
|
+
memory,
|
|
16148
|
+
resourceId,
|
|
16149
|
+
currentThreadId: currentThreadId || "",
|
|
16150
|
+
page: page ?? 0,
|
|
16151
|
+
limit: limit ?? 20,
|
|
16152
|
+
before,
|
|
16153
|
+
after
|
|
16154
|
+
});
|
|
16155
|
+
}
|
|
16156
|
+
const hasExplicitThreadId = typeof explicitThreadId === "string" && explicitThreadId.length > 0;
|
|
16157
|
+
const hasCursor = typeof cursor === "string" && cursor.length > 0;
|
|
16158
|
+
if (!hasExplicitThreadId && !hasCursor) {
|
|
16159
|
+
throw new Error('Either cursor or threadId is required for mode="messages"');
|
|
16160
|
+
}
|
|
16161
|
+
let targetThreadId;
|
|
16162
|
+
let threadScope;
|
|
16163
|
+
if (!isResourceScope) {
|
|
16164
|
+
targetThreadId = currentThreadId;
|
|
16165
|
+
threadScope = currentThreadId || void 0;
|
|
16166
|
+
} else if (hasExplicitThreadId) {
|
|
16167
|
+
if (!resourceId) {
|
|
16168
|
+
throw new Error("Resource ID is required for recall");
|
|
16169
|
+
}
|
|
16170
|
+
if (!memory.getThreadById) {
|
|
16171
|
+
throw new Error("Memory instance cannot verify thread access for recall");
|
|
16172
|
+
}
|
|
16173
|
+
const thread = await memory.getThreadById({ threadId: explicitThreadId });
|
|
16174
|
+
if (!thread || thread.resourceId !== resourceId) {
|
|
16175
|
+
throw new Error("Thread does not belong to the active resource");
|
|
16176
|
+
}
|
|
16177
|
+
targetThreadId = thread.id;
|
|
16178
|
+
threadScope = thread.id;
|
|
16179
|
+
} else {
|
|
16180
|
+
targetThreadId = currentThreadId;
|
|
16181
|
+
threadScope = currentThreadId || void 0;
|
|
16182
|
+
}
|
|
16183
|
+
if (hasCursor && !hasExplicitThreadId && !currentThreadId) {
|
|
16184
|
+
throw new Error("Current thread is required when browsing by cursor");
|
|
16185
|
+
}
|
|
16186
|
+
if (!targetThreadId) {
|
|
15847
16187
|
throw new Error("Thread ID is required for recall");
|
|
15848
16188
|
}
|
|
16189
|
+
if (!cursor) {
|
|
16190
|
+
return recallThreadFromStart({
|
|
16191
|
+
memory,
|
|
16192
|
+
threadId: targetThreadId,
|
|
16193
|
+
resourceId: isResourceScope ? resourceId : void 0,
|
|
16194
|
+
page: page ?? 1,
|
|
16195
|
+
limit: limit ?? 20,
|
|
16196
|
+
detail: detail ?? "low"
|
|
16197
|
+
});
|
|
16198
|
+
}
|
|
15849
16199
|
if (partIndex !== void 0 && partIndex !== null) {
|
|
15850
16200
|
return recallPart({
|
|
15851
16201
|
memory,
|
|
15852
|
-
threadId,
|
|
16202
|
+
threadId: targetThreadId,
|
|
16203
|
+
resourceId: isResourceScope ? resourceId : void 0,
|
|
15853
16204
|
cursor,
|
|
15854
|
-
partIndex
|
|
16205
|
+
partIndex,
|
|
16206
|
+
threadScope
|
|
15855
16207
|
});
|
|
15856
16208
|
}
|
|
15857
16209
|
return recallMessages({
|
|
15858
16210
|
memory,
|
|
15859
|
-
threadId,
|
|
15860
|
-
resourceId,
|
|
16211
|
+
threadId: targetThreadId,
|
|
16212
|
+
resourceId: isResourceScope ? resourceId : void 0,
|
|
15861
16213
|
cursor,
|
|
15862
16214
|
page,
|
|
15863
16215
|
limit,
|
|
15864
|
-
detail: detail ?? "low"
|
|
16216
|
+
detail: detail ?? "low",
|
|
16217
|
+
threadScope
|
|
15865
16218
|
});
|
|
15866
16219
|
}
|
|
15867
16220
|
});
|
|
@@ -16113,6 +16466,19 @@ var Memory = class extends memory.MastraMemory {
|
|
|
16113
16466
|
observationalMemory: config.options?.observationalMemory
|
|
16114
16467
|
});
|
|
16115
16468
|
this.threadConfig = mergedConfig;
|
|
16469
|
+
const omConfig = normalizeObservationalMemoryConfig(mergedConfig.observationalMemory);
|
|
16470
|
+
if (omConfig?.retrieval && typeof omConfig.retrieval === "object" && omConfig.retrieval.vector) {
|
|
16471
|
+
if (!this.vector) {
|
|
16472
|
+
throw new Error(
|
|
16473
|
+
"`retrieval: { vector: true }` requires a vector store. Pass a `vector` option to your Memory instance."
|
|
16474
|
+
);
|
|
16475
|
+
}
|
|
16476
|
+
if (!this.embedder) {
|
|
16477
|
+
throw new Error(
|
|
16478
|
+
"`retrieval: { vector: true }` requires an embedder. Pass an `embedder` option to your Memory instance."
|
|
16479
|
+
);
|
|
16480
|
+
}
|
|
16481
|
+
}
|
|
16116
16482
|
}
|
|
16117
16483
|
/**
|
|
16118
16484
|
* Gets the memory storage domain, throwing if not available.
|
|
@@ -16882,13 +17248,17 @@ ${workingMemory}`;
|
|
|
16882
17248
|
"Observational memory requires @mastra/core support for request-response-id-rotation. Please bump @mastra/core to a newer version."
|
|
16883
17249
|
);
|
|
16884
17250
|
}
|
|
16885
|
-
const { ObservationalMemory: OMClass } = await import('./observational-memory-
|
|
17251
|
+
const { ObservationalMemory: OMClass } = await import('./observational-memory-FATH657E.cjs');
|
|
17252
|
+
const onIndexObservations = this.hasRetrievalSearch(omConfig.retrieval) ? async (observation) => {
|
|
17253
|
+
await this.indexObservation(observation);
|
|
17254
|
+
} : void 0;
|
|
16886
17255
|
return new OMClass({
|
|
16887
17256
|
storage: memoryStore,
|
|
16888
17257
|
scope: omConfig.scope,
|
|
16889
17258
|
retrieval: omConfig.retrieval,
|
|
16890
17259
|
shareTokenBudget: omConfig.shareTokenBudget,
|
|
16891
17260
|
model: omConfig.model,
|
|
17261
|
+
onIndexObservations,
|
|
16892
17262
|
observation: omConfig.observation ? {
|
|
16893
17263
|
model: omConfig.observation.model,
|
|
16894
17264
|
messageTokens: omConfig.observation.messageTokens,
|
|
@@ -17024,6 +17394,176 @@ Notes:
|
|
|
17024
17394
|
const isMDWorkingMemory = !(`schema` in config.workingMemory) && (typeof config.workingMemory.template === `string` || config.workingMemory.template) && config.workingMemory;
|
|
17025
17395
|
return Boolean(isMDWorkingMemory && isMDWorkingMemory.version === `vnext`);
|
|
17026
17396
|
}
|
|
17397
|
+
getObservationEmbeddingIndexName(dimensions) {
|
|
17398
|
+
const defaultDimensions = 384;
|
|
17399
|
+
const usedDimensions = dimensions ?? defaultDimensions;
|
|
17400
|
+
const separator = this.vector?.indexSeparator ?? "_";
|
|
17401
|
+
return `memory${separator}observations${separator}${usedDimensions}`;
|
|
17402
|
+
}
|
|
17403
|
+
async createObservationEmbeddingIndex(dimensions) {
|
|
17404
|
+
const defaultDimensions = 384;
|
|
17405
|
+
const usedDimensions = dimensions ?? defaultDimensions;
|
|
17406
|
+
const indexName = this.getObservationEmbeddingIndexName(dimensions);
|
|
17407
|
+
if (typeof this.vector === `undefined`) {
|
|
17408
|
+
throw new Error(
|
|
17409
|
+
`Tried to create observation embedding index but no vector db is attached to this Memory instance.`
|
|
17410
|
+
);
|
|
17411
|
+
}
|
|
17412
|
+
await this.vector.createIndex({
|
|
17413
|
+
indexName,
|
|
17414
|
+
dimension: usedDimensions
|
|
17415
|
+
});
|
|
17416
|
+
return { indexName };
|
|
17417
|
+
}
|
|
17418
|
+
/**
|
|
17419
|
+
* Search observation groups across threads by semantic similarity.
|
|
17420
|
+
* Requires a vector store and embedder to be configured.
|
|
17421
|
+
*/
|
|
17422
|
+
async searchMessages({
|
|
17423
|
+
query,
|
|
17424
|
+
resourceId,
|
|
17425
|
+
topK = 10,
|
|
17426
|
+
filter: filter3
|
|
17427
|
+
}) {
|
|
17428
|
+
if (!this.vector) {
|
|
17429
|
+
throw new Error("searchMessages requires a vector store. Configure vector and embedder on your Memory instance.");
|
|
17430
|
+
}
|
|
17431
|
+
const { embeddings, dimension } = await this.embedMessageContent(query);
|
|
17432
|
+
const { indexName } = await this.createObservationEmbeddingIndex(dimension);
|
|
17433
|
+
const vectorFilter = { resource_id: resourceId };
|
|
17434
|
+
if (filter3?.threadId) {
|
|
17435
|
+
vectorFilter.thread_id = filter3.threadId;
|
|
17436
|
+
}
|
|
17437
|
+
if (filter3?.observedAfter || filter3?.observedBefore) {
|
|
17438
|
+
vectorFilter.observed_at = {
|
|
17439
|
+
...filter3.observedAfter ? { $gt: filter3.observedAfter.toISOString() } : {},
|
|
17440
|
+
...filter3.observedBefore ? { $lt: filter3.observedBefore.toISOString() } : {}
|
|
17441
|
+
};
|
|
17442
|
+
}
|
|
17443
|
+
const queryResults = [];
|
|
17444
|
+
await Promise.all(
|
|
17445
|
+
embeddings.map(async (embedding) => {
|
|
17446
|
+
const results2 = await this.vector.query({
|
|
17447
|
+
indexName,
|
|
17448
|
+
queryVector: embedding,
|
|
17449
|
+
topK,
|
|
17450
|
+
filter: vectorFilter
|
|
17451
|
+
});
|
|
17452
|
+
for (const r of results2) {
|
|
17453
|
+
if (!r.metadata?.thread_id) {
|
|
17454
|
+
continue;
|
|
17455
|
+
}
|
|
17456
|
+
const groupId = typeof r.metadata.group_id === "string" ? r.metadata.group_id : void 0;
|
|
17457
|
+
if (!groupId) {
|
|
17458
|
+
continue;
|
|
17459
|
+
}
|
|
17460
|
+
queryResults.push({
|
|
17461
|
+
threadId: r.metadata.thread_id,
|
|
17462
|
+
score: r.score,
|
|
17463
|
+
groupId,
|
|
17464
|
+
range: typeof r.metadata.range === "string" ? r.metadata.range : void 0,
|
|
17465
|
+
text: typeof r.metadata.text === "string" ? r.metadata.text : void 0,
|
|
17466
|
+
observedAt: typeof r.metadata.observed_at === "string" || r.metadata.observed_at instanceof Date ? new Date(r.metadata.observed_at) : void 0
|
|
17467
|
+
});
|
|
17468
|
+
}
|
|
17469
|
+
})
|
|
17470
|
+
);
|
|
17471
|
+
const bestByGroup = /* @__PURE__ */ new Map();
|
|
17472
|
+
for (const result of queryResults) {
|
|
17473
|
+
if (!result.groupId) {
|
|
17474
|
+
continue;
|
|
17475
|
+
}
|
|
17476
|
+
const existing = bestByGroup.get(result.groupId);
|
|
17477
|
+
if (!existing || result.score > existing.score) {
|
|
17478
|
+
bestByGroup.set(result.groupId, result);
|
|
17479
|
+
}
|
|
17480
|
+
}
|
|
17481
|
+
const results = [...bestByGroup.values()].sort((a, b) => b.score - a.score);
|
|
17482
|
+
return { results };
|
|
17483
|
+
}
|
|
17484
|
+
/**
|
|
17485
|
+
* Index a single observation group into the observation vector store.
|
|
17486
|
+
*/
|
|
17487
|
+
async indexObservation({
|
|
17488
|
+
text: text4,
|
|
17489
|
+
groupId,
|
|
17490
|
+
range,
|
|
17491
|
+
threadId,
|
|
17492
|
+
resourceId,
|
|
17493
|
+
observedAt
|
|
17494
|
+
}) {
|
|
17495
|
+
if (!this.vector || !this.embedder) return;
|
|
17496
|
+
const embedResult = await this.embedMessageContent(text4);
|
|
17497
|
+
if (embedResult.embeddings.length === 0 || embedResult.dimension === void 0) {
|
|
17498
|
+
return;
|
|
17499
|
+
}
|
|
17500
|
+
const { indexName } = await this.createObservationEmbeddingIndex(embedResult.dimension);
|
|
17501
|
+
await this.vector.upsert({
|
|
17502
|
+
indexName,
|
|
17503
|
+
vectors: embedResult.embeddings,
|
|
17504
|
+
metadata: embedResult.chunks.map((chunk) => ({
|
|
17505
|
+
group_id: groupId,
|
|
17506
|
+
range,
|
|
17507
|
+
thread_id: threadId,
|
|
17508
|
+
resource_id: resourceId,
|
|
17509
|
+
observed_at: observedAt?.toISOString(),
|
|
17510
|
+
text: chunk
|
|
17511
|
+
}))
|
|
17512
|
+
});
|
|
17513
|
+
}
|
|
17514
|
+
/**
|
|
17515
|
+
* Index a list of messages directly (without querying storage).
|
|
17516
|
+
* Used by observe-time indexing to vectorize newly-observed messages.
|
|
17517
|
+
*/
|
|
17518
|
+
async indexMessagesList(messages) {
|
|
17519
|
+
if (!this.vector || !this.embedder) return;
|
|
17520
|
+
const embeddingData = [];
|
|
17521
|
+
let dimension;
|
|
17522
|
+
await Promise.all(
|
|
17523
|
+
messages.map(async (message) => {
|
|
17524
|
+
let textForEmbedding = null;
|
|
17525
|
+
if (message.content.content && typeof message.content.content === "string" && message.content.content.trim() !== "") {
|
|
17526
|
+
textForEmbedding = message.content.content;
|
|
17527
|
+
} else if (message.content.parts && message.content.parts.length > 0) {
|
|
17528
|
+
const joined = message.content.parts.filter((part) => part.type === "text").map((part) => part.text).join(" ").trim();
|
|
17529
|
+
if (joined) textForEmbedding = joined;
|
|
17530
|
+
}
|
|
17531
|
+
if (!textForEmbedding) return;
|
|
17532
|
+
const embedResult = await this.embedMessageContent(textForEmbedding);
|
|
17533
|
+
dimension = embedResult.dimension;
|
|
17534
|
+
embeddingData.push({
|
|
17535
|
+
embeddings: embedResult.embeddings,
|
|
17536
|
+
metadata: embedResult.chunks.map(() => ({
|
|
17537
|
+
message_id: message.id,
|
|
17538
|
+
thread_id: message.threadId,
|
|
17539
|
+
resource_id: message.resourceId
|
|
17540
|
+
}))
|
|
17541
|
+
});
|
|
17542
|
+
})
|
|
17543
|
+
);
|
|
17544
|
+
if (embeddingData.length > 0 && dimension !== void 0) {
|
|
17545
|
+
const { indexName } = await this.createEmbeddingIndex(dimension);
|
|
17546
|
+
const allVectors = [];
|
|
17547
|
+
const allMetadata = [];
|
|
17548
|
+
for (const data of embeddingData) {
|
|
17549
|
+
allVectors.push(...data.embeddings);
|
|
17550
|
+
allMetadata.push(...data.metadata);
|
|
17551
|
+
}
|
|
17552
|
+
await this.vector.upsert({
|
|
17553
|
+
indexName,
|
|
17554
|
+
vectors: allVectors,
|
|
17555
|
+
metadata: allMetadata
|
|
17556
|
+
});
|
|
17557
|
+
}
|
|
17558
|
+
}
|
|
17559
|
+
/**
|
|
17560
|
+
* Check whether retrieval search (vector-based) is enabled.
|
|
17561
|
+
* Returns true when `retrieval: { vector: true }` and Memory has vector + embedder configured.
|
|
17562
|
+
*/
|
|
17563
|
+
hasRetrievalSearch(retrieval) {
|
|
17564
|
+
if (!retrieval || retrieval === true) return false;
|
|
17565
|
+
return !!retrieval.vector && !!this.vector && !!this.embedder;
|
|
17566
|
+
}
|
|
17027
17567
|
listTools(config) {
|
|
17028
17568
|
const mergedConfig = this.getMergedThreadConfig(config);
|
|
17029
17569
|
const tools = {};
|
|
@@ -17031,8 +17571,9 @@ Notes:
|
|
|
17031
17571
|
tools.updateWorkingMemory = this.isVNextWorkingMemoryConfig(mergedConfig) ? __experimental_updateWorkingMemoryToolVNext(mergedConfig) : updateWorkingMemoryTool(mergedConfig);
|
|
17032
17572
|
}
|
|
17033
17573
|
const omConfig = normalizeObservationalMemoryConfig(mergedConfig.observationalMemory);
|
|
17034
|
-
if (omConfig?.retrieval
|
|
17035
|
-
|
|
17574
|
+
if (omConfig?.retrieval) {
|
|
17575
|
+
const retrievalScope = typeof omConfig.retrieval === "object" ? omConfig.retrieval.scope ?? "resource" : "resource";
|
|
17576
|
+
tools.recall = recallTool(mergedConfig, { retrievalScope });
|
|
17036
17577
|
}
|
|
17037
17578
|
return tools;
|
|
17038
17579
|
}
|
|
@@ -17595,18 +18136,18 @@ Notes:
|
|
|
17595
18136
|
if (!effectiveConfig) return null;
|
|
17596
18137
|
const engine = await this.omEngine;
|
|
17597
18138
|
if (!engine) return null;
|
|
17598
|
-
const { ObservationalMemoryProcessor } = await import('./observational-memory-
|
|
18139
|
+
const { ObservationalMemoryProcessor } = await import('./observational-memory-FATH657E.cjs');
|
|
17599
18140
|
return new ObservationalMemoryProcessor(engine, this);
|
|
17600
18141
|
}
|
|
17601
18142
|
};
|
|
17602
18143
|
|
|
17603
18144
|
Object.defineProperty(exports, "ModelByInputTokens", {
|
|
17604
18145
|
enumerable: true,
|
|
17605
|
-
get: function () { return
|
|
18146
|
+
get: function () { return chunkVINRPDYQ_cjs.ModelByInputTokens; }
|
|
17606
18147
|
});
|
|
17607
18148
|
Object.defineProperty(exports, "getObservationsAsOf", {
|
|
17608
18149
|
enumerable: true,
|
|
17609
|
-
get: function () { return
|
|
18150
|
+
get: function () { return chunkVINRPDYQ_cjs.getObservationsAsOf; }
|
|
17610
18151
|
});
|
|
17611
18152
|
Object.defineProperty(exports, "extractWorkingMemoryContent", {
|
|
17612
18153
|
enumerable: true,
|