spacedriveapp / spacedriveapp/spacebot

[bug] WebChatPanel lags when typing with a long conversation history

Open
#553 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
2.4k
Forks
367
PR merge metrics
No merged PRs in 30d

Description

Description

Typing in the WebChatPanel input becomes progressively slower as the conversation history grows. With a long chat, every keypress causes noticeable lag/jank.

Root cause

There are three compounding issues:

1. All markdown re-renders on every keystroke (primary cause)

input state lives in WebChatPanel alongside timeline.map(). Every keypress re-renders WebChatPanel, which walks the entire message list and re-runs react-markdown's full remark-gfm + rehype-raw AST pipeline for every assistant message. No message components are wrapped in React.memo.

Additionally, the components, remarkPlugins, and rehypePlugins props passed to <ReactMarkdown> are defined inline — new object/array references on every render — so ReactMarkdown cannot bail out even if the content string is unchanged.

2. No message list virtualization

@tanstack/react-virtual is already installed and used in AgentMemories.tsx, but never applied to any chat panel. All messages are always in the DOM.

3. DOM reflow per keystroke (textarea auto-resize)

FloatingChatInput has a useEffect([value]) dependency on the input string. On every character typed it removes the "input" event listener, calls adjustHeight() directly (forcing a height="auto" write → scrollHeight read → height write reflow cycle), then re-adds the listener.

Steps to reproduce

  1. Start a long conversation with an agent (20+ message exchanges with markdown-heavy responses)
  2. Click in the input field and type — lag increases proportionally to history length

Suggested fixes

  • Wrap Markdown with React.memo and hoist remarkPlugins, rehypePlugins, and components to module-level constants so ReactMarkdown skips re-rendering when content is unchanged
  • Move input state into FloatingChatInput so keystrokes only re-render the small input component, not WebChatPanel and its message list
  • Change the useEffect([value]) to run once on mount ([]) and rely on a native "input" event listener for height adjustment — eliminating the reflow-per-keystroke
  • (Follow-up) Apply useVirtualizer from @tanstack/react-virtual to the scroll container — the dependency is already installed

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating WebChatPanel, Markdown, FloatingChatInput, and the AgentMemories.tsx use of @tanstack/react-virtual. Trace how input state and markdown props flow through the message list, then inspect the textarea height effect. Done means typing stays responsive with long markdown-heavy histories, while message rendering and input resizing avoid unnecessary per-keystroke work.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
frontend, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.