From 04985dab2315eaaae720ecc58f853a67d0e3f057 Mon Sep 17 00:00:00 2001 From: Jaewon Hwang Date: Fri, 13 Feb 2026 09:50:42 +0900 Subject: [PATCH] fix: enable auto-scroll during assistant response streaming Fix auto-scroll behavior when AI assistant streams responses in the web UI. Previously, the viewport would remain at the sent message position and users had to manually click a badge to see streaming responses. Fixes #14959 Changes: - Reset chat scroll state before sending message to ensure viewport readiness - Force scroll to bottom after message send to position viewport correctly - Detect streaming start (chatStream: null -> string) and trigger auto-scroll - Ensure smooth scroll-following during entire streaming response Co-Authored-By: Claude Opus 4.6 --- ui/src/ui/app-chat.ts | 7 +++++-- ui/src/ui/app-lifecycle.ts | 8 +++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ui/src/ui/app-chat.ts b/ui/src/ui/app-chat.ts index ec5f7300000..dc8eaf39be6 100644 --- a/ui/src/ui/app-chat.ts +++ b/ui/src/ui/app-chat.ts @@ -1,5 +1,5 @@ import { parseAgentSessionKey } from "../../../src/sessions/session-key-utils.js"; -import { scheduleChatScroll } from "./app-scroll.ts"; +import { scheduleChatScroll, resetChatScroll } from "./app-scroll.ts"; import { setLastActiveSessionKey } from "./app-settings.ts"; import { resetToolStream } from "./app-tool-stream.ts"; import type { OpenClawApp } from "./app.ts"; @@ -121,6 +121,8 @@ async function sendChatMessageNow( }, ) { resetToolStream(host as unknown as Parameters[0]); + // Reset scroll state before sending to ensure auto-scroll works for the response + resetChatScroll(host as unknown as Parameters[0]); const runId = await sendChatMessage(host as unknown as OpenClawApp, message, opts?.attachments); const ok = Boolean(runId); if (!ok && opts?.previousDraft != null) { @@ -141,7 +143,8 @@ async function sendChatMessageNow( if (ok && opts?.restoreAttachments && opts.previousAttachments?.length) { host.chatAttachments = opts.previousAttachments; } - scheduleChatScroll(host as unknown as Parameters[0]); + // Force scroll after sending to ensure viewport is at bottom for incoming stream + scheduleChatScroll(host as unknown as Parameters[0], true); if (ok && !host.chatRunId) { void flushChatQueue(host); } diff --git a/ui/src/ui/app-lifecycle.ts b/ui/src/ui/app-lifecycle.ts index 28fb5271ecc..66c3b54e77b 100644 --- a/ui/src/ui/app-lifecycle.ts +++ b/ui/src/ui/app-lifecycle.ts @@ -99,9 +99,15 @@ export function handleUpdated(host: LifecycleHost, changed: Map[0], - forcedByTab || forcedByLoad || !host.chatHasAutoScrolled, + forcedByTab || forcedByLoad || streamJustStarted || !host.chatHasAutoScrolled, ); } if (