增强进料配方注入,并拆分转述侧创作与跑团体验配方。

让文本生成器与数值跑团各走清晰进料路径,开玩后槽位与分工自动对齐。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-10 02:18:23 +08:00
co-authored by Cursor
parent 3d720f23fe
commit 92dd412e14
15 changed files with 292 additions and 36 deletions
+20 -3
View File
@@ -12,6 +12,7 @@ import {
listCallableCatalogModules,
formatModuleCatalogForAgent,
formatRecipeCatalogForAgent,
formatDictateRecipeBrief,
formatSelectedRecipeForAgent,
isCreationFlowComplete,
loadAllRecipeDetails,
@@ -516,12 +517,28 @@ describe("creation-flow", () => {
);
expect(dictate?.recipes.some((r) => r.id === "文本生成器")).toBe(true);
expect(dictate?.recipes.some((r) => r.name === "文本生成器")).toBe(true);
expect(dictate?.recipes.some((r) => r.name === "世界模拟器")).toBe(false);
expect(dictate?.recipes.some((r) => r.name === "交互式长文生成器")).toBe(true);
expect(dictate?.recipes.some((r) => r.name === "数据化跑团体验")).toBe(true);
expect(dictate?.recipes[0]?.id).toBe("数据化跑团体验");
const entry = dictate!.recipes.find((r) => r.id === "文本生成器")!;
expect(entry.family).toBe("dictate");
const detail = await loadRecipeDetail("dialogue/world-simulator", entry);
expect(detail.core).toBeTruthy();
expect(detail.core).toMatch(/范例|模仿|转述|游玩/);
expect(detail.seed).toBeNull();
expect(formatDictateRecipeBrief(detail)).toMatch(/模仿|范例|转述|开玩/);
expect(formatDictateRecipeBrief(detail)).toMatch(/模仿要点|学哪些面|要点|文风/);
const longform = dictate!.recipes.find((r) => r.id === "交互式长文生成器")!;
const longDetail = await loadRecipeDetail("dialogue/world-simulator", longform);
expect(longDetail.brief).toMatch(/长文/);
expect(longDetail.core).toMatch(/长文|分段/);
const rpg = dictate!.recipes.find((r) => r.id === "数据化跑团体验")!;
const rpgDetail = await loadRecipeDetail("dialogue/world-simulator", rpg);
expect(rpgDetail.brief).toMatch(/数据化跑团|真值|映射/);
expect(rpgDetail.core).toMatch(/真值|declare_variable|数值/);
expect(formatDictateRecipeBrief(rpgDetail)).toContain("declare_variable");
expect(formatDictateRecipeBrief(rpgDetail)).toContain("declare_map");
});
it("parses selected recipe ref", () => {
@@ -619,7 +636,7 @@ recipes:
name: 缺声明
`);
expect(cat?.recipes).toEqual([
{ id: "ok", name: "好配方", declaration: "有声明" },
{ id: "ok", name: "好配方", declaration: "有声明", family: "recipe" },
]);
});
+58 -1
View File
@@ -14,6 +14,8 @@ describe("dictate play-bind", () => {
it("classifies style tags", () => {
expect(isDictateStyleBindTag("设计.美学纲领")).toBe(true);
expect(isDictateStyleBindTag("设计.正文组成")).toBe(true);
expect(isDictateStyleBindTag("设计.模仿范例")).toBe(true);
expect(isDictateStyleBindTag("设计.模仿要点")).toBe(true);
expect(isDictateStyleBindTag("用户.需求")).toBe(false);
});
@@ -77,13 +79,68 @@ describe("dictate play-bind", () => {
const narrRefs = narr!.inserts.map((i) => i.ref);
expect(narrRefs).toContain("设计.美学纲领");
expect(narrRefs).not.toContain("用户.需求");
expect(narrRefs).toContain("运行.本轮.裁决");
expect(narrRefs).toContain("输出.用户展示");
expect(narrRefs).not.toContain("运行.本轮.裁决");
const gm = result.contextOrder.slots.find((s) => s.ref === "world-simulator");
expect(gm!.inserts.map((i) => i.ref)).toContain("用户.需求");
expect(result.workerSetJson).toContain("context_order");
});
it("forces narrator on for 文本生成器 and mounts creation-period style context", () => {
const board = new Blackboard();
board.write({
tag: "创作.选用配方",
content: JSON.stringify({ id: "文本生成器", name: "文本生成器" }),
source: "user",
});
board.write({
tag: "设计.模仿范例",
content: "范例正文",
source: "dictate",
metadata: { [DICTATE_ORDER_META_KEY]: -28 },
});
board.write({
tag: "设计.模仿要点",
content: "- 句式节奏\n- 感官密度",
source: "dictate",
metadata: { [DICTATE_ORDER_META_KEY]: -28 },
});
board.write({
tag: "设计.叙事指南与故事推进",
content: "用户输入用法:大纲扩写。禁止扮演停笔。",
source: "dictate",
metadata: { [DICTATE_ORDER_META_KEY]: -22 },
});
board.write({
tag: "用户.需求",
content: "短篇",
source: "dictate",
});
board.write({
tag: "设计.worker集",
content: JSON.stringify({
play_slots: { gm: true, narrator: false, auditor: false, perspective: false },
}),
source: "test",
});
const result = bindDictateProductsToPlaySpec(board);
expect(result.contextOrder.play_slots?.narrator).toBe(true);
const narr = result.contextOrder.slots.find((s) => s.ref === "narrator");
expect(narr).toBeTruthy();
const narrRefs = narr!.inserts.map((i) => i.ref);
expect(narrRefs).toContain("设计.模仿范例");
expect(narrRefs).toContain("设计.模仿要点");
expect(narrRefs).toContain("设计.叙事指南与故事推进");
expect(narrRefs).not.toContain("用户.需求");
expect(JSON.parse(result.workerSetJson).play_slots.narrator).toBe(true);
// 落档不改写创作期叙事指南
expect(board.getContentByTag("设计.叙事指南与故事推进")).toBe(
"用户输入用法:大纲扩写。禁止扮演停笔。",
);
});
it("does not invent variable mappings; binds declared map slots and catalog", () => {
const board = new Blackboard();
board.write({ tag: "用户.需求", content: "x", source: "dictate" });
+9 -2
View File
@@ -64,8 +64,8 @@ describe("dictate context", () => {
it("system prompt requires insert toolcall and relative order", () => {
const prompt = buildDictateSystemPrompt({
recipeName: "正文组成",
recipeBrief: "钉呈现壳与可见块",
recipeName: "数据化跑团体验",
recipeBrief: "设定 + 真值 + 分档映射\n怎么做:\n- declare_variable\n- declare_map",
});
expect(prompt).toContain("设计.正文组成");
expect(prompt).toContain("设计.开场白");
@@ -73,8 +73,15 @@ describe("dictate context", () => {
expect(prompt).toContain("insert");
expect(prompt).toContain("declare_variable");
expect(prompt).toContain("declare_map");
expect(prompt).toContain("数据化跑团体验");
expect(prompt).toMatch(/order/);
expect(prompt).toContain("仅允许 toolcall");
expect(prompt).toContain("设计.模仿范例");
expect(prompt).toContain("设计.模仿要点");
expect(prompt).toContain("设计.叙事指南与故事推进");
expect(prompt).toContain("大纲扩写");
expect(prompt).toContain("禁止扮演停笔");
expect(prompt).toContain("只挂载这些产物");
});
it("sorts products by relative order: neg then 0 then pos", () => {