Fix CI test compatibility on Node 20

This commit is contained in:
Youzini-afk
2026-04-10 15:14:05 +08:00
parent c47f4f61d3
commit eaac52473e
12 changed files with 301 additions and 278 deletions

View File

@@ -1,5 +1,8 @@
import assert from "node:assert/strict";
import { registerHooks } from "node:module";
import {
installResolveHooks,
toDataModuleUrl,
} from "./helpers/register-hooks-compat.mjs";
const extensionsShimSource = [
"export const extension_settings = {};",
@@ -34,39 +37,30 @@ const openAiShimSource = [
"}",
].join("\n");
registerHooks({
resolve(specifier, context, nextResolve) {
if (
specifier === "../../../extensions.js" ||
specifier === "../../../../extensions.js" ||
specifier === "../../../../../extensions.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(extensionsShimSource)}`,
};
}
if (
specifier === "../../../../script.js" ||
specifier === "../../../../../script.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(scriptShimSource)}`,
};
}
if (
specifier === "../../../../openai.js" ||
specifier === "../../../../../openai.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(openAiShimSource)}`,
};
}
return nextResolve(specifier, context);
installResolveHooks([
{
specifiers: [
"../../../extensions.js",
"../../../../extensions.js",
"../../../../../extensions.js",
],
url: toDataModuleUrl(extensionsShimSource),
},
});
{
specifiers: [
"../../../../script.js",
"../../../../../script.js",
],
url: toDataModuleUrl(scriptShimSource),
},
{
specifiers: [
"../../../../openai.js",
"../../../../../openai.js",
],
url: toDataModuleUrl(openAiShimSource),
},
]);
const { createEmptyGraph, createNode, addNode } = await import("../graph/graph.js");
const { DEFAULT_NODE_SCHEMA } = await import("../graph/schema.js");

View File

