From 68053087375be71e4dcff64b80de183118464106 Mon Sep 17 00:00:00 2001 From: bielie Date: Tue, 24 Feb 2026 16:40:04 +0800 Subject: [PATCH] fix: preserve fact metadata and trend on manual edits --- modules/story-summary/story-summary.js | 57 +++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/modules/story-summary/story-summary.js b/modules/story-summary/story-summary.js index 9787b41..9e2dd5a 100644 --- a/modules/story-summary/story-summary.js +++ b/modules/story-summary/story-summary.js @@ -1092,6 +1092,57 @@ function mergeCharacterRelationshipsIntoFacts(existingFacts, relationships, floo return [...nonRelationFacts, ...newRelationFacts]; } +function getCurrentFloorHint() { + const { chat } = getContext(); + const lastFloor = (Array.isArray(chat) ? chat.length : 0) - 1; + return Math.max(0, lastFloor); +} + +function factKeyBySubjectPredicate(fact) { + const s = String(fact?.s || "").trim(); + const p = String(fact?.p || "").trim(); + return `${s}::${p}`; +} + +function mergeEditedFactsWithTimestamps(existingFacts, editedFacts, floorHint = 0) { + const currentFacts = Array.isArray(existingFacts) ? existingFacts : []; + const incomingFacts = Array.isArray(editedFacts) ? editedFacts : []; + const oldMap = new Map(currentFacts.map((f) => [factKeyBySubjectPredicate(f), f])); + + let nextFactId = getNextFactIdValue(currentFacts); + const merged = []; + + for (const fact of incomingFacts) { + const s = String(fact?.s || "").trim(); + const p = String(fact?.p || "").trim(); + const o = String(fact?.o || "").trim(); + if (!s || !p || !o) continue; + + const key = `${s}::${p}`; + const oldFact = oldMap.get(key); + const since = oldFact?.since ?? fact?.since ?? floorHint; + const addedAt = oldFact?._addedAt ?? fact?._addedAt ?? floorHint; + + const out = { + id: oldFact?.id || fact?.id || `f-${nextFactId++}`, + s, + p, + o, + since, + _addedAt: addedAt, + }; + if (oldFact?._isState != null) out._isState = oldFact._isState; + + const mergedTrend = fact?.trend ?? oldFact?.trend; + if (mergedTrend != null && String(mergedTrend).trim()) { + out.trend = String(mergedTrend).trim(); + } + merged.push(out); + } + + return merged; +} + function openPanelForMessage(mesId) { createOverlay(); showOverlay(); @@ -1428,13 +1479,17 @@ async function handleFrameMessage(event) { // 如果是 events,先记录旧数据用于同步向量 const oldEvents = data.section === "events" ? [...(store.json.events || [])] : null; + const oldFacts = data.section === "facts" ? [...(store.json.facts || [])] : null; if (VALID_SECTIONS.includes(data.section)) { store.json[data.section] = data.data; } + if (data.section === "facts") { + store.json.facts = mergeEditedFactsWithTimestamps(oldFacts, data.data, getCurrentFloorHint()); + } if (data.section === "characters") { const rels = data?.data?.relationships || []; - const floorHint = Math.max(0, Number(store.lastSummarizedMesId) || 0); + const floorHint = getCurrentFloorHint(); store.json.facts = mergeCharacterRelationshipsIntoFacts(store.json.facts, rels, floorHint); } store.updatedAt = Date.now();