Files
ST-Bionic-Memory-Ecology/host/st-context.js
2026-04-10 14:06:26 +08:00

178 lines
4.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ST-BME: SillyTavern 上下文数据读取辅助
// 为 prompt 变量扩展Phase 2提供统一的 ST 上下文数据接口
import { getContext } from "../../../../extensions.js";
import { buildPluginVisibleChatMessages } from "../maintenance/chat-history.js";
function safeClone(value, fallback) {
if (value == null) {
return fallback;
}
try {
if (typeof structuredClone === "function") {
return structuredClone(value);
}
} catch {
// ignore and fall back to JSON clone
}
try {
return JSON.parse(JSON.stringify(value));
} catch {
return fallback ?? value;
}
}
function resolveCharacter(ctx) {
const charId = ctx?.characterId;
return (
ctx?.character ||
ctx?.characters?.[Number(charId)] ||
ctx?.characters?.[charId] ||
null
);
}
function resolvePersona(ctx) {
return (
ctx?.powerUserSettings?.persona_description ||
ctx?.extensionSettings?.persona_description ||
ctx?.name1_description ||
ctx?.persona ||
""
);
}
function resolveCharacterDescription(char) {
return (
char?.description ||
char?.data?.description ||
char?.data?.personality ||
""
);
}
function resolveLastUserMessage(chat = []) {
return (
chat.findLast?.((message) => message?.is_user)?.mes ||
[...chat].reverse().find((message) => message?.is_user)?.mes ||
""
);
}
function buildStructuredSnapshot(ctx = {}) {
const char = resolveCharacter(ctx);
const chat = Array.isArray(ctx.chat)
? buildPluginVisibleChatMessages(ctx.chat)
: [];
const currentTime = new Date().toLocaleString("zh-CN");
const globalVars = safeClone(
ctx.extensionSettings?.variables?.global || {},
{},
);
const localVars = safeClone(ctx.chatMetadata?.variables || {}, {});
return {
persona: {
text: resolvePersona(ctx),
lorebook:
ctx.extensionSettings?.persona_description_lorebook ||
ctx.powerUserSettings?.persona_description_lorebook ||
ctx.power_user?.persona_description_lorebook ||
"",
},
character: {
id: ctx.characterId ?? null,
name: ctx.name2 || char?.name || "",
description: resolveCharacterDescription(char),
avatar: char?.avatar ? `/characters/${char.avatar}` : "",
worldbook: char?.data?.extensions?.world || char?.extensions?.world || "",
raw: safeClone(char, null),
},
user: {
name: ctx.name1 || "",
avatar: "",
raw: safeClone(ctx.user || null, null),
},
chat: {
id: ctx.chatId || globalThis.getCurrentChatId?.() || "",
messages: chat,
lastUserMessage: resolveLastUserMessage(chat),
},
worldbook: {
character: char?.data?.extensions?.world || char?.extensions?.world || "",
persona:
ctx.extensionSettings?.persona_description_lorebook ||
ctx.powerUserSettings?.persona_description_lorebook ||
ctx.power_user?.persona_description_lorebook ||
"",
chat: ctx.chatMetadata?.world || "",
},
variables: {
global: globalVars,
local: localVars,
merged: {
...globalVars,
...localVars,
},
},
time: {
current: currentTime,
locale: "zh-CN",
},
host: {
meta: {
onlineStatus: ctx.onlineStatus || "",
selectedGroupId: ctx.selectedGroupId ?? null,
},
capabilities: {
hasGetContext: typeof getContext === "function",
hasGlobalGetContext:
typeof globalThis.SillyTavern?.getContext === "function",
hasCurrentChatId: typeof globalThis.getCurrentChatId === "function",
},
},
raw: safeClone(ctx, {}),
};
}
function buildCompatPromptAliases(snapshot) {
return {
userPersona: snapshot.persona.text,
charDescription: snapshot.character.description,
charName: snapshot.character.name,
userName: snapshot.user.name,
currentTime: snapshot.time.current,
};
}
export function getSTContextSnapshot() {
try {
const ctx = getContext?.() || {};
const snapshot = buildStructuredSnapshot(ctx);
return {
snapshot,
prompt: buildCompatPromptAliases(snapshot),
};
} catch (e) {
console.warn("[ST-BME] getSTContextSnapshot 失败:", e);
const snapshot = buildStructuredSnapshot({});
return {
snapshot,
prompt: buildCompatPromptAliases(snapshot),
};
}
}
/**
* 从 SillyTavern 的 getContext() 提取当前上下文数据,
* 返回的字段可直接展开传入 buildTaskPrompt 的 context 参数,
* 用户在自定义 prompt 块中可通过 {{key}} 引用。
*
* @returns {object} 上下文字段映射
*/
export function getSTContextForPrompt() {
return getSTContextSnapshot().prompt;
}