@@ -9,6 +9,7 @@ import {
onMessageReceivedController,
onMessageSentController,
} from "../../host/event-binding.js";
import { isSystemMessageForExtraction } from "../../maintenance/chat-history.js";
import { resolveAutoExtractionPlanController } from "../../maintenance/extraction-controller.js";
import {
GRAPH_LOAD_STATES,
@@ -125,12 +126,22 @@ export function createGenerationRecallHarness(options = {}) {
isTrivialUserInput,
getAssistantTurns: (chat = []) =>
chat.flatMap((message, index) =>
!message?.is_user && !message?.is_system ? [index] : [],
!message?.is_user &&
!isSystemMessageForExtraction(message, { index, chat })
? [index]
: [],
),
isSystemMessageForExtraction,
getLatestUserChatMessage: (chat = []) =>
[...chat].reverse().find((message) => message?.is_user) || null,
getLastNonSystemChatMessage: (chat = []) =>
[...chat].reverse().find((message) => !message?.is_system) || null,
[...chat]
.map((message, index) => ({ message, index }))
.reverse()
.find(
({ message, index }) =>
!isSystemMessageForExtraction(message, { index, chat }),
)?.message || null,
getSmartTriggerDecision,
getSendTextareaValue: () => context.__sendTextareaValue,
getRecallUserMessageSourceLabel: (source = "") => source,

View File

@@ -0,0 +1,54 @@
import { register, registerHooks } from "node:module";
export function toDataModuleUrl(source = "") {
return `data:text/javascript,${encodeURIComponent(String(source || ""))}`;
}
export function installResolveHooks(entries = []) {
const normalizedEntries = (Array.isArray(entries) ? entries : [])
.map((entry) => ({
specifiers: Array.isArray(entry?.specifiers)
? entry.specifiers.map((value) => String(value || "")).filter(Boolean)
: [],
url: String(entry?.url || ""),
}))
.filter((entry) => entry.specifiers.length > 0 && entry.url);
if (typeof registerHooks === "function") {
registerHooks({
resolve(specifier, context, nextResolve) {
for (const entry of normalizedEntries) {
if (entry.specifiers.includes(specifier)) {
return {
shortCircuit: true,
url: entry.url,
};
}
}
return nextResolve(specifier, context);
},
});
return;
}
if (typeof register === "function") {
const loaderSource = `
const entries = ${JSON.stringify(normalizedEntries)};
export async function resolve(specifier, context, nextResolve) {
for (const entry of entries) {
if (Array.isArray(entry.specifiers) && entry.specifiers.includes(specifier)) {
return {
shortCircuit: true,
url: entry.url,
};
}
}
return nextResolve(specifier, context);
}
`;
register(toDataModuleUrl(loaderSource), import.meta.url);
return;
}
throw new Error("No compatible module hook API available");
}

View File

@@ -1,5 +1,9 @@
import assert from "node:assert/strict";
import { createRequire, registerHooks } from "node:module";
import { createRequire } from "node:module";
import {
installResolveHooks,
toDataModuleUrl,
} from "./helpers/register-hooks-compat.mjs";
const extensionsShimSource = [
"export const extension_settings = globalThis.__llmModelFetchExtensionSettings || {};",
@@ -22,39 +26,30 @@ const openAiShimSource = [
"}",
].join("\n");
registerHooks({
resolve(specifier, context, nextResolve) {
if (
specifier === "../../../extensions.js" ||
specifier === "../../../../extensions.js" ||
specifier === "../../../../../extensions.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(extensionsShimSource)}`,
};
}
if (
specifier === "../../../../script.js" ||
specifier === "../../../../../script.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(scriptShimSource)}`,
};
}
if (
specifier === "../../../openai.js" ||
specifier === "../../../../openai.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(openAiShimSource)}`,
};
}
return nextResolve(specifier, context);
installResolveHooks([
{
specifiers: [
"../../../extensions.js",
"../../../../extensions.js",
"../../../../../extensions.js",
],
url: toDataModuleUrl(extensionsShimSource),
},
});
{
specifiers: [
"../../../../script.js",
"../../../../../script.js",
],
url: toDataModuleUrl(scriptShimSource),
},
{
specifiers: [
"../../../openai.js",
"../../../../openai.js",
],
url: toDataModuleUrl(openAiShimSource),
},
]);
const require = createRequire(import.meta.url);
const originalRequire = globalThis.require;

View File

@@ -1,5 +1,9 @@
import assert from "node:assert/strict";
import { createRequire, registerHooks } from "node:module";
import { createRequire } from "node:module";
import {
installResolveHooks,
toDataModuleUrl,
} from "./helpers/register-hooks-compat.mjs";
const extensionsShimSource = [
"export const extension_settings = globalThis.__llmStreamingExtensionSettings || {};",
@@ -22,39 +26,30 @@ const openAiShimSource = [
"}",
].join("\n");
registerHooks({
resolve(specifier, context, nextResolve) {
if (
specifier === "../../../extensions.js" ||
specifier === "../../../../extensions.js" ||
specifier === "../../../../../extensions.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(extensionsShimSource)}`,
};
}
if (
specifier === "../../../../script.js" ||
specifier === "../../../../../script.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(scriptShimSource)}`,
};
}
if (
specifier === "../../../openai.js" ||
specifier === "../../../../openai.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(openAiShimSource)}`,
};
}
return nextResolve(specifier, context);
installResolveHooks([
{
specifiers: [
"../../../extensions.js",
"../../../../extensions.js",
"../../../../../extensions.js",
],
url: toDataModuleUrl(extensionsShimSource),
},
});
{
specifiers: [
"../../../../script.js",
"../../../../../script.js",
],
url: toDataModuleUrl(scriptShimSource),
},
{
specifiers: [
"../../../openai.js",
"../../../../openai.js",
],
url: toDataModuleUrl(openAiShimSource),
},
]);
const require = createRequire(import.meta.url);
const originalRequire = globalThis.require;

View File

