Files
writing-agent/tests/chat-keep-stats.test.ts
T
chenmoranzhi 9dc927282f 预设兼容:按真实抓包对齐装配与包装层,补上声明式工具与预设正则。
- 装配只认 prompt_order.enabled;squash_system_messages 只合并相邻 system(新增 system 档,连接符按酒馆用单换行)
- 包装层:new_chat_prompt、示例对话(new_example_chat_prompt + <START> 切段 + name)、角色卡三块与 personality_format/scenario_format、{{user}}/{{char}} 取值、任务契约并进预设条目
- 工具协议:按 ToolBindings / 伪工具协议数据声明真 tools(presetToolPolicy=preset),工具描述用到的条目不再重复作为消息发出
- 正则:promptOnly 作用于对话历史(含 depth 过滤)、写入时脚本改写回复;{{//}} 注释按配平扫描
- tools/st-request-diff:真假上游抓包对比工具、三份预设的机制结论与实测报告
2026-10-23 00:13:08 +08:00

107 lines
3.6 KiB
TypeScript

import { beforeEach, describe, expect, it } from "vitest";
import {
bumpKeepStats,
clearKeepStats,
copyKeepStats,
keepStatPercent,
keepStatText,
keepStatTotal,
readKeepStats,
sortKeepStats,
} from "../web/chat-keep-stats.js";
const STORAGE_KEY = "wa-direct-chat-keep-stats-v1";
function fakeStorage() {
const map = new Map();
return {
getItem: (k) => (map.has(k) ? map.get(k) : null),
setItem: (k, v) => map.set(k, String(v)),
removeItem: (k) => map.delete(k),
clear: () => map.clear(),
};
}
const gpt = { profileId: "p-gpt", profileName: "主配置", model: "gpt-4o" };
const claude = { profileId: "p-claude", profileName: "备用", model: "claude-3-7" };
beforeEach(() => {
globalThis.localStorage = fakeStorage();
});
describe("chat keep stats", () => {
it("counts keeps per conversation and sorts them", () => {
bumpKeepStats("conv-a", gpt);
bumpKeepStats("conv-a", claude);
bumpKeepStats("conv-a", claude);
const stats = readKeepStats("conv-a");
expect(stats.map((s) => s.label)).toEqual(["备用", "主配置"]);
expect(stats[0].count).toBe(2);
expect(keepStatTotal(stats)).toBe(3);
});
it("keeps conversations apart", () => {
bumpKeepStats("conv-a", gpt);
bumpKeepStats("conv-b", claude);
expect(readKeepStats("conv-a").map((s) => s.label)).toEqual(["主配置"]);
expect(readKeepStats("conv-b").map((s) => s.label)).toEqual(["备用"]);
clearKeepStats("conv-a");
expect(readKeepStats("conv-a")).toEqual([]);
expect(readKeepStats("conv-b")).toHaveLength(1);
});
it("subtracts on unkeep and drops the model at zero", () => {
bumpKeepStats("conv-a", gpt);
bumpKeepStats("conv-a", gpt);
expect(readKeepStats("conv-a")[0].count).toBe(2);
bumpKeepStats("conv-a", gpt, -1);
expect(readKeepStats("conv-a")[0].count).toBe(1);
bumpKeepStats("conv-a", gpt, -1);
expect(readKeepStats("conv-a")).toEqual([]);
});
it("treats the same profile + model as the same model even if the window id changes", () => {
bumpKeepStats("conv-a", { ...gpt, id: "w1" });
bumpKeepStats("conv-a", { ...gpt, id: "w2" });
expect(readKeepStats("conv-a")).toHaveLength(1);
expect(readKeepStats("conv-a")[0].count).toBe(2);
});
it("falls back to the profile name when the model is the same string", () => {
const text = keepStatText({ profileName: "本地", model: "本地" });
expect(text.label).toBe("本地");
expect(text.model).toBe("");
});
it("moves the counts when a conversation is copied or promoted", () => {
bumpKeepStats("conv-a", gpt);
bumpKeepStats("conv-a", claude);
bumpKeepStats("conv-a", claude);
copyKeepStats("conv-a", "conv-copy");
expect(readKeepStats("conv-copy").map((s) => s.count)).toEqual([2, 1]);
expect(readKeepStats("conv-a")).toEqual([]);
});
it("survives a broken storage payload", () => {
globalThis.localStorage.setItem(STORAGE_KEY, "{not json");
expect(readKeepStats("conv-a")).toEqual([]);
bumpKeepStats("conv-a", gpt);
expect(readKeepStats("conv-a")).toHaveLength(1);
});
it("sorts equal counts by label and scales bar widths", () => {
const sorted = sortKeepStats([
{ id: "b", label: "乙", model: "", count: 1 },
{ id: "a", label: "甲", model: "", count: 1 },
{ id: "c", label: "丙", model: "", count: 3 },
]);
expect(sorted.map((s) => s.id)).toEqual(["c", "a", "b"]);
expect(keepStatPercent(3, 3)).toBe(100);
expect(keepStatPercent(1, 3)).toBe(33);
expect(keepStatPercent(1, 100)).toBe(6);
expect(keepStatPercent(0, 3)).toBe(0);
expect(keepStatPercent(1, 0)).toBe(0);
});
});