// 从「酒馆真实抓包」直接复刻出一个预设:messages 原样搬,tools.description 搬成 system 块。 // 用法: node build-clone-from-capture.mjs <输出名> import { mkdirSync, readFileSync, writeFileSync } from "node:fs"; import path from "node:path"; const captureFile = process.argv[2]; const name = process.argv[3] || "wa-clone"; const OUT = "D:/progarm/my/writing-agent/tools/st-request-diff/presets/" + name + ".json"; mkdirSync(path.dirname(OUT), { recursive: true }); const outer = JSON.parse(readFileSync(captureFile, "utf8")); const body = JSON.parse(outer.body); const msgs = body.messages || []; const toolDescs = (body.tools || []).map((t) => { const fn = t.function || t; return "# [工具声明] " + (fn.name || "") + "\n" + String(fn.description || ""); }); const blocks = []; msgs.forEach((m, i) => { const content = String(m.content ?? ""); if (!content.trim()) return; blocks.push({ identifier: "clone_" + String(i).padStart(2, "0"), name: "复刻消息 " + i + "(" + m.role + ")", role: ["system", "user", "assistant"].includes(m.role) ? m.role : "system", content, }); }); toolDescs.forEach((d, i) => { blocks.push({ identifier: "clone_tool_" + i, name: "复刻工具声明 " + i, role: "system", content: d }); }); const markers = [ ["worldInfoBefore", "World Info (before)"], ["personaDescription", "Persona Description"], ["charDescription", "Char Description"], ["charPersonality", "Char Personality"], ["scenario", "Scenario"], ["worldInfoAfter", "World Info (after)"], ["dialogueExamples", "Chat Examples"], ["chatHistory", "Chat History"], ].map(([identifier, nm]) => ({ identifier, name: nm, marker: true, system_prompt: true, role: "system", content: "", injection_position: 0, injection_depth: 4, injection_order: 100, enabled: true, })); const prompts = [ ...markers, ...blocks.map((b) => ({ identifier: b.identifier, name: b.name, enabled: true, role: b.role, content: b.content, injection_position: 0, injection_depth: 4, injection_order: 100, system_prompt: false, marker: false, forbid_overrides: false, })), ]; const prompt_order = [ { character_id: 100001, order: [ ...blocks.map((b) => b.identifier), "worldInfoBefore", "personaDescription", "charDescription", "charPersonality", "scenario", "worldInfoAfter", "dialogueExamples", "chatHistory", ].map((identifier) => ({ identifier, enabled: true })), }, ]; const preset = { name, temperature: 1, frequency_penalty: 0, presence_penalty: 0, top_p: 0.99, top_k: 60, max_context_unlocked: true, openai_max_context: 200000, openai_max_tokens: 3000, names_behavior: 0, send_if_empty: "", new_chat_prompt: "[chat Start]", new_example_chat_prompt: "{{mesExamples}}", continue_nudge_prompt: "[继续]", wi_format: "{0}", scenario_format: "{{scenario}}", personality_format: "{{personality}}", stream_openai: true, use_sysprompt: true, squash_system_messages: true, function_calling: false, reasoning_effort: "low", seed: -1, n: 1, prompts, prompt_order, }; writeFileSync(OUT, JSON.stringify(preset, null, 2), "utf8"); console.log("已写入 " + OUT); console.log("消息 " + msgs.length + " 条(原样搬 " + blocks.filter((b) => b.name.startsWith("复刻消息")).length + " 条)、工具声明 " + toolDescs.length + " 段"); console.log("正文合计 " + prompts.reduce((n, p) => n + String(p.content || "").length, 0) + " 字"); console.log("来源抓包: " + path.basename(captureFile) + " receivedAt=" + outer.receivedAt);