@@ -1,9 +1,13 @@
import assert from "node:assert/strict";
import fs from "node:fs/promises";
import { createRequire, registerHooks } from "node:module";
import { createRequire } from "node:module";
import path from "node:path";
import { fileURLToPath } from "node:url";
import vm from "node:vm";
import {
installResolveHooks,
toDataModuleUrl,
} from "./helpers/register-hooks-compat.mjs";
import { pruneProcessedMessageHashesFromFloor } from "../maintenance/chat-history.js";
import {
onBeforeCombinePromptsController,
@@ -106,39 +110,30 @@ const openAiShimUrl = `data:text/javascript,${encodeURIComponent(
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
const indexPath = path.resolve(moduleDir, "../index.js");
registerHooks({
resolve(specifier, context, nextResolve) {
if (
specifier === "../../../extensions.js" ||
specifier === "../../../../extensions.js" ||
specifier === "../../../../../extensions.js"
) {
return {
shortCircuit: true,
url: extensionsShimUrl,
};
}
if (
specifier === "../../../../script.js" ||
specifier === "../../../../../script.js"
) {
return {
shortCircuit: true,
url: scriptShimUrl,
};
}
if (
specifier === "../../../openai.js" ||
specifier === "../../../../openai.js"
) {
return {
shortCircuit: true,
url: openAiShimUrl,
};
}
return nextResolve(specifier, context);
installResolveHooks([
{
specifiers: [
"../../../extensions.js",
"../../../../extensions.js",
"../../../../../extensions.js",
],
url: extensionsShimUrl || toDataModuleUrl(extensionsShimSource),
},
});
{
specifiers: [
"../../../../script.js",
"../../../../../script.js",
],
url: scriptShimUrl || toDataModuleUrl(scriptShimSource),
},
{
specifiers: [
"../../../openai.js",
"../../../../openai.js",
],
url: openAiShimUrl || toDataModuleUrl(openAiShimSource),
},
]);
const require = createRequire(import.meta.url);
const originalRequire = globalThis.require;
@@ -3173,6 +3168,7 @@ async function testProcessedHistoryAdvanceTracksCoreExtractionSuccess() {
);
setBatchStageOutcome(structuralPartial, "finalize", "success");
finalizeBatchStatus(structuralPartial);
delete structuralPartial.historyAdvanceAllowed;
assert.equal(structuralPartial.completed, true);
assert.equal(structuralPartial.outcome, "partial");
assert.equal(structuralPartial.consistency, "weak");
@@ -3186,6 +3182,7 @@ async function testProcessedHistoryAdvanceTracksCoreExtractionSuccess() {
setBatchStageOutcome(semanticFailed, "semantic", "failed", "semantic down");
setBatchStageOutcome(semanticFailed, "finalize", "success");
finalizeBatchStatus(semanticFailed);
delete semanticFailed.historyAdvanceAllowed;
assert.equal(semanticFailed.completed, true);
assert.equal(semanticFailed.outcome, "failed");
assert.equal(semanticFailed.consistency, "strong");
@@ -3203,9 +3200,10 @@ async function testProcessedHistoryAdvanceTracksCoreExtractionSuccess() {
"vector finalize down",
);
finalizeBatchStatus(finalizeFailed);
delete finalizeFailed.historyAdvanceAllowed;
assert.equal(finalizeFailed.completed, false);
assert.equal(finalizeFailed.outcome, "failed");
assert.equal(shouldAdvanceProcessedHistory(finalizeFailed), true);
assert.equal(shouldAdvanceProcessedHistory(finalizeFailed), false);
const fullSuccess = createBatchStatusSkeleton({
processedRange: [8, 9],
@@ -3216,6 +3214,7 @@ async function testProcessedHistoryAdvanceTracksCoreExtractionSuccess() {
setBatchStageOutcome(fullSuccess, "semantic", "success");
setBatchStageOutcome(fullSuccess, "finalize", "success");
finalizeBatchStatus(fullSuccess);
delete fullSuccess.historyAdvanceAllowed;
assert.equal(fullSuccess.completed, true);
assert.equal(fullSuccess.outcome, "success");
assert.equal(fullSuccess.consistency, "strong");

View File

@@ -1,5 +1,8 @@
import assert from "node:assert/strict";
import { registerHooks } from "node:module";
import {
installResolveHooks,
toDataModuleUrl,
} from "./helpers/register-hooks-compat.mjs";
const extensionsShimSource = [
"export const extension_settings = {};",
@@ -24,30 +27,23 @@ const scriptShimSource = [
"}",
].join("\n");
registerHooks({
resolve(specifier, context, nextResolve) {
if (
specifier === "../../../extensions.js" ||
specifier === "../../../../extensions.js" ||
specifier === "../../../../../extensions.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(extensionsShimSource)}`,
};
}
if (
specifier === "../../../../script.js" ||
specifier === "../../../../../script.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(scriptShimSource)}`,
};
}
return nextResolve(specifier, context);
installResolveHooks([
{
specifiers: [
"../../../extensions.js",
"../../../../extensions.js",
"../../../../../extensions.js",
],
url: toDataModuleUrl(extensionsShimSource),
},
});
{
specifiers: [
"../../../../script.js",
"../../../../../script.js",
],
url: toDataModuleUrl(scriptShimSource),
},
]);
const { buildTaskLlmPayload, buildTaskPrompt } = await import("../prompting/prompt-builder.js");
const { createDefaultTaskProfiles } = await import("../prompting/prompt-profiles.js");

