Skip to content

fix(desktop): keep in-flight new chats from vanishing on refresh#37908

Merged
OutThisLife merged 2 commits into
mainfrom
bb/desktop-concurrent-session-loss
Jun 3, 2026
Merged

fix(desktop): keep in-flight new chats from vanishing on refresh#37908
OutThisLife merged 2 commits into
mainfrom
bb/desktop-concurrent-session-loss

Conversation

@OutThisLife

@OutThisLife OutThisLife commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes a bug where rapidly creating several chats (Ctrl-N → type → send, ~3×) and then waiting for one to finish caused the other still-running chats to disappear from the sidebar.

Root cause. A new session's first user message isn't flushed to the SessionDB until its turn is persisted (_persist_session at turn end). The gateway lazily creates the DB row on prompt.submit with message_count = 0 (_ensure_session_db_row), so a session that's still mid-first-response has message_count = 0 in the DB.

refreshSessions() lists with min_messages=1 and then hard-replaces $sessions. Every message.complete triggers a refresh (completeAssistantMessagerefreshSessions()), so the instant one session finished, the others — still at message_count = 0 — were filtered out of the server page and dropped from the list.

Fix. Merge instead of replace. New mergeWorkingSessions() preserves any session that is still in $workingSessionIds but missing from the server page, so concurrent new chats stay visible until their own turn persists and the server starts returning them. Optimistic deletes/archives already drop the row from the previous list, so a removed session can't be resurrected by the merge. The sidebar re-sorts by recency, so merge order is cosmetic; the Math.max(sessionsTotal, length) footer math already tolerates the extra rows.

UX follow-up. The send path created the optimistic row with a null preview, so an in-flight chat read "Untitled session" until its turn persisted and auto-title ran. Now that concurrent in-flight chats are preserved, several "Untitled session" rows could appear at once. Seed the optimistic preview with the user's first message (the branch path already does this) so each row is labeled immediately; the server's preview/title supersedes it once the turn persists.

Changes

  • store/session.ts — add pure, testable mergeWorkingSessions(previous, incoming, workingIds) helper.
  • app/desktop-controller.tsxrefreshSessions() merges working sessions instead of hard-replacing.
  • session/hooks/use-session-actions.ts + use-prompt-actions.ts — seed optimistic sidebar preview with the first message.
  • store/session.test.ts — 4 unit tests (preserve omitted working sessions, no duplication, never resurrect deleted, no-op when nothing working).

Test plan

  • vitest run src/store/session.test.ts — 6/6 pass
  • npm run type-check — clean
  • eslint on changed files — 0 new problems (pre-existing warnings/import-sort error already on main)
  • Full src/ suite — 232 pass; the single failure (pane-shell width test) is pre-existing on main and unrelated (verified via git stash)
  • Manual: Ctrl-N → message ×3, let one finish, confirm the other two remain (labeled with their message) and finish normally

Creating several sessions in a row (Ctrl-N, type, send, repeat) and
waiting for one to finish made the other still-running chats disappear
from the sidebar.

Root cause: a new session's first user message isn't flushed to the
SessionDB until its turn is persisted, so the row's message_count stays
0 mid-response. `refreshSessions()` lists with min_messages=1 and then
hard-replaces $sessions. Because every message.complete triggers a
refresh, the moment one session finished, the others (still at
message_count 0) were filtered out of the server page and dropped from
the list.

Fix: merge instead of replace. `mergeWorkingSessions()` preserves any
session that is still in $workingSessionIds but absent from the server
page, so concurrent new chats stay visible until their own turn persists.
Optimistic deletes/archives already remove the row from the previous
list, so a removed session can't be resurrected by the merge.
@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

🔎 Lint report: bb/desktop-concurrent-session-loss vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 9709 on HEAD, 9709 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 5031 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

The send path created the optimistic sidebar row with a null preview, so
a new chat read "Untitled session" until its turn persisted and auto-title
ran. With concurrent new chats now preserved across refreshes, several
"Untitled session" rows could show at once.

Seed the optimistic preview with the user's first message (the branch path
already does this) so each in-flight row is labeled immediately. The
server's own preview/title supersedes it once the turn persists.
@OutThisLife OutThisLife merged commit feb50ee into main Jun 3, 2026
19 checks passed
@OutThisLife OutThisLife deleted the bb/desktop-concurrent-session-loss branch June 3, 2026 05:29
davidgut1982 pushed a commit to davidgut1982/hermes-agent that referenced this pull request Jun 5, 2026
…ncurrent-session-loss

fix(desktop): keep in-flight new chats from vanishing on refresh
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