Skip to content

fix(chat): keep the first message on screen when a new session starts - #257

Merged
bbsngg merged 1 commit into
mainfrom
claude/keep-first-message
Nov 10, 2026
Merged

bbsngg merged 1 commit into
mainfrom
claude/keep-first-message

Conversation

@bbsngg

@bbsngg bbsngg commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

Problem

The first message sent in a new session disappears for a second or two, then comes back.

Cause

In useChatSessionState:

  1. session-created sets isSystemSessionChange and selects the new session. The load effect sees the flag, skips the fetch (the message is already on screen) and resets the flag to false.
  2. isSystemSessionChange is a dependency of that same effect, so it runs again for the same session. This time the flag is gone and it fetches the transcript from the server.
  3. The CLI often has not written the question to the transcript yet, so the result is empty. It replaces the chat messages through the sessionMessages → chatMessages sync until a later update restores them.

The external-update reload effect had a similar path. After any earlier external update the counter stays above 0, and the effect re-ran whenever the selected session object changed identity, for example on a projects refresh.

Fix

  • The load effect records which session it is showing and over which socket (displayedSessionRef). decideSessionMessageLoad in chatSessionTransition.ts returns:
    • adopt: the session we just created; keep the messages on screen.
    • keep: the effect re-ran for the session already shown over the same socket; no fetch.
    • load: a different session, or a reconnected socket that may have missed events.
  • The external-update reload runs only when externalMessageUpdate changes (isNewExternalMessageUpdate).

Test plan

  • Unit tests for decideSessionMessageLoad and isNewExternalMessageUpdate (chatSessionTransition.test.ts).
  • npm test: all pass except codexCli.test.js, which fails only because this worktree's node_modules is a symlink to another checkout.
  • npm run typecheck
  • Browser, dev server, new session in a scratch project. To make the race repeatable, the page answered paginated message fetches with an empty transcript for 1.5 s after send:
    • before: the question was visible at 3.8 s, gone at 4.8 s, back at 6.3 s;
    • after: visible from 3.9 s on and never removed; no message fetch happened in that window.
  • Switching to another session and opening a session URL directly still load its messages.

🤖 Generated with Claude Code

Sending the first message of a new session made it vanish for a second or
two. When session-created arrived, the load effect correctly skipped the
fetch, but then reset isSystemSessionChange. That flag is one of the
effect's dependencies, so the effect ran again for the same session and
fetched the transcript from the server. The CLI often has not written the
question yet, so the empty result replaced the messages on screen until a
later update brought them back.

- The load effect now remembers which session (and socket) it is showing.
  A re-run for that same session keeps what is on screen instead of
  fetching again. A different session, or a reconnected socket, still loads.
- The external-update reload only runs when its counter moves. Before, it
  also ran whenever the selected session object changed identity after any
  earlier external update, which could do the same overwrite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bbsngg bbsngg mentioned this pull request Nov 10, 2026
1 of 2 tasks
@bbsngg
bbsngg merged commit bb36d7f into main Nov 10, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant