From a4e80371085fe95411550c4d888c43cc42ed900d Mon Sep 17 00:00:00 2001 From: kurihada Date: Tue, 16 Dec 2025 23:50:18 +0800 Subject: [PATCH] =?UTF-8?q?fix(core):=20=E4=BF=AE=E5=A4=8D=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E8=B0=83=E7=94=A8=E9=87=8D=E5=A4=8D=E8=A7=A6=E5=8F=91?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E5=89=8D=E7=AB=AF=E6=98=BE=E7=A4=BA=E4=B8=A4?= =?UTF-8?q?=E6=AC=A1=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题原因: - onToolStart 同时传给了 toVercelTools 和 streamChat 两处 - 导致工具开始事件在 onChunk 和 executeTool 中各触发一次 - 两处生成的 toolCallId 不同,前端去重逻辑无法生效 修复方案: - 移除传给 toVercelTools 的 onToolStart,只保留 streamChat 中的触发 - 在 handleToolCallChunk 中增加 toolCallId 去重检查(防止 AI SDK 发送重复 chunk) --- packages/core/src/core/agent-message-handler.ts | 7 ++++++- packages/core/src/core/agent.ts | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/core/src/core/agent-message-handler.ts b/packages/core/src/core/agent-message-handler.ts index 4647b71..b8d04f5 100644 --- a/packages/core/src/core/agent-message-handler.ts +++ b/packages/core/src/core/agent-message-handler.ts @@ -225,6 +225,11 @@ export class AgentMessageHandler { ): void { const toolCallId = chunk.toolCallId || `tool-${Date.now()}`; + // 去重:如果该工具调用已经被处理过,跳过 + if (toolStartTimes.has(toolCallId)) { + return; + } + // Doom Loop 检测 this.doomLoopDetector.record(chunk.toolName, chunk.input); @@ -236,7 +241,7 @@ export class AgentMessageHandler { onStream?.(DOOM_LOOP_WARNING); } - // 记录开始时间 + // 记录开始时间(同时作为去重标记) toolStartTimes.set(toolCallId, Date.now()); // 调用回调 diff --git a/packages/core/src/core/agent.ts b/packages/core/src/core/agent.ts index b899516..3c8b1ae 100644 --- a/packages/core/src/core/agent.ts +++ b/packages/core/src/core/agent.ts @@ -193,10 +193,11 @@ export class Agent { this.toolExecutor.setAgentMode(this.modeManager.getCurrentMode()); // 获取工具 + // 注意:不传 onToolStart 给 toVercelTools,因为 streamChat 的 onChunk 已经会触发 + // 如果同时传给两处,会导致前端收到两次 tool_start 事件 const vercelTools = this.toolExecutor.toVercelTools({ sessionId: this.sessionManager?.getSession()?.id || 'default', agentMode: this.modeManager.getCurrentMode(), - onToolStart, onToolEnd, });