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 (