Skip to content

fix(desktop): sync sessions across remote clients - #69061

Open
Ason-Lee wants to merge 2 commits into
NousResearch:mainfrom
Ason-Lee:fix/desktop-cross-client-session-sync
Open

Ason-Lee wants to merge 2 commits into
NousResearch:mainfrom
Ason-Lee:fix/desktop-cross-client-session-sync

Conversation

@Ason-Lee

@Ason-Lee Ason-Lee commented Jul 22, 2026 •

Copy link
Copy Markdown

What does this PR do?

Keeps ordinary Desktop session lists and the currently open persisted transcript synchronized across multiple Desktop clients connected to the same remote gateway.

The gateway does not currently broadcast another client's session-list or ordinary transcript writes into each renderer websocket. A visible remote Desktop now reconciles the backend-owned session list every two seconds, and also refreshes the selected ordinary Desktop transcript every two seconds when the receiving client is idle. New chats and completed cross-client turns therefore appear without a manual reload or navigating away and back.

The polling paths are scoped to remote connections, visible documents, and the active connection/profile. Session-list requests reject stale responses after connection changes. Open-transcript requests coalesce while in flight, skip local streaming/busy state, re-check session identity before publishing, and signature-gate unchanged transcripts.

Related Issue

No existing issue or PR found for this behavior.

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • Add visible two-second session-list reconciliation for remote Desktop connections.
  • Add visible two-second reconciliation for the open ordinary Desktop transcript on remote shared gateways.
  • Reuse the existing persisted-transcript hydration path for local and messaging sessions while preserving local assistant errors.
  • Skip active-transcript publication while the receiving client is busy, and reject responses after session/runtime switches.
  • Coalesce slow transcript and session-list requests so timer ticks never overlap.
  • Key session-list poll ownership by remote gateway URL and profile so remote-to-remote switches invalidate stale responses.
  • Preserve the dedicated cron and messaging polling cadences.
  • Add regression tests for remote polling, local exclusion, in-flight coalescing, gateway invalidation, stale-response rejection, and cron-side-effect suppression.

How to Test

  1. Connect two Hermes Desktop clients to the same remote gateway and profile.
  2. Create and send a new ordinary Desktop chat from client A.
  3. Verify client B shows the new session in its sidebar within two seconds without a manual reload.
  4. Open the same completed conversation on both clients.
  5. Send a new turn from client A and leave client B on the open conversation.
  6. Verify client B displays the persisted turn within two seconds without navigating away and back.
  7. Verify a local-mode Desktop does not perform the two-second ordinary chat polls.
  8. Switch client B to another session or remote connection while a refresh is pending and verify stale messages/rows are not applied.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs and issues to make sure this isn't a duplicate
  • My PR contains only changes related to this fix
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes
  • I've tested on macOS with two Desktop clients sharing a Tailscale-restricted remote gateway

Python tests could not start because the existing project venv does not include pytest. This change is limited to Desktop TypeScript. The relevant Desktop checks passed:

  • npm run test:ui: 1,792 passed, 1 skipped
  • active transcript and polling targeted regression tests: 20 passed
  • npm run typecheck
  • ESLint on the modified Desktop files
  • npm run pack
  • git diff --check
  • static security scan
  • real MacBook → iMac open-transcript reconciliation without navigation
  • independent fail-closed review

Documentation & Housekeeping

  • Documentation update: N/A
  • cli-config.yaml.example: N/A
  • CONTRIBUTING.md / AGENTS.md: N/A
  • Cross-platform impact considered: renderer-only timers, fetch coordination, and nanostore state; no platform-specific APIs
  • Tool descriptions/schemas: N/A

Screenshots / Logs

Not applicable. The regression is cross-client timing. Hook tests cover polling and overlap behavior, and the packaged app was verified with two live Desktop clients.

@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/desktop Electron desktop app (apps/desktop/*) sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Jul 22, 2026
@teknium1

Copy link
Copy Markdown
Collaborator

Thanks for addressing cross-client Desktop consistency. The ordinary active-transcript gap is still present on current main: apps/desktop/src/app/contrib/hooks/use-background-sync.ts:358-375 only refreshes persisted transcripts for messaging sessions.

Problems

  • The PR's two-second remote polls were written before current main's event-driven change watcher. tui_gateway/server.py:3060-3123 now broadcasts sessions.changed for shared state.db writes, and apps/desktop/src/app/contrib/hooks/use-background-sync.ts:299-338 already coalesces that signal into sidebar-list refreshes. Adding unconditional remote polls would duplicate that work on event-capable gateways.

Suggested changes

  • Rework the active ordinary-transcript refresh to subscribe to $sessionsChangeTick, retaining the PR's idle/staleness guards.
  • Keep a polling fallback only for gateways without change_events, mirroring the compatibility split used for messaging transcripts at apps/desktop/src/app/contrib/hooks/use-background-sync.ts:358-386.

This is an automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform area/sessions Session lifecycle, resume, persistence, history labels Jul 30, 2026

This branch has not been deployed

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

Labels

area/sessions Session lifecycle, resume, persistence, history comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades 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.

4 participants