-
Notifications
You must be signed in to change notification settings - Fork 1.4k
feat(site): migrate agent chat scrolling #28130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
49445cc
8c4b929
8d0badb
1663956
ce8f668
6e78691
17e99c0
0d030d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -338,10 +338,9 @@ export const settlePromotedQueueHead = async ( | |
| ); | ||
| }; | ||
|
|
||
| export async function submitEditAndScroll({ | ||
| export async function submitEdit({ | ||
| editMessage, | ||
| editArgs, | ||
| scrollToBottom, | ||
| onError, | ||
| }: { | ||
| editMessage: (args: { | ||
|
|
@@ -354,7 +353,6 @@ export async function submitEditAndScroll({ | |
| optimisticMessage?: TypesGen.ChatMessage; | ||
| req: TypesGen.EditChatMessageRequest; | ||
| }; | ||
| scrollToBottom: (() => void) | null | undefined; | ||
| onError: (error: unknown) => void; | ||
| }): Promise<void> { | ||
| try { | ||
|
|
@@ -363,13 +361,6 @@ export async function submitEditAndScroll({ | |
| onError(error); | ||
| throw error; | ||
| } | ||
| // Scroll after the mutation resolves so the optimistic | ||
| // truncation and server reconciliation have already been | ||
| // applied to the DOM. Scrolling before this point causes | ||
| // the sticky user message to cycle through prior messages | ||
| // as the IntersectionObserver reacts to rapid layout | ||
| // shifts between the old and truncated content. | ||
| scrollToBottom?.(); | ||
| } | ||
|
|
||
| /** @internal Exported for testing. */ | ||
|
|
@@ -882,7 +873,6 @@ const AgentChatPage: FC = () => { | |
| isSidebarCollapsed, | ||
| onToggleSidebarCollapsed, | ||
| onChatReady, | ||
| scrollContainerRef, | ||
| } = useOutletContext<AgentsPageOutletContext>(); | ||
| const queryClient = useQueryClient(); | ||
| const { permissions, user: currentUser } = useAuthenticated(); | ||
|
|
@@ -891,7 +881,6 @@ const AgentChatPage: FC = () => { | |
| const [selectedModel, setSelectedModel] = useState(""); | ||
| const [selectedReasoningEffort, setSelectedReasoningEffort] = useState(""); | ||
| const isEditReasoningEffortDirtyRef = useRef(false); | ||
| const scrollToBottomRef = useRef<(() => void) | null>(null); | ||
| const chatInputRef = useRef<ChatMessageInputRef | null>(null); | ||
| const inputValueRef = useRef( | ||
| agentId | ||
|
|
@@ -1240,6 +1229,7 @@ const AgentChatPage: FC = () => { | |
| }; | ||
|
|
||
| const aiGatewayDisabled = !useAIGatewayEnabled(); | ||
| const [liveEdgeSignal, setLiveEdgeSignal] = useState(0); | ||
| const { | ||
| store, | ||
| acceptServerChatStatus, | ||
|
|
@@ -1627,6 +1617,9 @@ const AgentChatPage: FC = () => { | |
| if (!hasContent || isSubmissionPending || !agentId || !hasModelOptions) { | ||
| return; | ||
| } | ||
| // Every accepted submission (send, edit, /compact) is an explicit ask | ||
| // to be at the live edge, even one that appends no visible prompt. | ||
| setLiveEdgeSignal((signal) => signal + 1); | ||
| // Wait for chat-setting mutations to settle before sending so the | ||
| // message observes the workspace and plan-mode choices the user just made. | ||
| await waitForPendingChatSettingsSyncs([ | ||
|
|
@@ -1662,7 +1655,6 @@ const AgentChatPage: FC = () => { | |
| clearStreamError(); | ||
| store.clearStreamState(); | ||
| store.setChatStatus("running"); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a user submits AGENTS.md reference: site/AGENTS.md:L9-L10 Useful? React with 👍 / 👎.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 0d030d3 without a ref bridge. Generated by Coder Agents on behalf of @DanielleMaywood. |
||
| scrollToBottomRef.current?.(); | ||
| try { | ||
| await compact(); | ||
| } catch (error) { | ||
|
|
@@ -1715,14 +1707,13 @@ const AgentChatPage: FC = () => { | |
| store.setChatStatus("running"); | ||
| store.clearStreamState(); | ||
| }); | ||
| await submitEditAndScroll({ | ||
| await submitEdit({ | ||
| editMessage, | ||
| editArgs: { | ||
| messageId: editedMessageID, | ||
| optimisticMessage, | ||
| req: request, | ||
| }, | ||
| scrollToBottom: scrollToBottomRef.current, | ||
| onError: (error) => { | ||
| restoreOptimisticRequestSnapshot(store, previousSnapshot); | ||
| handleRequestError(error); | ||
|
|
@@ -1758,7 +1749,6 @@ const AgentChatPage: FC = () => { | |
| }; | ||
| clearChatErrorReason(agentId); | ||
| clearStreamError(); | ||
| scrollToBottomRef.current?.(); | ||
|
|
||
| // An errored-chat send may promote the queue head that existed when the request began. | ||
| const queuedMessagesBeforeSend = store.getSnapshot().queuedMessages; | ||
|
|
@@ -1973,6 +1963,7 @@ const AgentChatPage: FC = () => { | |
| workspaceAgent={workspaceAgent} | ||
| chatBuildId={chatQuery.data?.build_id} | ||
| store={store} | ||
| liveEdgeSignal={liveEdgeSignal} | ||
| editing={{ ...editing, handleEditUserMessage }} | ||
| effectiveSelectedModel={effectiveSelectedModel} | ||
| setSelectedModel={setSelectedModel} | ||
|
|
@@ -2035,12 +2026,10 @@ const AgentChatPage: FC = () => { | |
| isPinned={(chatRecord?.pin_order ?? 0) > 0} | ||
| isChildChat={parentChatID !== undefined} | ||
| urlTransform={urlTransform} | ||
| scrollContainerRef={scrollContainerRef} | ||
| scrollToBottomRef={scrollToBottomRef} | ||
| hasMoreMessages={chatMessagesQuery.hasNextPage ?? false} | ||
| isFetchingMoreMessages={chatMessagesQuery.isFetchingNextPage} | ||
| hasFetchMoreError={chatMessagesQuery.isFetchNextPageError} | ||
| onFetchMoreMessages={chatMessagesQuery.fetchNextPage} | ||
| messageCount={storeMessageCount} | ||
| desktopChatId={desktopEnabled ? agentId : undefined} | ||
| mcpServers={mcpServers} | ||
| selectedMCPServerIds={effectiveMCPServerIds} | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a user submits while a plan-mode or workspace update is pending, this signal scrolls them away from historical messages before
waitForPendingChatSettingsSyncscompletes. If either update rejects, the function exits without sending or compacting anything, but the user's reading position has already been lost; emit the signal only after the prerequisite sync succeeds and the requested operation actually begins.Useful? React with 👍 / 👎.