chat UX: persist in-flight exchange across leave/refresh + bottom-sticky autoscroll for accumulating tool calls (CTO) #2560

Open
opened 2026-06-10 23:28:43 +00:00 by core-devops · 0 comments
Member

Two CTO asks (2026-06-10/11), one PR or two:

1. Chat must persist across leave/refresh — today returning mid-turn shows ONLY the typing dots.
Mechanism: useChatHistory.loadInitial hydrates from /workspaces/:id/chat-history (DB), but the user's outgoing message is only appended to LOCAL state (onUserMessage) and the server writes chat-history rows at turn completion — so on remount mid-turn the current exchange is missing entirely (worst on a fresh agent with no prior history: empty pane + dots).
Fix (both halves):

  • Server: write the inbound user chat message to chat history at RECEIPT (not completion), flagged/ordered so the eventual agent reply lands after it. Idempotent on messageId.
  • Client: on mount, if the workspace has an active turn (active task / send-in-flight state from the server), restore the thinking indicator + elapsed timer instead of starting blank; hydrated history now includes the pending user message.
    Tests: hydrate-mid-turn renders the user bubble + dots; completed turn renders both bubbles; no dup when WS reply arrives after hydration.

2. Bottom-sticky autoscroll while tool calls accumulate.
Mechanism: ChatTab's scroll useLayoutEffect deps are [history.messages] — the live activity feed (activityLog, the tool-call lines under the spinner) grows without triggering scroll, so the user manually chases it.
Fix: track atBottom (scroll listener with a small threshold); when at bottom, also scroll on activityLog growth; when the user has scrolled up, NEVER yank (this should also gate the existing message-append smooth-scroll — currently it always scrolls even if the user is reading older history). Preserve the loadOlder scroll-anchor logic untouched.
Tests: activity growth scrolls when at bottom; does not scroll when scrolled up; message append respects the same gate; anchor restore unaffected.

🤖 Generated with Claude Code

Two CTO asks (2026-06-10/11), one PR or two: **1. Chat must persist across leave/refresh — today returning mid-turn shows ONLY the typing dots.** Mechanism: `useChatHistory.loadInitial` hydrates from `/workspaces/:id/chat-history` (DB), but the user's outgoing message is only appended to LOCAL state (`onUserMessage`) and the server writes chat-history rows at turn completion — so on remount mid-turn the current exchange is missing entirely (worst on a fresh agent with no prior history: empty pane + dots). Fix (both halves): - **Server**: write the inbound user chat message to chat history at RECEIPT (not completion), flagged/ordered so the eventual agent reply lands after it. Idempotent on messageId. - **Client**: on mount, if the workspace has an active turn (active task / send-in-flight state from the server), restore the thinking indicator + elapsed timer instead of starting blank; hydrated history now includes the pending user message. Tests: hydrate-mid-turn renders the user bubble + dots; completed turn renders both bubbles; no dup when WS reply arrives after hydration. **2. Bottom-sticky autoscroll while tool calls accumulate.** Mechanism: `ChatTab`'s scroll `useLayoutEffect` deps are `[history.messages]` — the live activity feed (`activityLog`, the tool-call lines under the spinner) grows without triggering scroll, so the user manually chases it. Fix: track `atBottom` (scroll listener with a small threshold); when at bottom, also scroll on `activityLog` growth; when the user has scrolled up, NEVER yank (this should also gate the existing message-append smooth-scroll — currently it always scrolls even if the user is reading older history). Preserve the loadOlder scroll-anchor logic untouched. Tests: activity growth scrolls when at bottom; does not scroll when scrolled up; message append respects the same gate; anchor restore unaffected. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: molecule-ai/molecule-core#2560