diff --git a/index.js b/index.js index aaddbf5..47f70b5 100644 --- a/index.js +++ b/index.js @@ -60,11 +60,6 @@ import { rollbackBatch, snapshotProcessedMessageHashes, } from "./runtime-state.js"; -import { - getRuntimeDebugSnapshot as readRuntimeDebugSnapshot, - recordHostCapabilitySnapshot, - recordInjectionSnapshot, -} from "./runtime-debug.js"; import { DEFAULT_NODE_SCHEMA, validateSchema } from "./schema.js"; import { deleteBackendVectorHashesForRecovery, @@ -87,6 +82,75 @@ const GRAPH_METADATA_KEY = "st_bme_graph"; const SERVER_SETTINGS_FILENAME = "st-bme-settings.json"; const SERVER_SETTINGS_URL = `/user/files/${SERVER_SETTINGS_FILENAME}`; +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 touchRuntimeDebugState() { + const state = getRuntimeDebugState(); + state.updatedAt = new Date().toISOString(); + return state; +} + +function recordHostCapabilitySnapshot(snapshot = null) { + const state = touchRuntimeDebugState(); + state.hostCapabilities = cloneRuntimeDebugValue(snapshot, null); +} + +function recordInjectionSnapshot(kind, snapshot = {}) { + const normalizedKind = String(kind || "").trim() || "default"; + const state = touchRuntimeDebugState(); + state.injections[normalizedKind] = { + updatedAt: new Date().toISOString(), + ...cloneRuntimeDebugValue(snapshot, {}), + }; +} + +function readRuntimeDebugSnapshot() { + const state = getRuntimeDebugState(); + return cloneRuntimeDebugValue( + { + hostCapabilities: state.hostCapabilities, + taskPromptBuilds: state.taskPromptBuilds, + taskLlmRequests: state.taskLlmRequests, + injections: state.injections, + updatedAt: state.updatedAt, + }, + { + hostCapabilities: null, + taskPromptBuilds: {}, + taskLlmRequests: {}, + injections: {}, + updatedAt: "", + }, + ); +} + // ==================== 默认设置 ==================== const defaultSettings = { diff --git a/llm.js b/llm.js index f584729..3d7d780 100644 --- a/llm.js +++ b/llm.js @@ -5,7 +5,6 @@ import { getRequestHeaders } from "../../../../script.js"; import { extension_settings } from "../../../extensions.js"; import { chat_completion_sources, sendOpenAIRequest } from "../../../openai.js"; import { resolveTaskGenerationOptions } from "./generation-options.js"; -import { recordTaskLlmRequest } from "./runtime-debug.js"; const MODULE_NAME = "st_bme"; const LLM_REQUEST_TIMEOUT_MS = 300000; @@ -13,6 +12,45 @@ const DEFAULT_TEXT_COMPLETION_TOKENS = 64000; const DEFAULT_JSON_COMPLETION_TOKENS = 64000; const RETRY_JSON_COMPLETION_TOKENS = 3200; +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 recordTaskLlmRequest(taskType, snapshot = {}) { + const normalizedTaskType = String(taskType || "").trim() || "unknown"; + const state = getRuntimeDebugState(); + state.taskLlmRequests[normalizedTaskType] = { + updatedAt: new Date().toISOString(), + ...cloneRuntimeDebugValue(snapshot, {}), + }; + state.updatedAt = new Date().toISOString(); +} + function getLlmTestOverride(name) { const override = globalThis.__stBmeTestOverrides?.llm?.[name]; return typeof override === "function" ? override : null; diff --git a/panel.js b/panel.js index f465b2b..271d287 100644 --- a/panel.js +++ b/panel.js @@ -25,13 +25,27 @@ import { getVectorIndexStats, } from "./vector-index.js"; -// 从 DEFAULT_TASK_BLOCKS 派生的合并文本(用于旧版兼容回退) -const DEFAULT_PROMPTS = Object.fromEntries( - Object.entries(DEFAULT_TASK_BLOCKS).map(([key, { role, format, rules }]) => [ - key, - [role, format, rules].filter(Boolean).join("\n\n"), - ]), -); +let defaultPromptCache = null; + +function getDefaultPrompts() { + if (defaultPromptCache) { + return defaultPromptCache; + } + + const prompts = {}; + for (const [key, block] of Object.entries(DEFAULT_TASK_BLOCKS || {})) { + prompts[key] = [block?.role, block?.format, block?.rules] + .filter(Boolean) + .join("\n\n"); + } + + defaultPromptCache = prompts; + return prompts; +} + +function getDefaultPromptText(taskType = "") { + return getDefaultPrompts()[taskType] || ""; +} const TASK_PROFILE_TABS = [ { id: "generation", label: "生成参数" }, @@ -1028,27 +1042,27 @@ function _refreshConfigTab() { _setInputValue( "bme-setting-extract-prompt", - settings.extractPrompt || DEFAULT_PROMPTS.extract, + settings.extractPrompt || getDefaultPromptText("extract"), ); _setInputValue( "bme-setting-recall-prompt", - settings.recallPrompt || DEFAULT_PROMPTS.recall, + settings.recallPrompt || getDefaultPromptText("recall"), ); _setInputValue( "bme-setting-consolidation-prompt", - settings.consolidationPrompt || DEFAULT_PROMPTS.consolidation, + settings.consolidationPrompt || getDefaultPromptText("consolidation"), ); _setInputValue( "bme-setting-compress-prompt", - settings.compressPrompt || DEFAULT_PROMPTS.compress, + settings.compressPrompt || getDefaultPromptText("compress"), ); _setInputValue( "bme-setting-synopsis-prompt", - settings.synopsisPrompt || DEFAULT_PROMPTS.synopsis, + settings.synopsisPrompt || getDefaultPromptText("synopsis"), ); _setInputValue( "bme-setting-reflection-prompt", - settings.reflectionPrompt || DEFAULT_PROMPTS.reflection, + settings.reflectionPrompt || getDefaultPromptText("reflection"), ); _refreshFetchedModelSelects(settings); @@ -1262,7 +1276,7 @@ function _bindConfigControls() { const targetId = button.dataset.targetId; if (!settingKey || !promptKey || !targetId) return; _patchSettings({ [settingKey]: "" }, { refreshPrompts: true }); - _setInputValue(targetId, DEFAULT_PROMPTS[promptKey] || ""); + _setInputValue(targetId, getDefaultPromptText(promptKey)); _refreshPromptCardStates(); }); button.dataset.bmeBound = "true"; @@ -1410,7 +1424,7 @@ function bindPromptText(id, settingKey, promptKey) { element.addEventListener("change", update); element.addEventListener("blur", () => { if (!String(element.value || "").trim()) { - _setInputValue(id, DEFAULT_PROMPTS[promptKey] || ""); + _setInputValue(id, getDefaultPromptText(promptKey)); } }); element.dataset.bmeBound = "true"; @@ -2498,7 +2512,7 @@ function _renderTaskBlockEditor(state) { const legacyField = getLegacyPromptFieldForTask(state.taskType); const legacyValue = legacyField && block.type === "legacyPrompt" - ? state.settings?.[legacyField] || block.content || DEFAULT_PROMPTS[state.taskType] || "" + ? state.settings?.[legacyField] || block.content || getDefaultPromptText(state.taskType) || "" : block.content || ""; return ` diff --git a/prompt-builder.js b/prompt-builder.js index 8e8dede..d60c8f2 100644 --- a/prompt-builder.js +++ b/prompt-builder.js @@ -2,7 +2,6 @@ // 统一负责任务预设块排序、变量渲染,以及世界书/EJS 上下文接入。 import { getActiveTaskProfile, getLegacyPromptForTask } from "./prompt-profiles.js"; -import { recordTaskPromptBuild } from "./runtime-debug.js"; import { resolveTaskWorldInfo } from "./task-worldinfo.js"; const WORLD_INFO_VARIABLE_KEYS = [ @@ -15,6 +14,45 @@ const WORLD_INFO_VARIABLE_KEYS = [ "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(); +} + function getByPath(target, path) { return String(path || "") .split(".")