mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-05-15 14:20:35 +08:00
fix: auto-repair malformed memory scope regions
This commit is contained in:
@@ -92,6 +92,7 @@ import {
|
||||
} from "../retrieval/recall-persistence.js";
|
||||
import { getNodeDisplayName } from "../graph/node-labels.js";
|
||||
import {
|
||||
hasGraphPersistDirtyState,
|
||||
normalizeGraphRuntimeState,
|
||||
pruneGraphPersistDirtyState,
|
||||
} from "../runtime/runtime-state.js";
|
||||
@@ -1041,6 +1042,7 @@ async function createGraphPersistenceHarness({
|
||||
buildSnapshotFromGraph,
|
||||
evaluateNativeHydrateGate,
|
||||
evaluatePersistNativeDeltaGate,
|
||||
hasGraphPersistDirtyState,
|
||||
pruneGraphPersistDirtyState,
|
||||
buildBmeDbName,
|
||||
BME_GRAPH_LOCAL_STORAGE_MODE_AUTO: "auto",
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
} from "../sync/bme-db.js";
|
||||
import { BmeChatManager } from "../sync/bme-chat-manager.js";
|
||||
import { createEmptyGraph } from "../graph/graph.js";
|
||||
import { getGraphPersistDirtyStateSnapshot } from "../runtime/runtime-state.js";
|
||||
|
||||
const PREFIX = "[ST-BME][indexeddb-persistence]";
|
||||
|
||||
@@ -744,6 +745,29 @@ async function testGraphSnapshotConverters() {
|
||||
const rebuiltMalformedButFlagged = buildGraphFromSnapshot(malformedButFlaggedSnapshot, {
|
||||
chatId: "chat-a",
|
||||
});
|
||||
const scopeRepairSnapshot = {
|
||||
...snapshot,
|
||||
meta: {
|
||||
...snapshot.meta,
|
||||
},
|
||||
nodes: [
|
||||
{
|
||||
...snapshot.nodes[0],
|
||||
scope: {
|
||||
layer: "objective",
|
||||
regionPrimary: "王都/钟楼",
|
||||
regionSecondary: "旧城区 / 集市 / 钟楼",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
delete scopeRepairSnapshot.meta[BME_RUNTIME_RECORDS_NORMALIZED_META_KEY];
|
||||
const rebuiltScopeRepair = buildGraphFromSnapshot(scopeRepairSnapshot, {
|
||||
chatId: "chat-a",
|
||||
});
|
||||
const scopeRepairDirtyState = getGraphPersistDirtyStateSnapshot(
|
||||
rebuiltScopeRepair,
|
||||
);
|
||||
assert.equal(rebuilt.historyState.lastProcessedAssistantFloor, 9);
|
||||
assert.equal(rebuilt.historyState.extractionCount, 4);
|
||||
assert.equal(rebuilt.nodes.length, 1);
|
||||
@@ -764,6 +788,23 @@ async function testGraphSnapshotConverters() {
|
||||
assert.equal(rebuiltMalformedButFlagged.nodes[0].scope?.layer, "objective");
|
||||
assert.equal(rebuiltMalformedButFlagged.nodes[0].storyTime?.tense, "unknown");
|
||||
assert.equal(rebuiltMalformedButFlagged.nodes[0].storyTimeSpan?.mixed, false);
|
||||
assert.equal(rebuiltScopeRepair.nodes[0].scope?.regionPrimary, "钟楼");
|
||||
assert.deepEqual(rebuiltScopeRepair.nodes[0].scope?.regionPath, ["王都", "钟楼"]);
|
||||
assert.deepEqual(rebuiltScopeRepair.nodes[0].scope?.regionSecondary, [
|
||||
"旧城区",
|
||||
"集市",
|
||||
]);
|
||||
assert.equal(
|
||||
scopeRepairDirtyState?.nodeUpsertIds?.includes("node-converter"),
|
||||
true,
|
||||
);
|
||||
assert.equal(rebuiltScopeRepair.vectorIndexState?.dirty, true);
|
||||
assert.equal(
|
||||
rebuiltScopeRepair.vectorIndexState?.replayRequiredNodeIds?.includes(
|
||||
"node-converter",
|
||||
),
|
||||
true,
|
||||
);
|
||||
|
||||
rebuilt.nodes[0].fields.title = "Mutated Converter Node";
|
||||
rebuilt.nodes[0].embedding[0] = 99;
|
||||
|
||||
@@ -8,7 +8,11 @@ import {
|
||||
findLatestNode,
|
||||
serializeGraph,
|
||||
} from "../graph/graph.js";
|
||||
import { normalizeMemoryScope } from "../graph/memory-scope.js";
|
||||
import {
|
||||
buildRegionLine,
|
||||
getScopeRegionTokens,
|
||||
normalizeMemoryScope,
|
||||
} from "../graph/memory-scope.js";
|
||||
import {
|
||||
normalizeStoryTime,
|
||||
normalizeStoryTimeSpan,
|
||||
@@ -73,6 +77,61 @@ assert.equal(
|
||||
"已规范的 scope 对象应直接复用",
|
||||
);
|
||||
|
||||
const malformedSecondaryScope = normalizeMemoryScope({
|
||||
layer: "objective",
|
||||
regionPrimary: "王都/钟楼",
|
||||
regionSecondary: "旧城区, 集市 / 下水道 / 钟楼",
|
||||
});
|
||||
assert.equal(malformedSecondaryScope.regionPrimary, "钟楼");
|
||||
assert.deepEqual(malformedSecondaryScope.regionPath, ["王都", "钟楼"]);
|
||||
assert.deepEqual(malformedSecondaryScope.regionSecondary, [
|
||||
"旧城区",
|
||||
"集市",
|
||||
"下水道",
|
||||
]);
|
||||
assert.deepEqual(getScopeRegionTokens(malformedSecondaryScope), [
|
||||
"钟楼",
|
||||
"王都",
|
||||
"旧城区",
|
||||
"集市",
|
||||
"下水道",
|
||||
]);
|
||||
assert.match(buildRegionLine(malformedSecondaryScope), /次级地区/);
|
||||
|
||||
const accessorBackedScope = {};
|
||||
Object.defineProperty(accessorBackedScope, "layer", {
|
||||
get() {
|
||||
return "objective";
|
||||
},
|
||||
enumerable: true,
|
||||
});
|
||||
Object.defineProperty(accessorBackedScope, "regionPrimary", {
|
||||
get() {
|
||||
return "钟楼";
|
||||
},
|
||||
enumerable: true,
|
||||
});
|
||||
Object.defineProperty(accessorBackedScope, "regionPath", {
|
||||
get() {
|
||||
return "王都 > 钟楼";
|
||||
},
|
||||
enumerable: true,
|
||||
});
|
||||
Object.defineProperty(accessorBackedScope, "regionSecondary", {
|
||||
get() {
|
||||
return { label: "旧城区 / 集市" };
|
||||
},
|
||||
enumerable: true,
|
||||
});
|
||||
const normalizedAccessorScope = normalizeMemoryScope(accessorBackedScope);
|
||||
assert.notEqual(
|
||||
normalizedAccessorScope,
|
||||
accessorBackedScope,
|
||||
"带 accessor 的 scope 不应复用原对象",
|
||||
);
|
||||
assert.deepEqual(normalizedAccessorScope.regionPath, ["王都", "钟楼"]);
|
||||
assert.deepEqual(normalizedAccessorScope.regionSecondary, ["旧城区", "集市"]);
|
||||
|
||||
const normalizedStoryTime = {
|
||||
segmentId: "tl-1",
|
||||
label: "第二天清晨",
|
||||
|
||||
Reference in New Issue
Block a user