mirror of
https://github.com/Wx-2025/ST-Amily2-Chat-Optimisation.git
synced 2026-06-12 08:45:51 +00:00
release: v2.2.5 [2026-06-10 12:41:11]
### 修复 - **翰林院(RAG)API Key 污染**: - 修复 `saveSettingsFromUI` 无差别遍历翰林院面板内全部 `[data-setting-key]` 输入(包含被 `profile-sync` 接管隐藏的字段),导致掩码占位符 `••••••••` 被当作真值写回 `settings.rerank.apiKey` / `settings.retrieval.apiKey`,URL / model 也被 Profile 值覆盖到 legacy 字段。修复后会跳过祖先带 `data-profile-hidden` 的输入 - `getRerankSettings` / `getEmbedRetrievalSettings` 同时加入防御性还原:识别历史污染留下的 `••••••••` 时归为空字符串,避免取消 Profile 分配后实际请求带占位符 token 被 401 ---
This commit is contained in:
@@ -49,6 +49,16 @@
|
||||
|
||||
---
|
||||
|
||||
## v2.2.5
|
||||
|
||||
### 修复
|
||||
|
||||
- **翰林院(RAG)API Key 污染**:
|
||||
- 修复 `saveSettingsFromUI` 无差别遍历翰林院面板内全部 `[data-setting-key]` 输入(包含被 `profile-sync` 接管隐藏的字段),导致掩码占位符 `••••••••` 被当作真值写回 `settings.rerank.apiKey` / `settings.retrieval.apiKey`,URL / model 也被 Profile 值覆盖到 legacy 字段。修复后会跳过祖先带 `data-profile-hidden` 的输入
|
||||
- `getRerankSettings` / `getEmbedRetrievalSettings` 同时加入防御性还原:识别历史污染留下的 `••••••••` 时归为空字符串,避免取消 Profile 分配后实际请求带占位符 token 被 401
|
||||
|
||||
---
|
||||
|
||||
## v2.2.4
|
||||
|
||||
### 新功能
|
||||
|
||||
51
core/memory-blocks/builtin-blocks.js
Normal file
51
core/memory-blocks/builtin-blocks.js
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* core/memory-blocks/builtin-blocks.js
|
||||
*
|
||||
* 内置块注册。当前只把剧情优化原硬编码的 sulv1-4 迁过来,作为新流水线的首批
|
||||
* 静态块——既验证 substitution 流程正常,又保留原行为字节级一致。
|
||||
*
|
||||
* 旧位置:core/summarizer.js 中 processPlotOptimization 的硬编码 replacements。
|
||||
*/
|
||||
|
||||
import { register } from './registry.js';
|
||||
|
||||
let initialized = false;
|
||||
|
||||
export function registerBuiltinBlocks() {
|
||||
if (initialized) return;
|
||||
initialized = true;
|
||||
|
||||
// 剧情优化(processPlotOptimization)的四个速率占位符
|
||||
register({
|
||||
id: 'plotOpt.sulv1',
|
||||
placeholder: 'sulv1',
|
||||
context: 'plotOptimization',
|
||||
generator: { type: 'static', valueKey: 'plotOpt_rateMain', defaultValue: 1.0 },
|
||||
name: '主线剧情速率',
|
||||
order: 1,
|
||||
});
|
||||
register({
|
||||
id: 'plotOpt.sulv2',
|
||||
placeholder: 'sulv2',
|
||||
context: 'plotOptimization',
|
||||
generator: { type: 'static', valueKey: 'plotOpt_ratePersonal', defaultValue: 1.0 },
|
||||
name: '个人线速率',
|
||||
order: 2,
|
||||
});
|
||||
register({
|
||||
id: 'plotOpt.sulv3',
|
||||
placeholder: 'sulv3',
|
||||
context: 'plotOptimization',
|
||||
generator: { type: 'static', valueKey: 'plotOpt_rateErotic', defaultValue: 1.0 },
|
||||
name: '速率3(留空)',
|
||||
order: 3,
|
||||
});
|
||||
register({
|
||||
id: 'plotOpt.sulv4',
|
||||
placeholder: 'sulv4',
|
||||
context: 'plotOptimization',
|
||||
generator: { type: 'static', valueKey: 'plotOpt_rateCuckold', defaultValue: 1.0 },
|
||||
name: '速率4(留空)',
|
||||
order: 4,
|
||||
});
|
||||
}
|
||||
98
core/memory-blocks/executor.js
Normal file
98
core/memory-blocks/executor.js
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* core/memory-blocks/executor.js
|
||||
*
|
||||
* 工作流执行器:拉 context 下的全部块 → Promise.all 并发执行 generator
|
||||
* → 把每个块的结果按 placeholder 替换回模板。
|
||||
*
|
||||
* 核心 API:
|
||||
* applyToTemplate(template, opts) 单模板进,字符串出
|
||||
* applyToTemplates(templates, opts) 多模板进(数组或对象),结构同形出;
|
||||
* 块只执行一次,对每个模板复用结果
|
||||
* generateBlockMap(opts) 不替换,返回 { id → value } 给调用方自己玩
|
||||
*
|
||||
* 中断行为:opts.signal 由调用方控制,传给每个 handler;任一 handler 抛
|
||||
* AbortError 时,executor 也抛 AbortError 向上传递(与现有 callAI 体系一致)。
|
||||
*/
|
||||
|
||||
import { getHandler } from './generator-handlers.js';
|
||||
import { listByContext } from './registry.js';
|
||||
|
||||
function escapeForRegex(s) {
|
||||
return String(s).replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||
}
|
||||
|
||||
async function runBlock(block, ctx) {
|
||||
const handler = getHandler(block.generator?.type);
|
||||
if (!handler) {
|
||||
console.warn(`[MemoryBlocks] 未注册的 generator 类型 "${block.generator?.type}",块 ${block.id} 已跳过。`);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const value = await handler(block, ctx);
|
||||
if (value === null || value === undefined) return null;
|
||||
return { block, value: String(value) };
|
||||
} catch (error) {
|
||||
if (error?.name === 'AbortError') throw error;
|
||||
console.error(`[MemoryBlocks] 块 ${block.id} 生成失败:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function substituteOne(template, results) {
|
||||
if (typeof template !== 'string' || !template) return template ?? '';
|
||||
let out = template;
|
||||
for (const r of results) {
|
||||
if (!r) continue;
|
||||
const re = new RegExp(escapeForRegex(r.block.placeholder), 'g');
|
||||
out = out.replace(re, r.value);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行 context 下的所有块,返回 [ {block, value} | null, ... ]。
|
||||
* 内部使用,applyToTemplate(s) 复用。
|
||||
*/
|
||||
async function executeBlocks({ context, settings, signal, extras } = {}) {
|
||||
const blocks = listByContext(context);
|
||||
if (blocks.length === 0) return [];
|
||||
const ctx = { settings: settings ?? {}, signal, context, extras };
|
||||
return await Promise.all(blocks.map(b => runBlock(b, ctx)));
|
||||
}
|
||||
|
||||
export async function applyToTemplate(template, opts = {}) {
|
||||
if (typeof template !== 'string' || !template) return template ?? '';
|
||||
const results = await executeBlocks(opts);
|
||||
return substituteOne(template, results);
|
||||
}
|
||||
|
||||
/**
|
||||
* 多模板批处理。templates 可以是:
|
||||
* - 字符串数组 → 返回字符串数组
|
||||
* - 对象 { key: template } → 返回对象 { key: replaced }
|
||||
* - 字符串 → 退化为 applyToTemplate
|
||||
*/
|
||||
export async function applyToTemplates(templates, opts = {}) {
|
||||
const results = await executeBlocks(opts);
|
||||
|
||||
if (typeof templates === 'string') return substituteOne(templates, results);
|
||||
if (Array.isArray(templates)) return templates.map(t => substituteOne(t, results));
|
||||
if (templates && typeof templates === 'object') {
|
||||
const out = {};
|
||||
for (const [k, v] of Object.entries(templates)) out[k] = substituteOne(v, results);
|
||||
return out;
|
||||
}
|
||||
return templates;
|
||||
}
|
||||
|
||||
/**
|
||||
* 不替换,只把块结果汇成 Map<id, value>,调用方拿去自由组合。
|
||||
*/
|
||||
export async function generateBlockMap(opts = {}) {
|
||||
const results = await executeBlocks(opts);
|
||||
const map = new Map();
|
||||
for (const r of results) {
|
||||
if (r) map.set(r.block.id, r.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
46
core/memory-blocks/generator-handlers.js
Normal file
46
core/memory-blocks/generator-handlers.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* core/memory-blocks/generator-handlers.js
|
||||
*
|
||||
* type → handler 函数 的注册表。BlockDefinition.generator.type 在这里查表后执行。
|
||||
*
|
||||
* Handler 签名:async (block, ctx) => string | null
|
||||
* - block: BlockDefinition
|
||||
* - ctx: ExecuteContext { settings, signal, context, extras }
|
||||
* - 返回 string:替换值;返回 null/undefined:视为"无内容,保留占位符"
|
||||
*
|
||||
* 当前内置 'static';'ai_call'/'plugin' 在后续 Phase 注册(保留接口)。
|
||||
*/
|
||||
|
||||
const handlers = new Map();
|
||||
|
||||
export function registerHandler(type, fn) {
|
||||
if (!type || typeof fn !== 'function') {
|
||||
throw new Error('[MemoryBlocks] registerHandler 需要 type 字符串 + 函数 fn。');
|
||||
}
|
||||
handlers.set(type, fn);
|
||||
}
|
||||
|
||||
export function unregisterHandler(type) {
|
||||
handlers.delete(type);
|
||||
}
|
||||
|
||||
export function getHandler(type) {
|
||||
return handlers.get(type) ?? null;
|
||||
}
|
||||
|
||||
export function listHandlerTypes() {
|
||||
return [...handlers.keys()];
|
||||
}
|
||||
|
||||
// ── 内置 handler:static ──────────────────────────────────────────────────────
|
||||
registerHandler('static', async (block, ctx) => {
|
||||
const gen = block.generator || {};
|
||||
// 优先级:硬编码 value > settings[valueKey] > defaultValue > ''
|
||||
if (gen.value !== undefined) return String(gen.value);
|
||||
if (gen.valueKey != null) {
|
||||
const v = ctx?.settings?.[gen.valueKey];
|
||||
if (v !== undefined && v !== null && v !== '') return String(v);
|
||||
}
|
||||
if (gen.defaultValue !== undefined) return String(gen.defaultValue);
|
||||
return '';
|
||||
});
|
||||
51
core/memory-blocks/index.js
Normal file
51
core/memory-blocks/index.js
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* core/memory-blocks/index.js
|
||||
*
|
||||
* 记忆块工作流系统对外入口。导入此模块即触发:
|
||||
* 1. generator-handlers 加载 → 注册内置 'static' handler
|
||||
* 2. registerBuiltinBlocks() → 注册首批内置块(sulv1-4)
|
||||
*
|
||||
* 公开 API:
|
||||
* - register / unregister / getById / listByContext / listAll
|
||||
* - registerHandler / getHandler / listHandlerTypes
|
||||
* - applyToTemplate(template, opts)
|
||||
* - applyToTemplates(templates, opts) ← 多模板批处理首选
|
||||
* - generateBlockMap(opts)
|
||||
*
|
||||
* opts 字段:{ context, settings, signal?, extras? }
|
||||
*
|
||||
* 设计目标:
|
||||
* - BlockDefinition 纯数据,可 JSON 序列化(Phase 3 用户自定义导入导出)
|
||||
* - generator 通过 type 查表,handler 集中注册,便于扩展 ai_call / plugin
|
||||
* - 同一 context 下的块 Promise.all 并发;任一块抛 AbortError 整体中断
|
||||
*/
|
||||
|
||||
export {
|
||||
register,
|
||||
unregister,
|
||||
getById,
|
||||
listByContext,
|
||||
listAll,
|
||||
clear,
|
||||
replaceContextBlocks,
|
||||
} from './registry.js';
|
||||
|
||||
export {
|
||||
registerHandler,
|
||||
unregisterHandler,
|
||||
getHandler,
|
||||
listHandlerTypes,
|
||||
} from './generator-handlers.js';
|
||||
|
||||
export {
|
||||
applyToTemplate,
|
||||
applyToTemplates,
|
||||
generateBlockMap,
|
||||
} from './executor.js';
|
||||
|
||||
import { registerBuiltinBlocks } from './builtin-blocks.js';
|
||||
|
||||
// 导入此模块即完成内置块注册(幂等)
|
||||
registerBuiltinBlocks();
|
||||
|
||||
export { registerBuiltinBlocks };
|
||||
63
core/memory-blocks/registry.js
Normal file
63
core/memory-blocks/registry.js
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* core/memory-blocks/registry.js
|
||||
*
|
||||
* BlockDefinition 的注册中心。所有块共享同一个全局 Map。
|
||||
*
|
||||
* 调用方:
|
||||
* - 内置块:builtin-blocks.js 在 bootstrap 时注册
|
||||
* - 用户块:未来 UI / JSON 导入注册
|
||||
* - 插件块:战斗系统等外部模块注册
|
||||
*
|
||||
* 字段校验只做最小必填检查,避免后续扩展时频繁报错。
|
||||
*/
|
||||
|
||||
const blocks = new Map();
|
||||
|
||||
function validate(def) {
|
||||
if (!def || typeof def !== 'object') throw new Error('[MemoryBlocks] BlockDefinition 必须是对象。');
|
||||
if (!def.id) throw new Error('[MemoryBlocks] BlockDefinition.id 必填。');
|
||||
if (!def.placeholder) throw new Error(`[MemoryBlocks] BlockDefinition[${def.id}].placeholder 必填。`);
|
||||
if (!def.context) throw new Error(`[MemoryBlocks] BlockDefinition[${def.id}].context 必填。`);
|
||||
if (!def.generator?.type) throw new Error(`[MemoryBlocks] BlockDefinition[${def.id}].generator.type 必填。`);
|
||||
}
|
||||
|
||||
export function register(def) {
|
||||
validate(def);
|
||||
blocks.set(def.id, { enabled: true, ...def });
|
||||
}
|
||||
|
||||
export function unregister(id) {
|
||||
return blocks.delete(id);
|
||||
}
|
||||
|
||||
export function getById(id) {
|
||||
return blocks.get(id) ?? null;
|
||||
}
|
||||
|
||||
export function listByContext(context) {
|
||||
const out = [];
|
||||
for (const b of blocks.values()) {
|
||||
if (b.context === context && b.enabled !== false) out.push(b);
|
||||
}
|
||||
out.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
||||
return out;
|
||||
}
|
||||
|
||||
export function listAll() {
|
||||
return [...blocks.values()];
|
||||
}
|
||||
|
||||
export function clear() {
|
||||
blocks.clear();
|
||||
}
|
||||
|
||||
/** 批量替换(用于 JSON 导入时整体覆盖某 context 下的块) */
|
||||
export function replaceContextBlocks(context, defs) {
|
||||
for (const [id, b] of blocks) {
|
||||
if (b.context === context) blocks.delete(id);
|
||||
}
|
||||
for (const d of defs) {
|
||||
if (d.context !== context) continue; // 防止越界注册
|
||||
register(d);
|
||||
}
|
||||
}
|
||||
56
core/memory-blocks/types.js
Normal file
56
core/memory-blocks/types.js
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* core/memory-blocks/types.js — 类型契约(JSDoc 文档,无运行时代码)
|
||||
*
|
||||
* BlockDefinition 是工作流的最小单位,描述"如何为某个占位符产出内容"。
|
||||
* 所有字段必须 JSON 可序列化,为后续支持 JSON 导入导出做准备。
|
||||
*
|
||||
* 生成器(generator)只承载"用哪个 handler、参数是什么"的元数据,
|
||||
* 真正的执行逻辑由 generator-handlers.js 按 type 查表的 handler 函数承担,
|
||||
* 因此 BlockDefinition 本身永远不持有函数引用、可直接 JSON.stringify。
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} StaticGenerator 直接读取 settings 或常量值
|
||||
* @property {'static'} type
|
||||
* @property {string} [valueKey] - 从 ctx.settings[valueKey] 读取
|
||||
* @property {*} [defaultValue]- valueKey 不存在/为空时的兜底
|
||||
* @property {*} [value] - 硬编码值,优先级高于 valueKey
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} AiCallGenerator (Phase 2 预留)
|
||||
* @property {'ai_call'} type
|
||||
* @property {string} apiSlot
|
||||
* @property {string} promptTemplate
|
||||
* @property {string} [extractTag]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} PluginGenerator (Phase 3 预留:战斗模块走这条)
|
||||
* @property {'plugin'} type
|
||||
* @property {string} handlerKey - 在 handler 注册表里查 handler 函数
|
||||
* @property {Object} [params]
|
||||
*/
|
||||
|
||||
/** @typedef {StaticGenerator | AiCallGenerator | PluginGenerator} GeneratorSpec */
|
||||
|
||||
/**
|
||||
* @typedef {Object} BlockDefinition
|
||||
* @property {string} id - 全局唯一
|
||||
* @property {string} placeholder - 在模板中要被替换的占位符(按字面量匹配,正则元字符自动转义)
|
||||
* @property {string} context - 所属流水线,如 'plotOptimization'
|
||||
* @property {GeneratorSpec} generator
|
||||
* @property {string} [name] - UI 显示名
|
||||
* @property {boolean} [enabled=true]
|
||||
* @property {number} [order] - 仅影响 listByContext 的返回顺序;执行并发,不阻塞
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ExecuteContext
|
||||
* @property {Object} settings - extension_settings[extensionName]
|
||||
* @property {AbortSignal} [signal] - 来自调用方的中断信号
|
||||
* @property {string} context
|
||||
* @property {Object} [extras] - 额外上下文,供 handler 自取
|
||||
*/
|
||||
|
||||
export {};
|
||||
@@ -14,6 +14,14 @@ import { extensionName } from '../utils/settings.js';
|
||||
const MODULE_NAME = 'hanlinyuan-rag-core';
|
||||
const GOOGLE_API_BASE_URL = 'https://generativelanguage.googleapis.com';
|
||||
|
||||
// profile-sync 在 UI 隐藏字段时填入的掩码占位符(const MASKED_KEY = '••••••••')。
|
||||
// 历史上 saveSettingsFromUI 曾把这个占位符写回 settings.{rerank,retrieval}.apiKey,
|
||||
// 导致取消 Profile 分配后实际请求带占位符 token 被 401。这里做防御性还原。
|
||||
const PROFILE_MASKED_KEY = '••••••••';
|
||||
function sanitizeMaskedKey(key) {
|
||||
return key === PROFILE_MASKED_KEY ? '' : key;
|
||||
}
|
||||
|
||||
function getSettings() {
|
||||
const root = extension_settings[extensionName];
|
||||
const nested = root && root[MODULE_NAME];
|
||||
@@ -35,12 +43,13 @@ export async function getEmbedRetrievalSettings() {
|
||||
return {
|
||||
apiEndpoint: profile.provider === 'google' ? 'google_direct' : 'custom',
|
||||
customApiUrl: profile.apiUrl,
|
||||
apiKey: profile.apiKey ?? '',
|
||||
apiKey: sanitizeMaskedKey(profile.apiKey ?? ''),
|
||||
embeddingModel: profile.model,
|
||||
batchSize: getSettings().retrieval?.batchSize ?? 5,
|
||||
};
|
||||
}
|
||||
return getSettings().retrieval || {};
|
||||
const fallback = getSettings().retrieval || {};
|
||||
return { ...fallback, apiKey: sanitizeMaskedKey(fallback.apiKey ?? '') };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,13 +61,14 @@ export async function getRerankSettings() {
|
||||
const manualSettings = getSettings().rerank || {};
|
||||
return {
|
||||
url: profile.apiUrl,
|
||||
apiKey: profile.apiKey ?? '',
|
||||
apiKey: sanitizeMaskedKey(profile.apiKey ?? ''),
|
||||
model: profile.model,
|
||||
top_n: manualSettings.top_n ?? 10,
|
||||
apiMode: manualSettings.apiMode ?? 'custom',
|
||||
};
|
||||
}
|
||||
return getSettings().rerank || {};
|
||||
const fallback = getSettings().rerank || {};
|
||||
return { ...fallback, apiKey: sanitizeMaskedKey(fallback.apiKey ?? '') };
|
||||
}
|
||||
|
||||
function normalizeApiResponse(responseData) {
|
||||
|
||||
@@ -16,6 +16,7 @@ import { resolveHistoriographyRuleConfig } from "../utils/config/RuleProfileMana
|
||||
import { getPresetPrompts, getMixedOrder } from '../PresetSettings/index.js';
|
||||
import { callAI, generateRandomSeed } from './api.js';
|
||||
import { callConcurrentAI } from './api/ConcurrentApi.js';
|
||||
import { applyToTemplates } from './memory-blocks/index.js';
|
||||
|
||||
export async function processOptimization(latestMessage, previousMessages) {
|
||||
if (window.AMILY2_SYSTEM_PARALYZED === true) {
|
||||
@@ -276,22 +277,18 @@ export async function processPlotOptimization(currentUserMessage, contextMessage
|
||||
const userName = context.name1 || '用户';
|
||||
const charName = context.name2 || '角色';
|
||||
|
||||
const replacements = {
|
||||
'sulv1': settings.plotOpt_rateMain ?? 1.0,
|
||||
'sulv2': settings.plotOpt_ratePersonal ?? 1.0,
|
||||
'sulv3': settings.plotOpt_rateErotic ?? 1.0,
|
||||
'sulv4': settings.plotOpt_rateCuckold ?? 1.0,
|
||||
};
|
||||
|
||||
let mainPrompt = settings.plotOpt_mainPrompt || '';
|
||||
let systemPrompt = settings.plotOpt_systemPrompt || '';
|
||||
|
||||
for (const key in replacements) {
|
||||
const value = replacements[key];
|
||||
const regex = new RegExp(key.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g');
|
||||
mainPrompt = mainPrompt.replace(regex, value);
|
||||
systemPrompt = systemPrompt.replace(regex, value);
|
||||
}
|
||||
// 【Phase 1 重构】sulv1-4 占位符替换迁入记忆块工作流。
|
||||
// 块定义见 core/memory-blocks/builtin-blocks.js,行为与旧硬编码字节级一致:
|
||||
// - 同一 context 内 Promise.all 并发执行 generator
|
||||
// - 模板批量替换,块只跑一次复用结果
|
||||
// - 后续新增占位符(含战斗系统)走 register({...}),此处零改动
|
||||
const { mainPrompt, systemPrompt } = await applyToTemplates(
|
||||
{
|
||||
mainPrompt: settings.plotOpt_mainPrompt || '',
|
||||
systemPrompt: settings.plotOpt_systemPrompt || '',
|
||||
},
|
||||
{ context: 'plotOptimization', settings },
|
||||
);
|
||||
|
||||
onProgress(getRandomText(['正在进行情感光谱分析...', '正在解析情绪波动频率...', '正在捕捉微表情信号...']), false);
|
||||
onProgress(getRandomText(['正在进行情感光谱分析...', '正在解析情绪波动频率...', '正在捕捉微表情信号...']), true);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Amily2号聊天优化助手",
|
||||
"display_name": "Amily2号助手",
|
||||
"version": "2.2.4",
|
||||
"version": "2.2.5",
|
||||
"author": "Wx-2025",
|
||||
"description": "一个拥有独立UI的智能引擎,正文优化、自动总结、记忆表格、rag向量、隐藏楼层、剧情推进等多功能整合。",
|
||||
"minSillyTavernVersion": "1.10.0",
|
||||
|
||||
@@ -706,6 +706,11 @@ function saveSettingsFromUI(isAutoSave = true) {
|
||||
const key = target.dataset.settingKey;
|
||||
if (!key) return;
|
||||
|
||||
// 被 profile-sync 接管的字段(祖先元素带 data-profile-hidden)会被填充
|
||||
// MASKED_KEY 占位符并隐藏,若一并写回会污染 settings.{rerank,retrieval}.apiKey
|
||||
// 等字段为 '••••••••',导致取消 Profile 分配后实际请求带占位符 token 被 401。
|
||||
if (target.closest('[data-profile-hidden]')) return;
|
||||
|
||||
let value;
|
||||
const type = target.dataset.type || 'string';
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
const a0_0x1676bb=a0_0x1deb;(function(_0x5dace7,_0x30b358){const _0x43d691=a0_0x1deb,_0x256e4b=_0x5dace7();while(!![]){try{const _0x2f4edf=-parseInt(_0x43d691(0x18b,'jC6G'))/0x1*(-parseInt(_0x43d691(0x190,'Emrc'))/0x2)+-parseInt(_0x43d691(0x189,'XWb!'))/0x3+parseInt(_0x43d691(0x19b,'j#K]'))/0x4*(parseInt(_0x43d691(0x194,'Rjs]'))/0x5)+parseInt(_0x43d691(0x185,'F1mB'))/0x6*(-parseInt(_0x43d691(0x186,'SV$*'))/0x7)+parseInt(_0x43d691(0x1a0,'a#w%'))/0x8+parseInt(_0x43d691(0x184,'#a0z'))/0x9*(parseInt(_0x43d691(0x19a,'0GOr'))/0xa)+parseInt(_0x43d691(0x19e,'ZnE5'))/0xb*(-parseInt(_0x43d691(0x195,'1@J7'))/0xc);if(_0x2f4edf===_0x30b358)break;else _0x256e4b['push'](_0x256e4b['shift']());}catch(_0x2c486e){_0x256e4b['push'](_0x256e4b['shift']());}}}(a0_0x4852,0x264fe));function a0_0x1deb(_0x1ac006,_0x2e3c31){_0x1ac006=_0x1ac006-0x183;const _0x485247=a0_0x4852();let _0x1deb77=_0x485247[_0x1ac006];if(a0_0x1deb['cEwbRd']===undefined){var _0x5b8488=function(_0xd54fea){const _0x60a846='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x492318='',_0x91a79d='';for(let _0x3e9f64=0x0,_0x1b7781,_0x4c1078,_0x5c5c04=0x0;_0x4c1078=_0xd54fea['charAt'](_0x5c5c04++);~_0x4c1078&&(_0x1b7781=_0x3e9f64%0x4?_0x1b7781*0x40+_0x4c1078:_0x4c1078,_0x3e9f64++%0x4)?_0x492318+=String['fromCharCode'](0xff&_0x1b7781>>(-0x2*_0x3e9f64&0x6)):0x0){_0x4c1078=_0x60a846['indexOf'](_0x4c1078);}for(let _0x3b0c8b=0x0,_0x2f9c57=_0x492318['length'];_0x3b0c8b<_0x2f9c57;_0x3b0c8b++){_0x91a79d+='%'+('00'+_0x492318['charCodeAt'](_0x3b0c8b)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x91a79d);};const _0x5ef89e=function(_0x1e5617,_0x5d0f33){let _0x534579=[],_0x4b4f14=0x0,_0x3f908b,_0x137f07='';_0x1e5617=_0x5b8488(_0x1e5617);let _0x593cda;for(_0x593cda=0x0;_0x593cda<0x100;_0x593cda++){_0x534579[_0x593cda]=_0x593cda;}for(_0x593cda=0x0;_0x593cda<0x100;_0x593cda++){_0x4b4f14=(_0x4b4f14+_0x534579[_0x593cda]+_0x5d0f33['charCodeAt'](_0x593cda%_0x5d0f33['length']))%0x100,_0x3f908b=_0x534579[_0x593cda],_0x534579[_0x593cda]=_0x534579[_0x4b4f14],_0x534579[_0x4b4f14]=_0x3f908b;}_0x593cda=0x0,_0x4b4f14=0x0;for(let _0x42f8e7=0x0;_0x42f8e7<_0x1e5617['length'];_0x42f8e7++){_0x593cda=(_0x593cda+0x1)%0x100,_0x4b4f14=(_0x4b4f14+_0x534579[_0x593cda])%0x100,_0x3f908b=_0x534579[_0x593cda],_0x534579[_0x593cda]=_0x534579[_0x4b4f14],_0x534579[_0x4b4f14]=_0x3f908b,_0x137f07+=String['fromCharCode'](_0x1e5617['charCodeAt'](_0x42f8e7)^_0x534579[(_0x534579[_0x593cda]+_0x534579[_0x4b4f14])%0x100]);}return _0x137f07;};a0_0x1deb['QCblwf']=_0x5ef89e,a0_0x1deb['kHvwiK']={},a0_0x1deb['cEwbRd']=!![];}const _0x5ae832=_0x485247[0x0],_0x57f6f3=_0x1ac006+_0x5ae832,_0x35c76f=a0_0x1deb['kHvwiK'][_0x57f6f3];return!_0x35c76f?(a0_0x1deb['fZGISM']===undefined&&(a0_0x1deb['fZGISM']=!![]),_0x1deb77=a0_0x1deb['QCblwf'](_0x1deb77,_0x2e3c31),a0_0x1deb['kHvwiK'][_0x57f6f3]=_0x1deb77):_0x1deb77=_0x35c76f,_0x1deb77;}function a0_0x4852(){const _0x5ada32=['imodW5ZcMSo+fZq','wCkjW5pdKgRcImo4s8kOWOCT','hmovwCkHW5BcT8ocaXWHqW','WOCHW7Cie8omWPpcQmo4W6tdUmkp','bSkCWP3dHLJdPdNdPCkSaSkpma','ESkWWR8Jxmks','umkkW5RdLMRcO8oXqmkvWO4F','gH7cSCkEvgZcISoTWQZdSGS','W6XIW6ddN0GgW5LxBq','WQjna1tcRuFcTSktWRtcJH4','W5mTaCkwiIJdOCoNWRldJq','W7mstqWdW6tdVmkLiW','WRtcVJNdKXxdHuHbrmoH','WPzgW5P1scqcW7Pb','imk5WRldR8kTkJdcSXpcLaO','W7a6shVcP8o5CupdLKiI','mSkEjNvsW7hdSmk6W4ztW4NcNW','F8oTW6JcR8oCprRcNWhcTa','W4rSs8kLbCkOWQVcRCkZ','EuzsW53cL8oRadb9dW','W6/dU3NcJ2FcHrvprmopW6/cK8kd','mqJcKSoQsbRcLZhcHmoNWOFdRflcS8oHqhhcImkFmmo8gYWD','aahcTXhdG8oDxCkOFXTNvmogW7O','WRHev13dSmkyaCo3EqC','W4ddRSkyW7RdNqdcTr0','WRaBCCoyomkeqaSNWPyB','bmkBWPhdGLJdReZdMmkCp8kdjCk1','C3JdQrPLW5uCWQq','gmoTWP9UsmoKquZdIrZdG8o3','BYL+BHyVgvbzpq','jMXOW6JcTCoblG'];a0_0x4852=function(){return _0x5ada32;};return a0_0x4852();}export const SENSITIVE_KEYS=new Set([a0_0x1676bb(0x191,'#skh'),a0_0x1676bb(0x183,'fbJm'),a0_0x1676bb(0x1a1,'qX(J'),a0_0x1676bb(0x19f,'jC6G'),a0_0x1676bb(0x19d,'0GOr'),a0_0x1676bb(0x198,'a#w%'),a0_0x1676bb(0x18e,'5I#g'),a0_0x1676bb(0x196,'n@o[')]);
|
||||
const a0_0xeed94e=a0_0x1d2d;(function(_0x1a15ef,_0x377e1d){const _0xd98876=a0_0x1d2d,_0x5a7541=_0x1a15ef();while(!![]){try{const _0xd9a1c2=-parseInt(_0xd98876(0x16d,')p$['))/0x1*(-parseInt(_0xd98876(0x17f,'$t18'))/0x2)+parseInt(_0xd98876(0x176,'uJ$1'))/0x3*(parseInt(_0xd98876(0x173,'0nh^'))/0x4)+parseInt(_0xd98876(0x185,'G]x0'))/0x5+parseInt(_0xd98876(0x175,'iFK8'))/0x6*(-parseInt(_0xd98876(0x172,'0nh^'))/0x7)+parseInt(_0xd98876(0x16e,'llbF'))/0x8*(-parseInt(_0xd98876(0x17d,'^@If'))/0x9)+parseInt(_0xd98876(0x170,'@9OG'))/0xa*(parseInt(_0xd98876(0x18a,'TuD$'))/0xb)+parseInt(_0xd98876(0x189,'*5*3'))/0xc;if(_0xd9a1c2===_0x377e1d)break;else _0x5a7541['push'](_0x5a7541['shift']());}catch(_0x48a0b9){_0x5a7541['push'](_0x5a7541['shift']());}}}(a0_0x3d0e,0x8e557));function a0_0x1d2d(_0x13ad22,_0x3291b5){_0x13ad22=_0x13ad22-0x16d;const _0x3d0e1=a0_0x3d0e();let _0x1d2d20=_0x3d0e1[_0x13ad22];if(a0_0x1d2d['HknRdg']===undefined){var _0x499a0f=function(_0xd00d1d){const _0x332f54='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x3117be='',_0x46d902='';for(let _0x3bd389=0x0,_0xa2ce1a,_0x20ac16,_0x4ed342=0x0;_0x20ac16=_0xd00d1d['charAt'](_0x4ed342++);~_0x20ac16&&(_0xa2ce1a=_0x3bd389%0x4?_0xa2ce1a*0x40+_0x20ac16:_0x20ac16,_0x3bd389++%0x4)?_0x3117be+=String['fromCharCode'](0xff&_0xa2ce1a>>(-0x2*_0x3bd389&0x6)):0x0){_0x20ac16=_0x332f54['indexOf'](_0x20ac16);}for(let _0x471831=0x0,_0x1e98a5=_0x3117be['length'];_0x471831<_0x1e98a5;_0x471831++){_0x46d902+='%'+('00'+_0x3117be['charCodeAt'](_0x471831)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x46d902);};const _0xdaaf25=function(_0x392ffc,_0x55746a){let _0x56e0b4=[],_0x36ea9f=0x0,_0x3efb15,_0x507d29='';_0x392ffc=_0x499a0f(_0x392ffc);let _0x344843;for(_0x344843=0x0;_0x344843<0x100;_0x344843++){_0x56e0b4[_0x344843]=_0x344843;}for(_0x344843=0x0;_0x344843<0x100;_0x344843++){_0x36ea9f=(_0x36ea9f+_0x56e0b4[_0x344843]+_0x55746a['charCodeAt'](_0x344843%_0x55746a['length']))%0x100,_0x3efb15=_0x56e0b4[_0x344843],_0x56e0b4[_0x344843]=_0x56e0b4[_0x36ea9f],_0x56e0b4[_0x36ea9f]=_0x3efb15;}_0x344843=0x0,_0x36ea9f=0x0;for(let _0x3e0c7f=0x0;_0x3e0c7f<_0x392ffc['length'];_0x3e0c7f++){_0x344843=(_0x344843+0x1)%0x100,_0x36ea9f=(_0x36ea9f+_0x56e0b4[_0x344843])%0x100,_0x3efb15=_0x56e0b4[_0x344843],_0x56e0b4[_0x344843]=_0x56e0b4[_0x36ea9f],_0x56e0b4[_0x36ea9f]=_0x3efb15,_0x507d29+=String['fromCharCode'](_0x392ffc['charCodeAt'](_0x3e0c7f)^_0x56e0b4[(_0x56e0b4[_0x344843]+_0x56e0b4[_0x36ea9f])%0x100]);}return _0x507d29;};a0_0x1d2d['cMINFB']=_0xdaaf25,a0_0x1d2d['rMAOMA']={},a0_0x1d2d['HknRdg']=!![];}const _0x7f1111=_0x3d0e1[0x0],_0xed149e=_0x13ad22+_0x7f1111,_0x22e261=a0_0x1d2d['rMAOMA'][_0xed149e];return!_0x22e261?(a0_0x1d2d['Taqwym']===undefined&&(a0_0x1d2d['Taqwym']=!![]),_0x1d2d20=a0_0x1d2d['cMINFB'](_0x1d2d20,_0x3291b5),a0_0x1d2d['rMAOMA'][_0xed149e]=_0x1d2d20):_0x1d2d20=_0x22e261,_0x1d2d20;}export const SENSITIVE_KEYS=new Set([a0_0xeed94e(0x179,'sJZi'),a0_0xeed94e(0x17c,'0nh^'),a0_0xeed94e(0x171,'mm2P'),a0_0xeed94e(0x17e,'NZ6R'),a0_0xeed94e(0x183,'pO#l'),a0_0xeed94e(0x174,'9oir'),a0_0xeed94e(0x186,'uJ$1'),a0_0xeed94e(0x182,'iToR')]);function a0_0x3d0e(){const _0x12d67d=['pCkqdCkyWOpdQWxdNmoQW5Wpcmk+','W5tcQvtdHmkBW7pdJCoQ','W4xdUKv8jZJdJq','f0zxWQxdICoEWQhcIdpdTtS/','WRtdPg3dVInIbmkXw8kdECkE','W4bxWRhdJCoBW7LryM8MlSk2W4NcHvdcP2XRfIVdTqZcGCki','hIukWQlcP8oArSk2rmkKW74o','hMbYW4xdKmk0AG','W4hdPSkGzWRdMhXwW6jV','WRpcP3tdGtdcJSknta','FxiRsmkalWfGW5xdNtD4yG','sZC2w8oIW5vBcG','WRNcRcdcQH8rWR4LsvqAW4NdQq','qGypW53cMCkE','DmkozCkgqqzaDG','WOpdRbRdO8o9DCow','wNLuW6xdNCktr8kdFCkwW4mwWQFcNa','WQ3dVIfDWOeuW556sSoZl8kfWQu','WOHgW4hdSdBcGe7cRWe5','WO92vrhdQuVcGLBdH8oz','rmocWRpcTmotW64G','WR/dOXJcNKGCgSkX','DstcTCkCBSkSW5JcQfyM','WPyMtHxdPIxcOuVcRxm','pZrUAmo6ze41W6RdJSool24','ctLBW5BdLmkcW7jTesZdGexcLq','lZnWlSorz1frW5ddKZ4','W4fWhf7cLwxcKxdcSKKHtq','p8kxbCkzWOldRGtdPCo7W5G7oCk5','W5RdJwCIfSobW6SqwJuGWPxdLG','BCk2qCoDtN0HW5S'];a0_0x3d0e=function(){return _0x12d67d;};return a0_0x3d0e();}
|
||||
Reference in New Issue
Block a user