From e06b44179c0c45b7001a5c1d324fe17b253ef231 Mon Sep 17 00:00:00 2001 From: viettranx Date: Sat, 7 Mar 2026 23:48:41 +0700 Subject: [PATCH] fix(ui): sync toolStreamRef on tool.result to prevent stale overwrite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tool.result updated React state via functional update but didn't sync toolStreamRef.current. When the next tool.call arrived and set state to toolStreamRef.current (direct value), it overwrote completed statuses with stale "calling" phase — causing tool cards to stay stuck at "Running..." forever. --- .../src/pages/chat/hooks/use-chat-messages.ts | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/ui/web/src/pages/chat/hooks/use-chat-messages.ts b/ui/web/src/pages/chat/hooks/use-chat-messages.ts index cd3ba07b..c3d76f67 100644 --- a/ui/web/src/pages/chat/hooks/use-chat-messages.ts +++ b/ui/web/src/pages/chat/hooks/use-chat-messages.ts @@ -144,18 +144,20 @@ export function useChatMessages(sessionKey: string, agentId: string) { } case "tool.result": { const isError = event.payload?.is_error; - setToolStream((prev) => - prev.map((t) => - t.toolCallId === event.payload?.id - ? { - ...t, - phase: isError ? "error" : "completed", - errorContent: isError ? event.payload?.content : undefined, - updatedAt: Date.now(), - } - : t, - ), + const resultId = event.payload?.id; + const now = Date.now(); + // Update ref first so subsequent tool.call events don't overwrite with stale data. + toolStreamRef.current = toolStreamRef.current.map((t) => + t.toolCallId === resultId + ? { + ...t, + phase: isError ? ("error" as const) : ("completed" as const), + errorContent: isError ? event.payload?.content : undefined, + updatedAt: now, + } + : t, ); + setToolStream(toolStreamRef.current); break; } case "run.completed": {