From 72565b322009629b27cbae0e967fa83e064bf8f1 Mon Sep 17 00:00:00 2001 From: thzxx Date: Wed, 22 Apr 2026 09:40:38 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=BD=BB=E5=BA=95=E4=BF=AE=E5=A4=8D=20T?= =?UTF-8?q?DZ=20=E9=94=99=E8=AF=AF=E5=92=8C=E7=94=A8=E6=88=B7=E6=B6=88?= =?UTF-8?q?=E6=81=AF=E4=B8=8D=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 的旧节点 --- src/renderer/components/chat-area.ts | 7 +++++++ src/renderer/components/input-area.ts | 8 +++++--- src/renderer/services/agent-engine.ts | 10 ++++++---- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/renderer/components/chat-area.ts b/src/renderer/components/chat-area.ts index 222458d..f4b8ca9 100644 --- a/src/renderer/components/chat-area.ts +++ b/src/renderer/components/chat-area.ts @@ -495,6 +495,13 @@ export function clearMessages(): void { currentPlaceholder = null; } +/** 清理 currentPlaceholder 引用(当 placeholder 从外部被移除时调用) */ +export function resetCurrentPlaceholder(): void { + if (currentPlaceholder && !currentPlaceholder.isConnected) { + currentPlaceholder = null; + } +} + export function enableAutoScroll(): void { autoScroll = true; if (scrollBtnEl) scrollBtnEl.style.display = 'none'; diff --git a/src/renderer/components/input-area.ts b/src/renderer/components/input-area.ts index 4e17b87..ccb4364 100644 --- a/src/renderer/components/input-area.ts +++ b/src/renderer/components/input-area.ts @@ -9,7 +9,7 @@ import { getSelectedModel, isThinkEnabled, isVisionAvailable, isToolCallingSuppo import { renderMessages, clearMessagesDOM, appendAssistantPlaceholder, appendSystemMessage, updateLastAssistantMessage, clearMessages, safeMarkdown, enableAutoScroll, updateTotalTokens, - appendToolCallCardToPlaceholder, updateToolCallCardInPlaceholder + appendToolCallCardToPlaceholder, updateToolCallCardInPlaceholder, resetCurrentPlaceholder } from './chat-area.js'; import { showToast } from './toast.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.querySelector('.loading-dots')?.remove(); placeholder.querySelector('.loading-text')?.remove(); - if (!assistantContent) placeholder.remove(); - else { + if (!assistantContent) { + placeholder.remove(); + resetCurrentPlaceholder(); + } else { const contentDiv = placeholder.querySelector('.msg-content'); if (contentDiv) contentDiv.innerHTML = safeMarkdown(assistantContent) + '

[已中断]

'; } diff --git a/src/renderer/services/agent-engine.ts b/src/renderer/services/agent-engine.ts index 9eee54d..6e2066f 100644 --- a/src/renderer/services/agent-engine.ts +++ b/src/renderer/services/agent-engine.ts @@ -513,8 +513,8 @@ export async function runAgentLoop( let totalEvalCount = 0; /** 跨轮去重:仅跟踪成功的工具调用(失败的允许重试) */ let prevLoopSuccessKeys: string[] = []; - /** 每轮工具调用计数(用于去重) */ - let allCallsThisLoop: ToolCall[] = []; + /** 保存上一轮的工具调用,供 onNewIteration 使用 */ + let prevToolCalls: ToolCall[] = []; const makeStats = () => { const totalDuration = (Date.now() - loopStartTime) * 1e6; @@ -535,7 +535,7 @@ export async function runAgentLoop( // 非首轮迭代:通知 UI 创建新的消息气泡(防止每轮内容互相覆盖) if (loopCount > 1 && callbacks.onNewIteration) { - callbacks.onNewIteration(toolCalls.length > 0 ? toolCalls : undefined); + callbacks.onNewIteration(prevToolCalls.length > 0 ? prevToolCalls : undefined); } logAgentLoop(loopCount, maxLoops); @@ -543,7 +543,6 @@ export async function runAgentLoop( let thinking = ''; content = ''; const toolCalls: ToolCall[] = []; - allCallsThisLoop = []; // v5.1.2 预算警告:接近迭代上限时注入临时提示 let budgetWarningIdx = -1; @@ -873,6 +872,9 @@ export async function runAgentLoop( `${r.name}: ${r.result?.success ? 'success' : 'error'}` ).join('; '); saveTrace(traceStep); + + // 保存本轮工具调用,供下一轮 onNewIteration 使用 + prevToolCalls = toolCalls; } logWarn('ReAct Agent Loop 达到最大工具调用次数限制');