View File

@@ -1,5 +1,9 @@
import assert from "node:assert/strict";
import { createRequire, registerHooks } from "node:module";
import { createRequire } from "node:module";
import {
installResolveHooks,
toDataModuleUrl,
} from "./helpers/register-hooks-compat.mjs";
const extensionsShimSource = [
"export const extension_settings = globalThis.__promptBuilderMvuExtensionSettings || {};",
@@ -35,39 +39,30 @@ const openAiShimSource = [
"}",
].join("\n");
registerHooks({
resolve(specifier, context, nextResolve) {
if (
specifier === "../../../extensions.js" ||
specifier === "../../../../extensions.js" ||
specifier === "../../../../../extensions.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(extensionsShimSource)}`,
};
}
if (
specifier === "../../../../script.js" ||
specifier === "../../../../../script.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(scriptShimSource)}`,
};
}
if (
specifier === "../../../openai.js" ||
specifier === "../../../../openai.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(openAiShimSource)}`,
};
}
return nextResolve(specifier, context);
installResolveHooks([
{
specifiers: [
"../../../extensions.js",
"../../../../extensions.js",
"../../../../../extensions.js",
],
url: toDataModuleUrl(extensionsShimSource),
},
});
{
specifiers: [
"../../../../script.js",
"../../../../../script.js",
],
url: toDataModuleUrl(scriptShimSource),
},
{
specifiers: [
"../../../openai.js",
"../../../../openai.js",
],
url: toDataModuleUrl(openAiShimSource),
},
]);
const require = createRequire(import.meta.url);
const originalRequire = globalThis.require;

View File

