@@ -6,11 +6,17 @@
// 2) 关闭隐藏 = 暴力全量 unhide, 确保立刻恢复
// 3) 开启隐藏 / 改Y / 切Chat / 收新消息:先全量 unhide, 再按边界重新 hide
// 4) Prompt 注入位置稳定:永远插在"最后一条 user 消息"之前
// 5) 注入不依赖 extension_prompts/depth, 不受 ST 裁剪/隐藏参照系影响
// 5) 注入回归 extension_prompts + IN_CHAT + depth( 动态计算)
// ═══════════════════════════════════════════════════════════════════════════
import { getContext } from "../../../../../extensions.js" ;
import { eventSource , event _types } from "../../../../../../script.js" ;
import {
eventSource ,
event _types ,
extension _prompts ,
extension _prompt _types ,
extension _prompt _roles ,
} from "../../../../../../script.js" ;
import { extensionFolderPath } from "../../core/constants.js" ;
import { xbLog , CacheRegistry } from "../../core/debug-core.js" ;
import { postToIframe , isTrustedMessage } from "../../core/iframe-messaging.js" ;
@@ -95,8 +101,6 @@ let vectorGenerating = false;
let vectorCancelled = false ;
let vectorAbortController = null ;
let pendingInjectText = "" ;
// ★ 用户消息缓存(解决 GENERATION_STARTED 时 chat 尚未包含用户消息的问题)
let lastSentUserMessage = null ;
let lastSentTimestamp = 0 ;
@@ -106,6 +110,8 @@ const HIDE_APPLY_DEBOUNCE_MS = 250;
const sleep = ( ms ) => new Promise ( ( r ) => setTimeout ( r , ms ) ) ;
const EXT _PROMPT _KEY = "LittleWhiteBox_StorySummary" ;
// ═══════════════════════════════════════════════════════════════════════════
// 工具:执行斜杠命令
// ═══════════════════════════════════════════════════════════════════════════
@@ -1110,6 +1116,10 @@ function handleMessageSentForRecall() {
}
}
function clearExtensionPrompt ( ) {
delete extension _prompts [ EXT _PROMPT _KEY ] ;
}
// ═══════════════════════════════════════════════════════════════════════════
// Prompt 注入
// ═══════════════════════════════════════════════════════════════════════════
@@ -1121,9 +1131,9 @@ async function handleGenerationStarted(type, _params, isDryRun) {
const excludeLastAi = type === "swipe" || type === "regenerate" ;
const vectorCfg = getVectorConfig ( ) ;
pendingInjectText = "" ;
clearExtensionPrompt ( ) ;
// ★ 判断是否使用缓存的用户消息( 30秒内有效)
// ★ 保留: 判断是否使用缓存的用户消息( 30秒内有效)
let pendingUserMessage = null ;
if ( type === "normal" && lastSentUserMessage && ( Date . now ( ) - lastSentTimestamp < 30000 ) ) {
pendingUserMessage = lastSentUserMessage ;
@@ -1132,51 +1142,50 @@ async function handleGenerationStarted(type, _params, isDryRun) {
lastSentUserMessage = null ;
lastSentTimestamp = 0 ;
const { chat , chatId } = getContext ( ) ;
const chatLen = Array . isArray ( chat ) ? chat . length : 0 ;
if ( chatLen === 0 ) return ;
const store = getSummaryStore ( ) ;
// 1) boundary:
// - 向量开: meta.lastChunkFloor( 若无则回退 lastSummarizedMesId)
// - 向量关: lastSummarizedMesId
let boundary = - 1 ;
if ( vectorCfg ? . enabled ) {
const meta = chatId ? await getMeta ( chatId ) : null ;
boundary = meta ? . lastChunkFloor ? ? - 1 ;
if ( boundary < 0 ) boundary = store ? . lastSummarizedMesId ? ? - 1 ;
} else {
boundary = store ? . lastSummarizedMesId ? ? - 1 ;
}
if ( boundary < 0 ) return ;
// 2) depth: 倒序插入, 从末尾往前数
const depth = chatLen - boundary - 1 ;
if ( depth < 0 ) return ;
// 3) 构建注入文本(保持原逻辑)
let text = "" ;
if ( vectorCfg ? . enabled ) {
const r = await buildVectorPromptText ( excludeLastAi , {
postToFrame ,
echo : executeSlashCommand ,
pendingUserMessage ,
} ) ;
pendingInjectT ext = r ? . text || "" ;
return ;
t ext = r ? . text || "" ;
} else {
text = buildNonVectorPromptText ( ) || "" ;
}
if ( ! text . trim ( ) ) return ;
pendingInjectText = buildNonVectorPromptText ( ) || "" ;
}
function clearPendingInject ( ) {
pendingInjectText = "" ;
}
function findInsertIndexBeforeLastUserMessage ( chat ) {
if ( ! Array . isArray ( chat ) || ! chat . length ) return 0 ;
for ( let i = chat . length - 1 ; i >= 0 ; i -- ) {
if ( chat [ i ] ? . role === "user" ) return i ;
}
// 没有 user, 退化为末尾前一位
return Math . max ( 0 , chat . length - 1 ) ;
}
function handleChatCompletionPromptReady ( eventData ) {
try {
if ( ! pendingInjectText ? . trim ( ) ) return ;
if ( ! eventData || eventData . dryRun ) return ;
if ( ! Array . isArray ( eventData . chat ) ) return ;
// 永远插在最后一条 user 消息之前,保证三段结构稳定
const insertAt = findInsertIndexBeforeLastUserMessage ( eventData . chat ) ;
eventData . chat . splice ( insertAt , 0 , {
role : "assistant" ,
content : pendingInjectText ,
} ) ;
clearPendingInject ( ) ;
} catch ( e ) {
xbLog . error ( MODULE _ID , "Prompt inject failed" , e ) ;
clearPendingInject ( ) ;
}
// 4) 写入 extension_prompts
extension _prompts [ EXT _PROMPT _KEY ] = {
value : text ,
position : extension _prompt _types . IN _CHAT ,
depth ,
role : extension _prompt _roles . SYSTEM ,
} ;
}
// ═══════════════════════════════════════════════════════════════════════════
@@ -1218,9 +1227,8 @@ function registerEvents() {
// 注入链路
eventSource . on ( event _types . GENERATION _STARTED , handleGenerationStarted ) ;
eventSource . on ( event _types . GENERATION _STOPPED , clearPendingInjec t ) ;
eventSource . on ( event _types . GENERATION _ENDED , clearPendingInjec t ) ;
eventSource . on ( event _types . CHAT _COMPLETION _PROMPT _READY , handleChatCompletionPromptReady ) ;
eventSource . on ( event _types . GENERATION _STOPPED , clearExtensionPromp t ) ;
eventSource . on ( event _types . GENERATION _ENDED , clearExtensionPromp t ) ;
}
function unregisterEvents ( ) {
@@ -1230,7 +1238,7 @@ function unregisterEvents() {
$ ( ".xiaobaix-story-summary-btn" ) . remove ( ) ;
hideOverlay ( ) ;
clearPendingInjec t ( ) ;
clearExtensionPromp t ( ) ;
}
// ═══════════════════════════════════════════════════════════════════════════