mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-05-15 22:30:38 +08:00
fix: delay automatic summary rollup until above threshold
This commit is contained in:
@@ -483,7 +483,8 @@ function buildRollupCandidateText(entries = []) {
|
||||
.join("\n");
|
||||
}
|
||||
|
||||
function getFoldableSummaryGroup(graph, fanIn = 3) {
|
||||
function getFoldableSummaryGroup(graph, fanIn = 3, options = {}) {
|
||||
const requireExcess = options?.requireExcess === true;
|
||||
const activeEntries = getActiveSummaryEntries(graph);
|
||||
const byLevel = new Map();
|
||||
for (const entry of activeEntries) {
|
||||
@@ -495,7 +496,7 @@ function getFoldableSummaryGroup(graph, fanIn = 3) {
|
||||
const sortedLevels = [...byLevel.keys()].sort((left, right) => left - right);
|
||||
for (const level of sortedLevels) {
|
||||
const entries = byLevel.get(level) || [];
|
||||
if (entries.length >= fanIn) {
|
||||
if (requireExcess ? entries.length > fanIn : entries.length >= fanIn) {
|
||||
return entries.slice(0, fanIn);
|
||||
}
|
||||
}
|
||||
@@ -510,12 +511,15 @@ export async function rollupSummaryFrontier({
|
||||
} = {}) {
|
||||
normalizeGraphSummaryState(graph);
|
||||
const fanIn = clampInt(settings.summaryRollupFanIn, 3, 2, 10);
|
||||
const requireExcess = force !== true;
|
||||
const createdEntries = [];
|
||||
let foldedCount = 0;
|
||||
|
||||
while (true) {
|
||||
throwIfAborted(signal);
|
||||
const candidates = getFoldableSummaryGroup(graph, fanIn);
|
||||
const candidates = getFoldableSummaryGroup(graph, fanIn, {
|
||||
requireExcess,
|
||||
});
|
||||
if (candidates.length < fanIn) {
|
||||
break;
|
||||
}
|
||||
@@ -616,7 +620,9 @@ export async function rollupSummaryFrontier({
|
||||
skipped: createdEntries.length === 0,
|
||||
reason:
|
||||
createdEntries.length === 0
|
||||
? `当前没有达到 ${fanIn} 条同层活跃总结的折叠候选`
|
||||
? requireExcess
|
||||
? `当前没有超过 ${fanIn} 条同层活跃总结的折叠候选`
|
||||
: `当前没有达到 ${fanIn} 条同层活跃总结的折叠候选`
|
||||
: "",
|
||||
};
|
||||
}
|
||||
|
||||
115
tests/summary-rollup-threshold.mjs
Normal file
115
tests/summary-rollup-threshold.mjs
Normal file
@@ -0,0 +1,115 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { registerHooks } from "node:module";
|
||||
|
||||
const extensionsShimSource = [
|
||||
"export const extension_settings = {};",
|
||||
"export function getContext() {",
|
||||
" return {",
|
||||
" chat: [],",
|
||||
" chatMetadata: {},",
|
||||
" extensionSettings: {},",
|
||||
" powerUserSettings: {},",
|
||||
" characters: {},",
|
||||
" characterId: null,",
|
||||
" name1: '',",
|
||||
" name2: '',",
|
||||
" chatId: 'test-chat',",
|
||||
" };",
|
||||
"}",
|
||||
].join("\n");
|
||||
|
||||
const scriptShimSource = [
|
||||
"export function substituteParamsExtended(value) {",
|
||||
" return String(value ?? '');",
|
||||
"}",
|
||||
"export function getRequestHeaders() {",
|
||||
" return {};",
|
||||
"}",
|
||||
].join("\n");
|
||||
|
||||
const openAiShimSource = [
|
||||
"export const chat_completion_sources = { OPENAI: 'openai' };",
|
||||
"export async function sendOpenAIRequest() {",
|
||||
" throw new Error('sendOpenAIRequest should not be called in summary-rollup-threshold test');",
|
||||
"}",
|
||||
].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);
|
||||
},
|
||||
});
|
||||
|
||||
const { createEmptyGraph } = await import("../graph/graph.js");
|
||||
const { appendSummaryEntry } = await import("../graph/summary-state.js");
|
||||
const { rollupSummaryFrontier } = await import("../maintenance/hierarchical-summary.js");
|
||||
|
||||
const graph = createEmptyGraph();
|
||||
|
||||
appendSummaryEntry(graph, {
|
||||
id: "summary-a",
|
||||
level: 0,
|
||||
kind: "small",
|
||||
text: "第一条小总结",
|
||||
messageRange: [1, 2],
|
||||
extractionRange: [1, 1],
|
||||
});
|
||||
appendSummaryEntry(graph, {
|
||||
id: "summary-b",
|
||||
level: 0,
|
||||
kind: "small",
|
||||
text: "第二条小总结",
|
||||
messageRange: [3, 4],
|
||||
extractionRange: [2, 2],
|
||||
});
|
||||
appendSummaryEntry(graph, {
|
||||
id: "summary-c",
|
||||
level: 0,
|
||||
kind: "small",
|
||||
text: "第三条小总结",
|
||||
messageRange: [5, 6],
|
||||
extractionRange: [3, 3],
|
||||
});
|
||||
|
||||
const result = await rollupSummaryFrontier({
|
||||
graph,
|
||||
settings: {
|
||||
summaryRollupFanIn: 3,
|
||||
},
|
||||
force: false,
|
||||
});
|
||||
|
||||
assert.equal(result.createdCount, 0);
|
||||
assert.equal(result.foldedCount, 0);
|
||||
assert.equal(result.skipped, true);
|
||||
assert.match(String(result.reason || ""), /超过 3 条同层活跃总结/);
|
||||
|
||||
console.log("summary-rollup-threshold tests passed");
|
||||
Reference in New Issue
Block a user