Merge pull request #312 from Tencent-Hunyuan/fix/memory-mode-confirm-copy
fix(memhub): clarify memory mode switch effects
This commit is contained in:
6 files changed
+96
-46
No files matched your search
@@ -1,5 +1,6 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { legacyMemoryModePlan } from "@one-memory/operations";
|
||||
import {
|
||||
cleanup,
|
||||
render,
|
||||
@@ -64,31 +65,9 @@ function prepare(mode: "lite" | "pro" | "ultra" = "pro") {
|
||||
running: [],
|
||||
});
|
||||
vi.mocked(getMemoryProcessing).mockResolvedValue({} as never);
|
||||
vi.mocked(planMemoryMode).mockImplementation(async (target) => ({
|
||||
current: mode,
|
||||
target,
|
||||
effective_target: target,
|
||||
capabilities: {
|
||||
content_plane: target === "lite" ? "raw" : "memory",
|
||||
generation_required: target !== "lite",
|
||||
graph_enabled: target === "ultra",
|
||||
evolve_available: target === "ultra",
|
||||
},
|
||||
effects: [
|
||||
...(target === "lite" ? (["higher_mode_memories_hidden"] as const) : []),
|
||||
...(mode === "lite" && target !== "lite"
|
||||
? (["earlier_raw_not_extracted", "lite_search_stops"] as const)
|
||||
: []),
|
||||
...(target === "ultra" && mode !== "ultra"
|
||||
? (["existing_memories_added_to_graph"] as const)
|
||||
: []),
|
||||
...(mode === "ultra" && target !== "ultra"
|
||||
? (["evolve_stopped"] as const)
|
||||
: []),
|
||||
],
|
||||
warnings: [],
|
||||
blockers: [],
|
||||
}));
|
||||
vi.mocked(planMemoryMode).mockImplementation(async (target) =>
|
||||
legacyMemoryModePlan(mode, target, { hasActiveModel: true }),
|
||||
);
|
||||
}
|
||||
|
||||
async function chooseMode(
|
||||
@@ -227,6 +206,20 @@ it("uses the isolated legacy plan only for a route-level old-Core 404", async ()
|
||||
expect(await screen.findByText(/已有记忆继续保留/)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("keeps downgrade effects when an old Core falls back from ultra to pro", async () => {
|
||||
prepare("ultra");
|
||||
vi.mocked(planMemoryMode).mockRejectedValue(new Error("404"));
|
||||
vi.mocked(memoryModePlanUnsupported).mockReturnValue(true);
|
||||
const user = userEvent.setup();
|
||||
render(<MemoryModeSettings hasActiveModel onConfigureModel={vi.fn()} />);
|
||||
|
||||
await chooseMode(user, /智能记忆(pro)/);
|
||||
|
||||
const dialog = screen.getByRole("dialog");
|
||||
expect(within(dialog).getAllByText("已有数据")).toHaveLength(1);
|
||||
expect(within(dialog).getByText("每天自动整合")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("explains model cost, search scope and the next step before switching to ultra", async () => {
|
||||
prepare("lite");
|
||||
const user = userEvent.setup();
|
||||
@@ -238,6 +231,8 @@ it("explains model cost, search scope and the next step before switching to ultr
|
||||
expect(screen.getByText("搜索范围")).toBeTruthy();
|
||||
expect(screen.getByText("切换后")).toBeTruthy();
|
||||
expect(screen.getByText(/已经处理完的旧对话不会补做/)).toBeTruthy();
|
||||
expect(screen.getByText("知识图谱")).toBeTruthy();
|
||||
expect(screen.getAllByText("已有数据")).toHaveLength(1);
|
||||
expect(screen.getByText(/切换本身不会立即整合/)).toBeTruthy();
|
||||
});
|
||||
|
||||
@@ -248,9 +243,27 @@ it("distinguishes regular memories from higher-level Ultra data when switching t
|
||||
|
||||
await chooseMode(user, /智能记忆(pro)/);
|
||||
|
||||
expect(screen.getByText(/普通沉淀记忆仍可使用/)).toBeTruthy();
|
||||
expect(screen.getByText(/更高层记忆和图谱数据继续保留/)).toBeTruthy();
|
||||
expect(screen.getByText(/每天自动整合会停止/)).toBeTruthy();
|
||||
const dialog = screen.getByRole("dialog");
|
||||
expect(within(dialog).getAllByText("已有数据")).toHaveLength(1);
|
||||
expect(within(dialog).getByText(/普通沉淀记忆仍可使用/)).toBeTruthy();
|
||||
expect(within(dialog).getByText(/更高层记忆和图谱数据继续保留/)).toBeTruthy();
|
||||
expect(within(dialog).getByText("每天自动整合")).toBeTruthy();
|
||||
expect(
|
||||
within(dialog).getByText("每天自动整合会停止;已生成的整合结果继续保留。"),
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it("does not show automatic consolidation when switching from lite to pro", async () => {
|
||||
prepare("lite");
|
||||
const user = userEvent.setup();
|
||||
render(<MemoryModeSettings hasActiveModel onConfigureModel={vi.fn()} />);
|
||||
|
||||
await chooseMode(user, /智能记忆(pro)/);
|
||||
|
||||
const dialog = screen.getByRole("dialog");
|
||||
expect(within(dialog).getAllByText("已有数据")).toHaveLength(1);
|
||||
expect(within(dialog).getByText(/已经处理完的旧对话不会补做/)).toBeTruthy();
|
||||
expect(within(dialog).queryByText("每天自动整合")).toBeNull();
|
||||
});
|
||||
|
||||
it("focuses the Evolve settings after switching to ultra", async () => {
|
||||
|
||||
@@ -85,18 +85,20 @@ function planRows(plan: MemoryModePlan) {
|
||||
if (plan.effects.includes("higher_mode_memories_hidden"))
|
||||
rows.push({
|
||||
label: "已有数据",
|
||||
content: "已有记忆继续保留,但高级记忆在当前模式下不显示、不参与召回。",
|
||||
content:
|
||||
plan.effective_target === "pro"
|
||||
? "普通沉淀记忆仍可使用;深度记忆新增的更高层记忆和图谱数据继续保留,但在智能记忆下不显示、不参与召回。原始对话不会删除。"
|
||||
: "已有记忆继续保留,但在基础记忆下不显示、不参与召回;原始对话不会删除。",
|
||||
});
|
||||
if (plan.effects.includes("existing_memories_added_to_graph"))
|
||||
rows.push({
|
||||
label: "已有数据",
|
||||
label: "知识图谱",
|
||||
content: "已有记忆会在后台加入知识图谱,期间仍可使用。",
|
||||
});
|
||||
if (plan.effects.includes("evolve_stopped"))
|
||||
rows.push({
|
||||
label: "已有数据",
|
||||
content:
|
||||
"普通沉淀记忆仍可使用;更高层记忆和图谱数据继续保留,但不参与当前召回;每天自动整合会停止。",
|
||||
label: "每天自动整合",
|
||||
content: "每天自动整合会停止,已经生成的数据不会删除。",
|
||||
});
|
||||
if (plan.capabilities.evolve_available)
|
||||
rows.push({
|
||||
|
||||
@@ -275,9 +275,10 @@ describe("Mode catalog", () => {
|
||||
"搜索沉淀记忆,并用知识图谱补充关联。",
|
||||
"搜索沉淀后的记忆。",
|
||||
"已经处理完的旧对话不会补做;原始对话全部保留。",
|
||||
"已有记忆继续保留,但高级记忆在当前模式下不显示、不参与召回。",
|
||||
"知识图谱",
|
||||
"普通沉淀记忆仍可使用;深度记忆新增的更高层记忆和图谱数据继续保留,但在智能记忆下不显示、不参与召回。原始对话不会删除。",
|
||||
"已有记忆会在后台加入知识图谱,期间仍可使用。",
|
||||
"普通沉淀记忆仍可使用;更高层记忆和图谱数据继续保留,但不参与当前召回;每天自动整合会停止。",
|
||||
"每天自动整合会停止,已经生成的数据不会删除。",
|
||||
"记忆维护正在进行,完成后才能切换模式。",
|
||||
"模式切换影响暂时无法读取,请重试。",
|
||||
] as const;
|
||||
|
||||
@@ -47,7 +47,7 @@ const modeChineseMessages = {
|
||||
"以前生成的高级记忆会继续保留,但在 lite 下不会显示或参与记忆召回。":
|
||||
"高级记忆会保留,但在 lite 下不显示、不参与召回。",
|
||||
"每天自动整合会停止,已经生成的数据不会删除。":
|
||||
"自动整合会停止,已有数据保留。",
|
||||
"每天自动整合会停止;已生成的整合结果继续保留。",
|
||||
"已有高级记忆会在后台加入知识图谱,期间可以继续使用 MemHub。":
|
||||
"已有高级记忆将在后台加入知识图谱。",
|
||||
"知识图谱仍在补建,不会重复启动。": "知识图谱仍在补建,不会重复启动。",
|
||||
@@ -97,6 +97,7 @@ const modeChineseMessages = {
|
||||
模型调用与费用: "模型调用与费用",
|
||||
搜索范围: "搜索范围",
|
||||
已有数据: "已有数据",
|
||||
知识图谱: "知识图谱",
|
||||
切换后: "切换后",
|
||||
"之后只保存原始对话,不再生成新记忆。":
|
||||
"之后只保存原始对话,不再生成新记忆。",
|
||||
@@ -295,6 +296,7 @@ export const modeEnglishMessages: ModeMessages = {
|
||||
模型调用与费用: "Model calls and cost",
|
||||
搜索范围: "Search scope",
|
||||
已有数据: "Existing data",
|
||||
知识图谱: "Knowledge graph",
|
||||
切换后: "After switching",
|
||||
"之后只保存原始对话,不再生成新记忆。":
|
||||
"New conversations are saved as original text only; no new memories are created.",
|
||||
@@ -498,6 +500,7 @@ export const modeSpanishMessages: ModeMessages = {
|
||||
模型调用与费用: "Llamadas al modelo y coste",
|
||||
搜索范围: "Ámbito de búsqueda",
|
||||
已有数据: "Datos existentes",
|
||||
知识图谱: "Grafo de conocimiento",
|
||||
切换后: "Después del cambio",
|
||||
"之后只保存原始对话,不再生成新记忆。":
|
||||
"Las conversaciones nuevas se guardan solo como texto original; no se crean memorias nuevas.",
|
||||
@@ -693,6 +696,7 @@ export const modeTraditionalChineseMessages: ModeMessages = {
|
||||
模型调用与费用: "模型呼叫與費用",
|
||||
搜索范围: "搜尋範圍",
|
||||
已有数据: "現有資料",
|
||||
知识图谱: "知識圖譜",
|
||||
切换后: "切換後",
|
||||
"之后只保存原始对话,不再生成新记忆。":
|
||||
"之後只儲存原始對話,不再產生新記憶。",
|
||||
@@ -843,6 +847,7 @@ export const modeJapaneseMessages: ModeMessages = {
|
||||
模型调用与费用: "モデル呼び出しと料金",
|
||||
搜索范围: "検索範囲",
|
||||
已有数据: "既存データ",
|
||||
知识图谱: "ナレッジグラフ",
|
||||
切换后: "切り替え後",
|
||||
"之后只保存原始对话,不再生成新记忆。":
|
||||
"以降は元の会話のみを保存し、新しい記憶は生成しません。",
|
||||
@@ -1043,6 +1048,7 @@ export const modeGermanMessages: ModeMessages = {
|
||||
模型调用与费用: "Modellaufrufe und Kosten",
|
||||
搜索范围: "Suchbereich",
|
||||
已有数据: "Vorhandene Daten",
|
||||
知识图谱: "Wissensgraph",
|
||||
切换后: "Nach dem Wechsel",
|
||||
"之后只保存原始对话,不再生成新记忆。":
|
||||
"Neue Unterhaltungen werden nur noch im Original gespeichert; es werden keine neuen Erinnerungen erstellt.",
|
||||
@@ -1246,6 +1252,7 @@ export const modePortugueseMessages: ModeMessages = {
|
||||
模型调用与费用: "Chamadas ao modelo e custos",
|
||||
搜索范围: "Âmbito da pesquisa",
|
||||
已有数据: "Dados existentes",
|
||||
知识图谱: "Grafo de conhecimento",
|
||||
切换后: "Após a mudança",
|
||||
"之后只保存原始对话,不再生成新记忆。":
|
||||
"As novas conversas passam a ser guardadas apenas como texto original; não são criadas novas memórias.",
|
||||
@@ -1451,6 +1458,7 @@ export const modeFrenchMessages: ModeMessages = {
|
||||
模型调用与费用: "Appels au modèle et coût",
|
||||
搜索范围: "Périmètre de recherche",
|
||||
已有数据: "Données existantes",
|
||||
知识图谱: "Graphe de connaissances",
|
||||
切换后: "Après le changement",
|
||||
"之后只保存原始对话,不再生成新记忆。":
|
||||
"Les nouvelles conversations sont uniquement enregistrées dans leur forme originale ; aucune nouvelle mémoire n’est créée.",
|
||||
@@ -1651,6 +1659,7 @@ export const modeKoreanMessages: ModeMessages = {
|
||||
模型调用与费用: "모델 호출 및 비용",
|
||||
搜索范围: "검색 범위",
|
||||
已有数据: "기존 데이터",
|
||||
知识图谱: "지식 그래프",
|
||||
切换后: "전환 후",
|
||||
"之后只保存原始对话,不再生成新记忆。":
|
||||
"이후 새 대화는 원본만 저장되며 새 메모리는 생성되지 않습니다.",
|
||||
@@ -1850,6 +1859,7 @@ export const modeRussianMessages: ModeMessages = {
|
||||
模型调用与费用: "Вызовы модели и расходы",
|
||||
搜索范围: "Область поиска",
|
||||
已有数据: "Существующие данные",
|
||||
知识图谱: "Граф знаний",
|
||||
切换后: "После переключения",
|
||||
"之后只保存原始对话,不再生成新记忆。":
|
||||
"Новые диалоги будут сохраняться только в исходном виде; новые воспоминания создаваться не будут.",
|
||||
@@ -2052,6 +2062,7 @@ export const modeIndonesianMessages: ModeMessages = {
|
||||
模型调用与费用: "Panggilan model dan biaya",
|
||||
搜索范围: "Cakupan pencarian",
|
||||
已有数据: "Data yang ada",
|
||||
知识图谱: "Graf pengetahuan",
|
||||
切换后: "Setelah beralih",
|
||||
"之后只保存原始对话,不再生成新记忆。":
|
||||
"Percakapan baru hanya disimpan sebagai teks asli; tidak ada memori baru yang dibuat.",
|
||||
|
||||
@@ -32,7 +32,31 @@ describe("memory mode plan", () => {
|
||||
expect(parseMemoryModePlan({ ...valid, blockers: ["unknown"] })).toBeNull();
|
||||
});
|
||||
|
||||
it("isolates the old-Core matrix in one helper", () => {
|
||||
it.each([
|
||||
["lite", "pro", ["earlier_raw_not_extracted", "lite_search_stops"]],
|
||||
[
|
||||
"lite",
|
||||
"ultra",
|
||||
[
|
||||
"earlier_raw_not_extracted",
|
||||
"lite_search_stops",
|
||||
"existing_memories_added_to_graph",
|
||||
],
|
||||
],
|
||||
["pro", "lite", ["higher_mode_memories_hidden"]],
|
||||
["pro", "ultra", ["existing_memories_added_to_graph"]],
|
||||
["ultra", "lite", ["higher_mode_memories_hidden", "evolve_stopped"]],
|
||||
["ultra", "pro", ["higher_mode_memories_hidden", "evolve_stopped"]],
|
||||
] as const)(
|
||||
"keeps the old-Core %s to %s effects aligned with the plan route",
|
||||
(current, target, effects) => {
|
||||
expect(
|
||||
legacyMemoryModePlan(current, target, { hasActiveModel: true }).effects,
|
||||
).toEqual(effects);
|
||||
},
|
||||
);
|
||||
|
||||
it("keeps the old-Core model blocker and target capabilities", () => {
|
||||
expect(
|
||||
legacyMemoryModePlan("lite", "ultra", { hasActiveModel: false }),
|
||||
).toMatchObject({
|
||||
@@ -42,10 +66,6 @@ describe("memory mode plan", () => {
|
||||
graph_enabled: true,
|
||||
},
|
||||
blockers: ["active_model_required"],
|
||||
effects: expect.arrayContaining([
|
||||
"earlier_raw_not_extracted",
|
||||
"existing_memories_added_to_graph",
|
||||
]),
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -106,12 +106,15 @@ export function legacyMemoryModePlan(
|
||||
options: { hasActiveModel: boolean },
|
||||
): MemoryModePlan {
|
||||
const effects: MemoryModeChange["effects"] = [];
|
||||
if (target === "lite") {
|
||||
effects.push("higher_mode_memories_hidden");
|
||||
if (current === "ultra") effects.push("evolve_stopped");
|
||||
} else if (current === "lite") {
|
||||
const rank: Record<MemoryPipelineMode, number> = {
|
||||
lite: 0,
|
||||
pro: 1,
|
||||
ultra: 2,
|
||||
};
|
||||
if (current !== target && current === "lite")
|
||||
effects.push("earlier_raw_not_extracted", "lite_search_stops");
|
||||
}
|
||||
if (rank[target] < rank[current]) effects.push("higher_mode_memories_hidden");
|
||||
if (current !== target && current === "ultra") effects.push("evolve_stopped");
|
||||
if (target === "ultra" && current !== "ultra")
|
||||
effects.push("existing_memories_added_to_graph");
|
||||
return {
|
||||
|
||||
Reference in new issue
Block a user