创作一轮改为先选题再填写,减少工具空转和重复覆盖。

上下文按规则、历史、产物分段拼装,便于吃提示缓存并核对费用。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-07 23:48:20 +08:00
co-authored by Cursor
parent d0a48f9431
commit 1cc4ae557a
20 changed files with 2660 additions and 123 deletions
+53 -15
View File
@@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest";
import {
buildDictateMessages,
buildDictateSystemPrompt,
formatDictateRoundTail,
buildDictateInsertFeedbackIndex,
defaultDictateOrder,
extractDictateDialogue,
@@ -47,7 +48,7 @@ describe("dictate context", () => {
});
const body = messages[1]?.content ?? "";
expect(body).toContain("冷色短句");
expect(body).toContain("尚无对话");
expect(body).toContain("尚无更早对话");
});
it("extracts only user + dictate_reply turns", () => {
@@ -73,8 +74,9 @@ describe("dictate context", () => {
expect(isDictateModeValue("recipe")).toBe(false);
});
it("system prompt starts from a plan and keeps generic write tools", () => {
const prompt = buildDictateSystemPrompt({
it("system prompt keeps stable rules; catalog and plan progress sit in the tail", () => {
const prompt = buildDictateSystemPrompt();
const tail = formatDictateRoundTail({
recipeName: "数据化跑团体验",
recipeBrief:
"设定 + 真值 + 分档映射\n怎么做:\n- declare_variable\n- declare_map",
@@ -90,17 +92,31 @@ describe("dictate context", () => {
expect(prompt).toContain("declare_map");
expect(prompt).toContain("remove_map");
expect(prompt).toContain("同 position 再 insert");
expect(prompt).toContain("数据化跑团体验");
expect(prompt).not.toContain("数据化跑团体验");
expect(prompt).toMatch(/order/);
expect(prompt).toContain("【能力 · 何时落盘】");
expect(prompt).toContain("设计.美学纲领与交互范式");
expect(prompt).not.toContain("【能力 · 何时落盘】");
expect(prompt).toContain("通常 2~3 个");
expect(prompt).toContain("给 2~3 个选项来问");
expect(prompt).toContain("不是 DAG");
expect(prompt).toContain("不是用户已选路径");
expect(prompt).not.toContain("不是用户已选路径");
expect(prompt).toContain("自然回应");
expect(prompt.indexOf("填写收尾")).toBeLessThan(prompt.indexOf("写入规则"));
expect(prompt).not.toContain("体验锚定(程序打分)");
expect(prompt).not.toContain("## 本轮落什么");
expect(tail).toContain("数据化跑团体验");
expect(tail).toContain("【能力 · 何时落盘】");
expect(tail).toContain("不是用户已选路径");
expect(tail).toContain("尚无本局创作方案");
});
it("puts the fill reply_user duty before plan progress in the tail", () => {
const fillTail = formatDictateRoundTail({
phase: "fill",
creationPlanState: "【当前决策】\n- mood:已落",
checklist: "本轮写入:设计.氛围",
});
expect(fillTail.indexOf("必须调用 reply_user")).toBeLessThan(fillTail.indexOf("当前决策"));
expect(fillTail.indexOf("必须调用 reply_user")).toBeLessThan(fillTail.indexOf("本轮写入"));
});
it("formats module catalog for dictate with land tags and when", async () => {
@@ -172,6 +188,12 @@ describe("dictate context", () => {
expect(
resolveModuleForInsertTag("设计.开场白", catalog!)?.id,
).toBe("opening-setup");
expect(
resolveModuleForInsertTag("设计.开场白#opening-cycle2", catalog!)?.id,
).toBe("opening-setup");
expect(
resolveModuleForInsertTag("设计.开场白与开场变量", catalog!)?.id,
).toBe("opening-setup");
expect(
resolveModuleForInsertTag("设计.具体实例#lei-ying", catalog!)?.id,
).toBe("concrete-instances");
@@ -244,31 +266,47 @@ describe("dictate context", () => {
expect("error" in overwriteBare).toBe(true);
const openingFamilies = new Set(["设计.开场白", "设计.主角设定"]);
const firstOpen = resolveRepeatableInsertTag({
const bareOpen = resolveRepeatableInsertTag({
tag: "设计.开场白",
content: "@玩家推开门。",
existingTags: [],
repeatableFamilies: openingFamilies,
});
expect("tag" in firstOpen && firstOpen.tag).toBe("设计.开场白");
const overwriteFirst = resolveRepeatableInsertTag({
tag: "设计.开场白",
content: "@玩家改写第一幕。",
expect("error" in bareOpen).toBe(true);
const namedFromBundle = resolveRepeatableInsertTag({
tag: "设计.开场白与开场变量",
content: JSON.stringify({
schema: "present.v1",
id: "opening-cycle2",
blocks: { body: "@玩家推开门。" },
}),
existingTags: ["设计.开场白"],
repeatableFamilies: openingFamilies,
});
expect("tag" in overwriteFirst && overwriteFirst.tag).toBe("设计.开场白");
expect("tag" in namedFromBundle && namedFromBundle.tag).toBe(
"设计.开场白#opening-cycle2",
);
const keepNamed = resolveRepeatableInsertTag({
tag: "设计.开场白#opening-cycle2",
content: JSON.stringify({
schema: "present.v1",
blocks: { body: "@玩家改写这一幕。" },
}),
existingTags: ["设计.开场白", "设计.开场白与开场变量", "设计.开场白#opening-cycle2"],
repeatableFamilies: openingFamilies,
});
expect("tag" in keepNamed && keepNamed.tag).toBe("设计.开场白#opening-cycle2");
const secondOpen = resolveRepeatableInsertTag({
tag: "设计.开场白#gate",
content: "@玩家在闸机前。",
existingTags: ["设计.开场白"],
existingTags: ["设计.开场白#opening-cycle2"],
repeatableFamilies: openingFamilies,
});
expect("tag" in secondOpen && secondOpen.tag).toBe("设计.开场白#gate");
const bareOpenConflict = resolveRepeatableInsertTag({
tag: "设计.开场白",
content: "又写一条",
existingTags: ["设计.开场白", "设计.开场白#gate"],
existingTags: ["设计.开场白#opening-cycle2", "设计.开场白#gate"],
repeatableFamilies: openingFamilies,
});
expect("error" in bareOpenConflict).toBe(true);