Skip to content

fix(tui): heartbeat and bounded reconnect for silent WebSocket drops - #89984

Open
100yenadmin wants to merge 1 commit into
NousResearch:mainfrom
100yenadmin:upstream/tui-client-heartbeat-reconnect
Open

fix(tui): heartbeat and bounded reconnect for silent WebSocket drops#89984
100yenadmin wants to merge 1 commit into
NousResearch:mainfrom
100yenadmin:upstream/tui-client-heartbeat-reconnect

Conversation

@100yenadmin

@100yenadmin 100yenadmin commented Aug 19, 2026

Copy link
Copy Markdown

What does this PR do?

Adds client-side heartbeat and bounded reconnect to the ink TUI's gateway client. The client periodically sends gateway.ping and, if it stops seeing acks past a deadline, treats the socket as silently dropped and reconnects with bounded exponential backoff. It's the client half of the gateway.ping wire contract in #89958 — it only starts the heartbeat when the server advertises heartbeat in gateway.ready, so against an older backend it's a no-op and behaves exactly as today.

Related Issue

Client half of #89958 (heartbeat wire contract); part of #83166.

Also addresses #32997, which names ui-tui/src/gatewayClient.ts and handleTransportExit() — the exact file and function this changes — and whose suggested fixes 1 and 2 (a WebSocket ping/pong, and exponential-backoff reconnect at 1s/2s/4s/8s capped at 30s) are what this implements. It does not cover that issue's suggested fix 3 (buffering unsent composer text across a reconnect); this only touches the client transport, so typed text is still lost on reconnect. #60727 is an earlier open PR over the same files — this is that work re-split against current main, not a claim over it.

Related: #53374 reports the same keepalive gap on Windows sleep/resume, and #89083 the macOS Desktop version.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • ui-tui/src/gatewayClient.ts — heartbeat interval/deadline + bounded-backoff reconnect; a disposed flag so kill() stops reconnecting; a heartbeat-ack short-circuit; all gated on the server's advertised heartbeat capability.
  • ui-tui/src/gatewayTypes.tsheartbeat? on gateway.ready, a gateway.reconnecting event.
  • ui-tui/src/__tests__/gatewayClient.test.ts — heartbeat/reconnect coverage.

Constants: WS_HEARTBEAT_INTERVAL_MS=15000, WS_HEARTBEAT_DEAD_MS=45000, RECONNECT_BASE_MS=1000, RECONNECT_MAX_MS=30000.

How to Test

cd ui-tui && npx vitest run src/__tests__/gatewayClient.test.ts   → 18 passed
tsc --noEmit                                                       → clean

Covers: healthy-idle-with-acks, auto-reconnect-on-missing-ack, older-backend-omits-capability (graceful no-op), no-double-reconnect, no-reconnect-after-kill().

Checklist

Code

  • I've read the Contributing Guide
  • Conventional Commits
  • Searched existing PRs
  • Only changes related to this fix
  • Ran the vitest suite + typecheck
  • Added tests
  • Tested on my platform: macOS 15

Documentation & Housekeeping

  • Docs — N/A
  • cli-config.yaml.example — N/A
  • CONTRIBUTING.md/AGENTS.md — N/A
  • Cross-platform — N/A (TS/Node)
  • Tool descriptions/schemas — N/A

Salvage-friendly: single commit on current main (13ce0c5c67), pairs with #89958 (no hard dependency — capability-gated) — cherry-pick welcome, authorship preservation appreciated but optional.

the client half of the gateway.ping heartbeat contract (NousResearch#89958); detects a silently-dropped socket via missed ping-acks and reconnects with bounded backoff; part of the NousResearch#83166 recovery series.
@100yenadmin

Copy link
Copy Markdown
Author

Context that turned up after filing: #89083 reports the Desktop version of this symptom (window permanently unresponsive after macOS sleep/wake because a half-open socket is never detected). The ink TUI client drops the same way on laptop sleep, which is what this fixes; #90012 covers the shared/Desktop client and #89958 supplies the ping primitive both use.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tui Terminal UI (ui-tui/ + tui_gateway/) P2 Medium — degraded but workaround exists sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants