Files
writing-agent/tests/message-squash.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

110 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from "vitest";
import type { ChatMessage } from "../src/llm/client.js";
import { squashMessages } from "../src/llm/message-squash.js";
const sys = (content: string): ChatMessage => ({ role: "system", content });
const user = (content: string): ChatMessage => ({ role: "user", content });
const asst = (content: string): ChatMessage => ({ role: "assistant", content });
const toolCall: ChatMessage = {
role: "assistant",
content: null,
tool_calls: [
{ id: "1", type: "function", function: { name: "t", arguments: "{}" } },
],
};
const toolResult: ChatMessage = { role: "tool", content: "{}", tool_call_id: "1" };
describe("squashMessages", () => {
it("none returns the list untouched", () => {
const input = [sys("a"), sys("b")];
expect(squashMessages(input, "none")).toBe(input);
});
it("merge joins adjacent same-role messages with a blank line", () => {
const out = squashMessages([sys("a"), sys("b"), user("c")], "merge");
expect(out).toEqual([sys("a\n\nb"), user("c")]);
});
it("merge keeps role changes intact", () => {
const out = squashMessages([sys("a"), user("b"), asst("c")], "merge");
expect(out.map((m) => m.role)).toEqual(["system", "user", "assistant"]);
});
it("never merges tool groups", () => {
const out = squashMessages(
[sys("a"), sys("b"), toolCall, toolResult, asst("x"), asst("y")],
"merge",
);
expect(out.map((m) => m.role)).toEqual([
"system",
"assistant",
"tool",
"assistant",
]);
// 工具组原样保留
expect(out[1]).toBe(toolCall);
expect(out[2]).toBe(toolResult);
});
it("semi folds system into neighbouring messages", () => {
const out = squashMessages(
[sys("规则"), user("问题"), sys("补充"), asst("回答")],
"semi",
);
expect(out).toEqual([user("规则\n\n问题"), asst("补充\n\n回答")]);
});
it("strict makes the first message a user", () => {
const out = squashMessages([asst("前言"), user("问题")], "strict");
expect(out[0]?.role).toBe("user");
expect(out[0]?.content).toBe("前言\n\n问题");
});
it("single-user-turn collapses everything into one user message", () => {
const out = squashMessages(
[sys("规则"), user("问题"), asst("回答")],
"single-user-turn",
);
expect(out).toEqual([user("规则\n\n问题\n\n回答")]);
});
it("falls back to merge when a tool group is present", () => {
const out = squashMessages(
[sys("a"), sys("b"), toolCall, toolResult],
"single-user-turn",
);
expect(out.map((m) => m.role)).toEqual(["system", "assistant", "tool"]);
expect(out[0]?.content).toBe("a\n\nb");
});
it("handles empty input", () => {
expect(squashMessages([], "strict")).toEqual([]);
});
});
describe("system 档(对齐酒馆 squashSystemMessages)", () => {
it("只合并相邻 system,user/assistant 不动", () => {
const out = squashMessages(
[sys("a"), sys("b"), user("u1"), user("u2"), asst("c1"), asst("c2"), sys("d"), sys("e")],
"system",
);
expect(out).toEqual([
sys("a\nb"),
user("u1"),
user("u2"),
asst("c1"),
asst("c2"),
sys("d\ne"),
]);
});
it("不碰工具组", () => {
const out = squashMessages(
[sys("a"), sys("b"), toolCall, toolResult, sys("c"), sys("d")],
"system",
);
expect(out.map((m) => m.role)).toEqual(["system", "assistant", "tool", "system"]);
});
});