






















@@ -46,6 +46,7 @@ const DEFAULT_PARTIAL_TRANSCRIPT_MAX_CHARS = 32_000;
4646const DEFAULT_TRANSCRIPT_READ_MAX_LINES = 2_000;
4747const DEFAULT_TRANSCRIPT_READ_MAX_BYTES = 50 * 1024 * 1024;
4848const TIMEOUT_PARTIAL_DATA_GRACE_MS = 50;
49+const MAX_ACTIVE_MEMORY_SEARCH_QUERY_CHARS = 480;
4950const TERMINAL_MEMORY_SEARCH_POLL_INTERVAL_MS = 25;
50515152const NO_RECALL_VALUES = new Set([
@@ -940,13 +941,16 @@ function buildPromptStyleLines(style: ActiveMemoryPromptStyle): string[] {
940941function buildRecallPrompt(params: {
941942config: ResolvedActiveRecallPluginConfig;
942943query: string;
944+searchQuery: string;
943945}): string {
944946const defaultInstructions = [
945947"You are a memory search agent.",
946948"Another model is preparing the final user-facing answer.",
947949"Your job is to search memory and return only the most relevant memory context for that model.",
948-"You receive conversation context, including the user's latest message.",
950+"You receive a bounded search query plus conversation context, including the user's latest message.",
949951"Use only the available memory tools.",
952+"Use the bounded search query as the memory_search or memory_recall query.",
953+"Do not use channel metadata, provider metadata, debug output, or the full conversation context as the memory tool query.",
950954"Prefer memory_recall when available.",
951955"If memory_recall is unavailable, use memory_search and memory_get.",
952956"When searching for preference or habit recall, use a permissive recall limit or memory_search threshold before deciding that no useful memory exists.",
@@ -998,7 +1002,11 @@ function buildRecallPrompt(params: {
9981002]
9991003.filter((section) => section.length > 0)
10001004.join("\n\n");
1001-return `${instructionBlock}\n\nConversation context:\n${params.query}`;
1005+return [
1006+instructionBlock,
1007+`Bounded memory search query:\n${params.searchQuery}`,
1008+`Conversation context:\n${params.query}`,
1009+].join("\n\n");
10021010}
1003101110041012function isEnabledForAgent(
@@ -2056,6 +2064,83 @@ function buildQuery(params: {
20562064].join("\n");
20572065}
205820662067+function stripExternalUntrustedBlocks(text: string): string {
2068+return text.replace(
2069+/<<<EXTERNAL_UNTRUSTED_CONTENT\b[^>]*>>>[\s\S]*?<<<END_EXTERNAL_UNTRUSTED_CONTENT\b[^>]*>>>/g,
2070+" ",
2071+);
2072+}
2073+2074+function stripJsonFences(text: string): string {
2075+return text.replace(/```(?:json)?\s*[\s\S]*?```/gi, " ");
2076+}
2077+2078+function stripActiveMemoryXmlBlocks(text: string): string {
2079+return text.replace(/<active_memory_plugin>[\s\S]*?<\/active_memory_plugin>/gi, " ");
2080+}
2081+2082+function normalizeSearchQueryText(text: string): string {
2083+return text
2084+.split("\n")
2085+.map((line) => line.trim())
2086+.filter((line) => {
2087+if (!line) {
2088+return false;
2089+}
2090+if (/^(conversation info|sender|untrusted context)\b/i.test(line)) {
2091+return false;
2092+}
2093+if (/^(source: external|---|untrusted discord message body)$/i.test(line)) {
2094+return false;
2095+}
2096+if (/^⚠️?\s*Agent couldn't generate a response/i.test(line)) {
2097+return false;
2098+}
2099+if (/^Please try again\.?$/i.test(line)) {
2100+return false;
2101+}
2102+return true;
2103+})
2104+.join(" ")
2105+.replace(/\s+/g, " ")
2106+.trim();
2107+}
2108+2109+function clampSearchQuery(text: string): string {
2110+const normalized = text.replace(/\s+/g, " ").trim();
2111+return normalized.length > MAX_ACTIVE_MEMORY_SEARCH_QUERY_CHARS
2112+ ? normalized.slice(0, MAX_ACTIVE_MEMORY_SEARCH_QUERY_CHARS).trim()
2113+ : normalized;
2114+}
2115+2116+function buildSearchQuery(params: {
2117+latestUserMessage: string;
2118+recentTurns?: ActiveRecallRecentTurn[];
2119+}): string {
2120+const latest = clampSearchQuery(
2121+normalizeSearchQueryText(
2122+stripActiveMemoryXmlBlocks(
2123+stripJsonFences(stripExternalUntrustedBlocks(params.latestUserMessage)),
2124+),
2125+),
2126+);
2127+if (latest.length >= 12 || !params.recentTurns?.length) {
2128+return latest || clampSearchQuery(params.latestUserMessage);
2129+}
2130+const previousUser = [...params.recentTurns]
2131+.toReversed()
2132+.find((turn) => turn.role === "user" && turn.text.trim() !== params.latestUserMessage.trim());
2133+if (!previousUser) {
2134+return latest || clampSearchQuery(params.latestUserMessage);
2135+}
2136+const context = clampSearchQuery(
2137+normalizeSearchQueryText(stripRecalledContextNoise(previousUser.text)),
2138+)
2139+.slice(0, 120)
2140+.trim();
2141+return clampSearchQuery(context ? `${context} ${latest}` : latest);
2142+}
2143+20592144function extractTextContent(content: unknown): string {
20602145if (typeof content === "string") {
20612146return content;
@@ -2224,6 +2309,7 @@ async function runRecallSubagent(params: {
22242309messageProvider?: string;
22252310channelId?: string;
22262311query: string;
2312+searchQuery: string;
22272313currentModelProviderId?: string;
22282314currentModelId?: string;
22292315modelRef?: { provider: string; model: string };
@@ -2278,6 +2364,7 @@ async function runRecallSubagent(params: {
22782364const prompt = buildRecallPrompt({
22792365config: params.config,
22802366query: params.query,
2367+searchQuery: params.searchQuery,
22812368});
22822369const { messageChannel, messageProvider } = resolveRecallRunChannelContext({
22832370api: params.api,
@@ -2367,6 +2454,7 @@ async function maybeResolveActiveRecall(params: {
23672454messageProvider?: string;
23682455channelId?: string;
23692456query: string;
2457+searchQuery: string;
23702458currentModelProviderId?: string;
23712459currentModelId?: string;
23722460}): Promise<ActiveRecallResult> {
@@ -2444,7 +2532,9 @@ async function maybeResolveActiveRecall(params: {
2444253224452533if (params.config.logging) {
24462534params.api.logger.info?.(
2447-`${logPrefix} start timeoutMs=${String(params.config.timeoutMs)} queryChars=${String(params.query.length)}`,
2535+`${logPrefix} start timeoutMs=${String(params.config.timeoutMs)} queryChars=${String(
2536+ params.query.length,
2537+ )} searchQueryChars=${String(params.searchQuery.length)}`,
24482538);
24492539}
24502540@@ -2813,11 +2903,16 @@ export default definePluginEntry({
28132903});
28142904return undefined;
28152905}
2906+const recentTurns = extractRecentTurns(event.messages);
28162907const query = buildQuery({
28172908latestUserMessage: event.prompt,
2818-recentTurns: extractRecentTurns(event.messages),
2909+ recentTurns,
28192910 config,
28202911});
2912+const searchQuery = buildSearchQuery({
2913+latestUserMessage: event.prompt,
2914+ recentTurns,
2915+});
28212916const result = await maybeResolveActiveRecall({
28222917 api,
28232918 config,
@@ -2827,6 +2922,7 @@ export default definePluginEntry({
28272922messageProvider: ctx.messageProvider,
28282923channelId: ctx.channelId,
28292924 query,
2925+ searchQuery,
28302926currentModelProviderId: ctx.modelProviderId,
28312927currentModelId: ctx.modelId,
28322928});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。