fix(desktop): reattach sessions after websocket reconnect - #45653
fix(desktop): reattach sessions after websocket reconnect#45653GwendalObsidian wants to merge 1 commit into
Conversation
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved
Correctness
- Desktop app now reattaches sessions after WebSocket reconnect, preventing session loss after temporary disconnection.
use-gateway-boot.tshandles reconnection with proper state management.gateway.tsstore updated to track reconnection state.tui_gateway/server.pyserver-side support for session reattachment.
Testing
use-gateway-boot.test.tsxtests the reconnection hooks.test_tui_gateway_server.pyadditions test server-side session reattachment.
No Issues Found
- No secrets, no debug artifacts.
Reviewed by Hermes Agent
teknium1
left a comment
There was a problem hiding this comment.
Thanks for isolating both the detach/reconnect and orphan-lifetime paths. The server-side orphan-reap fix remains relevant: current tui_gateway/server.py:760-762 excludes running detached sessions, while _schedule_ws_orphan_reap() returns at :786-787 without scheduling another check after that turn settles.
Problems
- The Desktop callback is only attached to
useGatewayBootin the primary reconnect path. Current main reconnects secondary profile sockets independently inapps/desktop/src/store/gateway.ts:167-176, and that path has no reattach notification. A detached turn on a secondary profile would therefore remain detached after its own socket reconnects. - Current main already owns foreground re-resume in
apps/desktop/src/app/session/hooks/use-route-resume.ts:145-150. It deliberately re-runsresumeSession()on a closed→open transition even when the cached runtime ID appears active. A salvage should compose with that owner rather than add a parallel foreground reconciler.
Suggested changes
- Keep the orphan-reap reschedule and regression test, rebased onto the current teardown code.
- Drive background-session recovery from each profile gateway's open transition and add a secondary-profile reconnect regression.
Automated hermes-sweeper review.
| onGatewayReady: g => { | ||
| gatewayRef.current = g | ||
| }, | ||
| onReconnectReady: recoverDetachedSessions, |
There was a problem hiding this comment.
onReconnectReady only runs after the primary useGatewayBoot socket reconnects. Secondary profile sockets reconnect independently; wire recovery to each profile gateway's open transition (and test a detached secondary-profile turn), otherwise that session remains on the detached transport.
|
Closing as implemented on main: the server half (mid-turn reap re-arm) landed via #93361 (salvaged #85598, first submitted in #44102 by @AIalliAI) with an interrupt-after-grace refinement, and the desktop half is covered by resetTileRuntimeBindings on reconnect (#93292) + force-redial of half-open sockets (#93361, salvaged #89092). Thanks @GwendalObsidian — both halves of your diagnosis were right. |
Summary
Fixes a Desktop reconnect edge case where sessions that were mid-turn when the WebSocket dropped could remain visually stuck after the renderer reconnected.
This change:
Why
A dropped Desktop WebSocket moves backend sessions to the detached/drop transport. Without an explicit
session.resumeafter the fresh WebSocket opens, final events can continue to be emitted to the drop transport, leaving Desktop looking like the turn is still stuck.There was also a backend cleanup gap: if the first orphan-reap timer fired while the detached session was still running, it skipped the session once and never checked again, so the session could become immortal after the turn settled.
Tests
venv/bin/python -m pytest tests/test_tui_gateway_server.py::test_ws_orphan_reap_reschedules_detached_mid_turn_until_it_settles tests/test_tui_gateway_server.py::test_ws_orphan_reap_disabled_when_grace_zero tests/test_tui_gateway_server.py::test_ws_orphan_reap_spares_reattached_session -q -o 'addopts='npm --workspace apps/desktop run test:ui -- src/app/gateway/hooks/use-gateway-boot.test.tsxnpm --workspace apps/desktop run typechecknpm --workspace apps/desktop run buildnpx eslint src/app/desktop-controller.tsx src/app/gateway/hooks/use-gateway-boot.ts src/app/gateway/hooks/use-gateway-boot.test.tsx src/app/session/hooks/use-session-actions.ts src/types/hermes.ts src/store/gateway.ts