fix: 彻底修复 TDZ 错误和用户消息不显示问题

1. agent-engine.ts: onNewIteration 改用 prevToolCalls 传递上一轮工具调用,
   避免引用未声明的 toolCalls 导致 TDZ (Cannot access 'B' before initialization)
2. chat-area.ts: 新增 resetCurrentPlaceholder() 清理悬空 DOM 引用
3. input-area.ts: 错误处理器删除 placeholder 后清理 currentPlaceholder 引用,
   防止后续 updateLastAssistantMessage 操作已脱离 DOM 的旧节点
This commit is contained in:
thzxx
2026-04-22 09:40:38 +08:00
parent 9915b71da1
commit 72565b3220
3 changed files with 18 additions and 7 deletions
+7
View File
@@ -495,6 +495,13 @@ export function clearMessages(): void {
currentPlaceholder = null; currentPlaceholder = null;
} }
/** 清理 currentPlaceholder 引用(当 placeholder 从外部被移除时调用) */
export function resetCurrentPlaceholder(): void {
if (currentPlaceholder && !currentPlaceholder.isConnected) {
currentPlaceholder = null;
}
}
export function enableAutoScroll(): void { export function enableAutoScroll(): void {
autoScroll = true; autoScroll = true;
if (scrollBtnEl) scrollBtnEl.style.display = 'none'; if (scrollBtnEl) scrollBtnEl.style.display = 'none';
+5 -3
View File
@@ -9,7 +9,7 @@ import { getSelectedModel, isThinkEnabled, isVisionAvailable, isToolCallingSuppo
import { import {
renderMessages, clearMessagesDOM, appendAssistantPlaceholder, appendSystemMessage, renderMessages, clearMessagesDOM, appendAssistantPlaceholder, appendSystemMessage,
updateLastAssistantMessage, clearMessages, safeMarkdown, enableAutoScroll, updateTotalTokens, updateLastAssistantMessage, clearMessages, safeMarkdown, enableAutoScroll, updateTotalTokens,
appendToolCallCardToPlaceholder, updateToolCallCardInPlaceholder appendToolCallCardToPlaceholder, updateToolCallCardInPlaceholder, resetCurrentPlaceholder
} from './chat-area.js'; } from './chat-area.js';
import { showToast } from './toast.js'; import { showToast } from './toast.js';
import { addToolCard, updateToolCard, clearToolCardsExternal, clearTerminalExternal } from './workspace-panel.js'; import { addToolCard, updateToolCard, clearToolCardsExternal, clearTerminalExternal } from './workspace-panel.js';
@@ -1109,8 +1109,10 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio
placeholder.classList.remove('loading'); placeholder.classList.remove('loading');
placeholder.querySelector('.loading-dots')?.remove(); placeholder.querySelector('.loading-dots')?.remove();
placeholder.querySelector('.loading-text')?.remove(); placeholder.querySelector('.loading-text')?.remove();
if (!assistantContent) placeholder.remove(); if (!assistantContent) {
else { placeholder.remove();
resetCurrentPlaceholder();
} else {
const contentDiv = placeholder.querySelector('.msg-content'); const contentDiv = placeholder.querySelector('.msg-content');
if (contentDiv) contentDiv.innerHTML = safeMarkdown(assistantContent) + '<p><code>[已中断]</code></p>'; if (contentDiv) contentDiv.innerHTML = safeMarkdown(assistantContent) + '<p><code>[已中断]</code></p>';
} }
+6 -4
View File
@@ -513,8 +513,8 @@ export async function runAgentLoop(
let totalEvalCount = 0; let totalEvalCount = 0;
/** 跨轮去重:仅跟踪成功的工具调用(失败的允许重试) */ /** 跨轮去重:仅跟踪成功的工具调用(失败的允许重试) */
let prevLoopSuccessKeys: string[] = []; let prevLoopSuccessKeys: string[] = [];
/** 每轮工具调用计数(用于去重) */ /** 保存上一轮的工具调用,供 onNewIteration 使用 */
let allCallsThisLoop: ToolCall[] = []; let prevToolCalls: ToolCall[] = [];
const makeStats = () => { const makeStats = () => {
const totalDuration = (Date.now() - loopStartTime) * 1e6; const totalDuration = (Date.now() - loopStartTime) * 1e6;
@@ -535,7 +535,7 @@ export async function runAgentLoop(
// 非首轮迭代:通知 UI 创建新的消息气泡(防止每轮内容互相覆盖) // 非首轮迭代:通知 UI 创建新的消息气泡(防止每轮内容互相覆盖)
if (loopCount > 1 && callbacks.onNewIteration) { if (loopCount > 1 && callbacks.onNewIteration) {
callbacks.onNewIteration(toolCalls.length > 0 ? toolCalls : undefined); callbacks.onNewIteration(prevToolCalls.length > 0 ? prevToolCalls : undefined);
} }
logAgentLoop(loopCount, maxLoops); logAgentLoop(loopCount, maxLoops);
@@ -543,7 +543,6 @@ export async function runAgentLoop(
let thinking = ''; let thinking = '';
content = ''; content = '';
const toolCalls: ToolCall[] = []; const toolCalls: ToolCall[] = [];
allCallsThisLoop = [];
// v5.1.2 预算警告:接近迭代上限时注入临时提示 // v5.1.2 预算警告:接近迭代上限时注入临时提示
let budgetWarningIdx = -1; let budgetWarningIdx = -1;
@@ -873,6 +872,9 @@ export async function runAgentLoop(
`${r.name}: ${r.result?.success ? 'success' : 'error'}` `${r.name}: ${r.result?.success ? 'success' : 'error'}`
).join('; '); ).join('; ');
saveTrace(traceStep); saveTrace(traceStep);
// 保存本轮工具调用,供下一轮 onNewIteration 使用
prevToolCalls = toolCalls;
} }
logWarn('ReAct Agent Loop 达到最大工具调用次数限制'); logWarn('ReAct Agent Loop 达到最大工具调用次数限制');