Guard auto extraction microtask scheduling

This commit is contained in:
Hao19911125
2026-04-03 07:10:01 +08:00
parent 2a6d15e036
commit e505f6ac50
2 changed files with 51 additions and 1 deletions

View File

@@ -506,6 +506,12 @@ export function onMessageReceivedController(
messageId = null,
_type = "",
) {
const enqueueMicrotask =
typeof runtime.queueMicrotask === "function"
? runtime.queueMicrotask.bind(runtime)
: typeof globalThis.queueMicrotask === "function"
? globalThis.queueMicrotask.bind(globalThis)
: (task) => Promise.resolve().then(task);
const persistenceState = runtime.getGraphPersistenceState?.() || {};
const loadState = persistenceState.loadState || "";
const dbReady =
@@ -552,7 +558,7 @@ export function onMessageReceivedController(
: lastMessage;
if (runtime.isAssistantChatMessage(targetMessage)) {
runtime.queueMicrotask(() => {
enqueueMicrotask(() => {
void runtime.runExtraction().catch((error) => {
runtime.console.error("[ST-BME] 异步自动提取失败:", error);
runtime.notifyExtractionIssue(

View File

@@ -10,6 +10,7 @@ import {
onChatChangedController,
onGenerationAfterCommandsController,
onGenerationStartedController,
onMessageReceivedController,
onMessageSwipedController,
registerCoreEventHooksController,
} from "../event-binding.js";
@@ -2946,6 +2947,48 @@ async function testSwipeRoutesToRerollWithoutHistoryRecoveryFallback() {
assert.equal(result.recoveryPath, "reverse-journal");
}
async function testMessageReceivedQueuesExtractionWithoutRuntimeQueueMicrotask() {
let runExtractionCalls = 0;
let refreshCalls = 0;
onMessageReceivedController(
{
getGraphPersistenceState: () => ({ loadState: "loaded", dbReady: true }),
getCurrentGraph: () => null,
getPendingRecallSendIntent: () => ({ text: "", at: 0 }),
isFreshRecallInputRecord: () => true,
createRecallInputRecord: () => ({ text: "", at: 0 }),
setPendingRecallSendIntent() {},
getContext: () => ({
chat: [
{ is_user: true, mes: "u1" },
{ is_user: false, mes: "a1" },
],
}),
isAssistantChatMessage(message) {
return Boolean(message) && !message.is_user && !message.is_system;
},
runExtraction: async () => {
runExtractionCalls += 1;
},
console: {
error() {},
},
notifyExtractionIssue() {},
refreshPersistedRecallMessageUi() {
refreshCalls += 1;
},
},
1,
"assistant",
);
await waitForTick();
assert.equal(runExtractionCalls, 1);
assert.equal(refreshCalls, 1);
}
async function testAutoExtractionDefersWhenGraphNotReady() {
const deferredReasons = [];
const statuses = [];
@@ -4218,6 +4261,7 @@ await testGenerationRecallSentMessageClearsStaleTransactionForSameKey();
await testRegisterCoreEventHooksIsIdempotent();
await testChatChangedDoesNotClearCoreEventBindings();
await testSwipeRoutesToRerollWithoutHistoryRecoveryFallback();
await testMessageReceivedQueuesExtractionWithoutRuntimeQueueMicrotask();
await testAutoExtractionDefersWhenGraphNotReady();
await testAutoExtractionDefersWhenAlreadyExtracting();
await testAutoExtractionDefersWhenHistoryRecoveryBusy();