From 6591b04a569a6707e0d3cdb5ea3d2310b93a9070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Fri, 4 Sep 2026 15:28:40 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=BA=AF=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E6=B5=81=E5=BC=8F=E5=9B=9E=E5=A4=8D=E6=BB=9A=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 恢复 standalone supervisor 聊天的流式消息自动跟随 保留用户上移后的滚动位置 统一使用底部阈值判断是否继续跟随 --- .../SupervisorChatOnlyView.tsx | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/SupervisorChatOnlyView.tsx b/apps/ai-game-creator-shell/src/features/project-workspace/SupervisorChatOnlyView.tsx index 1153ddf33..f5b59ab38 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/SupervisorChatOnlyView.tsx +++ b/apps/ai-game-creator-shell/src/features/project-workspace/SupervisorChatOnlyView.tsx @@ -5,8 +5,10 @@ import type { FormEventHandler, RefObject, SetStateAction, + UIEvent, UIEventHandler, } from 'react'; +import { useLayoutEffect, useRef } from 'react'; import type { AgentRuntimeState, @@ -33,6 +35,8 @@ type RuntimeControlProps = ComponentProps< typeof ProjectSupervisorRuntimeControls >; +const CHAT_SCROLL_BOTTOM_THRESHOLD = 24; + type SupervisorChatOnlyViewProps = { chatAgentBusy: boolean; chatInput: string; @@ -95,6 +99,7 @@ export function SupervisorChatOnlyView({ visibleMessages, workspaceStatus, }: SupervisorChatOnlyViewProps) { + const shouldFollowLatestRef = useRef(true); const running = Boolean( chatAgentBusy || (runtime && !isAgentRuntimeTerminalState(runtime)), ); @@ -107,6 +112,34 @@ export function SupervisorChatOnlyView({ : runtime ? projectSupervisorChatRuntimeStatus(runtime) : projectWorkspaceStatusForDisplay(workspaceStatus); + useLayoutEffect(() => { + if (!running) { + return; + } + const messageList = messagesRef.current; + if (!messageList) { + return; + } + if (shouldFollowLatestRef.current) { + messageList.scrollTop = messageList.scrollHeight; + } + }, [ + messagesRef, + running, + runtime?.updatedAt, + transientReply, + visibleMessages.length, + ]); + function handleScroll(event: UIEvent) { + const messageList = event.currentTarget; + const distanceFromBottom = + messageList.scrollHeight - + messageList.scrollTop - + messageList.clientHeight; + shouldFollowLatestRef.current = + distanceFromBottom <= CHAT_SCROLL_BOTTOM_THRESHOLD; + onScroll(event); + } const conversationLabel = directCodex ? '陶泥儿项目对话' : '项目总控 Agent 纯聊天'; @@ -139,7 +172,7 @@ export function SupervisorChatOnlyView({ ref={messagesRef} className="message-list supervisor-chat-only-message-list" aria-label={directCodex ? '陶泥儿消息' : '项目总控消息'} - onScroll={onScroll} + onScroll={handleScroll} > {hiddenConversationCount > 0 ? (