重构世界模拟器为模块化配方架构,完善创作编排、会话运行时与 Web UI,并清理过时技能。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-30 00:39:32 +08:00
parent 2b74c30d36
commit e670a5129c
167 changed files with 22955 additions and 5659 deletions

View File

@@ -4,24 +4,13 @@ import {
buildIntakeProgress,
extractIntakeHeuristic,
intakeFieldsFromInquiry,
synthesizeDemandText,
} from "../src/intake/intake.js";
import { applyEvent, createSession } from "../src/runtime/phase-machine.js";
import { toActiveSkillSnapshot } from "../src/skills/snapshot.js";
import { loadSkill } from "../src/skills/loader.js";
describe("intake fields", () => {
it("parses required and optional from roleplay skill", async () => {
const skill = await loadSkill("roleplay-game-theory");
const fields = intakeFieldsFromInquiry(skill.startupInquiry);
expect(fields.filter((f) => f.required).length).toBe(3);
expect(fields.filter((f) => !f.required).length).toBe(3);
});
it("marks ready when all required filled", () => {
const fields = intakeFieldsFromInquiry({
prompt: "p",
targetKey: "用户.博弈需求",
targetKey: "用户.需求",
requiredFields: ["情境", "角色", "轮次"],
optionalFields: ["输出偏好"],
});
@@ -46,23 +35,10 @@ describe("intake fields", () => {
requiredFields: ["实验情境", "轮次模式"],
optionalFields: [],
});
const values = extractIntakeHeuristic(
"德州扑克,单轮定胜负",
fields,
{},
);
const values = extractIntakeHeuristic("德州扑克,单轮定胜负", fields, {});
expect(Object.keys(values).length).toBeGreaterThan(0);
});
it("parses roleplay intake fields as 3 required + optional", async () => {
const skill = await loadSkill("roleplay-game-theory");
const fields = intakeFieldsFromInquiry(skill.startupInquiry);
expect(fields.filter((f) => f.required).length).toBe(3);
expect(fields.filter((f) => !f.required).length).toBe(3);
expect(fields.some((f) => f.label.includes("情境"))).toBe(true);
expect(fields.some((f) => f.label.includes("进程"))).toBe(true);
});
it("buildIntakeFollowUpMessage lists missing required fields", () => {
const fields = intakeFieldsFromInquiry({
prompt: "p",
@@ -78,40 +54,4 @@ describe("intake fields", () => {
expect(msg).toContain("角色");
expect(msg).toContain("进程");
});
it("confirm intake writes structured demand tag", async () => {
const snap = toActiveSkillSnapshot(await loadSkill("basic"));
let session = createSession("default");
session = applyEvent(session, {
type: "session_started",
payload: {
presetId: "default",
availableSkills: [{ name: "basic", description: "", category: "novel" }],
},
}).session;
session = applyEvent(session, {
type: "skill_selected",
payload: { skill: snap },
}).session;
expect(session.waitingReason?.kind).toBe("intake");
const fields = snap.intakeFields;
const values: Record<string, string> = {};
for (const f of fields) {
values[f.id] = `值-${f.label}`;
}
session = applyEvent(session, {
type: "user_submitted_input",
payload: { text: "一次性提交", intakeValues: values },
}).session;
expect(session.waitingReason?.kind).toBe("intake");
session = applyEvent(session, {
type: "user_confirmed_intake",
payload: {},
}).session;
expect(session.slots.startupCompleted).toBe(true);
expect(String(session.slots["book.brief"])).toContain("题材");
expect(synthesizeDemandText(fields, values)).toContain("值-题材");
});
});