diff --git a/modules/ena-planner/ena-planner.css b/modules/ena-planner/ena-planner.css index e819880..52dec9c 100644 --- a/modules/ena-planner/ena-planner.css +++ b/modules/ena-planner/ena-planner.css @@ -618,6 +618,50 @@ textarea.input { font-size: .8125rem; } +/* Message cards inside log */ +.msg-list { + display: flex; + flex-direction: column; + gap: 8px; + margin-top: 8px; +} + +.msg-card { + border-radius: var(--radius); + border-left: 3px solid var(--bdr); + background: var(--code-bg); + padding: 8px 12px; +} + +.msg-card.msg-system { border-left-color: #6b8afd; } +.msg-card.msg-user { border-left-color: #4ecdc4; } +.msg-card.msg-assistant { border-left-color: #f7a046; } + +.msg-role { + font-size: .6875rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: .04em; + margin-bottom: 4px; + color: var(--txt3); +} + +.msg-system .msg-role { color: #6b8afd; } +.msg-user .msg-role { color: #4ecdc4; } +.msg-assistant .msg-role { color: #f7a046; } + +.msg-content { + font-family: 'SF Mono', Monaco, Consolas, 'Liberation Mono', monospace; + font-size: .6875rem; + line-height: 1.6; + white-space: pre-wrap; + word-break: break-word; + color: var(--code-txt); + margin: 0; + max-height: 300px; + overflow-y: auto; +} + details { margin-bottom: 6px; } @@ -841,4 +885,4 @@ details summary:hover { details summary { padding: 8px 0; } -} \ No newline at end of file +} diff --git a/modules/ena-planner/ena-planner.html b/modules/ena-planner/ena-planner.html index e27e2e8..12e9f4b 100644 --- a/modules/ena-planner/ena-planner.html +++ b/modules/ena-planner/ena-planner.html @@ -636,6 +636,23 @@ const time = item.time ? new Date(item.time).toLocaleString() : '-'; const cls = item.ok ? 'success' : 'error'; const label = item.ok ? '成功' : '失败'; + + // Format request messages: one card per message with role label + let msgHtml = ''; + if (Array.isArray(item.requestMessages) && item.requestMessages.length) { + msgHtml = item.requestMessages.map((m, i) => { + const role = escapeHtml(m.role || 'unknown'); + const roleClass = role === 'system' ? 'msg-system' : role === 'user' ? 'msg-user' : 'msg-assistant'; + const content = escapeHtml(m.content || ''); + return `
+
[${i + 1}] ${role}
+
${content}
+
`; + }).join(''); + } else { + msgHtml = '
无消息
'; + } + return `
@@ -643,8 +660,8 @@ ${escapeHtml(item.model || '-')}
${item.error ? `
${escapeHtml(item.error)}
` : ''} -
请求消息 -
${escapeHtml(JSON.stringify(item.requestMessages || [], null, 2))}
+
请求消息 (${(item.requestMessages || []).length} 条) +
${msgHtml}
原始回复
${escapeHtml(item.rawReply || '')}
diff --git a/modules/ena-planner/ena-planner.js b/modules/ena-planner/ena-planner.js index 590521e..db12f4f 100644 --- a/modules/ena-planner/ena-planner.js +++ b/modules/ena-planner/ena-planner.js @@ -7,6 +7,7 @@ import { extensionFolderPath } from '../../core/constants.js'; import { EnaPlannerStorage } from '../../core/server-storage.js'; import { postToIframe, isTrustedIframeEvent } from '../../core/iframe-messaging.js'; import { DEFAULT_PROMPT_BLOCKS, BUILTIN_TEMPLATES } from './ena-planner-presets.js'; +import { formatOutlinePrompt } from '../story-outline/story-outline.js'; const EXT_NAME = 'ena-planner'; const OVERLAY_ID = 'xiaobaix-ena-planner-overlay'; @@ -307,7 +308,8 @@ function formatCharCardBlock(charObj) { function cleanAiMessageText(text) { let out = String(text ?? ''); - // 1) Strip properly wrapped / blocks only. + // 1) Strip everything before and including (handles unclosed think blocks) + out = out.replace(/^[\s\S]*?<\/think>/i, ''); out = out.replace(/]*>[\s\S]*?<\/think>/gi, ''); out = out.replace(/]*>[\s\S]*?<\/thinking>/gi, ''); @@ -1134,6 +1136,7 @@ async function buildPlannerMessages(rawUserInput) { const scanText = [charBlockRaw, cachedSummary, recentChatRaw, vectorRaw, plotsRaw, rawUserInput].join('\n\n'); const worldbookRaw = await buildWorldbookBlock(scanText); + const outlineRaw = typeof formatOutlinePrompt === 'function' ? (formatOutlinePrompt() || '') : ''; // Render templates/macros const charBlock = await renderTemplateAll(charBlockRaw, env, messageVars); @@ -1143,6 +1146,7 @@ async function buildPlannerMessages(rawUserInput) { const storySummary = cachedSummary.trim().length > 30 ? await renderTemplateAll(cachedSummary, env, messageVars) : ''; const worldbook = await renderTemplateAll(worldbookRaw, env, messageVars); const userInput = await renderTemplateAll(rawUserInput, env, messageVars); + const storyOutline = outlineRaw.trim().length > 10 ? await renderTemplateAll(outlineRaw, env, messageVars) : ''; const messages = []; @@ -1158,6 +1162,11 @@ async function buildPlannerMessages(rawUserInput) { // 3) Worldbook if (String(worldbook).trim()) messages.push({ role: 'system', content: worldbook }); + // 3.5) Story Outline / 剧情地图(小白板世界架构) + if (storyOutline.trim()) { + messages.push({ role: 'system', content: `\n${storyOutline}\n` }); + } + // 4) Chat history (last 2 AI responses — floors N-1 & N-3) if (String(recentChat).trim()) messages.push({ role: 'system', content: recentChat }); diff --git a/modules/story-outline/story-outline.js b/modules/story-outline/story-outline.js index aa01a92..3a0a08c 100644 --- a/modules/story-outline/story-outline.js +++ b/modules/story-outline/story-outline.js @@ -1395,4 +1395,4 @@ jQuery(() => { window.registerModuleCleanup?.('storyOutline', cleanup); }); -export { cleanup }; +export { cleanup, formatOutlinePrompt };