mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-05-15 22:30:38 +08:00
317 lines
8.2 KiB
JavaScript
317 lines
8.2 KiB
JavaScript
import assert from "node:assert/strict";
|
|
|
|
import { executeExtractionBatchController } from "../maintenance/extraction-controller.js";
|
|
import {
|
|
createBatchStatusSkeleton,
|
|
finalizeBatchStatus,
|
|
setBatchStageOutcome,
|
|
} from "../ui/ui-status.js";
|
|
|
|
function createRuntime(persistResult) {
|
|
const graph = {
|
|
nodes: [],
|
|
edges: [],
|
|
historyState: {},
|
|
batchJournal: [],
|
|
};
|
|
let processedHistoryUpdates = 0;
|
|
let persistedGraphSnapshot = null;
|
|
let lastPersistDeltaOptions = null;
|
|
|
|
return {
|
|
graph,
|
|
processedHistoryUpdates,
|
|
persistedGraphSnapshot,
|
|
ensureCurrentGraphRuntimeState() {},
|
|
throwIfAborted() {},
|
|
getCurrentGraph() {
|
|
return graph;
|
|
},
|
|
getLastProcessedAssistantFloor() {
|
|
return 4;
|
|
},
|
|
getExtractionCount() {
|
|
return 6;
|
|
},
|
|
cloneGraphSnapshot(value) {
|
|
return JSON.parse(JSON.stringify(value));
|
|
},
|
|
buildPersistDelta(_beforeSnapshot, _afterSnapshot, options = {}) {
|
|
lastPersistDeltaOptions = { ...(options || {}) };
|
|
return {
|
|
upsertNodes: [],
|
|
upsertEdges: [],
|
|
deleteNodeIds: [],
|
|
deleteEdgeIds: [],
|
|
tombstones: [],
|
|
countDelta: {
|
|
nodes: 0,
|
|
edges: 0,
|
|
tombstones: 0,
|
|
},
|
|
runtimeMetaPatch: {},
|
|
};
|
|
},
|
|
buildExtractionMessages() {
|
|
return [{ seq: 5, role: "assistant", content: "测试消息" }];
|
|
},
|
|
createBatchStatusSkeleton,
|
|
async extractMemories() {
|
|
return {
|
|
success: true,
|
|
newNodes: 1,
|
|
updatedNodes: 0,
|
|
newEdges: 0,
|
|
newNodeIds: ["node-1"],
|
|
processedRange: [5, 5],
|
|
};
|
|
},
|
|
getSchema() {
|
|
return [];
|
|
},
|
|
getEmbeddingConfig() {
|
|
return null;
|
|
},
|
|
setLastExtractionStatus() {},
|
|
setBatchStageOutcome,
|
|
async handleExtractionSuccess(result, _endIdx, _settings, _signal, batchStatus) {
|
|
setBatchStageOutcome(batchStatus, "finalize", "success");
|
|
return {
|
|
postProcessArtifacts: [],
|
|
vectorHashesInserted: [],
|
|
warnings: [],
|
|
batchStatus,
|
|
};
|
|
},
|
|
async persistExtractionBatchResult() {
|
|
persistedGraphSnapshot = arguments[0]?.graphSnapshot || null;
|
|
return persistResult;
|
|
},
|
|
finalizeBatchStatus,
|
|
shouldAdvanceProcessedHistory(batchStatus) {
|
|
return batchStatus.historyAdvanceAllowed === true;
|
|
},
|
|
updateProcessedHistorySnapshot() {
|
|
processedHistoryUpdates += 1;
|
|
},
|
|
appendBatchJournal(targetGraph, entry) {
|
|
if (!targetGraph.batchJournal) targetGraph.batchJournal = [];
|
|
targetGraph.batchJournal.push(entry);
|
|
},
|
|
createBatchJournalEntry() {
|
|
return { id: "journal-1", processedRange: [5, 5] };
|
|
},
|
|
computePostProcessArtifacts() {
|
|
return [];
|
|
},
|
|
applyProcessedHistorySnapshotToGraph(targetGraph, _chat, floor) {
|
|
targetGraph.historyState.lastProcessedAssistantFloor = floor;
|
|
targetGraph.lastProcessedSeq = floor;
|
|
},
|
|
getGraphPersistenceState() {
|
|
return { chatId: "chat-test" };
|
|
},
|
|
console,
|
|
get processedHistoryUpdates() {
|
|
return processedHistoryUpdates;
|
|
},
|
|
get persistedGraphSnapshot() {
|
|
return persistedGraphSnapshot;
|
|
},
|
|
get lastPersistDeltaOptions() {
|
|
return lastPersistDeltaOptions;
|
|
},
|
|
};
|
|
}
|
|
|
|
{
|
|
const runtime = createRuntime({
|
|
saved: false,
|
|
queued: true,
|
|
blocked: true,
|
|
accepted: false,
|
|
reason: "persist-queued",
|
|
revision: 7,
|
|
saveMode: "immediate",
|
|
storageTier: "none",
|
|
});
|
|
const result = await executeExtractionBatchController(runtime, {
|
|
chat: [{ is_user: false, mes: "测试" }],
|
|
startIdx: 5,
|
|
endIdx: 5,
|
|
settings: {},
|
|
});
|
|
|
|
assert.equal(result.success, true);
|
|
assert.equal(result.historyAdvanceAllowed, false);
|
|
assert.equal(runtime.processedHistoryUpdates, 0);
|
|
assert.equal(
|
|
runtime.graph.historyState.lastBatchStatus.persistence.outcome,
|
|
"queued",
|
|
);
|
|
assert.equal(
|
|
runtime.graph.historyState.lastBatchStatus.historyAdvanceAllowed,
|
|
false,
|
|
);
|
|
assert.equal(
|
|
runtime.persistedGraphSnapshot?.historyState?.lastProcessedAssistantFloor,
|
|
5,
|
|
);
|
|
assert.equal(
|
|
runtime.persistedGraphSnapshot?.batchJournal?.length,
|
|
1,
|
|
);
|
|
}
|
|
|
|
{
|
|
const runtime = createRuntime({
|
|
saved: true,
|
|
queued: false,
|
|
blocked: false,
|
|
accepted: true,
|
|
reason: "indexeddb",
|
|
revision: 8,
|
|
saveMode: "indexeddb",
|
|
storageTier: "indexeddb",
|
|
});
|
|
const result = await executeExtractionBatchController(runtime, {
|
|
chat: [{ is_user: false, mes: "测试" }],
|
|
startIdx: 5,
|
|
endIdx: 5,
|
|
settings: {},
|
|
});
|
|
|
|
assert.equal(result.success, true);
|
|
assert.equal(result.historyAdvanceAllowed, true);
|
|
assert.equal(runtime.processedHistoryUpdates, 1);
|
|
assert.equal(
|
|
runtime.graph.historyState.lastBatchStatus.persistence.outcome,
|
|
"saved",
|
|
);
|
|
assert.equal(
|
|
runtime.graph.historyState.lastBatchStatus.historyAdvanceAllowed,
|
|
true,
|
|
);
|
|
assert.equal(
|
|
runtime.persistedGraphSnapshot?.historyState?.lastProcessedAssistantFloor,
|
|
5,
|
|
);
|
|
assert.equal(
|
|
runtime.persistedGraphSnapshot?.batchJournal?.length,
|
|
1,
|
|
);
|
|
}
|
|
|
|
{
|
|
const runtime = createRuntime({
|
|
saved: false,
|
|
queued: false,
|
|
blocked: false,
|
|
accepted: false,
|
|
reason: "should-not-run",
|
|
revision: 0,
|
|
saveMode: "",
|
|
storageTier: "none",
|
|
});
|
|
runtime.extractMemories = async () => ({
|
|
success: false,
|
|
error: "提取 LLM 未返回有效操作",
|
|
processedRange: [4, 4],
|
|
});
|
|
const result = await executeExtractionBatchController(runtime, {
|
|
chat: [{ is_user: false, mes: "测试" }],
|
|
startIdx: 5,
|
|
endIdx: 5,
|
|
settings: {},
|
|
});
|
|
|
|
assert.equal(result.success, false);
|
|
assert.equal(result.batchStatus.completed, false);
|
|
assert.equal(result.batchStatus.stages.core.outcome, "failed");
|
|
assert.equal(result.batchStatus.stages.finalize.outcome, "failed");
|
|
assert.equal(runtime.graph.historyState.lastBatchStatus.persistence, null);
|
|
}
|
|
|
|
{
|
|
const originalNativeBuilder = globalThis.__stBmeNativeBuildPersistDelta;
|
|
globalThis.__stBmeNativeBuildPersistDelta = () => ({
|
|
upsertNodes: [],
|
|
upsertEdges: [],
|
|
deleteNodeIds: [],
|
|
deleteEdgeIds: [],
|
|
tombstones: [],
|
|
runtimeMetaPatch: {},
|
|
});
|
|
const runtime = createRuntime({
|
|
saved: true,
|
|
queued: false,
|
|
blocked: false,
|
|
accepted: true,
|
|
reason: "indexeddb",
|
|
revision: 9,
|
|
saveMode: "indexeddb",
|
|
storageTier: "indexeddb",
|
|
});
|
|
const result = await executeExtractionBatchController(runtime, {
|
|
chat: [{ is_user: false, mes: "测试" }],
|
|
startIdx: 5,
|
|
endIdx: 5,
|
|
settings: {
|
|
persistUseNativeDelta: true,
|
|
graphNativeForceDisable: false,
|
|
nativeEngineFailOpen: true,
|
|
persistNativeDeltaThresholdRecords: 123,
|
|
persistNativeDeltaThresholdStructuralDelta: 45,
|
|
persistNativeDeltaThresholdSerializedChars: 6789,
|
|
persistNativeDeltaBridgeMode: "hash",
|
|
},
|
|
});
|
|
|
|
assert.equal(result.success, true);
|
|
assert.equal(runtime.lastPersistDeltaOptions.useNativeDelta, true);
|
|
assert.equal(runtime.lastPersistDeltaOptions.nativeFailOpen, true);
|
|
assert.equal(runtime.lastPersistDeltaOptions.persistNativeDeltaThresholdRecords, 123);
|
|
assert.equal(
|
|
runtime.lastPersistDeltaOptions.persistNativeDeltaThresholdStructuralDelta,
|
|
45,
|
|
);
|
|
assert.equal(
|
|
runtime.lastPersistDeltaOptions.persistNativeDeltaThresholdSerializedChars,
|
|
6789,
|
|
);
|
|
assert.equal(runtime.lastPersistDeltaOptions.persistNativeDeltaBridgeMode, "hash");
|
|
|
|
if (typeof originalNativeBuilder === "function") {
|
|
globalThis.__stBmeNativeBuildPersistDelta = originalNativeBuilder;
|
|
} else {
|
|
delete globalThis.__stBmeNativeBuildPersistDelta;
|
|
}
|
|
}
|
|
|
|
{
|
|
const runtime = createRuntime({
|
|
saved: true,
|
|
queued: false,
|
|
blocked: false,
|
|
accepted: true,
|
|
reason: "indexeddb",
|
|
revision: 10,
|
|
saveMode: "indexeddb",
|
|
storageTier: "indexeddb",
|
|
});
|
|
const result = await executeExtractionBatchController(runtime, {
|
|
chat: [{ is_user: false, mes: "测试" }],
|
|
startIdx: 5,
|
|
endIdx: 5,
|
|
settings: {
|
|
persistUseNativeDelta: true,
|
|
graphNativeForceDisable: true,
|
|
},
|
|
});
|
|
|
|
assert.equal(result.success, true);
|
|
assert.equal(runtime.lastPersistDeltaOptions.useNativeDelta, false);
|
|
}
|
|
|
|
console.log("extraction-persistence-gating tests passed");
|