预设兼容:按真实抓包对齐装配与包装层,补上声明式工具与预设正则。

- 装配只认 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:真假上游抓包对比工具、三份预设的机制结论与实测报告
This commit is contained in:
2026-10-23 00:13:08 +08:00
parent ed09e5c831
commit 9dc927282f
94 changed files with 11558 additions and 413 deletions
+32 -1
View File
@@ -1,4 +1,19 @@
import { describe, expect, it } from "vitest";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { mkdtempSync, rmSync } from "node:fs";
import os from "node:os";
import path from "node:path";
// 这些用例只测夹心与整形,不该被本机 ~/.writing-agent/settings.json 里的
// messageSquash / presetToolPolicy 覆盖,跑的时候给一份干净的临时数据目录。
let isolatedDataDir = "";
beforeAll(() => {
isolatedDataDir = mkdtempSync(path.join(os.tmpdir(), "wa-preset-wrapper-"));
process.env.WRITING_AGENT_DATA_DIR = isolatedDataDir;
});
afterAll(() => {
delete process.env.WRITING_AGENT_DATA_DIR;
if (isolatedDataDir) rmSync(isolatedDataDir, { recursive: true, force: true });
});
import type {
ChatMessage,
CompleteResult,
@@ -25,6 +40,8 @@ const samplePreset: PresetPackage = {
],
promptOrder: [{ promptId: "sys", enabled: true, orderIndex: 0 }],
generation: { temperature: 0.91, maxOutputTokens: 1234, reasoningEffort: "max" },
// 这组用例测的是夹心,不是整形;整形单独有用例。
messagePolicy: { squash: "none" },
unsupported: [],
importedAt: "2026-01-01T00:00:00.000Z",
};
@@ -163,4 +180,18 @@ describe("wrapLlmForSession", () => {
await llm.complete([{ role: "user", content: "TASK" }]);
expect(received[0].messages[0].content).toBe("称呼 @玩家");
});
it("defaults to strict squash when the preset says nothing", async () => {
const preset: PresetPackage = { ...samplePreset };
delete (preset as { messagePolicy?: unknown }).messagePolicy;
const { provider, received } = recordingProvider();
const llm = wrapLlmForSession(provider, undefined, () => preset);
await llm.complete([{ role: "user", content: "TASK" }]);
// strict:system 折进 user,首条为 user
expect(received[0].messages.map((m) => m.role)).toEqual(["user"]);
expect(received[0].messages[0]!.content).toContain("PRESET_RULES");
expect(received[0].messages[0]!.content).toContain("TASK");
});
});