mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-05-15 22:30:38 +08:00
Fix processed history hash rebuild after recovery
This commit is contained in:
9
index.js
9
index.js
@@ -11609,6 +11609,14 @@ async function recoverHistoryIfNeeded(trigger = "history-recovery") {
|
|||||||
resultCode: "history.recovery.fallback-full-rebuild",
|
resultCode: "history.recovery.fallback-full-rebuild",
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
const recoveredLastProcessedFloor = Number.isFinite(
|
||||||
|
currentGraph?.historyState?.lastProcessedAssistantFloor,
|
||||||
|
)
|
||||||
|
? currentGraph.historyState.lastProcessedAssistantFloor
|
||||||
|
: -1;
|
||||||
|
if (recoveredLastProcessedFloor >= 0) {
|
||||||
|
updateProcessedHistorySnapshot(chat, recoveredLastProcessedFloor);
|
||||||
|
}
|
||||||
currentGraph.vectorIndexState.lastIntegrityIssue = null;
|
currentGraph.vectorIndexState.lastIntegrityIssue = null;
|
||||||
saveGraphToChat({ reason: "history-recovery-fallback-rebuild" });
|
saveGraphToChat({ reason: "history-recovery-fallback-rebuild" });
|
||||||
refreshPanelLiveState();
|
refreshPanelLiveState();
|
||||||
@@ -12390,6 +12398,7 @@ async function onRebuild() {
|
|||||||
replayExtractionFromHistory,
|
replayExtractionFromHistory,
|
||||||
restoreRuntimeUiState,
|
restoreRuntimeUiState,
|
||||||
saveGraphToChat,
|
saveGraphToChat,
|
||||||
|
updateProcessedHistorySnapshot,
|
||||||
setCurrentGraph: (graph) => {
|
setCurrentGraph: (graph) => {
|
||||||
currentGraph = graph;
|
currentGraph = graph;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -257,6 +257,17 @@ export function normalizeGraphRuntimeState(graph, chatId = "") {
|
|||||||
historyState.processedMessageHashVersion = PROCESSED_MESSAGE_HASH_VERSION;
|
historyState.processedMessageHashVersion = PROCESSED_MESSAGE_HASH_VERSION;
|
||||||
historyState.processedMessageHashesNeedRefresh = true;
|
historyState.processedMessageHashesNeedRefresh = true;
|
||||||
}
|
}
|
||||||
|
const lastProcessedAssistantFloor = Number(
|
||||||
|
historyState.lastProcessedAssistantFloor,
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
historyState.processedMessageHashesNeedRefresh !== true &&
|
||||||
|
Number.isFinite(lastProcessedAssistantFloor) &&
|
||||||
|
lastProcessedAssistantFloor >= 0 &&
|
||||||
|
Object.keys(historyState.processedMessageHashes).length === 0
|
||||||
|
) {
|
||||||
|
historyState.processedMessageHashesNeedRefresh = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!vectorIndexState.hashToNodeId ||
|
!vectorIndexState.hashToNodeId ||
|
||||||
@@ -613,10 +624,15 @@ export function clearHistoryDirty(graph, result = null) {
|
|||||||
graph.historyState.historyDirtyFrom = null;
|
graph.historyState.historyDirtyFrom = null;
|
||||||
graph.historyState.lastMutationReason = "";
|
graph.historyState.lastMutationReason = "";
|
||||||
graph.historyState.lastMutationSource = "";
|
graph.historyState.lastMutationSource = "";
|
||||||
|
const lastProcessedAssistantFloor = Number(
|
||||||
|
graph.historyState.lastProcessedAssistantFloor,
|
||||||
|
);
|
||||||
graph.historyState.processedMessageHashVersion =
|
graph.historyState.processedMessageHashVersion =
|
||||||
PROCESSED_MESSAGE_HASH_VERSION;
|
PROCESSED_MESSAGE_HASH_VERSION;
|
||||||
graph.historyState.processedMessageHashes = {};
|
graph.historyState.processedMessageHashes = {};
|
||||||
graph.historyState.processedMessageHashesNeedRefresh = false;
|
graph.historyState.processedMessageHashesNeedRefresh =
|
||||||
|
Number.isFinite(lastProcessedAssistantFloor) &&
|
||||||
|
lastProcessedAssistantFloor >= 0;
|
||||||
if (result) {
|
if (result) {
|
||||||
graph.historyState.lastRecoveryResult = result;
|
graph.historyState.lastRecoveryResult = result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -456,10 +456,17 @@ async function testManualExtractIgnoresFailedBatchWithoutPersistenceAttempt() {
|
|||||||
|
|
||||||
async function testManualRebuildSetsTerminalRuntimeStatus() {
|
async function testManualRebuildSetsTerminalRuntimeStatus() {
|
||||||
const chat = [{ is_user: true, mes: "u" }, { is_user: false, mes: "a" }];
|
const chat = [{ is_user: true, mes: "u" }, { is_user: false, mes: "a" }];
|
||||||
|
let savedHashes = null;
|
||||||
|
let savedNeedRefresh = null;
|
||||||
const context = {
|
const context = {
|
||||||
...createBaseStatusContext(),
|
...createBaseStatusContext(),
|
||||||
__confirmHost: true,
|
__confirmHost: true,
|
||||||
currentGraph: {
|
currentGraph: {
|
||||||
|
historyState: {
|
||||||
|
lastProcessedAssistantFloor: -1,
|
||||||
|
processedMessageHashes: {},
|
||||||
|
processedMessageHashesNeedRefresh: false,
|
||||||
|
},
|
||||||
vectorIndexState: {
|
vectorIndexState: {
|
||||||
lastWarning: "",
|
lastWarning: "",
|
||||||
},
|
},
|
||||||
@@ -489,6 +496,11 @@ async function testManualRebuildSetsTerminalRuntimeStatus() {
|
|||||||
},
|
},
|
||||||
createEmptyGraph() {
|
createEmptyGraph() {
|
||||||
return {
|
return {
|
||||||
|
historyState: {
|
||||||
|
lastProcessedAssistantFloor: -1,
|
||||||
|
processedMessageHashes: {},
|
||||||
|
processedMessageHashesNeedRefresh: false,
|
||||||
|
},
|
||||||
vectorIndexState: {
|
vectorIndexState: {
|
||||||
lastWarning: "",
|
lastWarning: "",
|
||||||
},
|
},
|
||||||
@@ -501,14 +513,31 @@ async function testManualRebuildSetsTerminalRuntimeStatus() {
|
|||||||
clearInjectionState() {},
|
clearInjectionState() {},
|
||||||
async prepareVectorStateForReplay() {},
|
async prepareVectorStateForReplay() {},
|
||||||
async replayExtractionFromHistory() {
|
async replayExtractionFromHistory() {
|
||||||
|
context.currentGraph.historyState.lastProcessedAssistantFloor = 1;
|
||||||
context.currentGraph.vectorIndexState.lastWarning = "";
|
context.currentGraph.vectorIndexState.lastWarning = "";
|
||||||
return 2;
|
return 2;
|
||||||
},
|
},
|
||||||
clearHistoryDirty() {},
|
clearHistoryDirty(graph) {
|
||||||
|
graph.historyState.processedMessageHashes = {};
|
||||||
|
graph.historyState.processedMessageHashesNeedRefresh = true;
|
||||||
|
},
|
||||||
buildRecoveryResult(status, extra = {}) {
|
buildRecoveryResult(status, extra = {}) {
|
||||||
return { status, ...extra };
|
return { status, ...extra };
|
||||||
},
|
},
|
||||||
saveGraphToChat() {},
|
updateProcessedHistorySnapshot(chatInput, floor) {
|
||||||
|
context.currentGraph.historyState.lastProcessedAssistantFloor = floor;
|
||||||
|
context.currentGraph.historyState.processedMessageHashes = {};
|
||||||
|
for (let index = 0; index <= floor; index += 1) {
|
||||||
|
context.currentGraph.historyState.processedMessageHashes[index] =
|
||||||
|
String(chatInput[index]?.mes || "");
|
||||||
|
}
|
||||||
|
context.currentGraph.historyState.processedMessageHashesNeedRefresh = false;
|
||||||
|
},
|
||||||
|
saveGraphToChat() {
|
||||||
|
savedHashes = { ...context.currentGraph.historyState.processedMessageHashes };
|
||||||
|
savedNeedRefresh =
|
||||||
|
context.currentGraph.historyState.processedMessageHashesNeedRefresh;
|
||||||
|
},
|
||||||
restoreRuntimeUiState() {},
|
restoreRuntimeUiState() {},
|
||||||
onRebuildController,
|
onRebuildController,
|
||||||
result: null,
|
result: null,
|
||||||
@@ -524,6 +553,11 @@ async function testManualRebuildSetsTerminalRuntimeStatus() {
|
|||||||
assert.equal(context.lastExtractionStatus.text, "图谱重建完成");
|
assert.equal(context.lastExtractionStatus.text, "图谱重建完成");
|
||||||
assert.equal(context.runtimeStatus.text, "图谱重建完成");
|
assert.equal(context.runtimeStatus.text, "图谱重建完成");
|
||||||
assert.equal(context.runtimeStatus.level, "success");
|
assert.equal(context.runtimeStatus.level, "success");
|
||||||
|
assert.deepEqual(savedHashes, {
|
||||||
|
0: "u",
|
||||||
|
1: "a",
|
||||||
|
});
|
||||||
|
assert.equal(savedNeedRefresh, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
testIndexDefinesLastProcessedAssistantFloorHelper();
|
testIndexDefinesLastProcessedAssistantFloorHelper();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
import {
|
import {
|
||||||
appendBatchJournal,
|
appendBatchJournal,
|
||||||
|
clearHistoryDirty,
|
||||||
cloneGraphSnapshot,
|
cloneGraphSnapshot,
|
||||||
createBatchJournalEntry,
|
createBatchJournalEntry,
|
||||||
detectHistoryMutation,
|
detectHistoryMutation,
|
||||||
@@ -95,6 +96,17 @@ assert.equal(migratedGraph.historyState.processedMessageHashesNeedRefresh, true)
|
|||||||
const migratedDetection = detectHistoryMutation(chat, migratedGraph.historyState);
|
const migratedDetection = detectHistoryMutation(chat, migratedGraph.historyState);
|
||||||
assert.equal(migratedDetection.dirty, false);
|
assert.equal(migratedDetection.dirty, false);
|
||||||
|
|
||||||
|
const emptyHashGraph = normalizeGraphRuntimeState({
|
||||||
|
historyState: {
|
||||||
|
chatId: "chat-history-test",
|
||||||
|
lastProcessedAssistantFloor: 3,
|
||||||
|
processedMessageHashVersion: PROCESSED_MESSAGE_HASH_VERSION,
|
||||||
|
processedMessageHashes: {},
|
||||||
|
processedMessageHashesNeedRefresh: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assert.equal(emptyHashGraph.historyState.processedMessageHashesNeedRefresh, true);
|
||||||
|
|
||||||
const importedGraph = normalizeGraphRuntimeState({
|
const importedGraph = normalizeGraphRuntimeState({
|
||||||
historyState: {
|
historyState: {
|
||||||
chatId: "chat-history-test",
|
chatId: "chat-history-test",
|
||||||
@@ -117,6 +129,19 @@ assert.deepEqual(
|
|||||||
snapshotProcessedMessageHashes(chat, 3),
|
snapshotProcessedMessageHashes(chat, 3),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const clearedGraph = normalizeGraphRuntimeState({
|
||||||
|
historyState: {
|
||||||
|
chatId: "chat-history-test",
|
||||||
|
lastProcessedAssistantFloor: 3,
|
||||||
|
processedMessageHashVersion: PROCESSED_MESSAGE_HASH_VERSION,
|
||||||
|
processedMessageHashes: hashes,
|
||||||
|
processedMessageHashesNeedRefresh: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
clearHistoryDirty(clearedGraph, { status: "replayed" });
|
||||||
|
assert.deepEqual(clearedGraph.historyState.processedMessageHashes, {});
|
||||||
|
assert.equal(clearedGraph.historyState.processedMessageHashesNeedRefresh, true);
|
||||||
|
|
||||||
const truncatedChat = chat.slice(0, 2);
|
const truncatedChat = chat.slice(0, 2);
|
||||||
const truncatedDetection = detectHistoryMutation(truncatedChat, {
|
const truncatedDetection = detectHistoryMutation(truncatedChat, {
|
||||||
lastProcessedAssistantFloor: 3,
|
lastProcessedAssistantFloor: 3,
|
||||||
|
|||||||
@@ -415,6 +415,22 @@ export async function onRebuildController(runtime) {
|
|||||||
reason: "用户手动触发全量重建",
|
reason: "用户手动触发全量重建",
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
const recoveredLastProcessedFloor = Number.isFinite(
|
||||||
|
runtime.getCurrentGraph()?.historyState?.lastProcessedAssistantFloor,
|
||||||
|
)
|
||||||
|
? runtime.getCurrentGraph().historyState.lastProcessedAssistantFloor
|
||||||
|
: -1;
|
||||||
|
if (recoveredLastProcessedFloor >= 0) {
|
||||||
|
if (typeof runtime.updateProcessedHistorySnapshot === "function") {
|
||||||
|
runtime.updateProcessedHistorySnapshot(chat, recoveredLastProcessedFloor);
|
||||||
|
} else if (typeof runtime.applyProcessedHistorySnapshotToGraph === "function") {
|
||||||
|
runtime.applyProcessedHistorySnapshotToGraph(
|
||||||
|
runtime.getCurrentGraph(),
|
||||||
|
chat,
|
||||||
|
recoveredLastProcessedFloor,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
runtime.saveGraphToChat({ reason: "manual-rebuild-complete" });
|
runtime.saveGraphToChat({ reason: "manual-rebuild-complete" });
|
||||||
runtime.setLastExtractionStatus(
|
runtime.setLastExtractionStatus(
|
||||||
"图谱重建完成",
|
"图谱重建完成",
|
||||||
|
|||||||
Reference in New Issue
Block a user