mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-05-15 22:30:38 +08:00
675 lines
20 KiB
JavaScript
675 lines
20 KiB
JavaScript
// ST-BME: Prompt Builder
|
|
// 统一负责任务预设块排序、变量渲染,以及世界书/EJS 上下文接入。
|
|
|
|
import { getActiveTaskProfile, getLegacyPromptForTask } from "./prompt-profiles.js";
|
|
import { resolveTaskWorldInfo } from "./task-worldinfo.js";
|
|
|
|
const WORLD_INFO_VARIABLE_KEYS = [
|
|
"worldInfoBefore",
|
|
"worldInfoAfter",
|
|
"worldInfoBeforeEntries",
|
|
"worldInfoAfterEntries",
|
|
"worldInfoAtDepthEntries",
|
|
"activatedWorldInfoNames",
|
|
"taskAdditionalMessages",
|
|
];
|
|
|
|
function cloneRuntimeDebugValue(value, fallback = null) {
|
|
if (value == null) {
|
|
return fallback;
|
|
}
|
|
|
|
try {
|
|
return JSON.parse(JSON.stringify(value));
|
|
} catch {
|
|
return fallback ?? value;
|
|
}
|
|
}
|
|
|
|
function getRuntimeDebugState() {
|
|
const stateKey = "__stBmeRuntimeDebugState";
|
|
if (
|
|
!globalThis[stateKey] ||
|
|
typeof globalThis[stateKey] !== "object"
|
|
) {
|
|
globalThis[stateKey] = {
|
|
hostCapabilities: null,
|
|
taskPromptBuilds: {},
|
|
taskLlmRequests: {},
|
|
injections: {},
|
|
updatedAt: "",
|
|
};
|
|
}
|
|
return globalThis[stateKey];
|
|
}
|
|
|
|
function recordTaskPromptBuild(taskType, snapshot = {}) {
|
|
const normalizedTaskType = String(taskType || "").trim() || "unknown";
|
|
const state = getRuntimeDebugState();
|
|
state.taskPromptBuilds[normalizedTaskType] = {
|
|
updatedAt: new Date().toISOString(),
|
|
...cloneRuntimeDebugValue(snapshot, {}),
|
|
};
|
|
state.updatedAt = new Date().toISOString();
|
|
}
|
|
|
|
export function buildTaskExecutionDebugContext(
|
|
promptBuild = null,
|
|
options = {},
|
|
) {
|
|
const promptDebug = promptBuild?.debug || {};
|
|
const worldInfoDebug =
|
|
promptBuild?.worldInfo?.debug || promptBuild?.worldInfoResolution?.debug || {};
|
|
const worldInfoHit =
|
|
Number(promptDebug.worldInfoBeforeCount || 0) +
|
|
Number(promptDebug.worldInfoAfterCount || 0) +
|
|
Number(promptDebug.worldInfoAtDepthCount || 0) >
|
|
0;
|
|
|
|
return {
|
|
promptAssembly: {
|
|
mode: "ordered-private-messages",
|
|
hostInjectionPlanMode:
|
|
promptDebug.hostInjectionPlanMode || "diagnostic-plan-only",
|
|
privateTaskMessageCount: Number(
|
|
promptDebug.executionMessageCount ??
|
|
promptBuild?.executionMessages?.length ??
|
|
promptDebug.privateTaskMessageCount ??
|
|
promptBuild?.privateTaskMessages?.length ??
|
|
0,
|
|
),
|
|
},
|
|
promptBuild: {
|
|
taskType: String(promptDebug.taskType || ""),
|
|
profileId: String(promptDebug.profileId || ""),
|
|
profileName: String(promptDebug.profileName || ""),
|
|
renderedBlockCount: Number(promptDebug.renderedBlockCount || 0),
|
|
privateTaskMessageCount: Number(promptDebug.privateTaskMessageCount || 0),
|
|
},
|
|
effectiveDelivery:
|
|
promptDebug.effectiveDelivery && typeof promptDebug.effectiveDelivery === "object"
|
|
? cloneRuntimeDebugValue(promptDebug.effectiveDelivery, {})
|
|
: null,
|
|
ejsRuntimeStatus: String(
|
|
promptDebug.ejsRuntimeStatus || worldInfoDebug.ejsRuntimeStatus || "",
|
|
),
|
|
worldInfo: {
|
|
requested: promptDebug.worldInfoRequested !== false,
|
|
hit: worldInfoHit,
|
|
cacheHit: Boolean(promptDebug.worldInfoCacheHit),
|
|
beforeCount: Number(promptDebug.worldInfoBeforeCount || 0),
|
|
afterCount: Number(promptDebug.worldInfoAfterCount || 0),
|
|
atDepthCount: Number(promptDebug.worldInfoAtDepthCount || 0),
|
|
loadMs: Number(worldInfoDebug.loadMs || 0),
|
|
},
|
|
regexInput:
|
|
options.regexInput && typeof options.regexInput === "object"
|
|
? cloneRuntimeDebugValue(options.regexInput, {})
|
|
: null,
|
|
};
|
|
}
|
|
|
|
function getByPath(target, path) {
|
|
return String(path || "")
|
|
.split(".")
|
|
.filter(Boolean)
|
|
.reduce((acc, key) => (acc == null ? undefined : acc[key]), target);
|
|
}
|
|
|
|
function normalizeRole(role) {
|
|
const value = String(role || "system").toLowerCase();
|
|
if (["system", "user", "assistant"].includes(value)) {
|
|
return value;
|
|
}
|
|
return "system";
|
|
}
|
|
|
|
function normalizeInjectionMode(mode) {
|
|
const value = String(mode || "append").toLowerCase();
|
|
if (["prepend", "append", "relative"].includes(value)) {
|
|
return value;
|
|
}
|
|
return "append";
|
|
}
|
|
|
|
function createExecutionMessage(
|
|
role,
|
|
content,
|
|
extra = {},
|
|
) {
|
|
const trimmedContent = String(content || "").trim();
|
|
if (!trimmedContent) {
|
|
return null;
|
|
}
|
|
return {
|
|
role: normalizeRole(role),
|
|
content: trimmedContent,
|
|
...extra,
|
|
};
|
|
}
|
|
|
|
function stringifyInterpolatedValue(value) {
|
|
if (value == null) return "";
|
|
if (typeof value === "string") return value;
|
|
if (typeof value === "number" || typeof value === "boolean") {
|
|
return String(value);
|
|
}
|
|
|
|
try {
|
|
return JSON.stringify(value, null, 2);
|
|
} catch {
|
|
return String(value);
|
|
}
|
|
}
|
|
|
|
function buildEmptyWorldInfoContext() {
|
|
return {
|
|
worldInfoBefore: "",
|
|
worldInfoAfter: "",
|
|
worldInfoBeforeEntries: [],
|
|
worldInfoAfterEntries: [],
|
|
worldInfoAtDepthEntries: [],
|
|
activatedWorldInfoNames: [],
|
|
taskAdditionalMessages: [],
|
|
worldInfoDebug: null,
|
|
};
|
|
}
|
|
|
|
function createHostInjectionEntry(
|
|
entry = {},
|
|
position = "after",
|
|
source = "worldInfo",
|
|
) {
|
|
return {
|
|
source,
|
|
position,
|
|
role: normalizeRole(entry.role),
|
|
content: String(entry.content || "").trim(),
|
|
name: String(entry.name || ""),
|
|
sourceName: String(entry.sourceName || entry.name || ""),
|
|
worldbook: String(entry.worldbook || ""),
|
|
depth:
|
|
position === "atDepth" && Number.isFinite(Number(entry.depth))
|
|
? Number(entry.depth)
|
|
: null,
|
|
order: Number.isFinite(Number(entry.order)) ? Number(entry.order) : 0,
|
|
};
|
|
}
|
|
|
|
function buildWorldInfoResolution(worldInfoContext = {}) {
|
|
const beforeEntries = Array.isArray(worldInfoContext.worldInfoBeforeEntries)
|
|
? worldInfoContext.worldInfoBeforeEntries
|
|
: [];
|
|
const afterEntries = Array.isArray(worldInfoContext.worldInfoAfterEntries)
|
|
? worldInfoContext.worldInfoAfterEntries
|
|
: [];
|
|
const atDepthEntries = Array.isArray(worldInfoContext.worldInfoAtDepthEntries)
|
|
? worldInfoContext.worldInfoAtDepthEntries
|
|
: [];
|
|
const additionalMessages = Array.isArray(worldInfoContext.taskAdditionalMessages)
|
|
? worldInfoContext.taskAdditionalMessages
|
|
: [];
|
|
|
|
return {
|
|
beforeText: String(worldInfoContext.worldInfoBefore || ""),
|
|
afterText: String(worldInfoContext.worldInfoAfter || ""),
|
|
beforeEntries,
|
|
afterEntries,
|
|
atDepthEntries,
|
|
activatedEntryNames: Array.isArray(worldInfoContext.activatedWorldInfoNames)
|
|
? worldInfoContext.activatedWorldInfoNames
|
|
: [],
|
|
additionalMessages,
|
|
debug:
|
|
worldInfoContext.worldInfoDebug &&
|
|
typeof worldInfoContext.worldInfoDebug === "object"
|
|
? worldInfoContext.worldInfoDebug
|
|
: null,
|
|
injections: {
|
|
before: beforeEntries
|
|
.map((entry) => createHostInjectionEntry(entry, "before"))
|
|
.filter((entry) => entry.content),
|
|
after: afterEntries
|
|
.map((entry) => createHostInjectionEntry(entry, "after"))
|
|
.filter((entry) => entry.content),
|
|
atDepth: atDepthEntries
|
|
.map((entry) => createHostInjectionEntry(entry, "atDepth"))
|
|
.filter((entry) => entry.content),
|
|
},
|
|
};
|
|
}
|
|
|
|
function sortInjectionEntries(entries = []) {
|
|
return [...entries].sort((left, right) => {
|
|
const orderLeft = Number.isFinite(Number(left?.order))
|
|
? Number(left.order)
|
|
: 0;
|
|
const orderRight = Number.isFinite(Number(right?.order))
|
|
? Number(right.order)
|
|
: 0;
|
|
return orderLeft - orderRight;
|
|
});
|
|
}
|
|
|
|
function createHostInjectionPlanEntry(block = {}, position, extra = {}) {
|
|
return {
|
|
source: "block",
|
|
origin: "profile-block",
|
|
position,
|
|
role: normalizeRole(block.role),
|
|
content: String(block.content || "").trim(),
|
|
blockId: String(block.id || ""),
|
|
blockName: String(block.name || ""),
|
|
sourceKey: String(block.sourceKey || ""),
|
|
injectionMode: normalizeInjectionMode(block.injectionMode),
|
|
order: Number.isFinite(Number(block.order)) ? Number(block.order) : 0,
|
|
...extra,
|
|
};
|
|
}
|
|
|
|
function buildHostInjectionPlan(renderedBlocks = [], worldInfoResolution = {}) {
|
|
const beforeEntryNames = (
|
|
Array.isArray(worldInfoResolution.beforeEntries)
|
|
? worldInfoResolution.beforeEntries
|
|
: []
|
|
)
|
|
.map((entry) => String(entry?.name || entry?.sourceName || "").trim())
|
|
.filter(Boolean);
|
|
const afterEntryNames = (
|
|
Array.isArray(worldInfoResolution.afterEntries)
|
|
? worldInfoResolution.afterEntries
|
|
: []
|
|
)
|
|
.map((entry) => String(entry?.name || entry?.sourceName || "").trim())
|
|
.filter(Boolean);
|
|
const atDepthEntries = Array.isArray(worldInfoResolution.injections?.atDepth)
|
|
? worldInfoResolution.injections.atDepth
|
|
: [];
|
|
|
|
const plan = {
|
|
before: [],
|
|
after: [],
|
|
atDepth: [],
|
|
};
|
|
|
|
for (const block of renderedBlocks) {
|
|
if (!block?.content) continue;
|
|
|
|
if (
|
|
block.type === "builtin" &&
|
|
String(block.sourceKey || "") === "worldInfoBefore"
|
|
) {
|
|
plan.before.push(
|
|
createHostInjectionPlanEntry(block, "before", {
|
|
entryNames: beforeEntryNames,
|
|
entryCount: beforeEntryNames.length,
|
|
}),
|
|
);
|
|
continue;
|
|
}
|
|
|
|
if (
|
|
block.type === "builtin" &&
|
|
String(block.sourceKey || "") === "worldInfoAfter"
|
|
) {
|
|
plan.after.push(
|
|
createHostInjectionPlanEntry(block, "after", {
|
|
entryNames: afterEntryNames,
|
|
entryCount: afterEntryNames.length,
|
|
}),
|
|
);
|
|
}
|
|
}
|
|
|
|
for (const entry of atDepthEntries) {
|
|
if (!entry?.content) continue;
|
|
plan.atDepth.push({
|
|
...entry,
|
|
origin: "worldInfo-entry",
|
|
entryName: String(entry.name || entry.sourceName || "").trim(),
|
|
});
|
|
}
|
|
|
|
return {
|
|
before: sortInjectionEntries(plan.before),
|
|
after: sortInjectionEntries(plan.after),
|
|
atDepth: sortInjectionEntries(plan.atDepth),
|
|
};
|
|
}
|
|
|
|
function resolveBlockDelivery(block = {}) {
|
|
return normalizeRole(block.role) === "system"
|
|
? "private.system"
|
|
: "private.message";
|
|
}
|
|
|
|
function getBlockDiagnosticInjectionPosition(block = {}) {
|
|
if (
|
|
block.type === "builtin" &&
|
|
String(block.sourceKey || "") === "worldInfoBefore"
|
|
) {
|
|
return "before";
|
|
}
|
|
if (
|
|
block.type === "builtin" &&
|
|
String(block.sourceKey || "") === "worldInfoAfter"
|
|
) {
|
|
return "after";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
function profileRequiresWorldInfo(profile) {
|
|
const blocks = Array.isArray(profile?.blocks) ? profile.blocks : [];
|
|
for (const block of blocks) {
|
|
if (!block || block.enabled === false) continue;
|
|
if (
|
|
block.type === "builtin" &&
|
|
["worldInfoBefore", "worldInfoAfter"].includes(String(block.sourceKey || ""))
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
const rawContent = String(block.content || "");
|
|
if (!rawContent.includes("{{")) continue;
|
|
if (
|
|
WORLD_INFO_VARIABLE_KEYS.some((key) =>
|
|
rawContent.includes(`{{${key}}}`) ||
|
|
rawContent.includes(`{{ ${key} }}`),
|
|
)
|
|
) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function extractWorldInfoChatMessages(context = {}) {
|
|
if (Array.isArray(context.chatMessages)) {
|
|
return context.chatMessages;
|
|
}
|
|
return [];
|
|
}
|
|
|
|
export async function buildTaskPrompt(settings = {}, taskType, context = {}) {
|
|
const profile = getActiveTaskProfile(settings, taskType);
|
|
const legacyPrompt = getLegacyPromptForTask(settings, taskType);
|
|
const rawBlocks = Array.isArray(profile?.blocks) ? profile.blocks : [];
|
|
const blocks = rawBlocks
|
|
.map((block, index) => ({ ...block, _orderIndex: index }))
|
|
.sort((a, b) => {
|
|
const orderA = Number.isFinite(Number(a.order))
|
|
? Number(a.order)
|
|
: a._orderIndex;
|
|
const orderB = Number.isFinite(Number(b.order))
|
|
? Number(b.order)
|
|
: b._orderIndex;
|
|
return orderA - orderB;
|
|
});
|
|
|
|
const worldInfoRequested = profileRequiresWorldInfo(profile);
|
|
const emptyWorldInfo = buildEmptyWorldInfoContext();
|
|
let resolvedWorldInfo = emptyWorldInfo;
|
|
|
|
if (worldInfoRequested) {
|
|
const worldInfo = await resolveTaskWorldInfo({
|
|
settings,
|
|
chatMessages: extractWorldInfoChatMessages(context),
|
|
userMessage: String(context.userMessage || ""),
|
|
templateContext: context,
|
|
});
|
|
resolvedWorldInfo = {
|
|
worldInfoBefore: worldInfo.beforeText || "",
|
|
worldInfoAfter: worldInfo.afterText || "",
|
|
worldInfoBeforeEntries: worldInfo.beforeEntries || [],
|
|
worldInfoAfterEntries: worldInfo.afterEntries || [],
|
|
worldInfoAtDepthEntries: worldInfo.atDepthEntries || [],
|
|
activatedWorldInfoNames: worldInfo.activatedEntryNames || [],
|
|
taskAdditionalMessages: worldInfo.additionalMessages || [],
|
|
worldInfoDebug: worldInfo.debug || null,
|
|
};
|
|
}
|
|
|
|
const resolvedContext = {
|
|
...context,
|
|
...emptyWorldInfo,
|
|
...resolvedWorldInfo,
|
|
};
|
|
const worldInfoResolution = buildWorldInfoResolution(resolvedContext);
|
|
|
|
let systemPrompt = "";
|
|
const customMessages = [];
|
|
const executionMessages = [];
|
|
const renderedBlocks = [];
|
|
let userRoleBlockCount = 0;
|
|
let assistantRoleBlockCount = 0;
|
|
let systemRoleBlockCount = 0;
|
|
|
|
for (const block of blocks) {
|
|
if (!block || block.enabled === false) continue;
|
|
|
|
const role = normalizeRole(block.role);
|
|
let content = "";
|
|
|
|
if (block.type === "legacyPrompt") {
|
|
content = legacyPrompt || block.content || "";
|
|
} else if (block.type === "builtin") {
|
|
if (block.content) {
|
|
content = interpolateVariables(block.content, resolvedContext);
|
|
} else if (block.sourceKey) {
|
|
content = stringifyInterpolatedValue(
|
|
getByPath(resolvedContext, block.sourceKey),
|
|
);
|
|
}
|
|
} else if (block.type === "custom") {
|
|
content = interpolateVariables(block.content || "", resolvedContext);
|
|
}
|
|
|
|
if (!String(content || "").trim()) continue;
|
|
|
|
const mode = normalizeInjectionMode(block.injectionMode);
|
|
renderedBlocks.push({
|
|
id: String(block.id || ""),
|
|
name: String(block.name || ""),
|
|
type: String(block.type || "custom"),
|
|
role,
|
|
sourceKey: String(block.sourceKey || ""),
|
|
sourceField: String(block.sourceField || ""),
|
|
content,
|
|
order: Number.isFinite(Number(block.order))
|
|
? Number(block.order)
|
|
: block._orderIndex,
|
|
injectionMode: mode,
|
|
delivery: resolveBlockDelivery(block),
|
|
effectiveDelivery: resolveBlockDelivery(block),
|
|
diagnosticInjectionPosition: getBlockDiagnosticInjectionPosition(block),
|
|
});
|
|
|
|
const executionMessage = createExecutionMessage(role, content, {
|
|
source: "profile-block",
|
|
blockId: String(block.id || ""),
|
|
blockName: String(block.name || ""),
|
|
blockType: String(block.type || "custom"),
|
|
sourceKey: String(block.sourceKey || ""),
|
|
injectionMode: mode,
|
|
});
|
|
if (executionMessage) {
|
|
executionMessages.push(executionMessage);
|
|
}
|
|
|
|
if (role === "system") {
|
|
systemRoleBlockCount += 1;
|
|
if (!systemPrompt) {
|
|
systemPrompt = content;
|
|
} else if (mode === "prepend") {
|
|
systemPrompt = `${content}\n\n${systemPrompt}`;
|
|
} else {
|
|
systemPrompt = `${systemPrompt}\n\n${content}`;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (role === "user") {
|
|
userRoleBlockCount += 1;
|
|
} else if (role === "assistant") {
|
|
assistantRoleBlockCount += 1;
|
|
}
|
|
if (mode === "prepend") {
|
|
customMessages.unshift({ role, content });
|
|
} else {
|
|
customMessages.push({ role, content });
|
|
}
|
|
}
|
|
|
|
for (const message of worldInfoResolution.additionalMessages || []) {
|
|
const executionMessage = createExecutionMessage(
|
|
message.role,
|
|
message.content,
|
|
{
|
|
source: "worldInfo-atDepth",
|
|
},
|
|
);
|
|
if (executionMessage) {
|
|
executionMessages.push(executionMessage);
|
|
}
|
|
}
|
|
|
|
const privateTaskMessages = [
|
|
...customMessages,
|
|
...worldInfoResolution.additionalMessages,
|
|
];
|
|
const hostInjectionPlan = buildHostInjectionPlan(
|
|
renderedBlocks,
|
|
worldInfoResolution,
|
|
);
|
|
|
|
const result = {
|
|
profile,
|
|
hostInjections: worldInfoResolution.injections,
|
|
hostInjectionPlan,
|
|
privateTaskPrompt: {
|
|
systemPrompt,
|
|
messages: privateTaskMessages,
|
|
},
|
|
executionMessages,
|
|
privateTaskMessages,
|
|
renderedBlocks,
|
|
worldInfoResolution,
|
|
systemPrompt,
|
|
customMessages,
|
|
additionalMessages: worldInfoResolution.additionalMessages,
|
|
worldInfo: {
|
|
beforeText: worldInfoResolution.beforeText,
|
|
afterText: worldInfoResolution.afterText,
|
|
beforeEntries: worldInfoResolution.beforeEntries,
|
|
afterEntries: worldInfoResolution.afterEntries,
|
|
atDepthEntries: worldInfoResolution.atDepthEntries,
|
|
activatedEntryNames: worldInfoResolution.activatedEntryNames,
|
|
debug: worldInfoResolution.debug,
|
|
},
|
|
debug: {
|
|
taskType,
|
|
profileId: profile?.id || "",
|
|
profileName: profile?.name || "",
|
|
usedLegacyPrompt: Boolean(legacyPrompt),
|
|
blockCount: blocks.length,
|
|
renderedBlockCount: renderedBlocks.length,
|
|
worldInfoRequested,
|
|
worldInfoBeforeCount: worldInfoResolution.beforeEntries.length,
|
|
worldInfoAfterCount: worldInfoResolution.afterEntries.length,
|
|
worldInfoAtDepthCount: worldInfoResolution.atDepthEntries.length,
|
|
hostInjectionCount:
|
|
worldInfoResolution.injections.before.length +
|
|
worldInfoResolution.injections.after.length +
|
|
worldInfoResolution.injections.atDepth.length,
|
|
hostInjectionPlanCount:
|
|
hostInjectionPlan.before.length +
|
|
hostInjectionPlan.after.length +
|
|
hostInjectionPlan.atDepth.length,
|
|
hostInjectionPlanMode: "diagnostic-plan-only",
|
|
customMessageCount: customMessages.length,
|
|
additionalMessageCount: worldInfoResolution.additionalMessages.length,
|
|
privateTaskMessageCount: privateTaskMessages.length,
|
|
executionMessageCount: executionMessages.length,
|
|
userRoleBlockCount,
|
|
assistantRoleBlockCount,
|
|
systemRoleBlockCount,
|
|
effectiveDelivery: {
|
|
profileBlocks: "ordered-private-messages",
|
|
worldInfoBeforeAfter: "inline-in-ordered-messages",
|
|
worldInfoAtDepth: "appended-private-messages",
|
|
},
|
|
worldInfoCacheHit: Boolean(worldInfoResolution.debug?.cache?.hit),
|
|
ejsRuntimeStatus: worldInfoResolution.debug?.ejsRuntimeStatus || "",
|
|
effectivePath: {
|
|
promptAssembly: "ordered-private-messages",
|
|
hostInjectionPlan: "diagnostic-plan-only",
|
|
ejs:
|
|
worldInfoResolution.debug?.ejsRuntimeStatus ||
|
|
"unknown",
|
|
worldInfo:
|
|
worldInfoRequested !== false
|
|
? worldInfoResolution.activatedEntryNames.length > 0
|
|
? "matched"
|
|
: "requested-but-missed"
|
|
: "disabled",
|
|
},
|
|
},
|
|
};
|
|
|
|
recordTaskPromptBuild(taskType, {
|
|
taskType,
|
|
profileId: profile?.id || "",
|
|
profileName: profile?.name || "",
|
|
systemPrompt,
|
|
privateTaskMessages,
|
|
executionMessages,
|
|
renderedBlocks,
|
|
hostInjections: worldInfoResolution.injections,
|
|
hostInjectionPlan,
|
|
worldInfoResolution,
|
|
debug: result.debug,
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
export function buildTaskLlmPayload(promptBuild = null, fallbackUserPrompt = "") {
|
|
const executionMessages = Array.isArray(promptBuild?.executionMessages)
|
|
? promptBuild.executionMessages
|
|
.map((message) =>
|
|
createExecutionMessage(message.role, message.content, {
|
|
source: String(message.source || ""),
|
|
blockId: String(message.blockId || ""),
|
|
blockName: String(message.blockName || ""),
|
|
blockType: String(message.blockType || ""),
|
|
sourceKey: String(message.sourceKey || ""),
|
|
injectionMode: String(message.injectionMode || ""),
|
|
}),
|
|
)
|
|
.filter(Boolean)
|
|
: [];
|
|
|
|
const hasUserMessage = executionMessages.some(
|
|
(message) => message.role === "user",
|
|
);
|
|
|
|
return {
|
|
systemPrompt: String(promptBuild?.systemPrompt || ""),
|
|
userPrompt: hasUserMessage ? "" : String(fallbackUserPrompt || ""),
|
|
promptMessages: executionMessages,
|
|
additionalMessages:
|
|
executionMessages.length > 0
|
|
? []
|
|
: Array.isArray(promptBuild?.privateTaskMessages)
|
|
? promptBuild.privateTaskMessages
|
|
: [],
|
|
};
|
|
}
|
|
|
|
export function interpolateVariables(template, context = {}) {
|
|
return String(template || "").replace(/\{\{\s*([\w.]+)\s*\}\}/g, (_, key) => {
|
|
return stringifyInterpolatedValue(getByPath(context, key));
|
|
});
|
|
}
|