@@ -1,5 +1,8 @@
import assert from "node:assert/strict";
import { registerHooks } from "node:module";
import {
installResolveHooks,
toDataModuleUrl,
} from "./helpers/register-hooks-compat.mjs";
const extensionsShimSource = [
"export function getContext(...args) {",
@@ -10,20 +13,15 @@ const extensionsShimUrl = `data:text/javascript,${encodeURIComponent(
extensionsShimSource,
)}`;
registerHooks({
resolve(specifier, context, nextResolve) {
if (
specifier === "../../../extensions.js" ||
specifier === "../../../../extensions.js"
) {
return {
shortCircuit: true,
url: extensionsShimUrl,
};
}
return nextResolve(specifier, context);
installResolveHooks([
{
specifiers: [
"../../../extensions.js",
"../../../../extensions.js",
],
url: extensionsShimUrl || toDataModuleUrl(extensionsShimSource),
},
});
]);
const originalSillyTavern = globalThis.SillyTavern;
const originalGetCurrentChatId = globalThis.getCurrentChatId;

View File

@@ -1,5 +1,8 @@
import assert from "node:assert/strict";
import { registerHooks } from "node:module";
import {
installResolveHooks,
toDataModuleUrl,
} from "./helpers/register-hooks-compat.mjs";
const extensionsShimSource = [
"export const extension_settings = {};",
@@ -34,39 +37,30 @@ const openAiShimSource = [
"}",
].join("\n");
registerHooks({
resolve(specifier, context, nextResolve) {
if (
specifier === "../../../extensions.js" ||
specifier === "../../../../extensions.js" ||
specifier === "../../../../../extensions.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(extensionsShimSource)}`,
};
}
if (
specifier === "../../../../script.js" ||
specifier === "../../../../../script.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(scriptShimSource)}`,
};
}
if (
specifier === "../../../openai.js" ||
specifier === "../../../../openai.js"
) {
return {
shortCircuit: true,
url: `data:text/javascript,${encodeURIComponent(openAiShimSource)}`,
};
}
return nextResolve(specifier, context);
installResolveHooks([
{
specifiers: [
"../../../extensions.js",
"../../../../extensions.js",
"../../../../../extensions.js",
],
url: toDataModuleUrl(extensionsShimSource),
},
});
{
specifiers: [
"../../../../script.js",
"../../../../../script.js",
],
url: toDataModuleUrl(scriptShimSource),
},
{
specifiers: [
"../../../openai.js",
"../../../../openai.js",
],
url: toDataModuleUrl(openAiShimSource),
},
]);
const { createEmptyGraph } = await import("../graph/graph.js");
const { appendSummaryEntry } = await import("../graph/summary-state.js");

View File

@@ -1,5 +1,7 @@
import assert from "node:assert/strict";
import { registerHooks } from "node:module";
import {
installResolveHooks,
} from "./helpers/register-hooks-compat.mjs";
const extensionsShimSource = [
"export const extension_settings = globalThis.__taskRegexTestExtensionSettings || {};",
@@ -11,21 +13,16 @@ const extensionsShimUrl = `data:text/javascript,${encodeURIComponent(
extensionsShimSource,
)}`;
registerHooks({
resolve(specifier, context, nextResolve) {
if (
specifier === "../../../extensions.js" ||
specifier === "../../../../extensions.js" ||
specifier === "../../../../../extensions.js"
) {
return {
shortCircuit: true,
url: extensionsShimUrl,
};
}
return nextResolve(specifier, context);
installResolveHooks([
{
specifiers: [
"../../../extensions.js",
"../../../../extensions.js",
"../../../../../extensions.js",
],
url: extensionsShimUrl,
},
});
]);
const originalSillyTavern = globalThis.SillyTavern;
const originalGetTavernRegexes = globalThis.getTavernRegexes;

View File

@@ -1,5 +1,7 @@
import assert from "node:assert/strict";
import { registerHooks } from "node:module";
import {
installResolveHooks,
} from "./helpers/register-hooks-compat.mjs";
const extensionsShimSource = [
"export const extension_settings = {};",
@@ -19,30 +21,23 @@ const scriptShimUrl = `data:text/javascript,${encodeURIComponent(
scriptShimSource,
)}`;
registerHooks({
resolve(specifier, context, nextResolve) {
if (
specifier === "../../../extensions.js" ||
specifier === "../../../../extensions.js" ||
specifier === "../../../../../extensions.js"
) {
return {
shortCircuit: true,
url: extensionsShimUrl,
};
}
if (
specifier === "../../../../script.js" ||
specifier === "../../../../../script.js"
) {
return {
shortCircuit: true,
url: scriptShimUrl,
};
}
return nextResolve(specifier, context);
installResolveHooks([
{
specifiers: [
"../../../extensions.js",
"../../../../extensions.js",
"../../../../../extensions.js",
],
url: extensionsShimUrl,
},
});
{
specifiers: [
"../../../../script.js",
"../../../../../script.js",
],
url: scriptShimUrl,
},
]);
const originalSillyTavern = globalThis.SillyTavern;
const originalEjsTemplate = globalThis.EjsTemplate;