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 达到最大工具调用次数限制');