fix(story-summary): guard delayed handlers by chatId and use module event wrapper

This commit is contained in:
2026-02-12 17:01:44 +08:00
parent a646a70224
commit 40f59d6571

View File

@@ -10,7 +10,6 @@
import { getContext } from "../../../../../extensions.js";
import {
eventSource,
event_types,
extension_prompts,
extension_prompt_types,
@@ -18,6 +17,7 @@ import {
} from "../../../../../../script.js";
import { extensionFolderPath } from "../../core/constants.js";
import { xbLog, CacheRegistry } from "../../core/debug-core.js";
import { createModuleEvents } from "../../core/event-manager.js";
import { postToIframe, isTrustedMessage } from "../../core/iframe-messaging.js";
import { CommonSettingStorage } from "../../core/server-storage.js";
@@ -111,7 +111,9 @@ let overlayCreated = false;
let frameReady = false;
let currentMesId = null;
let pendingFrameMessages = [];
let eventsRegistered = false;
/** @type {ReturnType<typeof createModuleEvents>|null} */
let events = null;
let activeChatId = null;
let vectorCancelled = false;
let vectorAbortController = null;
@@ -1371,7 +1373,9 @@ async function handleManualGenerate(mesId, config) {
// ═══════════════════════════════════════════════════════════════════════════
async function handleChatChanged() {
if (!events) return;
const { chat } = getContext();
activeChatId = getContext().chatId || null;
const newLength = Array.isArray(chat) ? chat.length : 0;
await rollbackSummaryIfNeeded();
@@ -1405,7 +1409,8 @@ async function handleChatChanged() {
setTimeout(() => checkVectorIntegrityAndWarn(), 2000);
}
async function handleMessageDeleted() {
async function handleMessageDeleted(scheduledChatId) {
if (isChatStale(scheduledChatId)) return;
const { chat, chatId } = getContext();
const newLength = chat?.length || 0;
@@ -1426,7 +1431,8 @@ async function handleMessageDeleted() {
applyHideStateDebounced();
}
async function handleMessageSwiped() {
async function handleMessageSwiped(scheduledChatId) {
if (isChatStale(scheduledChatId)) return;
const { chat, chatId } = getContext();
const lastFloor = (chat?.length || 1) - 1;
@@ -1447,7 +1453,8 @@ async function handleMessageSwiped() {
await sendVectorStatsToFrame();
}
async function handleMessageReceived() {
async function handleMessageReceived(scheduledChatId) {
if (isChatStale(scheduledChatId)) return;
const { chat, chatId } = getContext();
const lastFloor = (chat?.length || 1) - 1;
const message = chat?.[lastFloor];
@@ -1480,12 +1487,14 @@ async function handleMessageReceived() {
setTimeout(() => maybeAutoExtractL0(), 2000);
}
function handleMessageSent() {
function handleMessageSent(scheduledChatId) {
if (isChatStale(scheduledChatId)) return;
initButtonsForAll();
setTimeout(() => maybeAutoRunSummary("before_user"), 1000);
}
async function handleMessageUpdated() {
async function handleMessageUpdated(scheduledChatId) {
if (isChatStale(scheduledChatId)) return;
await rollbackSummaryIfNeeded();
initButtonsForAll();
applyHideStateDebounced();
@@ -1601,25 +1610,21 @@ async function handleGenerationStarted(type, _params, isDryRun) {
// 事件注册
// ═══════════════════════════════════════════════════════════════════════════
const boundHandlers = {
chatChanged: () => setTimeout(handleChatChanged, 80),
messageDeleted: () => setTimeout(handleMessageDeleted, 50),
messageReceived: () => setTimeout(handleMessageReceived, 150),
messageSent: () => setTimeout(handleMessageSent, 150),
messageSentRecall: handleMessageSentForRecall,
messageSwiped: () => setTimeout(handleMessageSwiped, 100),
messageUpdated: () => setTimeout(handleMessageUpdated, 100),
messageEdited: () => setTimeout(handleMessageUpdated, 100),
userRendered: (data) => setTimeout(() => handleMessageRendered(data), 50),
charRendered: (data) => setTimeout(() => handleMessageRendered(data), 50),
genStarted: handleGenerationStarted,
genStopped: clearExtensionPrompt,
genEnded: clearExtensionPrompt,
};
function scheduleWithChatGuard(fn, delay = 0) {
const scheduledChatId = getContext().chatId;
setTimeout(() => fn(scheduledChatId), delay);
}
function isChatStale(scheduledChatId) {
if (!scheduledChatId || scheduledChatId !== activeChatId) return true;
const { chatId } = getContext();
return chatId !== scheduledChatId;
}
function registerEvents() {
if (eventsRegistered) return;
eventsRegistered = true;
if (events) return;
events = createModuleEvents(MODULE_ID);
activeChatId = getContext().chatId || null;
CacheRegistry.register(MODULE_ID, {
name: "待发送消息队列",
@@ -1639,44 +1644,36 @@ function registerEvents() {
initButtonsForAll();
eventSource.on(event_types.CHAT_CHANGED, boundHandlers.chatChanged);
eventSource.on(event_types.MESSAGE_DELETED, boundHandlers.messageDeleted);
eventSource.on(event_types.MESSAGE_RECEIVED, boundHandlers.messageReceived);
eventSource.on(event_types.MESSAGE_SENT, boundHandlers.messageSent);
eventSource.on(event_types.MESSAGE_SENT, boundHandlers.messageSentRecall);
eventSource.on(event_types.MESSAGE_SWIPED, boundHandlers.messageSwiped);
eventSource.on(event_types.MESSAGE_UPDATED, boundHandlers.messageUpdated);
eventSource.on(event_types.MESSAGE_EDITED, boundHandlers.messageEdited);
eventSource.on(event_types.USER_MESSAGE_RENDERED, boundHandlers.userRendered);
eventSource.on(event_types.CHARACTER_MESSAGE_RENDERED, boundHandlers.charRendered);
events.on(event_types.CHAT_CHANGED, () => {
activeChatId = getContext().chatId || null;
scheduleWithChatGuard(handleChatChanged, 80);
});
events.on(event_types.MESSAGE_DELETED, () => scheduleWithChatGuard(handleMessageDeleted, 50));
events.on(event_types.MESSAGE_RECEIVED, () => scheduleWithChatGuard(handleMessageReceived, 150));
events.on(event_types.MESSAGE_SENT, () => scheduleWithChatGuard(handleMessageSent, 150));
events.on(event_types.MESSAGE_SENT, handleMessageSentForRecall);
events.on(event_types.MESSAGE_SWIPED, () => scheduleWithChatGuard(handleMessageSwiped, 100));
events.on(event_types.MESSAGE_UPDATED, () => scheduleWithChatGuard(handleMessageUpdated, 100));
events.on(event_types.MESSAGE_EDITED, () => scheduleWithChatGuard(handleMessageUpdated, 100));
events.on(event_types.USER_MESSAGE_RENDERED, (data) => setTimeout(() => handleMessageRendered(data), 50));
events.on(event_types.CHARACTER_MESSAGE_RENDERED, (data) => setTimeout(() => handleMessageRendered(data), 50));
// 用户输入捕获(原生捕获阶段)
document.addEventListener("pointerdown", onSendPointerdown, true);
document.addEventListener("keydown", onSendKeydown, true);
// 注入链路
eventSource.on(event_types.GENERATION_STARTED, boundHandlers.genStarted);
eventSource.on(event_types.GENERATION_STOPPED, boundHandlers.genStopped);
eventSource.on(event_types.GENERATION_ENDED, boundHandlers.genEnded);
events.on(event_types.GENERATION_STARTED, handleGenerationStarted);
events.on(event_types.GENERATION_STOPPED, clearExtensionPrompt);
events.on(event_types.GENERATION_ENDED, clearExtensionPrompt);
}
function unregisterEvents() {
if (!events) return;
CacheRegistry.unregister(MODULE_ID);
eventsRegistered = false;
eventSource.off(event_types.CHAT_CHANGED, boundHandlers.chatChanged);
eventSource.off(event_types.MESSAGE_DELETED, boundHandlers.messageDeleted);
eventSource.off(event_types.MESSAGE_RECEIVED, boundHandlers.messageReceived);
eventSource.off(event_types.MESSAGE_SENT, boundHandlers.messageSent);
eventSource.off(event_types.MESSAGE_SENT, boundHandlers.messageSentRecall);
eventSource.off(event_types.MESSAGE_SWIPED, boundHandlers.messageSwiped);
eventSource.off(event_types.MESSAGE_UPDATED, boundHandlers.messageUpdated);
eventSource.off(event_types.MESSAGE_EDITED, boundHandlers.messageEdited);
eventSource.off(event_types.USER_MESSAGE_RENDERED, boundHandlers.userRendered);
eventSource.off(event_types.CHARACTER_MESSAGE_RENDERED, boundHandlers.charRendered);
eventSource.off(event_types.GENERATION_STARTED, boundHandlers.genStarted);
eventSource.off(event_types.GENERATION_STOPPED, boundHandlers.genStopped);
eventSource.off(event_types.GENERATION_ENDED, boundHandlers.genEnded);
events.cleanup();
events = null;
activeChatId = null;
$(".xiaobaix-story-summary-btn").remove();
hideOverlay();