3.15Update
本次调整:
wrapper-inline.js:新增数据中继(这可能不安全,但是别人提的意见)
scheduled-tasks.js:解除了插件必须等待上一个任务进程完成的限制,同时新增了一键清理进行中的任务(/xbtaskreset)。
xbgen流式命令:支持<varevent>和{{xbgetvar::}}语法
This commit is contained in:
@@ -268,5 +268,122 @@ export function getTemplateExtrasScript() {
|
||||
try{window.dispatchEvent(new Event('contentUpdated'))}catch(e){}
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
(function(){
|
||||
var parentOrigin;
|
||||
try{parentOrigin=new URL(document.referrer).origin}catch(_){parentOrigin='*'}
|
||||
var relayMap=new Map();
|
||||
|
||||
window.addEventListener('message',function(e){
|
||||
if(e.source===parent||e.source===window)return;
|
||||
var d=e.data;if(!d||typeof d!=='object')return;
|
||||
if((d.type==='runCommand'||d.type==='generateRequest')&&d.id){
|
||||
relayMap.set(d.id,e.source);
|
||||
try{parent.postMessage(d,parentOrigin)}catch(_){}
|
||||
return;
|
||||
}
|
||||
if(d.type==='getAvatars'){
|
||||
var k='_av_'+Date.now()+'_'+Math.random().toString(36).slice(2);
|
||||
relayMap.set(k,e.source);
|
||||
try{parent.postMessage(d,parentOrigin)}catch(_){}
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('message',function(e){
|
||||
if(e.source!==parent)return;
|
||||
var d=e.data;if(!d||d.source!=='xiaobaix-host')return;
|
||||
if(d.id&&relayMap.has(d.id)){
|
||||
var child=relayMap.get(d.id);
|
||||
try{child.postMessage(d,'*')}catch(_){}
|
||||
var t=d.type;
|
||||
if(t==='commandResult'||t==='commandError'||t==='generateResult'||t==='generateError'||t==='generateStreamComplete'||t==='generateStreamError'){
|
||||
relayMap.delete(d.id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(d.type==='avatars'){
|
||||
relayMap.forEach(function(src,key){
|
||||
if(key.indexOf('_av_')===0){try{src.postMessage(d,'*')}catch(_){}relayMap.delete(key);}
|
||||
});
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
(function(){
|
||||
function buildInjection(){
|
||||
var code='('+function(){
|
||||
var po;try{po=new URL(document.referrer).origin}catch(_){po='*'}
|
||||
function post(m){try{parent.postMessage(m,po)}catch(_){}}
|
||||
window.STscript=window.stscript=function(cmd){
|
||||
return new Promise(function(resolve,reject){
|
||||
if(!cmd){reject(new Error('empty'));return}
|
||||
if(cmd[0]!=='/')cmd='/'+cmd;
|
||||
var id=Date.now().toString(36)+Math.random().toString(36).slice(2);
|
||||
function h(e){
|
||||
if(po!=='*'&&e.origin!==po)return;
|
||||
var d=e.data||{};if(d.source!=='xiaobaix-host')return;
|
||||
if((d.type==='commandResult'||d.type==='commandError')&&d.id===id){
|
||||
window.removeEventListener('message',h);
|
||||
d.type==='commandResult'?resolve(d.result):reject(new Error(d.error||'fail'));
|
||||
}
|
||||
}
|
||||
window.addEventListener('message',h);
|
||||
post({type:'runCommand',id:id,command:cmd});
|
||||
setTimeout(function(){window.removeEventListener('message',h);reject(new Error('timeout'))},180000);
|
||||
});
|
||||
};
|
||||
function applyAvatar(u){
|
||||
var r=document.documentElement;
|
||||
r.style.setProperty('--xb-user-avatar',u&&u.user?'url("'+u.user+'")':'none');
|
||||
r.style.setProperty('--xb-char-avatar',u&&u.char?'url("'+u.char+'")':'none');
|
||||
if(!document.getElementById('xb-avatar-style')){
|
||||
var s=document.createElement('style');s.id='xb-avatar-style';
|
||||
s.textContent='.xb-avatar,.xb-user-avatar,.xb-char-avatar{width:36px;height:36px;border-radius:50%;background-size:cover;background-position:center;background-repeat:no-repeat;display:inline-block}.xb-user-avatar{background-image:var(--xb-user-avatar)}.xb-char-avatar{background-image:var(--xb-char-avatar)}';
|
||||
document.head.appendChild(s);
|
||||
}
|
||||
}
|
||||
function reqAv(){post({type:'getAvatars'})}
|
||||
window.addEventListener('message',function f(e){
|
||||
if(po!=='*'&&e.origin!==po)return;
|
||||
var d=e.data||{};
|
||||
if(d.source==='xiaobaix-host'&&d.type==='avatars'){applyAvatar(d.urls);window.removeEventListener('message',f)}
|
||||
});
|
||||
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',reqAv,{once:true});
|
||||
else reqAv();
|
||||
}+')()';
|
||||
return '<scr'+'ipt>'+code+'</'+'scr'+'ipt>';
|
||||
}
|
||||
|
||||
window.loadExternalPage=function(url,mountId,options){
|
||||
var mount=typeof mountId==='string'?document.getElementById(mountId):mountId;
|
||||
if(!mount)return Promise.reject(new Error('mount not found'));
|
||||
var opts=options||{};
|
||||
var style='width:100%;border:none;overflow:hidden;';
|
||||
if(opts.minHeight)style+='min-height:'+opts.minHeight+';';
|
||||
else style+='min-height:800px;';
|
||||
|
||||
return (async function(){
|
||||
var html=null;
|
||||
try{var r=await fetch(url);if(r.ok)html=await r.text()}catch(_){}
|
||||
if(!html){try{var r2=await fetch('/cors/'+url);if(r2.ok)html=await r2.text()}catch(_){}}
|
||||
if(!html){
|
||||
mount.innerHTML='<iframe src="'+url.replace(/"/g,'"')+'" style="'+style+'"><\\/iframe>';
|
||||
return;
|
||||
}
|
||||
var inj=buildInjection();
|
||||
if(html.indexOf('<head>')>-1)html=html.replace('<head>','<head>'+inj);
|
||||
else if(html.indexOf('<HEAD>')>-1)html=html.replace('<HEAD>','<HEAD>'+inj);
|
||||
else if(/<body/i.test(html))html=html.replace(/<body/i,'<head>'+inj+'</head><body');
|
||||
else html=inj+html;
|
||||
var iframe=document.createElement('iframe');
|
||||
iframe.style.cssText=style;
|
||||
iframe.setAttribute('frameborder','0');
|
||||
iframe.setAttribute('scrolling','auto');
|
||||
mount.appendChild(iframe);
|
||||
iframe.srcdoc=html;
|
||||
})();
|
||||
};
|
||||
})();`;
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ let state = {
|
||||
currentEditingTask: null, currentEditingIndex: -1, currentEditingId: null, currentEditingScope: 'global',
|
||||
lastChatId: null, chatJustChanged: false,
|
||||
isNewChat: false, lastTurnCount: 0, executingCount: 0, isCommandGenerated: false,
|
||||
executingRecords: new Map(),
|
||||
taskLastExecutionTime: new Map(), cleanupTimer: null, lastTasksHash: '', taskBarVisible: true,
|
||||
processedMessagesSet: new Set(),
|
||||
taskBarSignature: '',
|
||||
@@ -117,7 +118,49 @@ let state = {
|
||||
// 工具函数
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
const isAnyTaskExecuting = () => (state.executingCount || 0) > 0;
|
||||
const normalizeTaskKey = (name) => String(name || '').trim();
|
||||
const refreshExecutionState = () => {
|
||||
const records = state.executingRecords instanceof Map ? state.executingRecords : new Map();
|
||||
state.executingRecords = records;
|
||||
state.executingCount = records.size;
|
||||
state.isCommandGenerated = Array.from(records.values()).some(entry => entry?.source === 'command');
|
||||
};
|
||||
const startExecutionRecord = (taskName, source = 'command') => {
|
||||
const token = uuidv4();
|
||||
state.executingRecords.set(token, { taskName: normalizeTaskKey(taskName), source });
|
||||
refreshExecutionState();
|
||||
return token;
|
||||
};
|
||||
const finishExecutionRecord = (token) => {
|
||||
if (!token) return;
|
||||
if (state.executingRecords.delete(token)) refreshExecutionState();
|
||||
};
|
||||
const clearExecutionRecordsByTask = (taskName) => {
|
||||
const key = normalizeTaskKey(taskName);
|
||||
if (!key) return 0;
|
||||
let removed = 0;
|
||||
for (const [token, entry] of state.executingRecords.entries()) {
|
||||
if (entry?.taskName === key) {
|
||||
state.executingRecords.delete(token);
|
||||
removed++;
|
||||
}
|
||||
}
|
||||
if (removed > 0) refreshExecutionState();
|
||||
return removed;
|
||||
};
|
||||
const clearAllExecutionRecords = () => {
|
||||
if (state.executingRecords.size > 0) state.executingRecords.clear();
|
||||
refreshExecutionState();
|
||||
};
|
||||
const isTaskExecutionActive = (taskName) => {
|
||||
const key = normalizeTaskKey(taskName);
|
||||
if (!key) return false;
|
||||
for (const entry of state.executingRecords.values()) {
|
||||
if (entry?.taskName === key) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const isAnyTaskExecuting = () => state.executingRecords.size > 0;
|
||||
const isGloballyEnabled = () => (window.isXiaobaixEnabled !== undefined ? window.isXiaobaixEnabled : true) && getSettings().enabled;
|
||||
const clampInt = (v, min, max, d = 0) => (Number.isFinite(+v) ? Math.max(min, Math.min(max, +v)) : d);
|
||||
const nowMs = () => Date.now();
|
||||
@@ -439,6 +482,54 @@ async function removeTaskByScope(scope, taskId, fallbackIndex = -1) {
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
const __taskRunMap = new Map();
|
||||
const __taskDynamicCallbackPrefix = (taskName) => `${normalizeTaskKey(taskName)}_fl_`;
|
||||
|
||||
function abortTaskRunEntry(entry) {
|
||||
if (!entry) return;
|
||||
try { entry.abort?.abort?.(); } catch {}
|
||||
try { entry.timers?.forEach?.((id) => clearTimeout(id)); } catch {}
|
||||
try { entry.intervals?.forEach?.((id) => clearInterval(id)); } catch {}
|
||||
}
|
||||
|
||||
function resetTaskRun(taskName) {
|
||||
const taskKey = normalizeTaskKey(taskName);
|
||||
if (!taskKey) return { taskKey, clearedRuns: 0, clearedCallbacks: 0, clearedExecutions: 0 };
|
||||
|
||||
let clearedRuns = 0;
|
||||
const runEntry = __taskRunMap.get(taskKey);
|
||||
if (runEntry) {
|
||||
abortTaskRunEntry(runEntry);
|
||||
__taskRunMap.delete(taskKey);
|
||||
clearedRuns = 1;
|
||||
}
|
||||
|
||||
let clearedCallbacks = 0;
|
||||
const callbackPrefix = __taskDynamicCallbackPrefix(taskKey);
|
||||
for (const [id, entry] of state.dynamicCallbacks.entries()) {
|
||||
if (!id.startsWith(callbackPrefix)) continue;
|
||||
try { entry?.abortController?.abort?.(); } catch {}
|
||||
state.dynamicCallbacks.delete(id);
|
||||
clearedCallbacks++;
|
||||
}
|
||||
|
||||
clearTaskCooldown(taskKey);
|
||||
const clearedExecutions = clearExecutionRecordsByTask(taskKey);
|
||||
return { taskKey, clearedRuns, clearedCallbacks, clearedExecutions };
|
||||
}
|
||||
|
||||
function resetAllTaskRuns() {
|
||||
for (const entry of __taskRunMap.values()) abortTaskRunEntry(entry);
|
||||
__taskRunMap.clear();
|
||||
|
||||
for (const [id, entry] of state.dynamicCallbacks.entries()) {
|
||||
try { entry?.abortController?.abort?.(); } catch {}
|
||||
state.dynamicCallbacks.delete(id);
|
||||
}
|
||||
|
||||
clearTaskCooldown();
|
||||
clearAllExecutionRecords();
|
||||
return { ok: true };
|
||||
}
|
||||
|
||||
CacheRegistry.register('scheduledTasks', {
|
||||
name: '循环任务状态',
|
||||
@@ -448,8 +539,9 @@ CacheRegistry.register('scheduledTasks', {
|
||||
const b = state.taskLastExecutionTime?.size || 0;
|
||||
const c = state.dynamicCallbacks?.size || 0;
|
||||
const d = __taskRunMap.size || 0;
|
||||
const e = TasksStorage.getCacheSize() || 0;
|
||||
return a + b + c + d + e;
|
||||
const e = state.executingRecords?.size || 0;
|
||||
const f = TasksStorage.getCacheSize() || 0;
|
||||
return a + b + c + d + e + f;
|
||||
} catch { return 0; }
|
||||
},
|
||||
getBytes: () => {
|
||||
@@ -474,6 +566,10 @@ CacheRegistry.register('scheduledTasks', {
|
||||
total += (entry?.timers?.size || 0) * 8;
|
||||
total += (entry?.intervals?.size || 0) * 8;
|
||||
});
|
||||
addMap(state.executingRecords, (entry) => {
|
||||
addStr(entry?.taskName);
|
||||
addStr(entry?.source);
|
||||
});
|
||||
total += TasksStorage.getCacheBytes();
|
||||
return total;
|
||||
} catch { return 0; }
|
||||
@@ -487,12 +583,7 @@ CacheRegistry.register('scheduledTasks', {
|
||||
if (s?.processedMessages) s.processedMessages = [];
|
||||
saveSettingsDebounced();
|
||||
} catch {}
|
||||
try {
|
||||
for (const [id, entry] of state.dynamicCallbacks.entries()) {
|
||||
try { entry?.abortController?.abort?.(); } catch {}
|
||||
state.dynamicCallbacks.delete(id);
|
||||
}
|
||||
} catch {}
|
||||
try { resetAllTaskRuns(); } catch {}
|
||||
},
|
||||
getDetail: () => {
|
||||
try {
|
||||
@@ -501,6 +592,7 @@ CacheRegistry.register('scheduledTasks', {
|
||||
cooldown: state.taskLastExecutionTime?.size || 0,
|
||||
dynamicCallbacks: state.dynamicCallbacks?.size || 0,
|
||||
runningSingleInstances: __taskRunMap.size || 0,
|
||||
executingTasks: state.executingRecords?.size || 0,
|
||||
scriptCache: TasksStorage.getCacheSize() || 0,
|
||||
};
|
||||
} catch { return {}; }
|
||||
@@ -523,7 +615,8 @@ async function __runTaskSingleInstance(taskName, jsRunner, signature = null) {
|
||||
|
||||
const addListener = (target, type, handler, opts = {}) => {
|
||||
if (!target?.addEventListener) return;
|
||||
target.addEventListener(type, handler, { ...opts, signal: abort.signal });
|
||||
const normalized = typeof opts === 'boolean' ? { capture: opts } : { ...(opts || {}) };
|
||||
target.addEventListener(type, handler, { ...normalized, signal: abort.signal });
|
||||
};
|
||||
const setTimeoutSafe = (fn, t, ...a) => {
|
||||
const id = setTimeout(() => {
|
||||
@@ -566,15 +659,11 @@ async function __runTaskSingleInstance(taskName, jsRunner, signature = null) {
|
||||
|
||||
async function executeCommands(commands, taskName) {
|
||||
if (!String(commands || '').trim()) return null;
|
||||
state.isCommandGenerated = true;
|
||||
state.executingCount = Math.max(0, (state.executingCount || 0) + 1);
|
||||
const execToken = startExecutionRecord(taskName || 'AnonymousTask', 'command');
|
||||
try {
|
||||
return await processTaskCommands(commands, taskName);
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
state.executingCount = Math.max(0, (state.executingCount || 0) - 1);
|
||||
if (!isAnyTaskExecuting()) state.isCommandGenerated = false;
|
||||
}, 500);
|
||||
setTimeout(() => finishExecutionRecord(execToken), 500);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -653,138 +742,94 @@ async function executeTaskJS(jsCode, taskName = 'AnonymousTask') {
|
||||
}
|
||||
|
||||
const jsRunner = async (utils) => {
|
||||
const { addListener, setTimeoutSafe, clearTimeoutSafe, setIntervalSafe, clearIntervalSafe, abortSignal } = utils;
|
||||
|
||||
const originalWindowFns = {
|
||||
setTimeout: window.setTimeout,
|
||||
clearTimeout: window.clearTimeout,
|
||||
setInterval: window.setInterval,
|
||||
clearInterval: window.clearInterval,
|
||||
};
|
||||
|
||||
const originals = {
|
||||
setTimeout: originalWindowFns.setTimeout.bind(window),
|
||||
clearTimeout: originalWindowFns.clearTimeout.bind(window),
|
||||
setInterval: originalWindowFns.setInterval.bind(window),
|
||||
clearInterval: originalWindowFns.clearInterval.bind(window),
|
||||
addEventListener: EventTarget.prototype.addEventListener,
|
||||
removeEventListener: EventTarget.prototype.removeEventListener,
|
||||
appendChild: Node.prototype.appendChild,
|
||||
insertBefore: Node.prototype.insertBefore,
|
||||
replaceChild: Node.prototype.replaceChild,
|
||||
};
|
||||
const {
|
||||
addListener: _addListener,
|
||||
setTimeoutSafe: _setTimeoutSafe,
|
||||
clearTimeoutSafe: _clearTimeoutSafe,
|
||||
setIntervalSafe: _setIntervalSafe,
|
||||
clearIntervalSafe: _clearIntervalSafe,
|
||||
abortSignal
|
||||
} = utils;
|
||||
|
||||
const timeouts = new Set();
|
||||
const intervals = new Set();
|
||||
const listeners = new Set();
|
||||
const createdNodes = new Set();
|
||||
const waiters = new Set();
|
||||
let suppressTimerTracking = false;
|
||||
const originalToastrFns = {};
|
||||
const toastrMethods = ['info', 'success', 'warning', 'error'];
|
||||
|
||||
const notifyActivityChange = () => {
|
||||
if (waiters.size === 0) return;
|
||||
for (const cb of Array.from(waiters)) { try { cb(); } catch {} }
|
||||
};
|
||||
|
||||
const normalizeListenerOptions = (options) => (typeof options === 'boolean' ? options : !!options?.capture);
|
||||
|
||||
window.setTimeout = function(fn, t, ...args) {
|
||||
const id = originals.setTimeout(function(...inner) {
|
||||
const setTimeoutSafe = (fn, t, ...args) => {
|
||||
const id = _setTimeoutSafe((...inner) => {
|
||||
try { fn?.(...inner); }
|
||||
finally {
|
||||
if (timeouts.delete(id)) notifyActivityChange();
|
||||
}
|
||||
}, t, ...args);
|
||||
if (!suppressTimerTracking) {
|
||||
timeouts.add(id);
|
||||
notifyActivityChange();
|
||||
}
|
||||
timeouts.add(id);
|
||||
notifyActivityChange();
|
||||
return id;
|
||||
};
|
||||
window.clearTimeout = function(id) {
|
||||
originals.clearTimeout(id);
|
||||
|
||||
const clearTimeoutSafe = (id) => {
|
||||
_clearTimeoutSafe(id);
|
||||
if (timeouts.delete(id)) notifyActivityChange();
|
||||
};
|
||||
window.setInterval = function(fn, t, ...args) { const id = originals.setInterval(fn, t, ...args); intervals.add(id); notifyActivityChange(); return id; };
|
||||
window.clearInterval = function(id) { originals.clearInterval(id); intervals.delete(id); notifyActivityChange(); };
|
||||
|
||||
if (window.toastr) {
|
||||
for (const method of toastrMethods) {
|
||||
if (typeof window.toastr[method] !== 'function') continue;
|
||||
originalToastrFns[method] = window.toastr[method];
|
||||
window.toastr[method] = function(...fnArgs) {
|
||||
suppressTimerTracking = true;
|
||||
try { return originalToastrFns[method].apply(window.toastr, fnArgs); }
|
||||
finally { suppressTimerTracking = false; }
|
||||
const setIntervalSafe = (fn, t, ...args) => {
|
||||
const id = _setIntervalSafe(fn, t, ...args);
|
||||
intervals.add(id);
|
||||
notifyActivityChange();
|
||||
return id;
|
||||
};
|
||||
|
||||
const clearIntervalSafe = (id) => {
|
||||
_clearIntervalSafe(id);
|
||||
if (intervals.delete(id)) notifyActivityChange();
|
||||
};
|
||||
|
||||
const addListener = (target, type, handler, opts = {}) => {
|
||||
if (!target?.addEventListener || typeof handler !== 'function') return () => {};
|
||||
const capture = !!(opts === true || opts?.capture);
|
||||
let wrapped = handler;
|
||||
let entry = null;
|
||||
|
||||
const isOnce = opts && typeof opts === 'object' && 'once' in opts && opts.once;
|
||||
if (isOnce) {
|
||||
wrapped = function (...args) {
|
||||
try { return handler.apply(this, args); }
|
||||
finally { if (entry) listeners.delete(entry); notifyActivityChange(); }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const addListenerEntry = (entry) => { listeners.add(entry); notifyActivityChange(); };
|
||||
const removeListenerEntry = (target, type, listener, options) => {
|
||||
let removed = false;
|
||||
entry = { target, type, listener: wrapped, originalListener: handler, capture };
|
||||
listeners.add(entry);
|
||||
notifyActivityChange();
|
||||
|
||||
const normalized = typeof opts === 'boolean' ? { capture: opts } : { ...(opts || {}) };
|
||||
_addListener(target, type, wrapped, { ...normalized, signal: abortSignal });
|
||||
|
||||
return () => removeListener(target, type, handler, opts);
|
||||
};
|
||||
|
||||
const removeListener = (target, type, handler, opts = {}) => {
|
||||
const capture = !!(opts === true || opts?.capture);
|
||||
for (const entry of listeners) {
|
||||
if (entry.target === target && entry.type === type && entry.listener === listener && entry.capture === normalizeListenerOptions(options)) {
|
||||
if (entry.target === target && entry.type === type && entry.capture === capture &&
|
||||
(entry.listener === handler || entry.originalListener === handler)) {
|
||||
listeners.delete(entry);
|
||||
removed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (removed) notifyActivityChange();
|
||||
};
|
||||
|
||||
EventTarget.prototype.addEventListener = function(type, listener, options) {
|
||||
addListenerEntry({ target: this, type, listener, capture: normalizeListenerOptions(options) });
|
||||
return originals.addEventListener.call(this, type, listener, options);
|
||||
};
|
||||
EventTarget.prototype.removeEventListener = function(type, listener, options) {
|
||||
removeListenerEntry(this, type, listener, options);
|
||||
return originals.removeEventListener.call(this, type, listener, options);
|
||||
};
|
||||
|
||||
const trackNode = (node) => { try { if (node && node.nodeType === 1) createdNodes.add(node); } catch {} };
|
||||
Node.prototype.appendChild = function(child) { trackNode(child); return originals.appendChild.call(this, child); };
|
||||
Node.prototype.insertBefore = function(newNode, refNode) { trackNode(newNode); return originals.insertBefore.call(this, newNode, refNode); };
|
||||
Node.prototype.replaceChild = function(newNode, oldNode) { trackNode(newNode); return originals.replaceChild.call(this, newNode, oldNode); };
|
||||
|
||||
const restoreGlobals = () => {
|
||||
window.setTimeout = originalWindowFns.setTimeout;
|
||||
window.clearTimeout = originalWindowFns.clearTimeout;
|
||||
window.setInterval = originalWindowFns.setInterval;
|
||||
window.clearInterval = originalWindowFns.clearInterval;
|
||||
EventTarget.prototype.addEventListener = originals.addEventListener;
|
||||
EventTarget.prototype.removeEventListener = originals.removeEventListener;
|
||||
Node.prototype.appendChild = originals.appendChild;
|
||||
Node.prototype.insertBefore = originals.insertBefore;
|
||||
Node.prototype.replaceChild = originals.replaceChild;
|
||||
if (window.toastr) {
|
||||
for (const method of toastrMethods) {
|
||||
if (typeof originalToastrFns[method] === 'function') {
|
||||
window.toastr[method] = originalToastrFns[method];
|
||||
}
|
||||
try { target?.removeEventListener?.(type, entry.listener, opts); } catch {}
|
||||
notifyActivityChange();
|
||||
return;
|
||||
}
|
||||
}
|
||||
try { target?.removeEventListener?.(type, handler, opts); } catch {}
|
||||
};
|
||||
|
||||
const hardCleanup = () => {
|
||||
try { timeouts.forEach(id => originals.clearTimeout(id)); } catch {}
|
||||
try { intervals.forEach(id => originals.clearInterval(id)); } catch {}
|
||||
try {
|
||||
for (const entry of listeners) {
|
||||
const { target, type, listener, capture } = entry;
|
||||
originals.removeEventListener.call(target, type, listener, capture);
|
||||
}
|
||||
} catch {}
|
||||
try {
|
||||
createdNodes.forEach(node => {
|
||||
if (!node?.parentNode) return;
|
||||
if (node.id?.startsWith('xiaobaix_') || node.tagName === 'SCRIPT' || node.tagName === 'STYLE') {
|
||||
try { node.parentNode.removeChild(node); } catch {}
|
||||
}
|
||||
});
|
||||
} catch {}
|
||||
try { timeouts.forEach(id => _clearTimeoutSafe(id)); } catch {}
|
||||
try { intervals.forEach(id => _clearIntervalSafe(id)); } catch {}
|
||||
listeners.clear();
|
||||
waiters.clear();
|
||||
};
|
||||
@@ -810,10 +855,10 @@ async function executeTaskJS(jsCode, taskName = 'AnonymousTask') {
|
||||
// eslint-disable-next-line no-new-func -- intentional: user-defined task expression
|
||||
const fn = new Function(
|
||||
'taskContext', 'ctx', 'STscript', 'addFloorListener',
|
||||
'addListener', 'setTimeoutSafe', 'clearTimeoutSafe', 'setIntervalSafe', 'clearIntervalSafe', 'abortSignal',
|
||||
'addListener', 'removeListener', 'setTimeoutSafe', 'clearTimeoutSafe', 'setIntervalSafe', 'clearIntervalSafe', 'abortSignal',
|
||||
`return (async () => { ${code} })();`
|
||||
);
|
||||
return await fn(taskContext, taskContext, STscript, addFloorListener, addListener, setTimeoutSafe, clearTimeoutSafe, setIntervalSafe, clearIntervalSafe, abortSignal);
|
||||
return await fn(taskContext, taskContext, STscript, addFloorListener, addListener, removeListener, setTimeoutSafe, clearTimeoutSafe, setIntervalSafe, clearIntervalSafe, abortSignal);
|
||||
};
|
||||
|
||||
const hasActiveResources = () => (timeouts.size > 0 || intervals.size > 0 || listeners.size > 0);
|
||||
@@ -834,7 +879,7 @@ async function executeTaskJS(jsCode, taskName = 'AnonymousTask') {
|
||||
result = await runInScope(jsCode);
|
||||
await waitForAsyncSettled();
|
||||
} finally {
|
||||
try { hardCleanup(); } finally { restoreGlobals(); }
|
||||
hardCleanup();
|
||||
}
|
||||
return result;
|
||||
};
|
||||
@@ -960,7 +1005,7 @@ async function checkAndExecuteTasks(triggerContext = 'after_ai', overrideChatCha
|
||||
|
||||
if (tasksToExecute.length === 0) return;
|
||||
|
||||
state.executingCount = Math.max(0, (state.executingCount || 0) + 1);
|
||||
const execToken = startExecutionRecord(`__trigger__${triggerContext}`, 'system');
|
||||
try {
|
||||
for (const task of tasksToExecute) {
|
||||
state.taskLastExecutionTime.set(task.name, n);
|
||||
@@ -980,7 +1025,7 @@ async function checkAndExecuteTasks(triggerContext = 'after_ai', overrideChatCha
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
state.executingCount = Math.max(0, (state.executingCount || 0) - 1);
|
||||
finishExecutionRecord(execToken);
|
||||
}
|
||||
|
||||
if (triggerContext === 'after_ai') state.lastTurnCount = calculateTurnCount();
|
||||
@@ -1026,8 +1071,7 @@ function onMessageDeleted() {
|
||||
const chatId = getContext().chatId;
|
||||
settings.processedMessages = settings.processedMessages.filter(key => !key.startsWith(`${chatId}_`));
|
||||
state.processedMessagesSet = new Set(settings.processedMessages);
|
||||
state.executingCount = 0;
|
||||
state.isCommandGenerated = false;
|
||||
clearAllExecutionRecords();
|
||||
recountFloors();
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
@@ -1038,9 +1082,8 @@ async function onChatChanged(chatId) {
|
||||
isNewChat: state.lastChatId !== chatId && chat.length <= 1,
|
||||
lastChatId: chatId,
|
||||
lastTurnCount: 0,
|
||||
executingCount: 0,
|
||||
isCommandGenerated: false
|
||||
});
|
||||
clearAllExecutionRecords();
|
||||
state.taskLastExecutionTime.clear();
|
||||
TasksStorage.clearCache();
|
||||
|
||||
@@ -1091,7 +1134,7 @@ function getTasksHash() {
|
||||
return `${presetName || ''}|${all.map(t => `${t.id}_${t.disabled}_${t.name}_${t.interval}_${t.floorType}_${t.triggerTiming || 'after_ai'}`).join('|')}`;
|
||||
}
|
||||
|
||||
function createTaskItemSimple(task, index, scope = 'global') {
|
||||
function createTaskItemSimple(task, scope = 'global') {
|
||||
if (!task.id) task.id = `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
const taskType = scope || 'global';
|
||||
const floorTypeText = { user: '用户楼层', llm: 'LLM楼层' }[task.floorType] || '全部楼层';
|
||||
@@ -1121,7 +1164,7 @@ function createTaskItemSimple(task, index, scope = 'global') {
|
||||
}
|
||||
|
||||
const taskElement = $('#task_item_template').children().first().clone();
|
||||
taskElement.attr({ id: task.id, 'data-index': index, 'data-type': taskType });
|
||||
taskElement.attr({ id: task.id, 'data-task-id': task.id, 'data-type': taskType });
|
||||
taskElement.find('.task_name').attr('title', task.name).text(displayName);
|
||||
taskElement.find('.disable_task').attr('id', `task_disable_${task.id}`).prop('checked', task.disabled);
|
||||
taskElement.find('label.checkbox').attr('for', `task_disable_${task.id}`);
|
||||
@@ -1168,16 +1211,16 @@ function refreshTaskLists() {
|
||||
updateTaskCounts(globalTasks.length, characterTasks.length, presetTasks.length);
|
||||
|
||||
const globalFragment = document.createDocumentFragment();
|
||||
globalTasks.forEach((task, i) => { globalFragment.appendChild(createTaskItemSimple(task, i, 'global')[0]); });
|
||||
globalTasks.forEach((task) => { globalFragment.appendChild(createTaskItemSimple(task, 'global')[0]); });
|
||||
$globalList.empty().append(globalFragment);
|
||||
|
||||
const charFragment = document.createDocumentFragment();
|
||||
characterTasks.forEach((task, i) => { charFragment.appendChild(createTaskItemSimple(task, i, 'character')[0]); });
|
||||
characterTasks.forEach((task) => { charFragment.appendChild(createTaskItemSimple(task, 'character')[0]); });
|
||||
$charList.empty().append(charFragment);
|
||||
|
||||
if ($presetList.length) {
|
||||
const presetFragment = document.createDocumentFragment();
|
||||
presetTasks.forEach((task, i) => { presetFragment.appendChild(createTaskItemSimple(task, i, 'preset')[0]); });
|
||||
presetTasks.forEach((task) => { presetFragment.appendChild(createTaskItemSimple(task, 'preset')[0]); });
|
||||
$presetList.empty().append(presetFragment);
|
||||
}
|
||||
|
||||
@@ -1422,6 +1465,13 @@ async function showTaskEditor(task = null, isEdit = false, scope = 'global') {
|
||||
});
|
||||
}
|
||||
|
||||
function resetTaskEditorState() {
|
||||
state.currentEditingTask = null;
|
||||
state.currentEditingIndex = -1;
|
||||
state.currentEditingId = null;
|
||||
state.currentEditingScope = 'global';
|
||||
}
|
||||
|
||||
async function saveTaskFromEditor(task, scope) {
|
||||
const targetScope = scope === 'character' || scope === 'preset' ? scope : 'global';
|
||||
const isManual = (task?.interval === 0);
|
||||
@@ -1454,7 +1504,7 @@ async function saveTaskFromEditor(task, scope) {
|
||||
|
||||
await persistTaskListByScope(targetScope, [...list]);
|
||||
|
||||
state.currentEditingScope = targetScope;
|
||||
resetTaskEditorState();
|
||||
state.lastTasksHash = '';
|
||||
refreshUI();
|
||||
}
|
||||
@@ -1483,6 +1533,9 @@ async function deleteTask(index, scope) {
|
||||
document.getElementById(styleId)?.remove();
|
||||
if (result) {
|
||||
await removeTaskByScope(scope, task.id, index);
|
||||
if (state.currentEditingId === task.id || (state.currentEditingScope === scope && state.currentEditingIndex === index)) {
|
||||
resetTaskEditorState();
|
||||
}
|
||||
refreshUI();
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -1769,8 +1822,7 @@ function refreshUI() {
|
||||
}
|
||||
|
||||
function onMessageSwiped() {
|
||||
state.executingCount = 0;
|
||||
state.isCommandGenerated = false;
|
||||
clearAllExecutionRecords();
|
||||
}
|
||||
|
||||
function onCharacterDeleted({ character }) {
|
||||
@@ -1790,18 +1842,9 @@ function cleanup() {
|
||||
clearInterval(state.cleanupTimer);
|
||||
state.cleanupTimer = null;
|
||||
}
|
||||
state.taskLastExecutionTime.clear();
|
||||
resetAllTaskRuns();
|
||||
TasksStorage.clearCache();
|
||||
|
||||
try {
|
||||
if (state.dynamicCallbacks && state.dynamicCallbacks.size > 0) {
|
||||
for (const entry of state.dynamicCallbacks.values()) {
|
||||
try { entry?.abortController?.abort(); } catch {}
|
||||
}
|
||||
state.dynamicCallbacks.clear();
|
||||
}
|
||||
} catch {}
|
||||
|
||||
events.cleanup();
|
||||
window.removeEventListener('message', handleTaskMessage);
|
||||
$(window).off('beforeunload', cleanup);
|
||||
@@ -1938,6 +1981,9 @@ window.xbqte = async (name) => {
|
||||
const task = tasks.find(t => t.name.toLowerCase() === name.toLowerCase());
|
||||
if (!task) throw new Error(`找不到名为 "${name}" 的任务`);
|
||||
if (task.disabled) throw new Error(`任务 "${name}" 已被禁用`);
|
||||
if (isTaskExecutionActive(task.name) || __taskRunMap.has(normalizeTaskKey(task.name))) {
|
||||
resetTaskRun(task.name);
|
||||
}
|
||||
if (isTaskInCooldown(task.name)) {
|
||||
const cd = getTaskCooldownStatus()[task.name];
|
||||
throw new Error(`任务 "${name}" 仍在冷却中,剩余 ${cd.remainingCooldown}ms`);
|
||||
@@ -1951,6 +1997,11 @@ window.xbqte = async (name) => {
|
||||
}
|
||||
};
|
||||
|
||||
window.xbtaskreset = async () => {
|
||||
resetAllTaskRuns();
|
||||
return '已清理所有运行中任务、动态回调、冷却和执行状态';
|
||||
};
|
||||
|
||||
window.setScheduledTaskInterval = async (name, interval) => {
|
||||
if (!name?.trim()) throw new Error('请提供任务名称');
|
||||
const intervalNum = parseInt(interval);
|
||||
@@ -2006,6 +2057,14 @@ function registerSlashCommands() {
|
||||
helpString: '执行指定名称的定时任务。例如: /xbqte 我的任务名称'
|
||||
}));
|
||||
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'xbtaskreset',
|
||||
callback: async () => {
|
||||
try { return await window.xbtaskreset(); } catch (error) { return `错误: ${error.message}`; }
|
||||
},
|
||||
helpString: '清理所有运行中任务、动态回调、冷却和执行状态'
|
||||
}));
|
||||
|
||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||
name: 'xbset',
|
||||
callback: async (namedArgs, taskName) => {
|
||||
@@ -2127,51 +2186,96 @@ async function initTasks() {
|
||||
|
||||
$('#global_tasks_list')
|
||||
.on('input', '.disable_task', function () {
|
||||
const $item = $(this).closest('.task-item');
|
||||
const idx = parseInt($item.attr('data-index'), 10);
|
||||
const id = $(this).closest('.task-item').attr('data-task-id');
|
||||
const list = getSettings().globalTasks;
|
||||
if (list[idx]) {
|
||||
const idx = list.findIndex(t => t?.id === id);
|
||||
if (idx !== -1) {
|
||||
list[idx].disabled = $(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
state.lastTasksHash = '';
|
||||
refreshTaskLists();
|
||||
}
|
||||
})
|
||||
.on('click', '.edit_task', function () { editTask(parseInt($(this).closest('.task-item').attr('data-index')), 'global'); })
|
||||
.on('click', '.export_task', function () { exportSingleTask(parseInt($(this).closest('.task-item').attr('data-index')), 'global'); })
|
||||
.on('click', '.delete_task', function () { deleteTask(parseInt($(this).closest('.task-item').attr('data-index')), 'global'); });
|
||||
.on('click', '.edit_task', function () {
|
||||
const id = $(this).closest('.task-item').attr('data-task-id');
|
||||
const list = getSettings().globalTasks;
|
||||
const idx = list.findIndex(t => t?.id === id);
|
||||
if (idx !== -1) editTask(idx, 'global');
|
||||
})
|
||||
.on('click', '.export_task', function () {
|
||||
const id = $(this).closest('.task-item').attr('data-task-id');
|
||||
const list = getSettings().globalTasks;
|
||||
const idx = list.findIndex(t => t?.id === id);
|
||||
if (idx !== -1) exportSingleTask(idx, 'global');
|
||||
})
|
||||
.on('click', '.delete_task', function () {
|
||||
const id = $(this).closest('.task-item').attr('data-task-id');
|
||||
const list = getSettings().globalTasks;
|
||||
const idx = list.findIndex(t => t?.id === id);
|
||||
if (idx !== -1) deleteTask(idx, 'global');
|
||||
});
|
||||
|
||||
$('#character_tasks_list')
|
||||
.on('input', '.disable_task', function () {
|
||||
const $item = $(this).closest('.task-item');
|
||||
const idx = parseInt($item.attr('data-index'), 10);
|
||||
const tasks = getCharacterTasks();
|
||||
if (tasks[idx]) {
|
||||
tasks[idx].disabled = $(this).prop('checked');
|
||||
saveCharacterTasks(tasks);
|
||||
const id = $(this).closest('.task-item').attr('data-task-id');
|
||||
const list = getCharacterTasks();
|
||||
const idx = list.findIndex(t => t?.id === id);
|
||||
if (idx !== -1) {
|
||||
list[idx].disabled = $(this).prop('checked');
|
||||
saveCharacterTasks(list);
|
||||
state.lastTasksHash = '';
|
||||
refreshTaskLists();
|
||||
}
|
||||
})
|
||||
.on('click', '.edit_task', function () { editTask(parseInt($(this).closest('.task-item').attr('data-index')), 'character'); })
|
||||
.on('click', '.export_task', function () { exportSingleTask(parseInt($(this).closest('.task-item').attr('data-index')), 'character'); })
|
||||
.on('click', '.delete_task', function () { deleteTask(parseInt($(this).closest('.task-item').attr('data-index')), 'character'); });
|
||||
.on('click', '.edit_task', function () {
|
||||
const id = $(this).closest('.task-item').attr('data-task-id');
|
||||
const list = getCharacterTasks();
|
||||
const idx = list.findIndex(t => t?.id === id);
|
||||
if (idx !== -1) editTask(idx, 'character');
|
||||
})
|
||||
.on('click', '.export_task', function () {
|
||||
const id = $(this).closest('.task-item').attr('data-task-id');
|
||||
const list = getCharacterTasks();
|
||||
const idx = list.findIndex(t => t?.id === id);
|
||||
if (idx !== -1) exportSingleTask(idx, 'character');
|
||||
})
|
||||
.on('click', '.delete_task', function () {
|
||||
const id = $(this).closest('.task-item').attr('data-task-id');
|
||||
const list = getCharacterTasks();
|
||||
const idx = list.findIndex(t => t?.id === id);
|
||||
if (idx !== -1) deleteTask(idx, 'character');
|
||||
});
|
||||
|
||||
$('#preset_tasks_list')
|
||||
.on('input', '.disable_task', async function () {
|
||||
const $item = $(this).closest('.task-item');
|
||||
const idx = parseInt($item.attr('data-index'), 10);
|
||||
const tasks = getPresetTasks();
|
||||
if (tasks[idx]) {
|
||||
tasks[idx].disabled = $(this).prop('checked');
|
||||
await savePresetTasks([...tasks]);
|
||||
const id = $(this).closest('.task-item').attr('data-task-id');
|
||||
const list = getPresetTasks();
|
||||
const idx = list.findIndex(t => t?.id === id);
|
||||
if (idx !== -1) {
|
||||
list[idx].disabled = $(this).prop('checked');
|
||||
await savePresetTasks([...list]);
|
||||
state.lastTasksHash = '';
|
||||
refreshTaskLists();
|
||||
}
|
||||
})
|
||||
.on('click', '.edit_task', function () { editTask(parseInt($(this).closest('.task-item').attr('data-index')), 'preset'); })
|
||||
.on('click', '.export_task', function () { exportSingleTask(parseInt($(this).closest('.task-item').attr('data-index')), 'preset'); })
|
||||
.on('click', '.delete_task', function () { deleteTask(parseInt($(this).closest('.task-item').attr('data-index')), 'preset'); });
|
||||
.on('click', '.edit_task', function () {
|
||||
const id = $(this).closest('.task-item').attr('data-task-id');
|
||||
const list = getPresetTasks();
|
||||
const idx = list.findIndex(t => t?.id === id);
|
||||
if (idx !== -1) editTask(idx, 'preset');
|
||||
})
|
||||
.on('click', '.export_task', function () {
|
||||
const id = $(this).closest('.task-item').attr('data-task-id');
|
||||
const list = getPresetTasks();
|
||||
const idx = list.findIndex(t => t?.id === id);
|
||||
if (idx !== -1) exportSingleTask(idx, 'preset');
|
||||
})
|
||||
.on('click', '.delete_task', function () {
|
||||
const id = $(this).closest('.task-item').attr('data-task-id');
|
||||
const list = getPresetTasks();
|
||||
const idx = list.findIndex(t => t?.id === id);
|
||||
if (idx !== -1) deleteTask(idx, 'preset');
|
||||
});
|
||||
|
||||
$('#scheduled_tasks_enabled').prop('checked', getSettings().enabled);
|
||||
refreshTaskLists();
|
||||
|
||||
@@ -411,12 +411,28 @@ class StreamingGeneration {
|
||||
|
||||
|
||||
async _emitPromptReady(chatArray) {
|
||||
if (!Array.isArray(chatArray)) return chatArray;
|
||||
const snapshot = this._cloneChat(chatArray);
|
||||
const shouldAdoptMutations = this._needsPromptPostProcess(chatArray);
|
||||
try {
|
||||
if (Array.isArray(chatArray)) {
|
||||
const snapshot = this._cloneChat(chatArray);
|
||||
await eventSource?.emit?.(event_types.CHAT_COMPLETION_PROMPT_READY, { chat: snapshot, dryRun: false });
|
||||
}
|
||||
await eventSource?.emit?.(event_types.CHAT_COMPLETION_PROMPT_READY, { chat: snapshot, dryRun: false });
|
||||
} catch {}
|
||||
return shouldAdoptMutations && Array.isArray(snapshot) ? snapshot : chatArray;
|
||||
}
|
||||
|
||||
_needsPromptPostProcess(chatArray) {
|
||||
const markers = ['<varevent', '{{xbgetvar::', '{{xbgetvar_yaml::', '{{xbgetvar_yaml_idx::'];
|
||||
const hasMarker = (text) => typeof text === 'string' && markers.some(marker => text.includes(marker));
|
||||
for (const msg of Array.isArray(chatArray) ? chatArray : []) {
|
||||
if (!msg) continue;
|
||||
if (hasMarker(msg.content) || hasMarker(msg.mes)) return true;
|
||||
if (Array.isArray(msg.content)) {
|
||||
for (const part of msg.content) {
|
||||
if (hasMarker(part?.text)) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
_cloneChat(chatArray) {
|
||||
@@ -1124,11 +1140,11 @@ class StreamingGeneration {
|
||||
.concat(prompt && prompt.trim().length ? [{ role, content: prompt.trim() }] : [])
|
||||
.concat(bottomMsgs.filter(m => typeof m?.content === 'string' && m.content.trim().length));
|
||||
|
||||
const common = { messages, apiOptions, stop: parsedStop };
|
||||
if (nonstream) {
|
||||
try { if (lock) deactivateSendButtons(); } catch {}
|
||||
try {
|
||||
await this._emitPromptReady(messages);
|
||||
const preparedMessages = await this._emitPromptReady(messages);
|
||||
const common = { messages: preparedMessages, apiOptions, stop: parsedStop };
|
||||
const finalText = await this.processGeneration(common, prompt || '', sessionId, false);
|
||||
return String(finalText ?? '');
|
||||
} finally {
|
||||
@@ -1136,7 +1152,8 @@ class StreamingGeneration {
|
||||
}
|
||||
} else {
|
||||
try { if (lock) deactivateSendButtons(); } catch {}
|
||||
await this._emitPromptReady(messages);
|
||||
const preparedMessages = await this._emitPromptReady(messages);
|
||||
const common = { messages: preparedMessages, apiOptions, stop: parsedStop };
|
||||
const p = this.processGeneration(common, prompt || '', sessionId, true);
|
||||
p.finally(() => { try { if (lock) activateSendButtons(); } catch {} });
|
||||
p.catch(() => {});
|
||||
@@ -1237,8 +1254,8 @@ class StreamingGeneration {
|
||||
try { if (lock) deactivateSendButtons(); } catch {}
|
||||
try {
|
||||
const finalMessages = await buildAddonFinalMessages();
|
||||
const common = { messages: finalMessages, apiOptions, stop: parsedStop };
|
||||
await this._emitPromptReady(finalMessages);
|
||||
const preparedMessages = await this._emitPromptReady(finalMessages);
|
||||
const common = { messages: preparedMessages, apiOptions, stop: parsedStop };
|
||||
const finalText = await this.processGeneration(common, prompt || '', sessionId, false);
|
||||
return String(finalText ?? '');
|
||||
} finally {
|
||||
@@ -1249,8 +1266,8 @@ class StreamingGeneration {
|
||||
try {
|
||||
try { if (lock) deactivateSendButtons(); } catch {}
|
||||
const finalMessages = await buildAddonFinalMessages();
|
||||
const common = { messages: finalMessages, apiOptions, stop: parsedStop };
|
||||
await this._emitPromptReady(finalMessages);
|
||||
const preparedMessages = await this._emitPromptReady(finalMessages);
|
||||
const common = { messages: preparedMessages, apiOptions, stop: parsedStop };
|
||||
await this.processGeneration(common, prompt || '', sessionId, true);
|
||||
} catch {} finally {
|
||||
try { if (lock) activateSendButtons(); } catch {}
|
||||
@@ -1367,8 +1384,11 @@ class StreamingGeneration {
|
||||
const dataWithOptions = await buildGenDataWithOptions();
|
||||
const chatMsgs = Array.isArray(dataWithOptions?.prompt) ? dataWithOptions.prompt
|
||||
: (Array.isArray(dataWithOptions?.messages) ? dataWithOptions.messages : []);
|
||||
await this._emitPromptReady(chatMsgs);
|
||||
const finalText = await this.processGeneration(dataWithOptions, prompt, sessionId, false);
|
||||
const preparedChatMsgs = await this._emitPromptReady(chatMsgs);
|
||||
const preparedData = Array.isArray(dataWithOptions?.prompt)
|
||||
? { ...dataWithOptions, prompt: preparedChatMsgs }
|
||||
: { ...dataWithOptions, messages: preparedChatMsgs };
|
||||
const finalText = await this.processGeneration(preparedData, prompt, sessionId, false);
|
||||
return String(finalText ?? '');
|
||||
} finally {
|
||||
try { if (lock) activateSendButtons(); } catch {}
|
||||
@@ -1380,8 +1400,11 @@ class StreamingGeneration {
|
||||
const dataWithOptions = await buildGenDataWithOptions();
|
||||
const chatMsgs = Array.isArray(dataWithOptions?.prompt) ? dataWithOptions.prompt
|
||||
: (Array.isArray(dataWithOptions?.messages) ? dataWithOptions.messages : []);
|
||||
await this._emitPromptReady(chatMsgs);
|
||||
const finalText = await this.processGeneration(dataWithOptions, prompt, sessionId, true);
|
||||
const preparedChatMsgs = await this._emitPromptReady(chatMsgs);
|
||||
const preparedData = Array.isArray(dataWithOptions?.prompt)
|
||||
? { ...dataWithOptions, prompt: preparedChatMsgs }
|
||||
: { ...dataWithOptions, messages: preparedChatMsgs };
|
||||
const finalText = await this.processGeneration(preparedData, prompt, sessionId, true);
|
||||
try { if (args && args._scope) args._scope.pipe = String(finalText ?? ''); } catch {}
|
||||
} catch {}
|
||||
finally {
|
||||
|
||||
Reference in New Issue
Block a user