mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-05-15 22:30:38 +08:00
feat: hide assistant card names in extraction transcript, split sectioned recentMessages into 2 system messages
This commit is contained in:
@@ -76,9 +76,23 @@ const chat = [
|
||||
{
|
||||
const mixed = [
|
||||
{ seq: 1, role: "user", content: "context user", speaker: "A", isContextOnly: true },
|
||||
{ seq: 2, role: "assistant", content: "context ai", speaker: "B", isContextOnly: true },
|
||||
{
|
||||
seq: 2,
|
||||
role: "assistant",
|
||||
content: "context ai",
|
||||
speaker: "B",
|
||||
hideSpeakerLabel: true,
|
||||
isContextOnly: true,
|
||||
},
|
||||
{ seq: 3, role: "user", content: "target user", speaker: "A", isContextOnly: false },
|
||||
{ seq: 4, role: "assistant", content: "target ai", speaker: "B", isContextOnly: false },
|
||||
{
|
||||
seq: 4,
|
||||
role: "assistant",
|
||||
content: "target ai",
|
||||
speaker: "B",
|
||||
hideSpeakerLabel: true,
|
||||
isContextOnly: false,
|
||||
},
|
||||
];
|
||||
const transcript = formatExtractionTranscript(mixed);
|
||||
assert.match(transcript, /已提取过/, "transcript should contain context review header");
|
||||
@@ -89,6 +103,8 @@ const chat = [
|
||||
);
|
||||
assert.match(transcript, /#1.*context user/, "context message should appear");
|
||||
assert.match(transcript, /#3.*target user/, "target message should appear");
|
||||
assert.match(transcript, /#2 \[assistant\]: context ai/, "assistant card name should be hidden");
|
||||
assert.doesNotMatch(transcript, /#2 \[assistant\|B\]:/, "assistant card name should not be rendered");
|
||||
console.log(" ✓ formatExtractionTranscript: section dividers for mixed context/target");
|
||||
}
|
||||
|
||||
@@ -132,8 +148,20 @@ const chat = [
|
||||
const targetFiltered = result.filteredMessages.filter((m) => !m.isContextOnly);
|
||||
assert.equal(contextFiltered.length, 2, "context messages propagated through filtering");
|
||||
assert.equal(targetFiltered.length, 2, "target messages propagated through filtering");
|
||||
assert.equal(
|
||||
result.filteredMessages.find((m) => m.seq === 2)?.hideSpeakerLabel,
|
||||
true,
|
||||
"active character assistant label should be hidden",
|
||||
);
|
||||
assert.equal(
|
||||
result.filteredMessages.find((m) => m.seq === 1)?.hideSpeakerLabel,
|
||||
false,
|
||||
"user label should remain visible",
|
||||
);
|
||||
assert.match(result.filteredTranscript, /已提取过/, "transcript includes context header");
|
||||
assert.match(result.filteredTranscript, /本次需要提取/, "transcript includes target header");
|
||||
assert.match(result.filteredTranscript, /#2 \[assistant\]: old answer/, "assistant transcript should hide character name");
|
||||
assert.doesNotMatch(result.filteredTranscript, /#2 \[assistant\|B\]:/, "assistant transcript should not show character name");
|
||||
console.log(" ✓ buildExtractionInputContext: isContextOnly propagated to filteredMessages and transcript");
|
||||
}
|
||||
|
||||
|
||||
@@ -141,8 +141,9 @@ try {
|
||||
(message) => message.sourceKey === "recentMessages",
|
||||
);
|
||||
assert.ok(recentBlock);
|
||||
assert.match(String(recentBlock?.content || ""), /#10 \[assistant\|艾琳\]: 继续说明/);
|
||||
assert.match(String(recentBlock?.content || ""), /#10 \[assistant\]: 继续说明/);
|
||||
assert.match(String(recentBlock?.content || ""), /#11 \[user\|玩家\]: 用户输入/);
|
||||
assert.doesNotMatch(String(recentBlock?.content || ""), /#10 \[assistant\|艾琳\]:/);
|
||||
assert.doesNotMatch(String(recentBlock?.content || ""), /隐式思维|<think>/);
|
||||
} finally {
|
||||
restore();
|
||||
|
||||
@@ -224,16 +224,25 @@ function collectAllPromptContent(captured) {
|
||||
assert.equal(result.success, true);
|
||||
assert.ok(captured);
|
||||
|
||||
const recentBlock = (Array.isArray(captured.promptMessages) ? captured.promptMessages : []).find(
|
||||
const recentMessages = (Array.isArray(captured.promptMessages)
|
||||
? captured.promptMessages
|
||||
: []
|
||||
).filter(
|
||||
(m) => m.sourceKey === "recentMessages",
|
||||
);
|
||||
assert.ok(recentBlock, "recentMessages block should exist");
|
||||
const recentContent = String(recentBlock?.content || "");
|
||||
assert.match(recentContent, /以下是上下文回顾(已提取过),仅供理解剧情/);
|
||||
assert.match(recentContent, /以下是本次需要提取记忆的新对话内容/);
|
||||
assert.equal(recentMessages.length, 2, "recentMessages should split into 2 section system messages");
|
||||
assert.equal(recentMessages[0]?.role, "system");
|
||||
assert.equal(recentMessages[0]?.transcriptSection, "context");
|
||||
assert.match(String(recentMessages[0]?.content || ""), /^--- 以下是上下文回顾(已提取过),仅供理解剧情 ---/);
|
||||
assert.match(String(recentMessages[0]?.content || ""), /#10 \[user\|玩家\]: 第一轮消息/);
|
||||
assert.equal(recentMessages[1]?.role, "system");
|
||||
assert.equal(recentMessages[1]?.transcriptSection, "target");
|
||||
assert.match(String(recentMessages[1]?.content || ""), /^--- 以下是本次需要提取记忆的新对话内容 ---/);
|
||||
assert.match(String(recentMessages[1]?.content || ""), /#12 \[user\|玩家\]: 第二轮消息/);
|
||||
assert.ok(
|
||||
recentContent.indexOf("已提取过") < recentContent.indexOf("本次需要提取"),
|
||||
"context review should appear before extraction target section",
|
||||
recentMessages[0].content.includes("已提取过") &&
|
||||
recentMessages[1].content.includes("本次需要提取"),
|
||||
"context and target sections should each be emitted as a single system message",
|
||||
);
|
||||
} finally {
|
||||
restore();
|
||||
|
||||
@@ -286,7 +286,7 @@ try {
|
||||
).find((message) => message.sourceKey === "recentMessages");
|
||||
assert.ok(recentBlock, "recentMessages block should exist");
|
||||
const recentContent = String(recentBlock?.content || "");
|
||||
assert.match(recentContent, /#30 \[assistant\|艾琳\]: 艾琳说:去调查蓝钥匙。/);
|
||||
assert.match(recentContent, /#30 \[assistant\]: 艾琳说:去调查蓝钥匙。/);
|
||||
assert.match(
|
||||
recentContent,
|
||||
/#31 \[assistant\|旁白\]: 旁白补充:<status mood='tense'>雨夜<\/status>巷子很安静。/,
|
||||
@@ -351,7 +351,7 @@ try {
|
||||
: []
|
||||
).find((message) => message.sourceKey === "recentMessages");
|
||||
assert.ok(recentBlock, "recentMessages block should still exist when worldbook is disabled");
|
||||
assert.match(String(recentBlock?.content || ""), /#30 \[assistant\|艾琳\]: 艾琳说:去调查蓝钥匙。/);
|
||||
assert.match(String(recentBlock?.content || ""), /#30 \[assistant\]: 艾琳说:去调查蓝钥匙。/);
|
||||
} finally {
|
||||
restore();
|
||||
}
|
||||
|
||||
@@ -117,6 +117,7 @@ const promptBuild = await buildTaskPrompt(settings, "extract", {
|
||||
content: "继续说明",
|
||||
name: "艾琳",
|
||||
speaker: "艾琳",
|
||||
hideSpeakerLabel: true,
|
||||
isContextOnly: true,
|
||||
},
|
||||
{
|
||||
@@ -133,25 +134,41 @@ const promptBuild = await buildTaskPrompt(settings, "extract", {
|
||||
currentRange: "41 ~ 42",
|
||||
});
|
||||
const payload = buildTaskLlmPayload(promptBuild, "fallback-user");
|
||||
const recentBlock = payload.promptMessages.find(
|
||||
const recentMessages = payload.promptMessages.filter(
|
||||
(message) => message.sourceKey === "recentMessages",
|
||||
);
|
||||
assert.match(
|
||||
String(recentBlock?.content || ""),
|
||||
/以下是上下文回顾(已提取过),仅供理解剧情/,
|
||||
assert.deepEqual(
|
||||
recentMessages.map((message) => ({
|
||||
role: message.role,
|
||||
sourceKey: message.sourceKey,
|
||||
transcriptSection: message.transcriptSection,
|
||||
transcriptSectionPart: message.transcriptSectionPart,
|
||||
})),
|
||||
[
|
||||
{
|
||||
role: "system",
|
||||
sourceKey: "recentMessages",
|
||||
transcriptSection: "context",
|
||||
transcriptSectionPart: "section",
|
||||
},
|
||||
{
|
||||
role: "system",
|
||||
sourceKey: "recentMessages",
|
||||
transcriptSection: "target",
|
||||
transcriptSectionPart: "section",
|
||||
},
|
||||
],
|
||||
);
|
||||
assert.match(
|
||||
String(recentBlock?.content || ""),
|
||||
/以下是本次需要提取记忆的新对话内容/,
|
||||
);
|
||||
assert.match(String(recentBlock?.content || ""), /#41 \[assistant\|艾琳\]: 助手已净化/);
|
||||
assert.match(String(recentBlock?.content || ""), /#42 \[user\|玩家\]: 用户已净化/);
|
||||
assert.match(String(recentMessages[0]?.content || ""), /^--- 以下是上下文回顾(已提取过),仅供理解剧情 ---/);
|
||||
assert.match(String(recentMessages[0]?.content || ""), /#41 \[assistant\]: 助手已净化/);
|
||||
assert.match(String(recentMessages[1]?.content || ""), /^--- 以下是本次需要提取记忆的新对话内容 ---/);
|
||||
assert.match(String(recentMessages[1]?.content || ""), /#42 \[user\|玩家\]: 用户已净化/);
|
||||
assert.doesNotMatch(
|
||||
String(recentBlock?.content || ""),
|
||||
/#41 \[assistant\|艾琳\]: 用户已净化/,
|
||||
String(recentMessages[0]?.content || ""),
|
||||
/#41 \[assistant\|艾琳\]:/,
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
String(recentBlock?.content || ""),
|
||||
String(recentMessages[1]?.content || ""),
|
||||
/#42 \[user\|玩家\]: 助手已净化/,
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user