Files
writing-agent/tests/context-fragment.test.ts
T
chenmoranzhiandCursor 3d720f23fe 主世界层直接写正文,转述与旁观改读用户展示输出。
去掉裁决包主路径,让无转述时可直出终稿、有转述时再改写镶壳。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-10 02:18:14 +08:00

315 lines
11 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
parseContextFragment,
projectFragmentContent,
contextFragmentToView,
extractFragmentAskSidecar,
isUsableContextFragment,
expectsContextFragmentTag,
} from "../src/skills/context-fragment.js";
import {
parseContextOrder,
contextOrderToSegments,
slotOrderForRef,
applyContextOrderEdit,
mergeContextOrderIntoWorkerSetJson,
serializeContextOrder,
} from "../src/skills/context-order.js";
import { assembleWorkerContext } from "../src/skills/context-segments.js";
import { Blackboard } from "../src/blackboard/blackboard.js";
import { buildDeclaredWorkerSkill } from "../src/skills/declared-worker.js";
import { parseWorkerSetYaml } from "../src/skills/worker-set-parse.js";
describe("context-fragment.v1", () => {
it("parses public header and projects summary", () => {
const frag = parseContextFragment({
schema: "context-fragment.v1",
技能: "美学纲领与交互范式",
brief: "特权求生紧张",
mount: ["world-simulator", "narrator"],
稳变: "stable",
正文: { 体验: { 内核: "紧张" } },
开放问题: [],
})!;
expect(frag.技能).toBe("美学纲领与交互范式");
expect(projectFragmentContent(JSON.stringify(frag), "summary")).toBe(
"特权求生紧张",
);
const view = contextFragmentToView(frag);
expect(view.ok).toBe(true);
expect(view.sections.some((s) => s.title === "概要")).toBe(true);
});
it("extracts 自评 + 追问 into ask sidecar", () => {
const side = extractFragmentAskSidecar({
schema: "context-fragment.v1",
brief: "孤立免疫",
正文: { 美学纲领: { 体验内核: "…" } },
自评: {
维度: [
{ 名: "交互范式", 分数: 7, 说明: "权限尚可" },
{ 名: "美学纲领", 分数: 5.5, 说明: "边界未锁" },
],
薄弱点: "暴力尺度未定",
},
追问: {
导语: "为贴近质感,还需确认:",
题目: [
{
问: "暴力与血腥如何服务压迫感?",
建议选项: ["偶发锋利高光", "常态压抑少见血", "其它"],
示例: "远处尖叫,近处只留锈迹",
},
],
},
});
expect(side.assessment).toContain("交互范式 7/10");
expect(side.assessment).toContain("美学纲领 5.5/10");
expect(side.assessment).toContain("薄弱点:暴力尺度未定");
expect(side.assessment).toContain("为贴近质感");
expect(side.questions).toHaveLength(1);
expect(side.questions[0]!.prompt).toContain("暴力与血腥");
expect(side.questions[0]!.prompt).toContain("示例:远处尖叫");
expect(side.questions[0]!.options?.map((o) => o.label)).toEqual([
"偶发锋利高光",
"常态压抑少见血",
"其它",
]);
});
it("does not surface empty 追问 导语 as sidecar assessment", () => {
const side = extractFragmentAskSidecar({
schema: "context-fragment.v1",
brief: "返现都市",
正文: { 美学纲领: { 体验内核: "被宠" } },
自评: {
维度: [{ 名: "交互范式", 分数: 9, 说明: "站位已清" }],
},
追问: {
导语: "为贴近你要的质感,还需确认:",
题目: [],
},
});
expect(side.questions).toHaveLength(0);
expect(side.assessment).toContain("交互范式 9/10");
expect(side.assessment).not.toContain("还需确认");
});
it("isUsableContextFragment requires non-empty 正文", () => {
expect(
isUsableContextFragment({
schema: "context-fragment.v1",
技能: "美学纲领与交互范式",
brief: "孤立免疫",
正文: { 美学纲领: { 体验内核: "特权" } },
}),
).toBe(true);
expect(
isUsableContextFragment({
schema: "context-fragment.v1",
技能: "美学纲领与交互范式",
brief: "孤立免疫",
}),
).toBe(false);
expect(expectsContextFragmentTag("设计.美学纲领与交互范式")).toBe(true);
expect(expectsContextFragmentTag("设计.创作流程")).toBe(false);
});
});
describe("context-order.v1", () => {
it("maps flat order to segments (history after stable)", () => {
const doc = parseContextOrder({
schema: "context-order.v1",
slots: [
{
ref: "world-simulator",
inserts: [
{ order: 0, ref: "worker.persona", projection: "fixed" },
{ order: 1, ref: "设计.实现机制", projection: "summary" },
{ order: 2, ref: "对话.历史", projection: "summary" },
{ order: 3, ref: "用户.最新输入", projection: "full" },
],
},
],
})!;
const slot = slotOrderForRef(doc, "world-simulator")!;
const segs = contextOrderToSegments({
slot,
personaText: "中立主世界层",
});
expect(segs[0].inline).toContain("中立主世界层");
expect(segs[1].tags).toEqual(["设计.实现机制"]);
expect(segs[2].tags).toEqual(["对话.历史"]);
expect(segs[3].tier).toBe("dynamic");
});
it("accepts agents[] roster and maps gm → world-simulator", () => {
const doc = parseContextOrder({
schema: "context-order.v1",
brief: "旁观+主世界层+转述",
agents: [
{
id: "auditor",
label: "表格管理",
enabled: true,
when: "every_turn",
inserts: [
{ order: 0, ref: "worker.persona", projection: "fixed" },
{ order: 1, ref: "设计.变量设计与更新规则", projection: "summary" },
],
},
{
id: "gm",
enabled: true,
inserts: [
{ order: 0, ref: "worker.persona", projection: "fixed" },
{ order: 1, ref: "对话.历史", projection: "summary" },
],
},
{ id: "narrator", enabled: true, inserts: [] },
{ id: "perspective", enabled: false, inserts: [] },
{ id: "chance", enabled: false, when: "on_demand", inserts: [] },
],
})!;
expect(doc.play_slots?.auditor).not.toBe(false);
expect(doc.play_slots?.gm).toBe(true);
expect(doc.play_slots?.perspective).toBe(false);
expect(doc.play_slots?.chance).toBe(false);
expect(slotOrderForRef(doc, "auditor")?.label).toBe("表格管理");
expect(slotOrderForRef(doc, "world-simulator")?.inserts.some((i) => i.ref === "对话.历史")).toBe(
true,
);
expect(slotOrderForRef(doc, "role-decide")).toBeUndefined();
});
it("index projection keeps brief, mount and 稳变 without 正文", () => {
const text = projectFragmentContent(
JSON.stringify({
schema: "context-fragment.v1",
技能: "美学纲领与交互范式",
brief: "免疫即权力",
mount: ["world-simulator", "narrator"],
稳变: "stable",
正文: { 美学纲领: { 体验内核: "很长不应出现在 index 里的正文" } },
}),
"index",
);
expect(text).toContain("免疫即权力");
expect(text).toContain("挂载:world-simulator、narrator");
expect(text).toContain("稳变:stable");
expect(text).not.toContain("很长不应出现在 index 里的正文");
});
it("reorders flat list and merges into worker set JSON", () => {
const doc = parseContextOrder({
schema: "context-order.v1",
slots: [
{
ref: "narrator",
inserts: [
{ order: 0, ref: "worker.persona", projection: "fixed" },
{ order: 1, ref: "设计.叙事指南", projection: "summary" },
{ order: 2, ref: "设计.美学纲领与交互范式", projection: "summary" },
{ order: 3, ref: "对话.历史", projection: "summary" },
{ order: 4, ref: "运行.本轮.裁决", projection: "full" },
],
},
],
})!;
const moved = applyContextOrderEdit(doc, {
action: "move",
slotRef: "narrator",
index: 2,
delta: -1,
});
expect(moved.slots[0]!.inserts.map((i) => i.ref)).toEqual([
"worker.persona",
"设计.美学纲领与交互范式",
"设计.叙事指南",
"对话.历史",
"运行.本轮.裁决",
]);
const afterHist = applyContextOrderEdit(moved, {
action: "set_anchor",
slotRef: "narrator",
index: 1,
anchor: "post_history",
});
const refs = afterHist.slots[0]!.inserts.map((i) => i.ref);
const histAt = refs.indexOf("对话.历史");
expect(refs.indexOf("设计.美学纲领与交互范式")).toBeGreaterThan(histAt);
const merged = mergeContextOrderIntoWorkerSetJson(
JSON.stringify({
play_slots: { gm: true, narrator: true, perspective: false },
workers: [],
}),
afterHist,
);
const again = JSON.parse(merged);
expect(again.context_order.schema).toBe("context-order.v1");
expect(serializeContextOrder(afterHist)).toContain("对话.历史");
});
it("declared worker prefers context_order segments", () => {
const parsed = parseWorkerSetYaml(
JSON.stringify({
play_slots: { gm: true, narrator: true, perspective: false },
context_order: {
schema: "context-order.v1",
slots: [
{
ref: "world-simulator",
inserts: [
{ order: 0, ref: "worker.persona", projection: "fixed" },
{ order: 1, ref: "对话.历史", projection: "summary" },
{ order: 2, ref: "用户.最新输入", projection: "full" },
],
},
],
},
workers: [],
}),
);
expect(parsed.parseError).toBeUndefined();
const entry = parsed.workers.find((w) => w.ref === "world-simulator")!;
const { worker } = buildDeclaredWorkerSkill({
skillPackName: "world-simulator",
entry,
template: {
id: "world-simulator",
label: "主世界层",
duty: "写正文",
suggested_context: { static: ["设计.worker集"], dynamic: ["用户.最新输入"] },
},
workerSet: parsed,
});
expect(
worker.contextSegments?.some((s) => s.inline?.includes("正文")),
).toBe(true);
expect(
worker.contextSegments?.some(
(s) => s.tier === "dynamic" && s.tags.includes("用户.最新输入"),
),
).toBe(true);
const bb = new Blackboard();
bb.write({
tag: "用户.最新输入",
content: "推门进去",
source: "test",
});
const text = assembleWorkerContext({
inputs: { "用户.最新输入": "推门进去" },
segments: worker.contextSegments,
blackboard: bb,
workerId: "world-simulator",
workerName: "主世界层",
outputTags: ["运行.本轮.裁决"],
});
expect(text).toContain("裁决");
expect(text).toContain("推门进去");
});
});