From c60ee2b4aeb73f469ad6d809fa9433c33ed43104 Mon Sep 17 00:00:00 2001 From: thzxx Date: Sun, 19 Apr 2026 17:19:45 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=9B=B4=E6=92=AD=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E6=97=B6=E5=AE=9E=E6=97=B6=E6=B8=B2=E6=9F=93=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E8=B0=83=E7=94=A8=E5=8D=A1=E7=89=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 appendToolCallCardToPlaceholder: 工具开始执行时显示 running 卡片 - 新增 updateToolCallCardInPlaceholder: 工具完成后更新为 success/error 卡片 - 修复 onToolCallStart/onToolCallResult/onToolCallError 空回调问题 - 修复历史记录有工具卡片但直播聊天没有的不一致问题 --- src/renderer/components/chat-area.ts | 37 +++++++++++++++++++++++++++ src/renderer/components/input-area.ts | 24 ++++++++++++----- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/renderer/components/chat-area.ts b/src/renderer/components/chat-area.ts index e746b1c..394a783 100644 --- a/src/renderer/components/chat-area.ts +++ b/src/renderer/components/chat-area.ts @@ -400,6 +400,43 @@ export function updateLastAssistantMessage(content: string, think: string | null scrollToBottom(); } +/** 实时追加工具调用卡片到当前 placeholder(直播聊天时使用) */ +export function appendToolCallCardToPlaceholder(tc: ToolCallRecord): void { + if (!currentPlaceholder) return; + let container = currentPlaceholder.querySelector('.tool-calls-container'); + if (!container) { + container = document.createElement('div'); + container.className = 'tool-calls-container'; + const msgBody = currentPlaceholder.querySelector('.msg-body'); + if (msgBody) msgBody.appendChild(container); + } + const cardDiv = document.createElement('div'); + cardDiv.innerHTML = renderToolCallCard(tc); + const card = cardDiv.firstElementChild as HTMLElement; + card.dataset.toolName = tc.name; + container.appendChild(card); + scrollToBottom(); +} + +/** 更新 placeholder 中已有的工具卡片状态(running → success/error) */ +export function updateToolCallCardInPlaceholder(tc: ToolCallRecord): void { + if (!currentPlaceholder) return; + const container = currentPlaceholder.querySelector('.tool-calls-container'); + if (!container) return; + // 找到第一个同名且状态为 running 的卡片 + const existing = container.querySelector(`.tool-call-card[data-tool-name="${tc.name}"].tool-call-running`) as HTMLElement; + if (existing) { + const cardDiv = document.createElement('div'); + cardDiv.innerHTML = renderToolCallCard(tc); + const newCard = cardDiv.firstElementChild as HTMLElement; + newCard.dataset.toolName = tc.name; + existing.replaceWith(newCard); + } else { + // 没找到 running 的卡片,直接追加 + appendToolCallCardToPlaceholder(tc); + } +} + export function appendAssistantPlaceholder(): void { const div = document.createElement('div'); div.className = 'message assistant loading'; diff --git a/src/renderer/components/input-area.ts b/src/renderer/components/input-area.ts index 8142ca2..d0cbc60 100644 --- a/src/renderer/components/input-area.ts +++ b/src/renderer/components/input-area.ts @@ -7,7 +7,8 @@ import { detectLanguage, truncate, escapeHtml, formatSize } from '../utils/utils import { getSelectedModel, isThinkEnabled, isVisionAvailable, isToolCallingSupported } from './model-bar.js'; import { renderMessages, clearMessagesDOM, appendAssistantPlaceholder, appendSystemMessage, - updateLastAssistantMessage, clearMessages, safeMarkdown, enableAutoScroll, updateTotalTokens + updateLastAssistantMessage, clearMessages, safeMarkdown, enableAutoScroll, updateTotalTokens, + appendToolCallCardToPlaceholder, updateToolCallCardInPlaceholder } from './chat-area.js'; import { showToast } from './toast.js'; import { ChatDB } from '../db/chat-db.js'; @@ -872,14 +873,23 @@ async function sendMessageWithAgentLoop(text: string, currentSession: ChatSessio assistantContent = content; updateLastAssistantMessage(assistantContent, thinkContent || null, null); }, - onToolCallStart: (_call) => { - // 实时更新已由 agent-engine 的 callbacks 处理 + onToolCallStart: (call) => { + appendToolCallCardToPlaceholder({ + name: call.function.name, arguments: call.function.arguments, + result: null, status: 'running', timestamp: Date.now() + }); }, - onToolCallResult: (_name, _result, _call) => { - // 工具结果实时更新 + onToolCallResult: (name, result, call) => { + updateToolCallCardInPlaceholder({ + name, arguments: call.function.arguments, + result, status: result.success ? 'success' : 'error', timestamp: Date.now() + }); }, - onToolCallError: (_name, _error, _call) => { - // 工具错误实时更新 + onToolCallError: (name, error, call) => { + updateToolCallCardInPlaceholder({ + name, arguments: call.function.arguments, + result: { success: false, error }, status: 'error', timestamp: Date.now() + }); }, onConfirmTool: async (call) => { return showToolConfirm(call);