feat(extract): add split extraction prompt plumbing

This commit is contained in:
youzini
2026-06-09 04:37:13 +00:00
parent 7f02fd45e2
commit 63fba2c8b4
6 changed files with 259 additions and 3 deletions

View File

@@ -110,8 +110,12 @@ assert.equal(defaultSettings.nativeRolloutVersion, 2);
assert.equal(defaultSettings.nativeEngineFailOpen, true);
assert.equal(defaultSettings.graphNativeForceDisable, false);
assert.equal(defaultSettings.taskProfilesVersion, 3);
assert.equal(defaultSettings.extractObjectivePrompt, "");
assert.equal(defaultSettings.extractSubjectivePrompt, "");
assert.ok(defaultSettings.taskProfiles);
assert.ok(defaultSettings.taskProfiles.extract);
assert.ok(defaultSettings.taskProfiles.extract_objective);
assert.ok(defaultSettings.taskProfiles.extract_subjective);
assert.ok(defaultSettings.taskProfiles.recall);
assert.ok(defaultSettings.globalTaskRegex);
assert.deepEqual(

View File

@@ -47,6 +47,7 @@ installResolveHooks([
const { buildTaskLlmPayload, buildTaskPrompt } = await import("../prompting/prompt-builder.js");
const {
createBuiltinPromptBlock,
createDefaultGlobalTaskRegex,
createDefaultTaskProfiles,
} = await import("../prompting/prompt-profiles.js");
@@ -256,4 +257,98 @@ assert.equal(
initializeHostAdapter({});
const splitContextTaskProfiles = createDefaultTaskProfiles();
const subjectiveProfile = splitContextTaskProfiles.extract_subjective.profiles[0];
subjectiveProfile.blocks = [
createBuiltinPromptBlock("extract_subjective", "objectiveExtractionDraft", {
name: "客观提取草稿",
order: 0,
}),
createBuiltinPromptBlock("extract_subjective", "objectiveRefMap", {
name: "客观引用映射",
order: 1,
}),
createBuiltinPromptBlock("extract_subjective", "ownerContext", {
name: "视角主体上下文",
order: 2,
}),
createBuiltinPromptBlock("extract_subjective", "batchStoryTime", {
name: "批次故事时间",
order: 3,
}),
createBuiltinPromptBlock("extract_subjective", "relevantPovMemories", {
name: "相关主观记忆",
order: 4,
}),
createBuiltinPromptBlock("extract_subjective", "cognitionStateDigest", {
name: "认知状态摘要",
order: 5,
}),
];
const splitContextPromptBuild = await buildTaskPrompt(
{
taskProfilesVersion: 3,
taskProfiles: splitContextTaskProfiles,
},
"extract_subjective",
{
objectiveExtractionDraft: { operations: [{ ref: "evt1", type: "event" }] },
objectiveRefMap: { evt1: "node-evt1" },
ownerContext: { ownerType: "character", ownerName: "艾琳" },
batchStoryTime: { label: "第二天清晨", confidence: "high" },
relevantPovMemories: ["旧 POV 记忆"],
cognitionStateDigest: "艾琳知道 evt1",
},
);
const splitContextPayload = buildTaskLlmPayload(
splitContextPromptBuild,
"fallback-user",
);
assert.deepEqual(
splitContextPayload.promptMessages
.map((message) => message.sourceKey)
.filter(Boolean),
[
"objectiveExtractionDraft",
"objectiveRefMap",
"ownerContext",
"batchStoryTime",
"relevantPovMemories",
"cognitionStateDigest",
],
);
assert.match(
String(
splitContextPayload.promptMessages.find(
(message) => message.sourceKey === "objectiveExtractionDraft",
)?.content || "",
),
/"ref": "evt1"/,
);
assert.match(
String(
splitContextPayload.promptMessages.find(
(message) => message.sourceKey === "ownerContext",
)?.content || "",
),
/"ownerName": "艾琳"/,
);
assert.match(
String(
splitContextPayload.promptMessages.find(
(message) => message.sourceKey === "batchStoryTime",
)?.content || "",
),
/"第二天清晨"/,
);
assert.match(
String(
splitContextPayload.promptMessages.find(
(message) => message.sourceKey === "relevantPovMemories",
)?.content || "",
),
/旧 POV 记忆/,
);
console.log("prompt-builder-defaults tests passed");

View File

@@ -7,7 +7,11 @@ import {
createLocalRegexRule,
exportTaskProfile,
getActiveTaskProfile,
getBuiltinBlockDefinitions,
getLegacyPromptFieldForTask,
getTaskTypeMeta,
getTaskTypeOptions,
getTaskTypes,
importTaskProfile,
restoreDefaultTaskProfile,
upsertTaskProfile,
@@ -97,4 +101,75 @@ const restoredActive = getActiveTaskProfile(
assert.equal(restoredActive.id, "default");
assert.equal(getLegacyPromptFieldForTask("extract"), "extractPrompt");
assert.ok(getTaskTypes().includes("extract_objective"));
assert.ok(getTaskTypes().includes("extract_subjective"));
assert.equal(
getTaskTypeOptions().some((option) => option.id === "extract_objective"),
false,
);
assert.equal(
getTaskTypeOptions().some((option) => option.id === "extract_subjective"),
false,
);
assert.deepEqual(
{
objective: getTaskTypeMeta("extract_objective"),
subjective: getTaskTypeMeta("extract_subjective"),
},
{
objective: {
id: "extract_objective",
label: "客观提取",
description: "从当前对话批次中抽取客观层结构化记忆。",
hidden: true,
},
subjective: {
id: "extract_subjective",
label: "主观提取",
description: "从客观提取草稿与视角上下文中抽取主观记忆。",
hidden: true,
},
},
);
assert.ok(taskProfiles.extract_objective?.profiles?.length > 0);
assert.ok(taskProfiles.extract_subjective?.profiles?.length > 0);
assert.equal(
taskProfiles.extract_objective.profiles[0].metadata.legacyPromptField,
"extractObjectivePrompt",
);
assert.equal(
taskProfiles.extract_subjective.profiles[0].metadata.legacyPromptField,
"extractSubjectivePrompt",
);
assert.equal(
taskProfiles.extract_objective.profiles[0].blocks.find((block) => block.id === "default-role")?.content,
baseProfile.blocks.find((block) => block.id === "default-role")?.content,
);
assert.equal(
taskProfiles.extract_subjective.profiles[0].blocks.find((block) => block.id === "default-rules")?.content,
baseProfile.blocks.find((block) => block.id === "default-rules")?.content,
);
assert.deepEqual(
getBuiltinBlockDefinitions("extract_subjective")
.map((definition) => definition.sourceKey)
.filter((sourceKey) =>
[
"objectiveExtractionDraft",
"objectiveRefMap",
"ownerContext",
"batchStoryTime",
"relevantPovMemories",
"cognitionStateDigest",
].includes(sourceKey),
),
[
"objectiveExtractionDraft",
"objectiveRefMap",
"ownerContext",
"batchStoryTime",
"relevantPovMemories",
"cognitionStateDigest",
],
);
console.log("task-profile-storage tests passed");