fix(vector): repair missing graph identity before rebuild

This commit is contained in:
youzini
2026-05-19 13:47:46 +00:00
parent f27c530069
commit 152913811f
2 changed files with 158 additions and 3 deletions

View File

@@ -4502,6 +4502,77 @@ function hasRuntimeGraphMutationContext(
return allowNoChatState === true && graphPersistenceState.loadState === GRAPH_LOAD_STATES.NO_CHAT;
}
function repairRuntimeGraphIdentityFromPersistence(
operationLabel = "当前操作",
{
context = getContext(),
graph = currentGraph,
reason = "runtime-graph-identity-repair",
} = {},
) {
if (
!graph ||
typeof graph !== "object" ||
Array.isArray(graph) ||
!graph.historyState ||
typeof graph.historyState !== "object" ||
Array.isArray(graph.historyState)
) {
return { repaired: false, reason: "missing-runtime-graph" };
}
const graphOwnedChatId = getGraphOwnedChatId(graph);
if (graphOwnedChatId) {
return { repaired: false, reason: "graph-identity-present", chatId: graphOwnedChatId };
}
const stateChatId = normalizeChatIdCandidate(graphPersistenceState.chatId);
if (!stateChatId) {
return { repaired: false, reason: "missing-persistence-chat-id" };
}
const identity = resolveCurrentChatIdentity(context);
const liveChatId = normalizeChatIdCandidate(identity.chatId);
if (
liveChatId &&
!areChatIdsEquivalentForResolvedIdentity(stateChatId, liveChatId, identity) &&
!areChatIdsEquivalentForResolvedIdentity(liveChatId, stateChatId, identity)
) {
return {
repaired: false,
reason: "live-chat-mismatch",
chatId: stateChatId,
liveChatId,
};
}
const markerChatId = normalizeChatIdCandidate(graphPersistenceState.commitMarker?.chatId);
if (markerChatId && markerChatId !== stateChatId) {
return {
repaired: false,
reason: "commit-marker-chat-mismatch",
chatId: stateChatId,
markerChatId,
};
}
graph.historyState.chatId = stateChatId;
stampGraphPersistenceMeta(graph, {
revision: graphPersistenceState.revision || graph?.meta?.revision || graph?.revision || 0,
reason: String(reason || operationLabel || "runtime-graph-identity-repair"),
chatId: stateChatId,
integrity:
normalizeChatIdCandidate(graphPersistenceState.commitMarker?.integrity) ||
getChatMetadataIntegrity(context),
});
debugDebug("[ST-BME] 已补齐运行时图谱聊天身份", {
operationLabel,
chatId: stateChatId,
reason,
});
return { repaired: true, reason: "repaired", chatId: stateChatId };
}
function isGraphReadableForRecall(
loadState = graphPersistenceState.loadState,
chatId = getCurrentChatId(),
@@ -4631,6 +4702,11 @@ function ensureGraphMutationReady(
}
return false;
}
if (allowRuntimeGraphFallback === true) {
repairRuntimeGraphIdentityFromPersistence(operationLabel, {
reason: "graph-mutation-ready-fallback",
});
}
if (
graphPersistenceState.dbReady ||
isGraphLoadStateDbReady() ||
@@ -14126,12 +14202,12 @@ function applyModuleInjectionPrompt(content = "", settings = getSettings()) {
};
}
function ensureCurrentGraphRuntimeState() {
function ensureCurrentGraphRuntimeState({ chatId = getCurrentChatId() } = {}) {
if (!currentGraph) {
currentGraph = createEmptyGraph();
}
currentGraph = normalizeGraphRuntimeState(currentGraph, getCurrentChatId());
currentGraph = normalizeGraphRuntimeState(currentGraph, chatId);
return currentGraph;
}
@@ -17444,7 +17520,16 @@ async function ensureVectorReadyIfNeeded(
signal = undefined,
) {
if (!currentGraph) return;
ensureCurrentGraphRuntimeState();
if (
!isGraphMetadataWriteAllowed() &&
!hasRuntimeGraphMutationContext(getContext(), currentGraph, {
allowNoChatState: true,
})
) {
repairRuntimeGraphIdentityFromPersistence("向量准备", {
reason: "vector-ready-fallback",
});
}
if (
!isGraphMetadataWriteAllowed() &&
!hasRuntimeGraphMutationContext(getContext(), currentGraph, {
@@ -17453,6 +17538,9 @@ async function ensureVectorReadyIfNeeded(
) {
return;
}
ensureCurrentGraphRuntimeState({
chatId: getGraphOwnedChatId(currentGraph) || getCurrentChatId(),
});
if (!currentGraph.vectorIndexState?.dirty) return;

View File

@@ -4237,6 +4237,42 @@ result = {
assert.match(status.meta, /维护操作会使用图谱身份继续/);
}
{
const graph = createMeaningfulGraph(
"chat-runtime-fallback-identity-repair",
"runtime-fallback-identity-repair",
);
graph.historyState.chatId = "";
const harness = await createGraphPersistenceHarness({
chatId: "",
globalChatId: "",
chat: [
{ is_user: true, mes: "已有聊天" },
{ is_user: false, mes: "已有回复" },
],
});
harness.api.setCurrentGraph(graph);
harness.api.setGraphPersistenceState({
loadState: GRAPH_LOAD_STATES.NO_CHAT,
chatId: "chat-runtime-fallback-identity-repair",
dbReady: false,
writesBlocked: true,
});
assert.equal(
harness.api.ensureGraphMutationReady("重建向量", {
notify: false,
allowRuntimeGraphFallback: true,
}),
true,
"面板/持久化状态已有聊天 ID 且图谱自身缺身份时,向量维护前应补齐缺失身份",
);
assert.equal(
harness.api.getCurrentGraph().historyState.chatId,
"chat-runtime-fallback-identity-repair",
);
}
{
const graph = createMeaningfulGraph(
"chat-runtime-fallback-denied",
@@ -4266,6 +4302,37 @@ result = {
);
}
{
const graph = createMeaningfulGraph(
"chat-runtime-fallback-conflict",
"runtime-fallback-conflict",
);
graph.historyState.chatId = "";
const harness = await createGraphPersistenceHarness({
chatId: "",
globalChatId: "",
chat: [{ is_user: true, mes: "已有聊天" }],
});
harness.api.setCurrentGraph(graph);
harness.api.setGraphPersistenceState({
loadState: GRAPH_LOAD_STATES.NO_CHAT,
chatId: "chat-runtime-fallback-conflict",
commitMarker: { chatId: "other-chat" },
dbReady: false,
writesBlocked: true,
});
assert.equal(
harness.api.ensureGraphMutationReady("重建向量", {
notify: false,
allowRuntimeGraphFallback: true,
}),
false,
"commit marker 指向其它聊天时,不应补齐身份或放开向量写入",
);
assert.equal(harness.api.getCurrentGraph().historyState.chatId, "");
}
{
const harness = await createGraphPersistenceHarness({
chatId: "chat-pending-persist-already-accepted",