- 装配只认 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:真假上游抓包对比工具、三份预设的机制结论与实测报告
107 lines
3.6 KiB
TypeScript
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);
|
|
});
|
|
});
|