feat:基于callGenerate增加assemblePrompt函数,用于单纯干跑获得提示词组装
This commit is contained in:
@@ -1,23 +1,23 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import { oai_settings, chat_completion_sources, getChatCompletionModel, promptManager } from "../../../../openai.js";
|
import { oai_settings, chat_completion_sources, getChatCompletionModel, promptManager } from "../../../../openai.js";
|
||||||
import { ChatCompletionService } from "../../../../custom-request.js";
|
import { ChatCompletionService } from "../../../../custom-request.js";
|
||||||
import { eventSource, event_types } from "../../../../../script.js";
|
import { eventSource, event_types } from "../../../../../script.js";
|
||||||
import { getContext } from "../../../../st-context.js";
|
import { getContext } from "../../../../st-context.js";
|
||||||
import { xbLog } from "../core/debug-core.js";
|
import { xbLog } from "../core/debug-core.js";
|
||||||
|
|
||||||
const SOURCE_TAG = 'xiaobaix-host';
|
const SOURCE_TAG = 'xiaobaix-host';
|
||||||
|
|
||||||
const POSITIONS = Object.freeze({ BEFORE_PROMPT: 'BEFORE_PROMPT', IN_PROMPT: 'IN_PROMPT', IN_CHAT: 'IN_CHAT', AFTER_COMPONENT: 'AFTER_COMPONENT' });
|
const POSITIONS = Object.freeze({ BEFORE_PROMPT: 'BEFORE_PROMPT', IN_PROMPT: 'IN_PROMPT', IN_CHAT: 'IN_CHAT', AFTER_COMPONENT: 'AFTER_COMPONENT' });
|
||||||
const KNOWN_KEYS = Object.freeze(new Set([
|
const KNOWN_KEYS = Object.freeze(new Set([
|
||||||
'main', 'chatHistory', 'worldInfo', 'worldInfoBefore', 'worldInfoAfter',
|
'main', 'chatHistory', 'worldInfo', 'worldInfoBefore', 'worldInfoAfter',
|
||||||
'charDescription', 'charPersonality', 'scenario', 'personaDescription',
|
'charDescription', 'charPersonality', 'scenario', 'personaDescription',
|
||||||
'dialogueExamples', 'authorsNote', 'vectorsMemory', 'vectorsDataBank',
|
'dialogueExamples', 'authorsNote', 'vectorsMemory', 'vectorsDataBank',
|
||||||
'smartContext', 'jailbreak', 'nsfw', 'summary', 'bias', 'impersonate', 'quietPrompt',
|
'smartContext', 'jailbreak', 'nsfw', 'summary', 'bias', 'impersonate', 'quietPrompt',
|
||||||
]));
|
]));
|
||||||
const resolveTargetOrigin = (origin) => {
|
const resolveTargetOrigin = (origin) => {
|
||||||
if (typeof origin === 'string' && origin) return origin;
|
if (typeof origin === 'string' && origin) return origin;
|
||||||
try { return window.location.origin; } catch { return '*'; }
|
try { return window.location.origin; } catch { return '*'; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
class CallGenerateService {
|
class CallGenerateService {
|
||||||
@@ -48,11 +48,11 @@ class CallGenerateService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendError(sourceWindow, requestId, streamingEnabled, err, fallbackCode = 'API_ERROR', details = null, targetOrigin = null) {
|
sendError(sourceWindow, requestId, streamingEnabled, err, fallbackCode = 'API_ERROR', details = null, targetOrigin = null) {
|
||||||
const e = this.normalizeError(err, fallbackCode, details);
|
const e = this.normalizeError(err, fallbackCode, details);
|
||||||
const type = streamingEnabled ? 'generateStreamError' : 'generateError';
|
const type = streamingEnabled ? 'generateStreamError' : 'generateError';
|
||||||
try { sourceWindow?.postMessage({ source: SOURCE_TAG, type, id: requestId, error: e }, resolveTargetOrigin(targetOrigin)); } catch {}
|
try { sourceWindow?.postMessage({ source: SOURCE_TAG, type, id: requestId, error: e }, resolveTargetOrigin(targetOrigin)); } catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string|undefined} rawId
|
* @param {string|undefined} rawId
|
||||||
@@ -257,11 +257,11 @@ class CallGenerateService {
|
|||||||
* @param {string} type
|
* @param {string} type
|
||||||
* @param {object} body
|
* @param {object} body
|
||||||
*/
|
*/
|
||||||
postToTarget(target, type, body, targetOrigin = null) {
|
postToTarget(target, type, body, targetOrigin = null) {
|
||||||
try {
|
try {
|
||||||
target?.postMessage({ source: SOURCE_TAG, type, ...body }, resolveTargetOrigin(targetOrigin));
|
target?.postMessage({ source: SOURCE_TAG, type, ...body }, resolveTargetOrigin(targetOrigin));
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== ST Prompt 干跑捕获与组件切换 =====
|
// ===== ST Prompt 干跑捕获与组件切换 =====
|
||||||
|
|
||||||
@@ -1008,7 +1008,7 @@ class CallGenerateService {
|
|||||||
|
|
||||||
_applyContentFilter(list, filterCfg) {
|
_applyContentFilter(list, filterCfg) {
|
||||||
if (!filterCfg) return list;
|
if (!filterCfg) return list;
|
||||||
const { contains, regex, fromUserNames } = filterCfg;
|
const { contains, regex, fromUserNames } = filterCfg;
|
||||||
let out = list.slice();
|
let out = list.slice();
|
||||||
if (contains) {
|
if (contains) {
|
||||||
const needles = Array.isArray(contains) ? contains : [contains];
|
const needles = Array.isArray(contains) ? contains : [contains];
|
||||||
@@ -1132,7 +1132,7 @@ class CallGenerateService {
|
|||||||
|
|
||||||
// ===== 发送实现(构建后的统一发送) =====
|
// ===== 发送实现(构建后的统一发送) =====
|
||||||
|
|
||||||
async _sendMessages(messages, options, requestId, sourceWindow, targetOrigin = null) {
|
async _sendMessages(messages, options, requestId, sourceWindow, targetOrigin = null) {
|
||||||
const sessionId = this.normalizeSessionId(options?.session?.id || 'xb1');
|
const sessionId = this.normalizeSessionId(options?.session?.id || 'xb1');
|
||||||
const session = this.ensureSession(sessionId);
|
const session = this.ensureSession(sessionId);
|
||||||
const streamingEnabled = options?.streaming?.enabled !== false; // 默认开
|
const streamingEnabled = options?.streaming?.enabled !== false; // 默认开
|
||||||
@@ -1143,11 +1143,11 @@ class CallGenerateService {
|
|||||||
const shouldExport = !!(options?.debug?.enabled || options?.debug?.exportPrompt);
|
const shouldExport = !!(options?.debug?.enabled || options?.debug?.exportPrompt);
|
||||||
const already = options?.debug?._exported === true;
|
const already = options?.debug?._exported === true;
|
||||||
if (shouldExport && !already) {
|
if (shouldExport && !already) {
|
||||||
this.postToTarget(sourceWindow, 'generatePromptPreview', { id: requestId, messages: (messages || []).map(m => ({ role: m.role, content: m.content })) }, targetOrigin);
|
this.postToTarget(sourceWindow, 'generatePromptPreview', { id: requestId, messages: (messages || []).map(m => ({ role: m.role, content: m.content })) }, targetOrigin);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streamingEnabled) {
|
if (streamingEnabled) {
|
||||||
this.postToTarget(sourceWindow, 'generateStreamStart', { id: requestId, sessionId }, targetOrigin);
|
this.postToTarget(sourceWindow, 'generateStreamStart', { id: requestId, sessionId }, targetOrigin);
|
||||||
const streamFn = await ChatCompletionService.sendRequest(payload, false, session.abortController.signal);
|
const streamFn = await ChatCompletionService.sendRequest(payload, false, session.abortController.signal);
|
||||||
let last = '';
|
let last = '';
|
||||||
const generator = typeof streamFn === 'function' ? streamFn() : null;
|
const generator = typeof streamFn === 'function' ? streamFn() : null;
|
||||||
@@ -1155,7 +1155,7 @@ class CallGenerateService {
|
|||||||
const chunk = text.slice(last.length);
|
const chunk = text.slice(last.length);
|
||||||
last = text;
|
last = text;
|
||||||
session.accumulated = text;
|
session.accumulated = text;
|
||||||
this.postToTarget(sourceWindow, 'generateStreamChunk', { id: requestId, chunk, accumulated: text, metadata: {} }, targetOrigin);
|
this.postToTarget(sourceWindow, 'generateStreamChunk', { id: requestId, chunk, accumulated: text, metadata: {} }, targetOrigin);
|
||||||
}
|
}
|
||||||
const result = {
|
const result = {
|
||||||
success: true,
|
success: true,
|
||||||
@@ -1163,7 +1163,7 @@ class CallGenerateService {
|
|||||||
sessionId,
|
sessionId,
|
||||||
metadata: { duration: Date.now() - session.startedAt, model: apiCfg.model, finishReason: 'stop' },
|
metadata: { duration: Date.now() - session.startedAt, model: apiCfg.model, finishReason: 'stop' },
|
||||||
};
|
};
|
||||||
this.postToTarget(sourceWindow, 'generateStreamComplete', { id: requestId, result }, targetOrigin);
|
this.postToTarget(sourceWindow, 'generateStreamComplete', { id: requestId, result }, targetOrigin);
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
const extracted = await ChatCompletionService.sendRequest(payload, true, session.abortController.signal);
|
const extracted = await ChatCompletionService.sendRequest(payload, true, session.abortController.signal);
|
||||||
@@ -1173,17 +1173,17 @@ class CallGenerateService {
|
|||||||
sessionId,
|
sessionId,
|
||||||
metadata: { duration: Date.now() - session.startedAt, model: apiCfg.model, finishReason: 'stop' },
|
metadata: { duration: Date.now() - session.startedAt, model: apiCfg.model, finishReason: 'stop' },
|
||||||
};
|
};
|
||||||
this.postToTarget(sourceWindow, 'generateResult', { id: requestId, result }, targetOrigin);
|
this.postToTarget(sourceWindow, 'generateResult', { id: requestId, result }, targetOrigin);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.sendError(sourceWindow, requestId, streamingEnabled, err, 'API_ERROR', null, targetOrigin);
|
this.sendError(sourceWindow, requestId, streamingEnabled, err, 'API_ERROR', null, targetOrigin);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== 主流程 =====
|
// ===== 主流程 =====
|
||||||
async handleRequestInternal(options, requestId, sourceWindow, targetOrigin = null) {
|
async handleRequestInternal(options, requestId, sourceWindow, targetOrigin = null, { assembleOnly = false } = {}) {
|
||||||
// 1) 校验
|
// 1) 校验
|
||||||
this.validateOptions(options);
|
this.validateOptions(options);
|
||||||
|
|
||||||
@@ -1226,6 +1226,7 @@ class CallGenerateService {
|
|||||||
|
|
||||||
// 3) 干跑捕获(基座)
|
// 3) 干跑捕获(基座)
|
||||||
let captured = [];
|
let captured = [];
|
||||||
|
let enabledIds = []; // assembleOnly 时用于 identifier 标注
|
||||||
if (baseStrategy === 'EMPTY') {
|
if (baseStrategy === 'EMPTY') {
|
||||||
captured = [];
|
captured = [];
|
||||||
} else {
|
} else {
|
||||||
@@ -1242,6 +1243,7 @@ class CallGenerateService {
|
|||||||
allow = new Set(order.map(e => e.identifier));
|
allow = new Set(order.map(e => e.identifier));
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
|
enabledIds = Array.from(allow);
|
||||||
const run = async () => await this._capturePromptMessages({ includeConfig: null, quietText: '', skipWIAN: false });
|
const run = async () => await this._capturePromptMessages({ includeConfig: null, quietText: '', skipWIAN: false });
|
||||||
captured = await this._withPromptEnabledSet(allow, run);
|
captured = await this._withPromptEnabledSet(allow, run);
|
||||||
} else if (baseStrategy === 'ALL_PREON') {
|
} else if (baseStrategy === 'ALL_PREON') {
|
||||||
@@ -1255,6 +1257,7 @@ class CallGenerateService {
|
|||||||
allow = new Set(order.filter(e => !!e?.enabled).map(e => e.identifier));
|
allow = new Set(order.filter(e => !!e?.enabled).map(e => e.identifier));
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
|
enabledIds = Array.from(allow);
|
||||||
const run = async () => await this._capturePromptMessages({ includeConfig: null, quietText: '', skipWIAN: false });
|
const run = async () => await this._capturePromptMessages({ includeConfig: null, quietText: '', skipWIAN: false });
|
||||||
captured = await this._withPromptEnabledSet(allow, run);
|
captured = await this._withPromptEnabledSet(allow, run);
|
||||||
} else {
|
} else {
|
||||||
@@ -1263,7 +1266,11 @@ class CallGenerateService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4) 依据策略计算启用集合与顺序
|
// 4) 依据策略计算启用集合与顺序
|
||||||
const annotateKeys = baseStrategy === 'SUBSET' ? orderedRefs : ((baseStrategy === 'ALL' || baseStrategy === 'ALL_PREON') ? orderedRefs : []);
|
let annotateKeys = baseStrategy === 'SUBSET' ? orderedRefs : ((baseStrategy === 'ALL' || baseStrategy === 'ALL_PREON') ? orderedRefs : []);
|
||||||
|
// assembleOnly 模式下,若无显式排序引用,则用全部启用组件做 identifier 标注
|
||||||
|
if (assembleOnly && annotateKeys.length === 0 && enabledIds.length > 0) {
|
||||||
|
annotateKeys = enabledIds;
|
||||||
|
}
|
||||||
let working = await this._annotateIdentifiersIfMissing(captured.slice(), annotateKeys);
|
let working = await this._annotateIdentifiersIfMissing(captured.slice(), annotateKeys);
|
||||||
working = this._applyOrderingStrategy(working, baseStrategy, orderedRefs, unorderedKeys);
|
working = this._applyOrderingStrategy(working, baseStrategy, orderedRefs, unorderedKeys);
|
||||||
|
|
||||||
@@ -1277,10 +1284,35 @@ class CallGenerateService {
|
|||||||
working = this._appendUserInput(working, options?.userInput);
|
working = this._appendUserInput(working, options?.userInput);
|
||||||
|
|
||||||
// 8) 调试导出
|
// 8) 调试导出
|
||||||
this._exportDebugData({ sourceWindow, requestId, working, baseStrategy, orderedRefs, inlineMapped, listLevelOverrides, debug: options?.debug, targetOrigin });
|
this._exportDebugData({ sourceWindow, requestId, working, baseStrategy, orderedRefs, inlineMapped, listLevelOverrides, debug: options?.debug, targetOrigin });
|
||||||
|
|
||||||
|
// assembleOnly 模式:只返回组装好的 messages,不调 LLM
|
||||||
|
if (assembleOnly) {
|
||||||
|
// 构建 identifier → name 映射(从 promptCollection 取,order 里没有 name)
|
||||||
|
const idToName = new Map();
|
||||||
|
try {
|
||||||
|
if (promptManager && typeof promptManager.getPromptCollection === 'function') {
|
||||||
|
const pc = promptManager.getPromptCollection();
|
||||||
|
const coll = pc?.collection || [];
|
||||||
|
for (const p of coll) {
|
||||||
|
if (p?.identifier) idToName.set(p.identifier, p.name || p.label || p.title || '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
const messages = working.map(m => {
|
||||||
|
const id = m.identifier || undefined;
|
||||||
|
const componentName = id ? (idToName.get(id) || undefined) : undefined;
|
||||||
|
return { role: m.role, content: m.content, identifier: id, name: componentName };
|
||||||
|
});
|
||||||
|
this.postToTarget(sourceWindow, 'assemblePromptResult', {
|
||||||
|
id: requestId,
|
||||||
|
messages: messages
|
||||||
|
}, targetOrigin);
|
||||||
|
return { messages };
|
||||||
|
}
|
||||||
|
|
||||||
// 9) 发送
|
// 9) 发送
|
||||||
return await this._sendMessages(working, { ...options, debug: { ...(options?.debug || {}), _exported: true } }, requestId, sourceWindow, targetOrigin);
|
return await this._sendMessages(working, { ...options, debug: { ...(options?.debug || {}), _exported: true } }, requestId, sourceWindow, targetOrigin);
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyOrderingStrategy(messages, baseStrategy, orderedRefs, unorderedKeys) {
|
_applyOrderingStrategy(messages, baseStrategy, orderedRefs, unorderedKeys) {
|
||||||
@@ -1340,9 +1372,9 @@ class CallGenerateService {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
_exportDebugData({ sourceWindow, requestId, working, baseStrategy, orderedRefs, inlineMapped, listLevelOverrides, debug, targetOrigin }) {
|
_exportDebugData({ sourceWindow, requestId, working, baseStrategy, orderedRefs, inlineMapped, listLevelOverrides, debug, targetOrigin }) {
|
||||||
const exportPrompt = !!(debug?.enabled || debug?.exportPrompt);
|
const exportPrompt = !!(debug?.enabled || debug?.exportPrompt);
|
||||||
if (exportPrompt) this.postToTarget(sourceWindow, 'generatePromptPreview', { id: requestId, messages: working.map(m => ({ role: m.role, content: m.content })) }, targetOrigin);
|
if (exportPrompt) this.postToTarget(sourceWindow, 'generatePromptPreview', { id: requestId, messages: working.map(m => ({ role: m.role, content: m.content })) }, targetOrigin);
|
||||||
if (debug?.exportBlueprint) {
|
if (debug?.exportBlueprint) {
|
||||||
try {
|
try {
|
||||||
const bp = {
|
const bp = {
|
||||||
@@ -1351,7 +1383,7 @@ class CallGenerateService {
|
|||||||
injections: (debug?.injections || []).concat(inlineMapped || []),
|
injections: (debug?.injections || []).concat(inlineMapped || []),
|
||||||
overrides: listLevelOverrides || null,
|
overrides: listLevelOverrides || null,
|
||||||
};
|
};
|
||||||
this.postToTarget(sourceWindow, 'blueprint', bp, targetOrigin);
|
this.postToTarget(sourceWindow, 'blueprint', bp, targetOrigin);
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1359,25 +1391,25 @@ class CallGenerateService {
|
|||||||
/**
|
/**
|
||||||
* 入口:处理 generateRequest(统一入口)
|
* 入口:处理 generateRequest(统一入口)
|
||||||
*/
|
*/
|
||||||
async handleGenerateRequest(options, requestId, sourceWindow, targetOrigin = null) {
|
async handleGenerateRequest(options, requestId, sourceWindow, targetOrigin = null) {
|
||||||
let streamingEnabled = false;
|
let streamingEnabled = false;
|
||||||
try {
|
try {
|
||||||
streamingEnabled = options?.streaming?.enabled !== false;
|
streamingEnabled = options?.streaming?.enabled !== false;
|
||||||
try {
|
try {
|
||||||
if (xbLog.isEnabled?.()) {
|
if (xbLog.isEnabled?.()) {
|
||||||
const comps = options?.components?.list;
|
const comps = options?.components?.list;
|
||||||
const compsCount = Array.isArray(comps) ? comps.length : 0;
|
const compsCount = Array.isArray(comps) ? comps.length : 0;
|
||||||
const userInputLen = String(options?.userInput || '').length;
|
const userInputLen = String(options?.userInput || '').length;
|
||||||
xbLog.info('callGenerateBridge', `generateRequest id=${requestId} stream=${!!streamingEnabled} comps=${compsCount} userInputLen=${userInputLen}`);
|
xbLog.info('callGenerateBridge', `generateRequest id=${requestId} stream=${!!streamingEnabled} comps=${compsCount} userInputLen=${userInputLen}`);
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
return await this.handleRequestInternal(options, requestId, sourceWindow, targetOrigin);
|
return await this.handleRequestInternal(options, requestId, sourceWindow, targetOrigin);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
try { xbLog.error('callGenerateBridge', `generateRequest failed id=${requestId}`, err); } catch {}
|
try { xbLog.error('callGenerateBridge', `generateRequest failed id=${requestId}`, err); } catch {}
|
||||||
this.sendError(sourceWindow, requestId, streamingEnabled, err, 'BAD_REQUEST', null, targetOrigin);
|
this.sendError(sourceWindow, requestId, streamingEnabled, err, 'BAD_REQUEST', null, targetOrigin);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 取消会话 */
|
/** 取消会话 */
|
||||||
cancel(sessionId) {
|
cancel(sessionId) {
|
||||||
@@ -1394,43 +1426,63 @@ class CallGenerateService {
|
|||||||
|
|
||||||
const callGenerateService = new CallGenerateService();
|
const callGenerateService = new CallGenerateService();
|
||||||
|
|
||||||
export async function handleGenerateRequest(options, requestId, sourceWindow, targetOrigin = null) {
|
export async function handleGenerateRequest(options, requestId, sourceWindow, targetOrigin = null) {
|
||||||
return await callGenerateService.handleGenerateRequest(options, requestId, sourceWindow, targetOrigin);
|
return await callGenerateService.handleGenerateRequest(options, requestId, sourceWindow, targetOrigin);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Host bridge for handling iframe generateRequest → respond via postMessage
|
// Host bridge for handling iframe generateRequest → respond via postMessage
|
||||||
let __xb_generate_listener_attached = false;
|
let __xb_generate_listener_attached = false;
|
||||||
let __xb_generate_listener = null;
|
let __xb_generate_listener = null;
|
||||||
|
|
||||||
export function initCallGenerateHostBridge() {
|
export function initCallGenerateHostBridge() {
|
||||||
if (typeof window === 'undefined') return;
|
if (typeof window === 'undefined') return;
|
||||||
if (__xb_generate_listener_attached) return;
|
if (__xb_generate_listener_attached) return;
|
||||||
try { xbLog.info('callGenerateBridge', 'initCallGenerateHostBridge'); } catch {}
|
try { xbLog.info('callGenerateBridge', 'initCallGenerateHostBridge'); } catch {}
|
||||||
__xb_generate_listener = async function (event) {
|
__xb_generate_listener = async function (event) {
|
||||||
try {
|
try {
|
||||||
const data = event && event.data || {};
|
const data = event && event.data || {};
|
||||||
if (!data || data.type !== 'generateRequest') return;
|
if (!data) return;
|
||||||
const id = data.id;
|
|
||||||
const options = data.options || {};
|
|
||||||
await handleGenerateRequest(options, id, event.source || window, event.origin);
|
|
||||||
} catch (e) {
|
|
||||||
try { xbLog.error('callGenerateBridge', 'generateRequest listener error', e); } catch {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// eslint-disable-next-line no-restricted-syntax -- bridge listener; origin can be null for sandboxed iframes.
|
|
||||||
try { window.addEventListener('message', __xb_generate_listener); } catch (e) {}
|
|
||||||
__xb_generate_listener_attached = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function cleanupCallGenerateHostBridge() {
|
if (data.type === 'generateRequest') {
|
||||||
if (typeof window === 'undefined') return;
|
const id = data.id;
|
||||||
if (!__xb_generate_listener_attached) return;
|
const options = data.options || {};
|
||||||
try { xbLog.info('callGenerateBridge', 'cleanupCallGenerateHostBridge'); } catch {}
|
await handleGenerateRequest(options, id, event.source || window, event.origin);
|
||||||
try { window.removeEventListener('message', __xb_generate_listener); } catch (e) {}
|
return;
|
||||||
__xb_generate_listener_attached = false;
|
}
|
||||||
__xb_generate_listener = null;
|
|
||||||
try { callGenerateService.cleanup(); } catch (e) {}
|
if (data.type === 'assemblePromptRequest') {
|
||||||
}
|
const id = data.id;
|
||||||
|
const options = data.options || {};
|
||||||
|
try {
|
||||||
|
await callGenerateService.handleRequestInternal(
|
||||||
|
options, id, event.source || window, event.origin,
|
||||||
|
{ assembleOnly: true }
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
callGenerateService.sendError(
|
||||||
|
event.source || window, id, false, err, 'ASSEMBLE_ERROR', null, event.origin
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
try { xbLog.error('callGenerateBridge', 'listener error', e); } catch {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// eslint-disable-next-line no-restricted-syntax -- bridge listener; origin can be null for sandboxed iframes.
|
||||||
|
try { window.addEventListener('message', __xb_generate_listener); } catch (e) {}
|
||||||
|
__xb_generate_listener_attached = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cleanupCallGenerateHostBridge() {
|
||||||
|
if (typeof window === 'undefined') return;
|
||||||
|
if (!__xb_generate_listener_attached) return;
|
||||||
|
try { xbLog.info('callGenerateBridge', 'cleanupCallGenerateHostBridge'); } catch {}
|
||||||
|
try { window.removeEventListener('message', __xb_generate_listener); } catch (e) {}
|
||||||
|
__xb_generate_listener_attached = false;
|
||||||
|
__xb_generate_listener = null;
|
||||||
|
try { callGenerateService.cleanup(); } catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
Object.assign(window, { xiaobaixCallGenerateService: callGenerateService, initCallGenerateHostBridge, cleanupCallGenerateHostBridge });
|
Object.assign(window, { xiaobaixCallGenerateService: callGenerateService, initCallGenerateHostBridge, cleanupCallGenerateHostBridge });
|
||||||
@@ -1514,8 +1566,8 @@ if (typeof window !== 'undefined') {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// eslint-disable-next-line no-restricted-syntax -- local listener for internal request flow.
|
// eslint-disable-next-line no-restricted-syntax -- local listener for internal request flow.
|
||||||
window.addEventListener('message', listener);
|
window.addEventListener('message', listener);
|
||||||
|
|
||||||
// 发送请求
|
// 发送请求
|
||||||
handleGenerateRequest(options, requestId, window).catch(err => {
|
handleGenerateRequest(options, requestId, window).catch(err => {
|
||||||
@@ -1525,6 +1577,49 @@ if (typeof window !== 'undefined') {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全局 assemblePrompt 函数
|
||||||
|
* 只组装提示词,不调用 LLM,返回组装好的 messages 数组
|
||||||
|
*
|
||||||
|
* @param {Object} options - 与 callGenerate 相同的选项格式(api/streaming 字段会被忽略)
|
||||||
|
* @returns {Promise<Array<{role: string, content: string}>>} 组装后的 messages 数组
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const messages = await window.LittleWhiteBox.assemblePrompt({
|
||||||
|
* components: { list: ['ALL_PREON'] },
|
||||||
|
* userInput: '可选的用户输入'
|
||||||
|
* });
|
||||||
|
* // messages = [{ role: 'system', content: '...' }, ...]
|
||||||
|
*/
|
||||||
|
window.LittleWhiteBox.assemblePrompt = async function(options) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const requestId = `assemble-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
||||||
|
|
||||||
|
const listener = (event) => {
|
||||||
|
const data = event.data;
|
||||||
|
if (!data || data.source !== SOURCE_TAG || data.id !== requestId) return;
|
||||||
|
|
||||||
|
if (data.type === 'assemblePromptResult') {
|
||||||
|
window.removeEventListener('message', listener);
|
||||||
|
resolve(data.messages);
|
||||||
|
} else if (data.type === 'generateError' || data.type === 'generateStreamError') {
|
||||||
|
window.removeEventListener('message', listener);
|
||||||
|
reject(data.error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-restricted-syntax -- local listener for internal request flow.
|
||||||
|
window.addEventListener('message', listener);
|
||||||
|
|
||||||
|
callGenerateService.handleRequestInternal(
|
||||||
|
options, requestId, window, null, { assembleOnly: true }
|
||||||
|
).catch(err => {
|
||||||
|
window.removeEventListener('message', listener);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取消指定会话
|
* 取消指定会话
|
||||||
* @param {string} sessionId - 会话 ID(如 'xb1', 'xb2' 等)
|
* @param {string} sessionId - 会话 ID(如 'xb1', 'xb2' 等)
|
||||||
@@ -1547,4 +1642,4 @@ if (typeof window !== 'undefined') {
|
|||||||
init: initCallGenerateHostBridge,
|
init: initCallGenerateHostBridge,
|
||||||
cleanup: cleanupCallGenerateHostBridge
|
cleanup: cleanupCallGenerateHostBridge
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user