预设兼容:按真实抓包对齐装配与包装层,补上声明式工具与预设正则。
- 装配只认 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:
@@ -19,6 +19,14 @@ const DEFAULTS = {
|
||||
port: 23377,
|
||||
out: path.join(HERE, "captures"),
|
||||
dataRoot: path.join(HERE, ".wa-data"),
|
||||
charName: "ProbeCard",
|
||||
toolPolicy: "adapt",
|
||||
exampleDialogue:
|
||||
"<START>\n{{user}}: EX_USER_TOKEN 今天做什么?\n{{char}}: EX_CHAR_TOKEN 读书。",
|
||||
// 跟酒馆那张探针卡的三块字段一致
|
||||
charDescription: "DESC_TOKEN 这是一张测试角色卡的描述,用来确认酒馆把它放在哪一段。",
|
||||
charPersonality: "PERS_TOKEN 冷静、话少、只答问题。",
|
||||
scenario: "SCEN_TOKEN 一间安静的书房,只有两个人在说话。",
|
||||
timeoutMs: 120000,
|
||||
};
|
||||
|
||||
@@ -33,6 +41,10 @@ async function postJson(url, body) {
|
||||
|
||||
async function main() {
|
||||
const args = parseArgs(process.argv.slice(2), DEFAULTS);
|
||||
const priorIndex = process.argv.indexOf("--prior");
|
||||
if (priorIndex > 0) args.prior = String(process.argv[priorIndex + 1] ?? "");
|
||||
const policyIndex = process.argv.indexOf("--tool-policy");
|
||||
if (policyIndex > 0) args.toolPolicy = String(process.argv[policyIndex + 1] ?? "adapt");
|
||||
if (!args.preset) throw new Error("缺少 --preset");
|
||||
const presetName = path.basename(args.preset, ".json");
|
||||
const raw = JSON.parse(readFileSync(args.preset, "utf8"));
|
||||
@@ -56,8 +68,26 @@ async function main() {
|
||||
],
|
||||
};
|
||||
writeFileSync(path.join(args.dataRoot, "profiles.json"), JSON.stringify(profiles, null, 2), "utf8");
|
||||
// 预设工具协议:preset = 按预设数据声明真 tools
|
||||
writeFileSync(
|
||||
path.join(args.dataRoot, "settings.json"),
|
||||
JSON.stringify(
|
||||
{
|
||||
version: 1,
|
||||
activeProfileId: null,
|
||||
activePresetId: null,
|
||||
messageSquash: "follow-preset",
|
||||
presetToolPolicy: args.toolPolicy,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
try { rmSync(path.join(args.dataRoot, "presets"), { recursive: true, force: true }); } catch (e) {} const known = new Set(listCaptures(args.out, "wa"));
|
||||
try { rmSync(path.join(args.dataRoot, "presets"), { recursive: true, force: true }); } catch (e) {}
|
||||
// 人设也用默认的(名字 User,跟酒馆一致),免得复用上一次跑留下的「玩家」
|
||||
try { rmSync(path.join(args.dataRoot, "personas.json"), { force: true }); } catch (e) {} const known = new Set(listCaptures(args.out, "wa"));
|
||||
const env = { ...process.env, PORT: String(args.port), WRITING_AGENT_DATA_DIR: args.dataRoot };
|
||||
const server = spawn(process.execPath, [path.join(REPO, "node_modules/tsx/dist/cli.mjs"), path.join(REPO, "src/server/web-server.ts")], { cwd: REPO, env, stdio: ["ignore", "pipe", "pipe"] });
|
||||
const logs = [];
|
||||
@@ -77,13 +107,28 @@ async function main() {
|
||||
text: args.message,
|
||||
presetId,
|
||||
complete: true,
|
||||
turns: [],
|
||||
turns: args.prior
|
||||
? [
|
||||
{
|
||||
id: "t1",
|
||||
user: { content: "上一轮用户", createdAt: now },
|
||||
replies: [{ windowId: "w1", content: args.prior }],
|
||||
createdAt: now,
|
||||
},
|
||||
]
|
||||
: [],
|
||||
windows: [{ id: "w1", profileId: "probe-mock" }],
|
||||
systemPrompt: "",
|
||||
loreBefore: "",
|
||||
seedHistory: "",
|
||||
loreAfter: "",
|
||||
postTurn: "",
|
||||
// 跟酒馆那张探针卡对齐:角色名 + 卡里的示例对话原文
|
||||
charName: args.charName,
|
||||
exampleDialogue: args.exampleDialogue,
|
||||
charDescription: args.charDescription,
|
||||
charPersonality: args.charPersonality,
|
||||
scenario: args.scenario,
|
||||
};
|
||||
const result = await postJson(base + "/api/direct-chat/ephemeral/complete", body);
|
||||
const first = result.multi && result.multi.results && result.multi.results[0];
|
||||
|
||||
Reference in New Issue
Block a user