mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-06-13 18:31:16 +08:00
@@ -189,13 +189,10 @@ export const DEFAULT_TASK_PROFILE_TEMPLATES = {
|
||||
"character": true
|
||||
},
|
||||
"stages": {
|
||||
"finalPrompt": true,
|
||||
"input.userMessage": false,
|
||||
"input.recentMessages": false,
|
||||
"input.candidateText": false,
|
||||
"input.finalPrompt": false,
|
||||
"rawResponse": false,
|
||||
"beforeParse": false,
|
||||
"output.rawResponse": false,
|
||||
"output.beforeParse": false,
|
||||
"input": true,
|
||||
@@ -396,13 +393,10 @@ export const DEFAULT_TASK_PROFILE_TEMPLATES = {
|
||||
"character": true
|
||||
},
|
||||
"stages": {
|
||||
"finalPrompt": true,
|
||||
"input.userMessage": false,
|
||||
"input.recentMessages": false,
|
||||
"input.candidateText": false,
|
||||
"input.finalPrompt": false,
|
||||
"rawResponse": false,
|
||||
"beforeParse": false,
|
||||
"output.rawResponse": false,
|
||||
"output.beforeParse": false,
|
||||
"input": true,
|
||||
@@ -579,13 +573,10 @@ export const DEFAULT_TASK_PROFILE_TEMPLATES = {
|
||||
"character": true
|
||||
},
|
||||
"stages": {
|
||||
"finalPrompt": true,
|
||||
"input.userMessage": false,
|
||||
"input.recentMessages": false,
|
||||
"input.candidateText": false,
|
||||
"input.finalPrompt": false,
|
||||
"rawResponse": false,
|
||||
"beforeParse": false,
|
||||
"output.rawResponse": false,
|
||||
"output.beforeParse": false,
|
||||
"input": true,
|
||||
@@ -774,13 +765,10 @@ export const DEFAULT_TASK_PROFILE_TEMPLATES = {
|
||||
"character": true
|
||||
},
|
||||
"stages": {
|
||||
"finalPrompt": true,
|
||||
"input.userMessage": false,
|
||||
"input.recentMessages": false,
|
||||
"input.candidateText": false,
|
||||
"input.finalPrompt": false,
|
||||
"rawResponse": false,
|
||||
"beforeParse": false,
|
||||
"output.rawResponse": false,
|
||||
"output.beforeParse": false,
|
||||
"input": true,
|
||||
@@ -981,13 +969,10 @@ export const DEFAULT_TASK_PROFILE_TEMPLATES = {
|
||||
"character": true
|
||||
},
|
||||
"stages": {
|
||||
"finalPrompt": true,
|
||||
"input.userMessage": false,
|
||||
"input.recentMessages": false,
|
||||
"input.candidateText": false,
|
||||
"input.finalPrompt": false,
|
||||
"rawResponse": false,
|
||||
"beforeParse": false,
|
||||
"output.rawResponse": false,
|
||||
"output.beforeParse": false,
|
||||
"input": true,
|
||||
@@ -1200,13 +1185,10 @@ export const DEFAULT_TASK_PROFILE_TEMPLATES = {
|
||||
"character": true
|
||||
},
|
||||
"stages": {
|
||||
"finalPrompt": true,
|
||||
"input.userMessage": false,
|
||||
"input.recentMessages": false,
|
||||
"input.candidateText": false,
|
||||
"input.finalPrompt": false,
|
||||
"rawResponse": false,
|
||||
"beforeParse": false,
|
||||
"output.rawResponse": false,
|
||||
"output.beforeParse": false,
|
||||
"input": true,
|
||||
|
||||
27
extractor.js
27
extractor.js
@@ -411,6 +411,33 @@ export async function extractMemories({
|
||||
systemPrompt,
|
||||
);
|
||||
|
||||
// 诊断:追踪 promptPayload
|
||||
{
|
||||
const pm = Array.isArray(promptPayload.promptMessages) ? promptPayload.promptMessages : [];
|
||||
const pmUser = pm.filter((m) => m?.role === "user");
|
||||
const am = Array.isArray(promptPayload.additionalMessages) ? promptPayload.additionalMessages : [];
|
||||
console.log(
|
||||
`[ST-BME][prompt-diag] resolveTaskPromptPayload: ` +
|
||||
`promptMessages=${pm.length} (user=${pmUser.length}), ` +
|
||||
`additionalMessages=${am.length}, ` +
|
||||
`userPrompt length=${String(promptPayload.userPrompt || "").length}, ` +
|
||||
`systemPrompt length=${String(promptPayload.systemPrompt || "").length}, ` +
|
||||
`llmSystemPrompt length=${String(llmSystemPrompt || "").length}`,
|
||||
);
|
||||
if (pmUser.length > 0) {
|
||||
for (const m of pmUser) {
|
||||
console.log(
|
||||
`[ST-BME][prompt-diag] user msg: contentLen=${String(m.content || "").length}, ` +
|
||||
`blockName="${m.blockName || ""}", preview="${String(m.content || "").slice(0, 60)}..."`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
console.warn(
|
||||
`[ST-BME][prompt-diag] NO user messages in promptMessages! Fallback userPrompt will be used.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 调用 LLM
|
||||
const result = await callLLMForJSON({
|
||||
systemPrompt: llmSystemPrompt,
|
||||
|
||||
33
llm.js
33
llm.js
@@ -1583,10 +1583,43 @@ export async function callLLMForJSON({
|
||||
additionalMessages,
|
||||
promptMessages,
|
||||
);
|
||||
{
|
||||
const asmUser = assembledMessages.filter((m) => m?.role === "user");
|
||||
console.log(
|
||||
`[ST-BME][prompt-diag] buildJsonAttemptMessages: ` +
|
||||
`total=${assembledMessages.length}, user=${asmUser.length}, ` +
|
||||
`roles=[${assembledMessages.map((m) => m?.role).join(",")}]`,
|
||||
);
|
||||
for (const m of asmUser) {
|
||||
console.log(
|
||||
`[ST-BME][prompt-diag] assembled user: len=${String(m.content || "").length}, ` +
|
||||
`preview="${String(m.content || "").slice(0, 80)}..."`,
|
||||
);
|
||||
}
|
||||
}
|
||||
const requestCleaning = applyTaskFinalInputRegex(
|
||||
taskType,
|
||||
assembledMessages,
|
||||
);
|
||||
{
|
||||
const rcMsgs = Array.isArray(requestCleaning.messages) ? requestCleaning.messages : [];
|
||||
const rcUser = rcMsgs.filter((m) => m?.role === "user");
|
||||
const dbg = requestCleaning.debug || {};
|
||||
console.log(
|
||||
`[ST-BME][prompt-diag] applyTaskFinalInputRegex: ` +
|
||||
`total=${rcMsgs.length}, user=${rcUser.length}, ` +
|
||||
`changed=${dbg.changed}, applied=${dbg.applied}, ` +
|
||||
`roles=[${rcMsgs.map((m) => m?.role).join(",")}]`,
|
||||
);
|
||||
if (rcUser.length === 0 && assembledMessages.filter((m) => m?.role === "user").length > 0) {
|
||||
console.warn(
|
||||
`[ST-BME][prompt-diag] *** USER MESSAGES LOST during applyTaskFinalInputRegex! ***`,
|
||||
);
|
||||
for (const rule of dbg.appliedRules || []) {
|
||||
console.warn(`[ST-BME][prompt-diag] applied rule: ${JSON.stringify(rule)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
const promptExecutionSnapshot = attachRequestCleaningToPromptExecution(
|
||||
promptExecutionSummary,
|
||||
requestCleaning.debug,
|
||||
|
||||
@@ -1098,6 +1098,12 @@ export async function buildTaskPrompt(settings = {}, taskType, context = {}) {
|
||||
let assistantRoleBlockCount = 0;
|
||||
let systemRoleBlockCount = 0;
|
||||
|
||||
console.log(
|
||||
`[ST-BME][prompt-diag] buildTaskPrompt: taskType=${taskType}, ` +
|
||||
`total blocks=${blocks.length}, ` +
|
||||
`block roles=[${blocks.map((b) => `${b.name}(${b.role},${b.enabled !== false ? "on" : "off"})`).join(", ")}]`,
|
||||
);
|
||||
|
||||
for (const block of blocks) {
|
||||
if (!block || block.enabled === false) continue;
|
||||
|
||||
@@ -1118,6 +1124,15 @@ export async function buildTaskPrompt(settings = {}, taskType, context = {}) {
|
||||
content = interpolateVariables(block.content || "", resolvedContext);
|
||||
}
|
||||
|
||||
if (role === "user") {
|
||||
console.log(
|
||||
`[ST-BME][prompt-diag] user block "${block.name || block.id}": ` +
|
||||
`type=${block.type}, contentLen=${String(content || "").length}, ` +
|
||||
`rawContentLen=${String(block.content || "").length}, ` +
|
||||
`blockedContentsCount=${worldInfoRuntimeBlockedContents.length}`,
|
||||
);
|
||||
}
|
||||
|
||||
const sanitizedBlockContent = sanitizeTaskPromptText(
|
||||
settings,
|
||||
taskType,
|
||||
@@ -1137,7 +1152,19 @@ export async function buildTaskPrompt(settings = {}, taskType, context = {}) {
|
||||
}
|
||||
content = sanitizedBlockContent.text;
|
||||
|
||||
if (!String(content || "").trim()) continue;
|
||||
if (!String(content || "").trim()) {
|
||||
if (role === "user" && String(block.content || "").trim()) {
|
||||
console.warn(
|
||||
`[ST-BME] buildTaskPrompt: user block "${block.name || block.id}" ` +
|
||||
`content emptied during sanitization! ` +
|
||||
`original length=${String(block.content || "").length}, ` +
|
||||
`dropped=${sanitizedBlockContent.dropped}, ` +
|
||||
`reasons=[${(sanitizedBlockContent.reasons || []).join(", ")}], ` +
|
||||
`blockedHitCount=${sanitizedBlockContent.blockedHitCount}`,
|
||||
);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const mode = normalizeInjectionMode(block.injectionMode);
|
||||
renderedBlocks.push({
|
||||
@@ -1193,6 +1220,13 @@ export async function buildTaskPrompt(settings = {}, taskType, context = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[ST-BME][prompt-diag] buildTaskPrompt done: ` +
|
||||
`executionMessages=${executionMessages.length}, ` +
|
||||
`userBlocks=${userRoleBlockCount}, systemBlocks=${systemRoleBlockCount}, ` +
|
||||
`customMessages=${customMessages.length}`,
|
||||
);
|
||||
|
||||
for (const message of worldInfoResolution.additionalMessages || []) {
|
||||
const executionMessage = createExecutionMessage(
|
||||
message.role,
|
||||
@@ -1361,6 +1395,39 @@ export function buildTaskLlmPayload(promptBuild = null, fallbackUserPrompt = "")
|
||||
const hasUserMessage = executionMessages.some(
|
||||
(message) => message.role === "user",
|
||||
);
|
||||
if (!hasUserMessage && rawExecutionMessages.length > 0) {
|
||||
const userBlocksBefore = (promptBuild?.executionMessages || []).filter(
|
||||
(m) => m?.role === "user",
|
||||
);
|
||||
const userBlocksAfterRaw = rawExecutionMessages.filter(
|
||||
(m) => m?.role === "user",
|
||||
);
|
||||
const userBlocksAfterSanitize = executionMessages.filter(
|
||||
(m) => m?.role === "user",
|
||||
);
|
||||
console.warn(
|
||||
`[ST-BME] buildTaskLlmPayload fallback triggered: ` +
|
||||
`user blocks in promptBuild=${userBlocksBefore.length}, ` +
|
||||
`after recreate=${userBlocksAfterRaw.length}, ` +
|
||||
`after sanitize=${userBlocksAfterSanitize.length}, ` +
|
||||
`blockedContents count=${blockedContents.length}, ` +
|
||||
`total executionMessages=${executionMessages.length}`,
|
||||
);
|
||||
if (userBlocksBefore.length > 0) {
|
||||
for (const block of userBlocksBefore) {
|
||||
console.warn(
|
||||
`[ST-BME] user block "${block.blockName || block.blockId}": ` +
|
||||
`content length=${String(block.content || "").length}, ` +
|
||||
`content preview="${String(block.content || "").slice(0, 80)}..."`,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (blockedContents.length > 0) {
|
||||
console.warn(
|
||||
`[ST-BME] blockedContents lengths: [${blockedContents.map((c) => String(c || "").length).join(", ")}]`,
|
||||
);
|
||||
}
|
||||
}
|
||||
const sanitizedFallbackUserPrompt = sanitizeTaskPromptText(
|
||||
{},
|
||||
promptBuild?.debug?.taskType || "",
|
||||
|
||||
@@ -637,15 +637,13 @@ export function normalizeTaskRegexStages(stages = {}) {
|
||||
for (const [legacyKey, canonicalKey] of Object.entries(
|
||||
TASK_REGEX_STAGE_ALIAS_MAP,
|
||||
)) {
|
||||
if (Object.prototype.hasOwnProperty.call(source, legacyKey)) {
|
||||
// Older exports may carry both legacy and canonical keys at the same
|
||||
// time. When that happens, keep the legacy intent instead of letting a
|
||||
// newer placeholder default silently flip stage timing.
|
||||
normalized[canonicalKey] = Boolean(source[legacyKey]);
|
||||
if (Object.prototype.hasOwnProperty.call(source, canonicalKey)) {
|
||||
// Respect an explicitly stored canonical key when both forms are
|
||||
// present. Legacy aliases should only backfill older exports.
|
||||
continue;
|
||||
}
|
||||
if (Object.prototype.hasOwnProperty.call(source, canonicalKey)) {
|
||||
normalized[canonicalKey] = Boolean(source[canonicalKey]);
|
||||
if (Object.prototype.hasOwnProperty.call(source, legacyKey)) {
|
||||
normalized[canonicalKey] = Boolean(source[legacyKey]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -893,13 +891,10 @@ function createFallbackDefaultTaskProfile(taskType) {
|
||||
character: true,
|
||||
},
|
||||
stages: normalizeTaskRegexStages({
|
||||
finalPrompt: true,
|
||||
"input.userMessage": false,
|
||||
"input.recentMessages": false,
|
||||
"input.candidateText": false,
|
||||
"input.finalPrompt": false,
|
||||
rawResponse: false,
|
||||
beforeParse: false,
|
||||
"output.rawResponse": false,
|
||||
"output.beforeParse": false,
|
||||
}),
|
||||
@@ -954,10 +949,10 @@ export function createDefaultTaskProfile(taskType) {
|
||||
...fallback.regex.sources,
|
||||
...(template?.regex?.sources || {}),
|
||||
},
|
||||
stages: normalizeTaskRegexStages({
|
||||
...fallback.regex.stages,
|
||||
...(template?.regex?.stages || {}),
|
||||
}),
|
||||
stages: {
|
||||
...normalizeTaskRegexStages(fallback.regex.stages || {}),
|
||||
...normalizeTaskRegexStages(template?.regex?.stages || {}),
|
||||
},
|
||||
localRules: Array.isArray(template?.regex?.localRules)
|
||||
? template.regex.localRules.map((rule, index) =>
|
||||
normalizeRegexLocalRule(rule, taskType, index),
|
||||
@@ -1148,10 +1143,10 @@ export function normalizeTaskProfile(taskType, profile = {}, settings = {}) {
|
||||
...base.regex.sources,
|
||||
...(profile?.regex?.sources || {}),
|
||||
},
|
||||
stages: normalizeTaskRegexStages({
|
||||
...base.regex.stages,
|
||||
...(profile?.regex?.stages || {}),
|
||||
}),
|
||||
stages: {
|
||||
...normalizeTaskRegexStages(base.regex.stages || {}),
|
||||
...normalizeTaskRegexStages(profile?.regex?.stages || {}),
|
||||
},
|
||||
localRules: Array.isArray(profile?.regex?.localRules)
|
||||
? profile.regex.localRules.map((rule, index) =>
|
||||
normalizeRegexLocalRule(rule, taskType, index),
|
||||
|
||||
@@ -156,6 +156,7 @@ try {
|
||||
const {
|
||||
createDefaultTaskProfiles,
|
||||
isTaskRegexStageEnabled,
|
||||
normalizeTaskProfile,
|
||||
normalizeTaskRegexStages,
|
||||
} = await import("../prompt-profiles.js");
|
||||
|
||||
@@ -170,7 +171,7 @@ try {
|
||||
"output.rawResponse": false,
|
||||
"output.beforeParse": false,
|
||||
});
|
||||
assert.equal(normalizedLegacyStages["input.finalPrompt"], true);
|
||||
assert.equal(normalizedLegacyStages["input.finalPrompt"], false);
|
||||
assert.equal(normalizedLegacyStages["input.userMessage"], false);
|
||||
assert.equal(normalizedLegacyStages["input.recentMessages"], false);
|
||||
assert.equal(normalizedLegacyStages["input.candidateText"], false);
|
||||
@@ -178,7 +179,7 @@ try {
|
||||
assert.equal(normalizedLegacyStages["output.beforeParse"], false);
|
||||
assert.equal(
|
||||
isTaskRegexStageEnabled(normalizedLegacyStages, "input.finalPrompt"),
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
isTaskRegexStageEnabled(normalizedLegacyStages, "input.userMessage"),
|
||||
@@ -198,7 +199,7 @@ try {
|
||||
defaultProfiles.extract?.profiles?.[0]?.regex?.stages || {};
|
||||
assert.equal(
|
||||
isTaskRegexStageEnabled(defaultExtractStages, "input.finalPrompt"),
|
||||
true,
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
isTaskRegexStageEnabled(defaultExtractStages, "input.userMessage"),
|
||||
@@ -213,6 +214,27 @@ try {
|
||||
false,
|
||||
);
|
||||
|
||||
const normalizedLegacyOnlyProfile = normalizeTaskProfile(
|
||||
"extract",
|
||||
{
|
||||
id: "legacy-only-profile",
|
||||
name: "legacy only",
|
||||
regex: {
|
||||
stages: {
|
||||
finalPrompt: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{},
|
||||
);
|
||||
assert.equal(
|
||||
isTaskRegexStageEnabled(
|
||||
normalizedLegacyOnlyProfile.regex?.stages || {},
|
||||
"input.finalPrompt",
|
||||
),
|
||||
true,
|
||||
);
|
||||
|
||||
globalThis.getTavernRegexes = () => {
|
||||
throw new Error("legacy global getter should not be used in regex tests");
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user