mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-06-13 18:31:16 +08:00
refactor(runtime): extract final recall injection factory (Phase 4d)
This commit is contained in:
877
runtime/final-recall-injection.js
Normal file
877
runtime/final-recall-injection.js
Normal file
@@ -0,0 +1,877 @@
|
||||
export function createFinalRecallInjection(deps = {}) {
|
||||
const normalizeRecallInputText = (value = "") =>
|
||||
deps.normalizeRecallInputText?.(value) ?? String(value || "").trim();
|
||||
const getContext = (...args) => deps.getContext?.(...args);
|
||||
const getSettings = (...args) => deps.getSettings?.(...args);
|
||||
const getLastRecallSentUserMessage = () =>
|
||||
deps.getLastRecallSentUserMessage?.() || {};
|
||||
const getLastInjectionContent = () =>
|
||||
String(deps.getLastInjectionContent?.() || "");
|
||||
const setLastInjectionContent = (value = "") => {
|
||||
deps.setLastInjectionContent?.(String(value || ""));
|
||||
};
|
||||
const setRuntimeStatus = (value) => {
|
||||
deps.setRuntimeStatus?.(value);
|
||||
};
|
||||
|
||||
function persistRecallInjectionRecord({
|
||||
recallInput = {},
|
||||
result = {},
|
||||
injectionText = "",
|
||||
tokenEstimate = 0,
|
||||
} = {}) {
|
||||
const chat = getContext()?.chat;
|
||||
if (!Array.isArray(chat)) return null;
|
||||
|
||||
const generationType =
|
||||
String(recallInput?.generationType || "normal").trim() || "normal";
|
||||
const lastRecallSentUserMessage = getLastRecallSentUserMessage();
|
||||
let resolvedTargetIndex = deps.resolveRecallPersistenceTargetUserMessageIndex(
|
||||
chat,
|
||||
{
|
||||
generationType,
|
||||
explicitTargetUserMessageIndex: recallInput?.targetUserMessageIndex,
|
||||
candidateTexts: [
|
||||
recallInput?.userMessage,
|
||||
recallInput?.overrideUserMessage,
|
||||
lastRecallSentUserMessage?.text,
|
||||
],
|
||||
preferredRecord: lastRecallSentUserMessage,
|
||||
},
|
||||
);
|
||||
|
||||
if (!Number.isFinite(resolvedTargetIndex)) {
|
||||
deps.debugPersistedRecallPersistence?.("目标 user 楼层解析失败", {
|
||||
generationType,
|
||||
explicitTargetUserMessageIndex: recallInput?.targetUserMessageIndex,
|
||||
lastSentUserMessageId: lastRecallSentUserMessage?.messageId,
|
||||
recallInputSource: String(recallInput?.source || ""),
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!chat[resolvedTargetIndex]?.is_user) {
|
||||
deps.debugPersistedRecallPersistence?.("目标楼层不是 user 消息,跳过持久化", {
|
||||
targetUserMessageIndex: resolvedTargetIndex,
|
||||
messageKeys: Object.keys(chat[resolvedTargetIndex] || {}),
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
const targetUserFloorText = normalizeRecallInputText(
|
||||
chat[resolvedTargetIndex]?.mes || "",
|
||||
);
|
||||
const boundUserFloorText = normalizeRecallInputText(
|
||||
recallInput?.boundUserFloorText || targetUserFloorText,
|
||||
);
|
||||
const record = deps.buildPersistedRecallRecord(
|
||||
{
|
||||
injectionText,
|
||||
selectedNodeIds: result?.selectedNodeIds || [],
|
||||
recallInput: String(recallInput?.userMessage || ""),
|
||||
recallSource: String(recallInput?.source || ""),
|
||||
hookName: String(recallInput?.hookName || ""),
|
||||
tokenEstimate,
|
||||
manuallyEdited: false,
|
||||
authoritativeInputUsed: Boolean(recallInput?.authoritativeInputUsed),
|
||||
boundUserFloorText,
|
||||
},
|
||||
deps.readPersistedRecallFromUserMessage(chat, resolvedTargetIndex),
|
||||
);
|
||||
if (!String(record?.injectionText || "").trim()) {
|
||||
deps.debugPersistedRecallPersistence?.("无有效 injectionText,跳过持久化", {
|
||||
targetUserMessageIndex: resolvedTargetIndex,
|
||||
selectedNodeCount: Array.isArray(result?.selectedNodeIds)
|
||||
? result.selectedNodeIds.length
|
||||
: 0,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
if (!deps.writePersistedRecallToUserMessage(chat, resolvedTargetIndex, record)) {
|
||||
deps.debugPersistedRecallPersistence?.("写入 user 楼层失败", {
|
||||
targetUserMessageIndex: resolvedTargetIndex,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
deps.triggerChatMetadataSave(getContext(), { immediate: false });
|
||||
deps.schedulePersistedRecallMessageUiRefresh();
|
||||
deps.debugPersistedRecallPersistence?.(
|
||||
"召回记录已写入 user 楼层",
|
||||
{
|
||||
targetUserMessageIndex: resolvedTargetIndex,
|
||||
injectionTextLength: String(record?.injectionText || "").length,
|
||||
selectedNodeCount: Array.isArray(record?.selectedNodeIds)
|
||||
? record.selectedNodeIds.length
|
||||
: 0,
|
||||
},
|
||||
`persist-success:${resolvedTargetIndex}`,
|
||||
);
|
||||
return {
|
||||
index: resolvedTargetIndex,
|
||||
record,
|
||||
};
|
||||
}
|
||||
|
||||
function ensurePersistedRecallRecordForGeneration({
|
||||
generationType = "normal",
|
||||
recallResult = null,
|
||||
transaction = null,
|
||||
recallOptions = null,
|
||||
hookName = "",
|
||||
} = {}) {
|
||||
const injectionText = String(recallResult?.injectionText || "").trim();
|
||||
if (
|
||||
recallResult?.status !== "completed" ||
|
||||
!recallResult?.didRecall ||
|
||||
!injectionText
|
||||
) {
|
||||
return {
|
||||
persisted: false,
|
||||
reason: "no-fresh-recall",
|
||||
targetUserMessageIndex: null,
|
||||
record: null,
|
||||
};
|
||||
}
|
||||
|
||||
const chat = getContext()?.chat;
|
||||
if (!Array.isArray(chat) || chat.length === 0) {
|
||||
return {
|
||||
persisted: false,
|
||||
reason: "missing-chat",
|
||||
targetUserMessageIndex: null,
|
||||
record: null,
|
||||
};
|
||||
}
|
||||
|
||||
const frozenRecallOptions =
|
||||
transaction?.frozenRecallOptions &&
|
||||
typeof transaction.frozenRecallOptions === "object"
|
||||
? transaction.frozenRecallOptions
|
||||
: null;
|
||||
const lastRecallSentUserMessage = getLastRecallSentUserMessage();
|
||||
const targetUserMessageIndex = deps.resolveRecallPersistenceTargetUserMessageIndex(
|
||||
chat,
|
||||
{
|
||||
generationType,
|
||||
explicitTargetUserMessageIndex:
|
||||
frozenRecallOptions?.targetUserMessageIndex ??
|
||||
recallOptions?.targetUserMessageIndex ??
|
||||
recallOptions?.explicitTargetUserMessageIndex ??
|
||||
null,
|
||||
candidateTexts: [
|
||||
frozenRecallOptions?.overrideUserMessage,
|
||||
frozenRecallOptions?.userMessage,
|
||||
recallOptions?.overrideUserMessage,
|
||||
recallOptions?.userMessage,
|
||||
recallResult?.recallInput,
|
||||
recallResult?.userMessage,
|
||||
...(Array.isArray(recallResult?.sourceCandidates)
|
||||
? recallResult.sourceCandidates.map((candidate) => candidate?.text)
|
||||
: []),
|
||||
lastRecallSentUserMessage?.text,
|
||||
],
|
||||
preferredRecord: lastRecallSentUserMessage,
|
||||
},
|
||||
);
|
||||
|
||||
if (
|
||||
!Number.isFinite(targetUserMessageIndex) ||
|
||||
!chat[targetUserMessageIndex]?.is_user
|
||||
) {
|
||||
return {
|
||||
persisted: false,
|
||||
reason: "target-unresolved",
|
||||
targetUserMessageIndex: Number.isFinite(targetUserMessageIndex)
|
||||
? targetUserMessageIndex
|
||||
: null,
|
||||
record: null,
|
||||
};
|
||||
}
|
||||
|
||||
const selectedNodeIds = deps.normalizeRecallNodeIdList(
|
||||
recallResult?.selectedNodeIds || [],
|
||||
);
|
||||
const existingRecord = deps.readPersistedRecallFromUserMessage(
|
||||
chat,
|
||||
targetUserMessageIndex,
|
||||
);
|
||||
const nextAuthoritativeInputUsed = Boolean(
|
||||
recallResult?.authoritativeInputUsed ??
|
||||
frozenRecallOptions?.authoritativeInputUsed ??
|
||||
recallOptions?.authoritativeInputUsed,
|
||||
);
|
||||
const targetUserFloorText = normalizeRecallInputText(
|
||||
chat[targetUserMessageIndex]?.mes || "",
|
||||
);
|
||||
const nextBoundUserFloorText = normalizeRecallInputText(
|
||||
recallResult?.boundUserFloorText ||
|
||||
frozenRecallOptions?.boundUserFloorText ||
|
||||
recallOptions?.boundUserFloorText ||
|
||||
targetUserFloorText ||
|
||||
"",
|
||||
);
|
||||
const existingBoundUserFloorText = normalizeRecallInputText(
|
||||
existingRecord?.boundUserFloorText || "",
|
||||
);
|
||||
const existingMetadataUpToDate =
|
||||
Boolean(existingRecord?.authoritativeInputUsed) === nextAuthoritativeInputUsed &&
|
||||
(!nextBoundUserFloorText ||
|
||||
existingBoundUserFloorText === nextBoundUserFloorText);
|
||||
if (
|
||||
existingRecord &&
|
||||
String(existingRecord.injectionText || "").trim() === injectionText &&
|
||||
deps.areRecallNodeIdListsEqual(existingRecord.selectedNodeIds, selectedNodeIds) &&
|
||||
String(existingRecord.recallInput || "").trim() &&
|
||||
existingMetadataUpToDate
|
||||
) {
|
||||
return {
|
||||
persisted: false,
|
||||
reason: "already-up-to-date",
|
||||
targetUserMessageIndex,
|
||||
record: existingRecord,
|
||||
};
|
||||
}
|
||||
|
||||
const nextRecord = deps.buildPersistedRecallRecord(
|
||||
{
|
||||
injectionText,
|
||||
selectedNodeIds,
|
||||
recallInput: String(
|
||||
recallResult?.recallInput ||
|
||||
recallResult?.userMessage ||
|
||||
frozenRecallOptions?.overrideUserMessage ||
|
||||
recallOptions?.overrideUserMessage ||
|
||||
recallOptions?.userMessage ||
|
||||
"",
|
||||
),
|
||||
recallSource: String(
|
||||
recallResult?.source ||
|
||||
frozenRecallOptions?.lockedSource ||
|
||||
frozenRecallOptions?.overrideSource ||
|
||||
recallOptions?.overrideSource ||
|
||||
"",
|
||||
),
|
||||
hookName: String(
|
||||
hookName ||
|
||||
recallResult?.hookName ||
|
||||
frozenRecallOptions?.hookName ||
|
||||
recallOptions?.hookName ||
|
||||
"",
|
||||
),
|
||||
tokenEstimate: deps.estimateTokens(injectionText),
|
||||
manuallyEdited: false,
|
||||
authoritativeInputUsed: nextAuthoritativeInputUsed,
|
||||
boundUserFloorText: nextBoundUserFloorText,
|
||||
},
|
||||
existingRecord,
|
||||
);
|
||||
|
||||
if (!deps.writePersistedRecallToUserMessage(chat, targetUserMessageIndex, nextRecord)) {
|
||||
return {
|
||||
persisted: false,
|
||||
reason: "write-failed",
|
||||
targetUserMessageIndex,
|
||||
record: null,
|
||||
};
|
||||
}
|
||||
|
||||
deps.triggerChatMetadataSave(getContext(), { immediate: false });
|
||||
deps.schedulePersistedRecallMessageUiRefresh();
|
||||
deps.debugPersistedRecallPersistence?.(
|
||||
"最终阶段已补写召回记录",
|
||||
{
|
||||
targetUserMessageIndex,
|
||||
hookName:
|
||||
String(
|
||||
hookName ||
|
||||
recallResult?.hookName ||
|
||||
frozenRecallOptions?.hookName ||
|
||||
recallOptions?.hookName ||
|
||||
"",
|
||||
) || "",
|
||||
injectionTextLength: injectionText.length,
|
||||
selectedNodeCount: selectedNodeIds.length,
|
||||
},
|
||||
`finalize-persist:${targetUserMessageIndex}`,
|
||||
);
|
||||
|
||||
return {
|
||||
persisted: true,
|
||||
reason: "backfilled",
|
||||
targetUserMessageIndex,
|
||||
record: nextRecord,
|
||||
};
|
||||
}
|
||||
|
||||
function rewriteRecallPayloadWithInjection(
|
||||
promptData = null,
|
||||
injectionText = "",
|
||||
) {
|
||||
const normalizedInjectionText = normalizeRecallInputText(injectionText);
|
||||
if (!normalizedInjectionText) {
|
||||
return {
|
||||
applied: false,
|
||||
path: "",
|
||||
field: "",
|
||||
reason: "empty-injection-text",
|
||||
};
|
||||
}
|
||||
|
||||
const finalMesSend = Array.isArray(promptData?.finalMesSend)
|
||||
? promptData.finalMesSend
|
||||
: null;
|
||||
if (Array.isArray(finalMesSend) && finalMesSend.length > 0) {
|
||||
for (let index = finalMesSend.length - 1; index >= 0; index--) {
|
||||
const entry = finalMesSend[index];
|
||||
if (!entry || typeof entry !== "object") continue;
|
||||
if (entry.injected === true) continue;
|
||||
const messageText = normalizeRecallInputText(
|
||||
entry.message || entry.mes || entry.content || "",
|
||||
);
|
||||
if (!messageText) continue;
|
||||
|
||||
entry.extensionPrompts = Array.isArray(entry.extensionPrompts)
|
||||
? entry.extensionPrompts
|
||||
: [];
|
||||
const alreadyPresent = entry.extensionPrompts.some((chunk) =>
|
||||
String(chunk || "").includes(normalizedInjectionText),
|
||||
);
|
||||
if (!alreadyPresent) {
|
||||
entry.extensionPrompts.push(`${normalizedInjectionText}\n`);
|
||||
}
|
||||
return {
|
||||
applied: true,
|
||||
path: "finalMesSend",
|
||||
field: `finalMesSend[${index}].extensionPrompts`,
|
||||
reason: alreadyPresent
|
||||
? "rewrite-already-present"
|
||||
: "finalMesSend-extensionPrompt-appended",
|
||||
targetIndex: index,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
applied: false,
|
||||
path: "finalMesSend",
|
||||
field: "",
|
||||
reason: "no-rewritable-finalMesSend-entry",
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
typeof promptData?.combinedPrompt === "string" &&
|
||||
promptData.combinedPrompt.trim()
|
||||
) {
|
||||
if (!promptData.combinedPrompt.includes(normalizedInjectionText)) {
|
||||
promptData.combinedPrompt = `${normalizedInjectionText}\n\n${promptData.combinedPrompt}`;
|
||||
}
|
||||
return {
|
||||
applied: true,
|
||||
path: "combinedPrompt",
|
||||
field: "combinedPrompt",
|
||||
reason: "combinedPrompt-prefixed",
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof promptData?.prompt === "string" && promptData.prompt.trim()) {
|
||||
if (!promptData.prompt.includes(normalizedInjectionText)) {
|
||||
promptData.prompt = `${normalizedInjectionText}\n\n${promptData.prompt}`;
|
||||
}
|
||||
return {
|
||||
applied: true,
|
||||
path: "prompt",
|
||||
field: "prompt",
|
||||
reason: "prompt-prefixed",
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
applied: false,
|
||||
path: "",
|
||||
field: "",
|
||||
reason: "prompt-payload-unavailable",
|
||||
};
|
||||
}
|
||||
|
||||
function rewriteRecallPayloadWithAuthoritativeUserInput(
|
||||
promptData = null,
|
||||
authoritativeText = "",
|
||||
boundUserFloorText = "",
|
||||
) {
|
||||
const normalizedAuthoritativeText = normalizeRecallInputText(authoritativeText);
|
||||
const normalizedBoundUserFloorText = normalizeRecallInputText(boundUserFloorText);
|
||||
if (!normalizedAuthoritativeText) {
|
||||
return {
|
||||
applied: false,
|
||||
changed: false,
|
||||
path: "",
|
||||
field: "",
|
||||
reason: "empty-authoritative-text",
|
||||
};
|
||||
}
|
||||
|
||||
const finalMesSend = Array.isArray(promptData?.finalMesSend)
|
||||
? promptData.finalMesSend
|
||||
: null;
|
||||
if (!Array.isArray(finalMesSend) || finalMesSend.length <= 0) {
|
||||
return {
|
||||
applied: false,
|
||||
changed: false,
|
||||
path: "",
|
||||
field: "",
|
||||
reason: "finalMesSend-unavailable",
|
||||
};
|
||||
}
|
||||
|
||||
let fallbackIndex = -1;
|
||||
let matchedIndex = -1;
|
||||
for (let index = finalMesSend.length - 1; index >= 0; index--) {
|
||||
const entry = finalMesSend[index];
|
||||
if (!entry || typeof entry !== "object") continue;
|
||||
if (entry.injected === true) continue;
|
||||
|
||||
const messageText = normalizeRecallInputText(
|
||||
entry.message || entry.mes || entry.content || "",
|
||||
);
|
||||
if (!messageText) continue;
|
||||
|
||||
if (fallbackIndex < 0) {
|
||||
fallbackIndex = index;
|
||||
}
|
||||
|
||||
if (
|
||||
messageText === normalizedAuthoritativeText ||
|
||||
(normalizedBoundUserFloorText &&
|
||||
messageText === normalizedBoundUserFloorText)
|
||||
) {
|
||||
matchedIndex = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const targetIndex =
|
||||
matchedIndex >= 0
|
||||
? matchedIndex
|
||||
: normalizedBoundUserFloorText
|
||||
? -1
|
||||
: fallbackIndex;
|
||||
if (targetIndex < 0) {
|
||||
return {
|
||||
applied: false,
|
||||
changed: false,
|
||||
path: "finalMesSend",
|
||||
field: "",
|
||||
reason: normalizedBoundUserFloorText
|
||||
? "bound-user-floor-text-not-found"
|
||||
: "no-rewritable-finalMesSend-entry",
|
||||
};
|
||||
}
|
||||
|
||||
const entry = finalMesSend[targetIndex];
|
||||
const fieldName = Object.prototype.hasOwnProperty.call(entry, "message")
|
||||
? "message"
|
||||
: Object.prototype.hasOwnProperty.call(entry, "mes")
|
||||
? "mes"
|
||||
: Object.prototype.hasOwnProperty.call(entry, "content")
|
||||
? "content"
|
||||
: "message";
|
||||
const previousText = normalizeRecallInputText(
|
||||
entry?.[fieldName] || entry?.message || entry?.mes || entry?.content || "",
|
||||
);
|
||||
const changed = previousText !== normalizedAuthoritativeText;
|
||||
if (changed) {
|
||||
entry[fieldName] = normalizedAuthoritativeText;
|
||||
}
|
||||
|
||||
return {
|
||||
applied: true,
|
||||
changed,
|
||||
path: "finalMesSend",
|
||||
field: `finalMesSend[${targetIndex}].${fieldName}`,
|
||||
reason: changed
|
||||
? "finalMesSend-authoritative-user-rewritten"
|
||||
: "authoritative-user-already-matched",
|
||||
targetIndex,
|
||||
};
|
||||
}
|
||||
|
||||
function applyFinalRecallInjectionForGeneration({
|
||||
generationType = "normal",
|
||||
freshRecallResult = null,
|
||||
transaction = null,
|
||||
promptData = null,
|
||||
hookName = "",
|
||||
} = {}) {
|
||||
const existingFinalResolution =
|
||||
deps.readGenerationRecallTransactionFinalResolution(transaction);
|
||||
if (existingFinalResolution) {
|
||||
if (
|
||||
promptData &&
|
||||
transaction?.frozenRecallOptions?.authoritativeInputUsed === true
|
||||
) {
|
||||
const recallResult =
|
||||
freshRecallResult ||
|
||||
deps.getGenerationRecallTransactionResult(transaction) ||
|
||||
null;
|
||||
const inputRewrite = rewriteRecallPayloadWithAuthoritativeUserInput(
|
||||
promptData,
|
||||
transaction?.frozenRecallOptions?.overrideUserMessage || "",
|
||||
transaction?.frozenRecallOptions?.boundUserFloorText || "",
|
||||
);
|
||||
const rewrite = rewriteRecallPayloadWithInjection(
|
||||
promptData,
|
||||
existingFinalResolution.usedText || recallResult?.injectionText || "",
|
||||
);
|
||||
const nextFinalResolution = {
|
||||
...existingFinalResolution,
|
||||
deliveryMode: "deferred",
|
||||
applicationMode:
|
||||
rewrite.applied || inputRewrite.applied
|
||||
? "rewrite"
|
||||
: existingFinalResolution.applicationMode,
|
||||
rewrite,
|
||||
inputRewrite,
|
||||
};
|
||||
deps.recordInjectionSnapshot("recall", {
|
||||
taskType: "recall",
|
||||
source:
|
||||
String(
|
||||
recallResult?.source ||
|
||||
transaction?.frozenRecallOptions?.lockedSource ||
|
||||
transaction?.frozenRecallOptions?.overrideSource ||
|
||||
"",
|
||||
).trim() || "unknown",
|
||||
sourceLabel:
|
||||
String(
|
||||
recallResult?.sourceLabel ||
|
||||
transaction?.frozenRecallOptions?.lockedSourceLabel ||
|
||||
transaction?.frozenRecallOptions?.overrideSourceLabel ||
|
||||
"",
|
||||
).trim() || "未知",
|
||||
reason:
|
||||
String(
|
||||
recallResult?.reason ||
|
||||
transaction?.frozenRecallOptions?.lockedReason ||
|
||||
transaction?.frozenRecallOptions?.overrideReason ||
|
||||
"",
|
||||
).trim() || "final-application-reused",
|
||||
sourceCandidates: Array.isArray(recallResult?.sourceCandidates)
|
||||
? recallResult.sourceCandidates.map((candidate) => ({ ...candidate }))
|
||||
: Array.isArray(transaction?.frozenRecallOptions?.sourceCandidates)
|
||||
? transaction.frozenRecallOptions.sourceCandidates.map((candidate) => ({
|
||||
...candidate,
|
||||
}))
|
||||
: [],
|
||||
hookName: String(hookName || recallResult?.hookName || "").trim(),
|
||||
selectedNodeIds: recallResult?.selectedNodeIds || [],
|
||||
retrievalMeta: recallResult?.retrievalMeta || {},
|
||||
llmMeta: recallResult?.llmMeta || {},
|
||||
stats: recallResult?.stats || {},
|
||||
injectionText: nextFinalResolution.usedText || "",
|
||||
deliveryMode: nextFinalResolution.deliveryMode || "",
|
||||
applicationMode: nextFinalResolution.applicationMode || "none",
|
||||
transport: nextFinalResolution.transport || {
|
||||
applied: false,
|
||||
source: "none",
|
||||
mode: "none",
|
||||
},
|
||||
rewrite: nextFinalResolution.rewrite || {
|
||||
applied: false,
|
||||
path: "",
|
||||
field: "",
|
||||
reason: "final-resolution-reused",
|
||||
},
|
||||
inputRewrite,
|
||||
targetUserMessageIndex: nextFinalResolution.targetUserMessageIndex,
|
||||
sourceKind: nextFinalResolution.source || "none",
|
||||
authoritativeInputUsed: true,
|
||||
boundUserFloorText: String(
|
||||
transaction?.frozenRecallOptions?.boundUserFloorText || "",
|
||||
),
|
||||
});
|
||||
deps.storeGenerationRecallTransactionFinalResolution(
|
||||
transaction,
|
||||
nextFinalResolution,
|
||||
);
|
||||
deps.refreshPanelLiveState();
|
||||
deps.schedulePersistedRecallMessageUiRefresh();
|
||||
return nextFinalResolution;
|
||||
}
|
||||
return existingFinalResolution;
|
||||
}
|
||||
|
||||
const recallResult =
|
||||
freshRecallResult ||
|
||||
deps.getGenerationRecallTransactionResult(transaction) ||
|
||||
null;
|
||||
const hookResolvedDeliveryMode =
|
||||
String(
|
||||
deps.resolveGenerationRecallDeliveryMode(
|
||||
hookName,
|
||||
generationType,
|
||||
transaction?.frozenRecallOptions || {},
|
||||
),
|
||||
).trim() || "immediate";
|
||||
const deliveryMode =
|
||||
String(
|
||||
promptData && hookName === "GENERATE_BEFORE_COMBINE_PROMPTS"
|
||||
? hookResolvedDeliveryMode
|
||||
: recallResult?.deliveryMode ||
|
||||
transaction?.lastDeliveryMode ||
|
||||
hookResolvedDeliveryMode,
|
||||
).trim() || "immediate";
|
||||
const chat = getContext()?.chat;
|
||||
|
||||
let transport = {
|
||||
applied: false,
|
||||
source: "none",
|
||||
mode: "none",
|
||||
};
|
||||
let targetUserMessageIndex = null;
|
||||
let resolved = {
|
||||
source: "none",
|
||||
injectionText: "",
|
||||
record: null,
|
||||
};
|
||||
const authoritativeInputRewrite =
|
||||
deliveryMode === "deferred" &&
|
||||
transaction?.frozenRecallOptions?.authoritativeInputUsed === true
|
||||
? rewriteRecallPayloadWithAuthoritativeUserInput(
|
||||
promptData,
|
||||
transaction?.frozenRecallOptions?.overrideUserMessage || "",
|
||||
transaction?.frozenRecallOptions?.boundUserFloorText || "",
|
||||
)
|
||||
: {
|
||||
applied: false,
|
||||
changed: false,
|
||||
path: "",
|
||||
field: "",
|
||||
reason:
|
||||
deliveryMode === "deferred"
|
||||
? "authoritative-input-unused"
|
||||
: "non-deferred-delivery",
|
||||
};
|
||||
const rewrite = {
|
||||
applied: false,
|
||||
path: "",
|
||||
field: "",
|
||||
reason: "no-recall-source",
|
||||
};
|
||||
let applicationMode = "none";
|
||||
|
||||
if (!Array.isArray(chat)) {
|
||||
transport = deps.applyModuleInjectionPrompt("", getSettings()) || transport;
|
||||
const emptyResolution = {
|
||||
source: "none",
|
||||
isFallback: false,
|
||||
targetUserMessageIndex: null,
|
||||
usedText: "",
|
||||
deliveryMode,
|
||||
applicationMode: "none",
|
||||
rewrite,
|
||||
transport,
|
||||
};
|
||||
deps.storeGenerationRecallTransactionFinalResolution(
|
||||
transaction,
|
||||
emptyResolution,
|
||||
);
|
||||
return emptyResolution;
|
||||
}
|
||||
|
||||
const ensuredPersistence = ensurePersistedRecallRecordForGeneration({
|
||||
generationType,
|
||||
recallResult,
|
||||
transaction,
|
||||
recallOptions: transaction?.frozenRecallOptions || null,
|
||||
hookName,
|
||||
});
|
||||
|
||||
const lastRecallSentUserMessage = getLastRecallSentUserMessage();
|
||||
targetUserMessageIndex = deps.resolveRecallPersistenceTargetUserMessageIndex(chat, {
|
||||
generationType,
|
||||
explicitTargetUserMessageIndex:
|
||||
transaction?.frozenRecallOptions?.targetUserMessageIndex,
|
||||
candidateTexts: [
|
||||
transaction?.frozenRecallOptions?.overrideUserMessage,
|
||||
recallResult?.recallInput,
|
||||
recallResult?.userMessage,
|
||||
recallResult?.sourceCandidates?.[0]?.text,
|
||||
lastRecallSentUserMessage?.text,
|
||||
],
|
||||
preferredRecord: lastRecallSentUserMessage,
|
||||
});
|
||||
if (Number.isFinite(ensuredPersistence?.targetUserMessageIndex)) {
|
||||
targetUserMessageIndex = ensuredPersistence.targetUserMessageIndex;
|
||||
}
|
||||
|
||||
const persistedRecord = Number.isFinite(targetUserMessageIndex)
|
||||
? deps.readPersistedRecallFromUserMessage(chat, targetUserMessageIndex)
|
||||
: null;
|
||||
resolved = deps.resolveFinalRecallInjectionSource({
|
||||
freshRecallResult: recallResult,
|
||||
persistedRecord,
|
||||
});
|
||||
|
||||
if (resolved.source === "fresh" && deliveryMode === "deferred") {
|
||||
const rewriteResult = rewriteRecallPayloadWithInjection(
|
||||
promptData,
|
||||
resolved.injectionText || "",
|
||||
);
|
||||
Object.assign(rewrite, rewriteResult);
|
||||
setLastInjectionContent(resolved.injectionText || "");
|
||||
if (rewriteResult.applied) {
|
||||
applicationMode = "rewrite";
|
||||
transport = deps.clearLiveRecallInjectionPromptForRewrite() || {
|
||||
applied: false,
|
||||
source: "rewrite-cleared",
|
||||
mode: "rewrite-cleared",
|
||||
};
|
||||
setRuntimeStatus(deps.createUiStatus(
|
||||
"召回已改写",
|
||||
`本轮发送载荷已 rewrite · ${rewriteResult.path || rewriteResult.field || "payload"}`,
|
||||
"success",
|
||||
));
|
||||
} else {
|
||||
applicationMode = "fallback-injection";
|
||||
transport =
|
||||
deps.applyModuleInjectionPrompt(
|
||||
resolved.injectionText || "",
|
||||
getSettings(),
|
||||
) || transport;
|
||||
setRuntimeStatus(deps.createUiStatus(
|
||||
"召回回退",
|
||||
`rewrite 未命中,已回退注入 · ${rewriteResult.reason}`,
|
||||
"warning",
|
||||
));
|
||||
}
|
||||
} else if (resolved.source === "fresh") {
|
||||
applicationMode = "injection";
|
||||
transport =
|
||||
deps.applyModuleInjectionPrompt(resolved.injectionText || "", getSettings()) ||
|
||||
transport;
|
||||
setLastInjectionContent(resolved.injectionText || "");
|
||||
rewrite.reason = "immediate-injection";
|
||||
setRuntimeStatus(deps.createUiStatus(
|
||||
"召回已注入",
|
||||
"本轮已使用最新召回结果",
|
||||
"success",
|
||||
));
|
||||
} else if (resolved.source === "persisted") {
|
||||
applicationMode = "persisted-injection";
|
||||
transport =
|
||||
deps.applyModuleInjectionPrompt(resolved.injectionText || "", getSettings()) ||
|
||||
transport;
|
||||
setLastInjectionContent(resolved.injectionText || "");
|
||||
rewrite.reason = "persisted-record-fallback";
|
||||
setRuntimeStatus(deps.createUiStatus(
|
||||
"召回回退",
|
||||
"已使用消息楼层持久化注入",
|
||||
"info",
|
||||
));
|
||||
} else {
|
||||
transport = deps.applyModuleInjectionPrompt("", getSettings()) || transport;
|
||||
setLastInjectionContent("");
|
||||
setRuntimeStatus(deps.createUiStatus("待命", "当前无有效注入内容", "idle"));
|
||||
}
|
||||
|
||||
if (
|
||||
resolved.source === "persisted" &&
|
||||
Number.isFinite(targetUserMessageIndex)
|
||||
) {
|
||||
deps.bumpPersistedRecallGenerationCount(chat, targetUserMessageIndex);
|
||||
deps.triggerChatMetadataSave(getContext(), { immediate: false });
|
||||
}
|
||||
|
||||
deps.recordInjectionSnapshot("recall", {
|
||||
taskType: "recall",
|
||||
source:
|
||||
String(
|
||||
recallResult?.source ||
|
||||
transaction?.frozenRecallOptions?.lockedSource ||
|
||||
transaction?.frozenRecallOptions?.overrideSource ||
|
||||
"",
|
||||
).trim() || "unknown",
|
||||
sourceLabel:
|
||||
String(
|
||||
recallResult?.sourceLabel ||
|
||||
transaction?.frozenRecallOptions?.lockedSourceLabel ||
|
||||
transaction?.frozenRecallOptions?.overrideSourceLabel ||
|
||||
"",
|
||||
).trim() || "未知",
|
||||
reason:
|
||||
String(
|
||||
recallResult?.reason ||
|
||||
transaction?.frozenRecallOptions?.lockedReason ||
|
||||
transaction?.frozenRecallOptions?.overrideReason ||
|
||||
"",
|
||||
).trim() || "final-application",
|
||||
sourceCandidates: Array.isArray(recallResult?.sourceCandidates)
|
||||
? recallResult.sourceCandidates.map((candidate) => ({ ...candidate }))
|
||||
: Array.isArray(transaction?.frozenRecallOptions?.sourceCandidates)
|
||||
? transaction.frozenRecallOptions.sourceCandidates.map((candidate) => ({
|
||||
...candidate,
|
||||
}))
|
||||
: [],
|
||||
hookName: String(hookName || recallResult?.hookName || "").trim(),
|
||||
selectedNodeIds: recallResult?.selectedNodeIds || [],
|
||||
retrievalMeta: recallResult?.retrievalMeta || {},
|
||||
llmMeta: recallResult?.llmMeta || {},
|
||||
stats: recallResult?.stats || {},
|
||||
injectionText: resolved.injectionText || "",
|
||||
deliveryMode,
|
||||
applicationMode,
|
||||
transport,
|
||||
rewrite,
|
||||
inputRewrite: authoritativeInputRewrite,
|
||||
targetUserMessageIndex,
|
||||
sourceKind: resolved.source,
|
||||
authoritativeInputUsed: Boolean(
|
||||
recallResult?.authoritativeInputUsed ??
|
||||
transaction?.frozenRecallOptions?.authoritativeInputUsed,
|
||||
),
|
||||
boundUserFloorText: String(
|
||||
recallResult?.boundUserFloorText ||
|
||||
transaction?.frozenRecallOptions?.boundUserFloorText ||
|
||||
"",
|
||||
),
|
||||
});
|
||||
|
||||
deps.refreshPanelLiveState();
|
||||
deps.schedulePersistedRecallMessageUiRefresh();
|
||||
|
||||
const finalResolution = {
|
||||
source: resolved.source,
|
||||
isFallback:
|
||||
resolved.source === "persisted" ||
|
||||
applicationMode === "fallback-injection",
|
||||
targetUserMessageIndex,
|
||||
usedText: resolved.injectionText || "",
|
||||
deliveryMode,
|
||||
applicationMode,
|
||||
rewrite,
|
||||
transport,
|
||||
inputRewrite: authoritativeInputRewrite,
|
||||
authoritativeInputUsed: Boolean(
|
||||
recallResult?.authoritativeInputUsed ??
|
||||
transaction?.frozenRecallOptions?.authoritativeInputUsed,
|
||||
),
|
||||
boundUserFloorText: String(
|
||||
recallResult?.boundUserFloorText ||
|
||||
transaction?.frozenRecallOptions?.boundUserFloorText ||
|
||||
"",
|
||||
),
|
||||
};
|
||||
deps.storeGenerationRecallTransactionFinalResolution(transaction, finalResolution);
|
||||
return finalResolution;
|
||||
}
|
||||
|
||||
return {
|
||||
persistRecallInjectionRecord,
|
||||
ensurePersistedRecallRecordForGeneration,
|
||||
rewriteRecallPayloadWithInjection,
|
||||
rewriteRecallPayloadWithAuthoritativeUserInput,
|
||||
applyFinalRecallInjectionForGeneration,
|
||||
getLastInjectionContent,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user