对话落盘同一轮填写失败后可以按次数补写。
游玩投影不再送进只给程序用的壳源码。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -46,7 +46,7 @@ async function fixture() {
|
||||
describe("creation plan", () => {
|
||||
it("covers all current content modules and excludes approved mechanical or legacy nodes", async () => {
|
||||
const { modules } = await fixture();
|
||||
expect(modules).toHaveLength(14);
|
||||
expect(modules).toHaveLength(15);
|
||||
expect(modules.map((module) => module.id)).not.toEqual(
|
||||
expect.arrayContaining([
|
||||
"creation-plan",
|
||||
@@ -99,7 +99,7 @@ describe("creation plan", () => {
|
||||
expect(catalog).toBeTruthy();
|
||||
const zeroModules = creationPlanModules(catalog!, "zero_layer");
|
||||
const ids = zeroModules.map((module) => module.id);
|
||||
expect(zeroModules).toHaveLength(14);
|
||||
expect(zeroModules).toHaveLength(15);
|
||||
expect(ids).toEqual(
|
||||
expect.arrayContaining([
|
||||
"zero-layer-status",
|
||||
|
||||
@@ -14,22 +14,58 @@ import { defaultPlaySlots } from "../src/skills/play-slots.js";
|
||||
|
||||
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(true);
|
||||
expect(isDictateStyleBindTag("设计.故事推进")).toBe(true);
|
||||
expect(isDictateStyleBindTag("设计.用户需求")).toBe(true);
|
||||
expect(isDictateStyleBindTag("设计.用户约束")).toBe(true);
|
||||
expect(isDictateStyleBindTag("设计.监控栏")).toBe(true);
|
||||
expect(isDictateStyleBindTag("用户.需求")).toBe(false);
|
||||
// 中转与壳不进游玩文风挂载
|
||||
expect(isDictateStyleBindTag("设计.美学纲领")).toBe(false);
|
||||
expect(isDictateStyleBindTag("设计.正文组成")).toBe(false);
|
||||
});
|
||||
|
||||
it("excludes design_only and reply shell from play bind products", () => {
|
||||
const board = new Blackboard();
|
||||
board.write({
|
||||
tag: "设计.实现机制",
|
||||
content: "因果",
|
||||
source: "dictate",
|
||||
metadata: { [DICTATE_ORDER_META_KEY]: 10 },
|
||||
});
|
||||
board.write({
|
||||
tag: "设计.本局创作方案",
|
||||
content: '{"schema":"creation-plan.v1","items":[]}',
|
||||
source: "dictate",
|
||||
});
|
||||
board.write({
|
||||
tag: "设计.美学纲领与交互范式",
|
||||
content: "体验",
|
||||
source: "dictate",
|
||||
});
|
||||
board.write({
|
||||
tag: "设计.正文组成",
|
||||
content: JSON.stringify({
|
||||
schema: "context-fragment.v1",
|
||||
正文: {
|
||||
frontend: { html: "<div>", css: "x", js: "y" },
|
||||
数据契约: { blocks: { body: { 类型: "markdown", 来源: "model_generated" } } },
|
||||
},
|
||||
}),
|
||||
source: "dictate",
|
||||
});
|
||||
const tags = collectDictateBindProducts(board).map((p) => p.tag);
|
||||
expect(tags).toEqual(["设计.实现机制"]);
|
||||
});
|
||||
|
||||
it("builds gm context_order: persona → products → history → input", () => {
|
||||
const order = buildDictateContextOrder({
|
||||
products: [
|
||||
{ tag: "用户.需求", content: "雨夜", order: -40 },
|
||||
{ tag: "设计.美学纲领", content: "冷色", order: -30 },
|
||||
{ tag: "设计.叙事指南", content: "冷色短句", order: -30 },
|
||||
{ tag: "设计.本局创作方案", content: "{}", order: -50 },
|
||||
{ tag: "设计.正文组成", content: "{}", order: 0 },
|
||||
],
|
||||
playSlots: defaultPlaySlots(),
|
||||
@@ -39,13 +75,44 @@ describe("dictate play-bind", () => {
|
||||
const refs = gm!.inserts.map((i) => i.ref);
|
||||
expect(refs[0]).toBe(WORKER_PERSONA_REF);
|
||||
expect(refs).toContain("用户.需求");
|
||||
expect(refs).toContain("设计.美学纲领");
|
||||
expect(refs).toContain("设计.正文组成");
|
||||
expect(refs).toContain("设计.叙事指南");
|
||||
expect(refs).not.toContain("设计.本局创作方案");
|
||||
expect(refs).not.toContain("设计.正文组成");
|
||||
expect(refs).toContain(DIALOGUE_HISTORY_TAG);
|
||||
expect(refs[refs.length - 1]).toBe("用户.最新输入");
|
||||
const histIdx = refs.indexOf(DIALOGUE_HISTORY_TAG);
|
||||
expect(refs.indexOf("用户.需求")).toBeLessThan(histIdx);
|
||||
expect(refs.indexOf("设计.正文组成")).toBeLessThan(histIdx);
|
||||
expect(refs.indexOf("设计.叙事指南")).toBeLessThan(histIdx);
|
||||
});
|
||||
|
||||
it("keeps image prompt on the auditor and off the main world", () => {
|
||||
const image = JSON.stringify({
|
||||
schema: "context-fragment.v1",
|
||||
技能: "画面与生图",
|
||||
brief: "西幻",
|
||||
mount: ["auditor"],
|
||||
稳变: "stable",
|
||||
正文: { 工作流: "western-fantasy" },
|
||||
});
|
||||
const order = buildDictateContextOrder({
|
||||
products: [
|
||||
{ tag: "设计.舞台骨架", content: "舞台", order: 1 },
|
||||
{ tag: "设计.画面与生图", content: image, order: 2 },
|
||||
{ tag: "设计.变量设计与更新规则", content: "真值", order: 3 },
|
||||
],
|
||||
playSlots: { ...defaultPlaySlots(), auditor: true },
|
||||
});
|
||||
const gm = order.slots
|
||||
.find((s) => s.ref === "world-simulator")!
|
||||
.inserts.map((i) => i.ref);
|
||||
const auditor = order.slots
|
||||
.find((s) => s.ref === "auditor")!
|
||||
.inserts.map((i) => i.ref);
|
||||
expect(gm).toContain("设计.舞台骨架");
|
||||
expect(gm).not.toContain("设计.画面与生图");
|
||||
expect(auditor).toContain("设计.画面与生图");
|
||||
expect(auditor).toContain("设计.变量设计与更新规则");
|
||||
expect(auditor).not.toContain("设计.舞台骨架");
|
||||
});
|
||||
|
||||
it("groups context by change frequency before applying importance order", () => {
|
||||
@@ -84,7 +151,7 @@ describe("dictate play-bind", () => {
|
||||
metadata: { [DICTATE_ORDER_META_KEY]: -40 },
|
||||
});
|
||||
board.write({
|
||||
tag: "设计.美学纲领",
|
||||
tag: "设计.叙事指南",
|
||||
content: "冷色短句",
|
||||
source: "dictate",
|
||||
metadata: { [DICTATE_ORDER_META_KEY]: -30 },
|
||||
@@ -103,14 +170,14 @@ describe("dictate play-bind", () => {
|
||||
});
|
||||
|
||||
const products = collectDictateBindProducts(board);
|
||||
expect(products.map((p) => p.tag)).toEqual(["用户.需求", "设计.美学纲领"]);
|
||||
expect(products.map((p) => p.tag)).toEqual(["用户.需求", "设计.叙事指南"]);
|
||||
expect(products.every((p) => p.tag !== "设计.开场白")).toBe(true);
|
||||
|
||||
const result = bindDictateProductsToPlaySpec(board);
|
||||
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).not.toContain("用户.需求");
|
||||
expect(narrRefs).toContain("输出.用户展示");
|
||||
expect(narrRefs).not.toContain("运行.本轮.裁决");
|
||||
|
||||
@@ -33,7 +33,7 @@ describe("dictate read_module", () => {
|
||||
self_score: {
|
||||
dims: [
|
||||
{ name: "美学纲领", score: 5 },
|
||||
{ name: "交互范式", score: 5 },
|
||||
{ name: "体验锚定", score: 5 },
|
||||
{ name: "背景与规则", score: 5 },
|
||||
],
|
||||
},
|
||||
@@ -84,7 +84,7 @@ describe("dictate read_module", () => {
|
||||
self_score: {
|
||||
dims: [
|
||||
{ name: "美学纲领", score: 5 },
|
||||
{ name: "交互范式", score: 5 },
|
||||
{ name: "体验锚定", score: 5 },
|
||||
{ name: "背景与规则", score: 3, gap: "规则因果仍需确认" },
|
||||
],
|
||||
},
|
||||
@@ -208,7 +208,7 @@ describe("dictate read_module", () => {
|
||||
self_score: {
|
||||
dims: [
|
||||
{ name: "美学纲领", score: 3 },
|
||||
{ name: "交互范式", score: 5 },
|
||||
{ name: "体验锚定", score: 5 },
|
||||
{ name: "背景与规则", score: 5 },
|
||||
],
|
||||
},
|
||||
@@ -230,7 +230,7 @@ describe("dictate read_module", () => {
|
||||
self_score: {
|
||||
dims: [
|
||||
{ name: "美学纲领", score: 3, gap: "发生方式仍偏宽" },
|
||||
{ name: "交互范式", score: 5 },
|
||||
{ name: "体验锚定", score: 5 },
|
||||
{ name: "背景与规则", score: 5 },
|
||||
],
|
||||
},
|
||||
|
||||
+309
-5
@@ -253,6 +253,7 @@ describe("dictate planned round", () => {
|
||||
expect(result.wroteTags).toEqual(["设计.氛围"]);
|
||||
expect(products).toEqual([{ tag: "设计.氛围", content: "细雨" }]);
|
||||
expect(result.reply).toContain("已写成细雨");
|
||||
expect(result.iterations).toBe(2);
|
||||
const state = parseDictateModuleReadState(tags.get(DICTATE_MODULE_READ_STATE_TAG));
|
||||
expect(state.modules.mood).toBe("v-test");
|
||||
expect(tags.get(DICTATE_REMEDIATE_TAG) ?? "").toBe("");
|
||||
@@ -287,10 +288,75 @@ describe("dictate planned round", () => {
|
||||
expect(result.reply).toContain("改成暖色");
|
||||
});
|
||||
|
||||
it("says the returned fields when the select plan writes nothing", async () => {
|
||||
it("returns an answer without writing when the first call is reply_user", async () => {
|
||||
let writes = 0;
|
||||
let calls = 0;
|
||||
const result = await runDictateTurn({
|
||||
llm: scriptedLlm([{ note: "看世界" }]),
|
||||
dialogue: [{ role: "user", text: "超级英雄" }],
|
||||
llm: {
|
||||
async complete() {
|
||||
throw new Error("对话落盘走工具,不走纯文本完成");
|
||||
},
|
||||
async completeWithTools() {
|
||||
calls += 1;
|
||||
return {
|
||||
content: null,
|
||||
toolCalls: [
|
||||
{
|
||||
id: "reply",
|
||||
name: "reply_user",
|
||||
arguments: JSON.stringify({ text: "下风位最适合先改顾晚棠。" }),
|
||||
},
|
||||
],
|
||||
usage: { promptTokens: 10, completionTokens: 4, totalTokens: 14 },
|
||||
};
|
||||
},
|
||||
},
|
||||
dialogue: [{ role: "user", text: "先不要落盘,告诉我该改谁" }],
|
||||
handlers: {
|
||||
listProducts: () => [],
|
||||
writeProduct: () => {
|
||||
writes += 1;
|
||||
},
|
||||
deleteProduct: () => false,
|
||||
readTag: () => undefined,
|
||||
writeTag: () => undefined,
|
||||
deleteTag: () => false,
|
||||
clearDialogue: () => undefined,
|
||||
},
|
||||
});
|
||||
expect(writes).toBe(0);
|
||||
expect(calls).toBe(1);
|
||||
expect(result.wroteTags).toEqual([]);
|
||||
expect(result.iterations).toBe(1);
|
||||
expect(result.reply).toContain("顾晚棠");
|
||||
expect(result.reply).not.toContain("没有写入产物");
|
||||
});
|
||||
|
||||
it("returns a question without writing when the first call is reply_user", async () => {
|
||||
let calls = 0;
|
||||
const result = await runDictateTurn({
|
||||
llm: {
|
||||
async complete() {
|
||||
throw new Error("对话落盘走工具,不走纯文本完成");
|
||||
},
|
||||
async completeWithTools() {
|
||||
calls += 1;
|
||||
return {
|
||||
content: null,
|
||||
toolCalls: [
|
||||
{
|
||||
id: "reply",
|
||||
name: "reply_user",
|
||||
arguments: JSON.stringify({
|
||||
text: "先改顾晚棠,还是先改表世界的同辈?",
|
||||
}),
|
||||
},
|
||||
],
|
||||
usage: { promptTokens: 10, completionTokens: 4, totalTokens: 14 },
|
||||
};
|
||||
},
|
||||
},
|
||||
dialogue: [{ role: "user", text: "先讨论,不要落盘" }],
|
||||
handlers: {
|
||||
listProducts: () => [],
|
||||
writeProduct: () => undefined,
|
||||
@@ -301,10 +367,10 @@ describe("dictate planned round", () => {
|
||||
clearDialogue: () => undefined,
|
||||
},
|
||||
});
|
||||
expect(calls).toBe(1);
|
||||
expect(result.wroteTags).toEqual([]);
|
||||
expect(result.iterations).toBe(1);
|
||||
expect(result.reply).toContain("note");
|
||||
expect(result.reply).toContain("没有写入产物");
|
||||
expect(result.reply).toContain("顾晚棠");
|
||||
});
|
||||
|
||||
it("follows a select result with a fill request that carries specs and products", async () => {
|
||||
@@ -973,4 +1039,242 @@ describe("dictate planned round", () => {
|
||||
expect(replyReq).not.toContain("#### task");
|
||||
expect(choices[2]).toEqual({ type: "function", function: { name: "reply_user" } });
|
||||
});
|
||||
|
||||
it("retries a failed fill in the same turn and patches from the previous draft", async () => {
|
||||
const products: Array<{ tag: string; content: string }> = [];
|
||||
const tags = new Map<string, string>();
|
||||
const seen: string[] = [];
|
||||
const rounds = [
|
||||
[{ id: "select", name: "select_nodes", arguments: JSON.stringify({ nodes: [{ module_id: "mood" }] }) }],
|
||||
[
|
||||
{
|
||||
id: "a",
|
||||
name: "insert",
|
||||
arguments: JSON.stringify({
|
||||
position: "设计.氛围",
|
||||
content: "细雨连绵,石板发亮",
|
||||
self_score: { dims: [{ name: "短句", score: 4 }] },
|
||||
}),
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
id: "b",
|
||||
name: "insert",
|
||||
arguments: JSON.stringify({
|
||||
position: "设计.氛围",
|
||||
content: "细雨连绵,石板发亮",
|
||||
self_score: {
|
||||
dims: [
|
||||
{ name: "短句", score: 4 },
|
||||
{ name: "画面", score: 5 },
|
||||
],
|
||||
},
|
||||
}),
|
||||
},
|
||||
{ id: "r", name: "reply_user", arguments: JSON.stringify({ text: "氛围补上了" }) },
|
||||
],
|
||||
];
|
||||
let index = 0;
|
||||
const result = await runDictateTurn({
|
||||
fillRetries: 1,
|
||||
llm: {
|
||||
async complete() {
|
||||
throw new Error("对话落盘走工具,不走纯文本完成");
|
||||
},
|
||||
async completeWithTools(messages) {
|
||||
seen.push(JSON.stringify(messages));
|
||||
return {
|
||||
content: null,
|
||||
toolCalls: rounds[index++] ?? [],
|
||||
usage: { promptTokens: 10, completionTokens: 4, totalTokens: 14 },
|
||||
};
|
||||
},
|
||||
},
|
||||
dialogue: [{ role: "user", text: "写成细雨" }],
|
||||
moduleCatalog: catalog,
|
||||
moduleReadIndex: new Map([
|
||||
["mood", { ...modulePayload, score_dimensions: ["短句", "画面"] }],
|
||||
]),
|
||||
handlers: {
|
||||
listProducts: () => products,
|
||||
writeProduct: (tag, content) => {
|
||||
products.push({ tag, content });
|
||||
},
|
||||
deleteProduct: () => false,
|
||||
readTag: (tag) => tags.get(tag),
|
||||
writeTag: (tag, content) => {
|
||||
tags.set(tag, content);
|
||||
},
|
||||
deleteTag: (tag) => tags.delete(tag),
|
||||
clearDialogue: () => undefined,
|
||||
},
|
||||
});
|
||||
|
||||
expect(seen).toHaveLength(3);
|
||||
expect(seen[2]).toContain("同轮补写");
|
||||
expect(seen[2]).toContain("细雨连绵,石板发亮");
|
||||
expect(seen[2]).toContain("只改失败点");
|
||||
expect(seen[2]).toContain("已接受、请原样保留:短句");
|
||||
expect(products).toEqual([{ tag: "设计.氛围", content: "细雨连绵,石板发亮" }]);
|
||||
expect(result.reply).toContain("氛围补上了");
|
||||
expect(tags.has(DICTATE_REMEDIATE_TAG)).toBe(false);
|
||||
});
|
||||
|
||||
it("keeps accepted self_score dims when a later attempt drops them", async () => {
|
||||
const scores: unknown[] = [];
|
||||
const rounds = [
|
||||
[{ id: "select", name: "select_nodes", arguments: JSON.stringify({ nodes: [{ module_id: "mood" }] }) }],
|
||||
[
|
||||
{
|
||||
id: "a",
|
||||
name: "insert",
|
||||
arguments: JSON.stringify({
|
||||
position: "设计.氛围",
|
||||
content: "细雨",
|
||||
self_score: { dims: [{ name: "短句", score: 4 }] },
|
||||
}),
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
id: "b",
|
||||
name: "insert",
|
||||
arguments: JSON.stringify({
|
||||
position: "设计.氛围",
|
||||
content: "细雨",
|
||||
self_score: { dims: [{ name: "画面", score: 5 }] },
|
||||
}),
|
||||
},
|
||||
{ id: "r", name: "reply_user", arguments: JSON.stringify({ text: "补上了" }) },
|
||||
],
|
||||
];
|
||||
let index = 0;
|
||||
const tags = new Map<string, string>();
|
||||
await runDictateTurn({
|
||||
fillRetries: 1,
|
||||
llm: {
|
||||
async complete() {
|
||||
throw new Error("对话落盘走工具,不走纯文本完成");
|
||||
},
|
||||
async completeWithTools() {
|
||||
return {
|
||||
content: null,
|
||||
toolCalls: rounds[index++] ?? [],
|
||||
usage: { promptTokens: 10, completionTokens: 4, totalTokens: 14 },
|
||||
};
|
||||
},
|
||||
},
|
||||
dialogue: [{ role: "user", text: "写成细雨" }],
|
||||
moduleCatalog: catalog,
|
||||
moduleReadIndex: new Map([
|
||||
["mood", { ...modulePayload, score_dimensions: ["短句", "画面"] }],
|
||||
]),
|
||||
handlers: {
|
||||
listProducts: () => [],
|
||||
writeProduct: (_tag, _content, _order, metadata) => {
|
||||
scores.push(metadata?.selfScore);
|
||||
},
|
||||
deleteProduct: () => false,
|
||||
readTag: (tag) => tags.get(tag),
|
||||
writeTag: (tag, content) => {
|
||||
tags.set(tag, content);
|
||||
},
|
||||
deleteTag: () => false,
|
||||
clearDialogue: () => undefined,
|
||||
},
|
||||
});
|
||||
|
||||
expect(scores).toHaveLength(1);
|
||||
const dims = (scores[0] as { dims: Array<{ name: string }> }).dims.map((dim) => dim.name).sort();
|
||||
expect(dims).toEqual(["画面", "短句"]);
|
||||
});
|
||||
|
||||
it("stores the failed draft and feeds it to the next turn", async () => {
|
||||
const tags = new Map<string, string>();
|
||||
const seen: string[] = [];
|
||||
const first = [
|
||||
[{ id: "select", name: "select_nodes", arguments: JSON.stringify({ nodes: [{ module_id: "mood" }] }) }],
|
||||
[
|
||||
{
|
||||
id: "a",
|
||||
name: "insert",
|
||||
arguments: JSON.stringify({ position: "设计.氛围", content: "细雨连绵" }),
|
||||
},
|
||||
],
|
||||
];
|
||||
let index = 0;
|
||||
const handlers = {
|
||||
listProducts: () => [],
|
||||
writeProduct: () => undefined,
|
||||
deleteProduct: () => false,
|
||||
readTag: (tag: string) => tags.get(tag),
|
||||
writeTag: (tag: string, content: string) => {
|
||||
tags.set(tag, content);
|
||||
},
|
||||
deleteTag: () => false,
|
||||
clearDialogue: () => undefined,
|
||||
};
|
||||
const failed = await runDictateTurn({
|
||||
llm: {
|
||||
async complete() {
|
||||
throw new Error("对话落盘走工具,不走纯文本完成");
|
||||
},
|
||||
async completeWithTools() {
|
||||
return {
|
||||
content: null,
|
||||
toolCalls: first[index++] ?? [],
|
||||
usage: { promptTokens: 10, completionTokens: 4, totalTokens: 14 },
|
||||
};
|
||||
},
|
||||
},
|
||||
dialogue: [{ role: "user", text: "写成细雨" }],
|
||||
moduleCatalog: catalog,
|
||||
moduleReadIndex: new Map([["mood", { ...modulePayload, score_dimensions: ["短句"] }]]),
|
||||
handlers,
|
||||
});
|
||||
expect(failed.reply).toContain("失败待补(下轮继续)");
|
||||
expect(failed.reply).not.toContain("已同轮补写");
|
||||
const stored = parseDictateRemediate(tags.get(DICTATE_REMEDIATE_TAG));
|
||||
expect(stored.items[0]?.draft).toBe("细雨连绵");
|
||||
|
||||
const second = [
|
||||
[{ id: "select2", name: "select_nodes", arguments: JSON.stringify({ nodes: [] }) }],
|
||||
[
|
||||
{
|
||||
id: "b",
|
||||
name: "insert",
|
||||
arguments: JSON.stringify({
|
||||
position: "设计.氛围",
|
||||
content: "细雨连绵",
|
||||
self_score: { dims: [{ name: "短句", score: 4 }] },
|
||||
}),
|
||||
},
|
||||
{ id: "r2", name: "reply_user", arguments: JSON.stringify({ text: "补上了" }) },
|
||||
],
|
||||
];
|
||||
index = 0;
|
||||
await runDictateTurn({
|
||||
llm: {
|
||||
async complete() {
|
||||
throw new Error("对话落盘走工具,不走纯文本完成");
|
||||
},
|
||||
async completeWithTools(messages) {
|
||||
seen.push(messages.map((message) => message.content ?? "").join("\n"));
|
||||
return {
|
||||
content: null,
|
||||
toolCalls: second[index++] ?? [],
|
||||
usage: { promptTokens: 10, completionTokens: 4, totalTokens: 14 },
|
||||
};
|
||||
},
|
||||
},
|
||||
dialogue: [{ role: "user", text: "继续" }],
|
||||
moduleCatalog: catalog,
|
||||
moduleReadIndex: new Map([["mood", { ...modulePayload, score_dimensions: ["短句"] }]]),
|
||||
handlers,
|
||||
});
|
||||
expect(seen[1]).toContain("底稿");
|
||||
expect(seen[1]).toContain("细雨连绵");
|
||||
expect(seen[1]).toContain("只改失败点");
|
||||
});
|
||||
});
|
||||
|
||||
+13
-9
@@ -124,8 +124,8 @@ describe("dictate context", () => {
|
||||
expect(catalog).toBeTruthy();
|
||||
const block = formatModuleCatalogForDictate(catalog!);
|
||||
expect(block).toContain("【能力 · 何时落盘】");
|
||||
expect(block).toContain("美学纲领与交互范式");
|
||||
expect(block).toContain("落盘:insert 「设计.美学纲领与交互范式」");
|
||||
expect(block).toContain("美学纲领:");
|
||||
expect(block).toContain("落盘:insert 「设计.美学纲领」");
|
||||
expect(block).toContain("何时用");
|
||||
expect(block).toContain("何时不用");
|
||||
expect(block).toContain("declare_variable");
|
||||
@@ -136,7 +136,7 @@ describe("dictate context", () => {
|
||||
expect(block).toContain("可增殖");
|
||||
expect(block).not.toContain("role=prototype");
|
||||
expect(block).toContain("落盘:insert 「设计.叙事指南」");
|
||||
expect(block).toContain("落盘:insert 「设计.故事推进」");
|
||||
expect(block).toContain("落盘:insert 「设计.故事推进与交互范式」");
|
||||
expect(block).not.toMatch(/^- 叙事指南与故事推进/m);
|
||||
});
|
||||
|
||||
@@ -180,11 +180,12 @@ describe("dictate context", () => {
|
||||
it("resolves insert tag to module and builds user-facing brief", async () => {
|
||||
const catalog = await loadModuleCatalog("dialogue/world-simulator");
|
||||
expect(catalog).toBeTruthy();
|
||||
const mod = resolveModuleForInsertTag(
|
||||
"设计.美学纲领与交互范式",
|
||||
catalog!,
|
||||
expect(resolveModuleForInsertTag("设计.美学纲领", catalog!)?.id).toBe(
|
||||
"aesthetics-interaction",
|
||||
);
|
||||
expect(mod?.id).toBe("aesthetics-interaction");
|
||||
expect(
|
||||
resolveModuleForInsertTag("设计.美学纲领与交互范式", catalog!)?.id,
|
||||
).toBe("aesthetics-interaction");
|
||||
expect(
|
||||
resolveModuleForInsertTag("设计.开场白", catalog!)?.id,
|
||||
).toBe("opening-setup");
|
||||
@@ -203,6 +204,9 @@ describe("dictate context", () => {
|
||||
expect(resolveModuleForInsertTag("设计.叙事指南", catalog!)?.id).toBe(
|
||||
"narrative-guide",
|
||||
);
|
||||
expect(
|
||||
resolveModuleForInsertTag("设计.故事推进与交互范式", catalog!)?.id,
|
||||
).toBe("story-progression");
|
||||
expect(resolveModuleForInsertTag("设计.故事推进", catalog!)?.id).toBe(
|
||||
"story-progression",
|
||||
);
|
||||
@@ -214,9 +218,9 @@ describe("dictate context", () => {
|
||||
catalog: catalog!,
|
||||
skillPackRoot: "dialogue/world-simulator",
|
||||
});
|
||||
const brief = index.get("设计.美学纲领与交互范式");
|
||||
const brief = index.get("设计.美学纲领");
|
||||
expect(brief).toBeTruthy();
|
||||
expect(brief!).toContain("# 本轮关注 · 美学纲领与交互范式");
|
||||
expect(brief!).toContain("# 本轮关注 · 美学纲领");
|
||||
expect(brief!).toContain("不要求固定标题");
|
||||
expect(brief!).toContain("本模块内容包括");
|
||||
expect(brief!).toContain("## 写入用户回复时做什么");
|
||||
|
||||
Reference in New Issue
Block a user