Skip to content

feat(desktop): switch registered gateways from Sessions - #88325

Closed
dokterdok wants to merge 15 commits into
NousResearch:mainfrom
dokterdok:fix/desktop-session-source-scope
Closed

dokterdok wants to merge 15 commits into
NousResearch:mainfrom
dokterdok:fix/desktop-session-source-scope

Conversation

@dokterdok

@dokterdok dokterdok commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Lets one Hermes Desktop app switch between every registered Hermes gateway from the Sessions workspace.

The v2 connection registry can already store local, remote, Cloud, and SSH gateways together, but the main session workspace still followed whichever route happened to be active. This change makes gateway identity explicit across REST, WebSocket, session, messaging, cron, project, and settings state while keeping background connections and backend work alive.

The UX stays quiet for simple setups: no gateway control is shown with one registered gateway, and search appears only once a registry reaches eight gateways. With multiple gateways, a compact, type-aware selector sits in the Sessions statusbar next to gateway health, leaving the profile rail entirely available to profiles. Local is listed first and the rest sort naturally. Each gateway restores its own last profile and session context.

Bot Mode remains federated across gateways, so the foreground Sessions selector and its single-gateway health readout are intentionally hidden there. Existing cached-roster recovery remains unchanged; richer per-gateway offline state belongs to a separate Bot Mode health contract rather than a misleading global indicator.

Related Issue

Completes the remaining in-workspace switching part of #44413.

#37876 was closed by the merged registry and routing campaign in #86679, #86839, and #86875, plus the discovery entry points and docs in #87603. This PR builds on that architecture.

The earlier switcher concept in draft #76709 by @rewbs is credited here. This implementation uses the current v2 registry and concurrent socket pool; favorites and inline Cloud-agent listing from that draft remain separate.

Foreground profile and session-tab ownership is handled separately by #88095.

Linked remote-profile aliases that coexist in one profile rail without switching the Sessions gateway are a separate model tracked in #89304.

Non-primary Bot Chat hydration/navigation is tracked in #89206 and #89284. This PR keeps Bot Mode federated and does not replace that flow.

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

  • Route renderer REST and WebSocket work through an explicit (connection, profile) identity, including a truthful compatibility bridge for migrated v1 routes.
  • Add a compact gateway selector to the Sessions statusbar, immediately before gateway health. Its content-sized width is bounded between 80 and 160 px, with tooltip-backed truncation for long labels; it is hidden for one gateway and outside Sessions, leaving the profile rail fully available to profiles.
  • Keep large registries usable without adding chrome to common setups: at eight gateways, Sessions and Settings gain local-first natural sorting and search across gateway name, kind, and visible endpoint metadata. Settings preserves the search position when possible while allowing filtered content to contract to its real height.
  • Keep the selector stable while filtering, reset transient queries when it closes, restore focus on Escape, and support Cmd/Ctrl+F plus arrow-key entry from the search field without opening Electron's global find bar.
  • Put full non-secret gateway identity in row tooltips and route Manage gateways... to the registry settings.
  • Re-home only foreground gateway-scoped state on a switch. Previous gateway sockets and backend work remain alive; stale responses cannot repaint the new foreground.
  • Remember the last selected profile per gateway and keep explicit local routing local even when another gateway is primary.
  • Add an At startup, return to Sessions on the last-used gateway toggle after the gateway registry. It is opt-in; when off, Sessions opens on Primary. Last-used records only a successful switch, survives app-bundle replacement, and falls back to Primary if its gateway disappears. Primary remains configurable because it is also the compatibility and recovery fallback.
  • Distinguish Current from registry Primary and label the local runtime App-managed.
  • Keep remote gateway names visible in federated Bot Mode rows even when profile handles are long, while hiding Sessions-only gateway chrome from the Bots view.
  • Update Desktop and multi-connection documentation and user-facing gateway terminology.

The fifteen commits are intentionally separated by concern so maintainers can review or cherry-pick transport, switching, state isolation, documentation, settings, launch restoration, terminology, Bot Mode layout, large-registry ergonomics, and Sessions chrome independently.

How to Test

  1. Register two remote gateways plus This device, then switch between them from the gateway selector beside Gateway ready in the Sessions statusbar.
  2. Confirm the profile rail keeps its full width and each gateway shows only its own profiles, chats, messaging channels, cron jobs, and projects.
  3. Start work on one gateway, switch elsewhere, and confirm the original gateway remains connected and its backend task is not cancelled.
  4. In Settings -> Gateways, confirm Current follows the active gateway while Primary remains the registry default.
  5. Leave At startup, return to Sessions on the last-used gateway off, quit/relaunch, and confirm Primary opens. Turn it on, switch successfully, quit/relaunch, and confirm the exact gateway and scoped sessions/channels return. A failed switch must not replace the saved gateway.
  6. With fewer than eight gateways, confirm no search field is shown. With eight or more, confirm Sessions and Settings search by name, kind, and endpoint; closing/reopening clears the query.
  7. In the open selector, confirm Cmd/Ctrl+F focuses search without opening the global find bar, arrows enter the filtered list, and Escape closes the selector and restores focus to its trigger.
  8. Open Bot Mode and confirm the Sessions gateway selector, profile rail, and single-gateway health readout are absent while the federated Bot roster remains available.
  9. Exercise one vs multiple gateways, one/zero/many search results, long and Unicode labels, narrow and wide layouts, and light/dark themes. In Settings, filter from two results to one after scrolling and confirm the page contracts without a blank scroll tail.
  10. Run npm --prefix apps/desktop run check.

Verification on macOS Apple Silicon:

  • Full renderer suite: 510 files / 4,757 tests passed.
  • Full plugin and Bot Mode suite: 262/262 tests passed, including current Slack-style threads, mention composer, cross-gateway roster, remote identity, and Sessions workspace coverage.
  • Full Electron suite: 1,413 tests passed / 2 skipped.
  • Focused post-rebase multi-gateway and Capabilities/Bot integration: 21 files / 386 tests passed.
  • TypeScript: clean.
  • ESLint: 0 errors (existing upstream warnings remain outside this change).
  • Production build, signed app packaging, and DMG generation passed.
  • Playwright visual matrix passed for common and dense registries, fixed selector geometry for full/filtered/zero results, Cmd/Ctrl+F ownership, query reset, narrow layouts, real light/dark themes, and the federated Bots boundary.
  • Hardware-accelerated packaged UI was exercised manually; large-list scrolling remained smooth. The test harness also confirmed no horizontal overflow or control collisions.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this feature
  • pytest tests/ -q - not run; no Python source changed and the Desktop CI lane is exercised below
  • I've added behavior and regression tests
  • I've tested on macOS (Apple Silicon)

Documentation & Housekeeping

  • I've updated relevant Desktop documentation
  • cli-config.yaml.example - N/A; no CLI config keys changed
  • CONTRIBUTING.md / AGENTS.md - N/A; no contributor workflow changed
  • Cross-platform impact considered; the renderer/Electron paths contain no new platform-specific branch
  • Tool descriptions/schemas - N/A

Screenshots / Logs

Sessions gateway selector in a common local, remote, Cloud, and SSH setup

A four-gateway setup stays compact: the selector lives beside gateway health in the Sessions statusbar, no search field is added, and the profile rail retains its full width.

Large registered gateway list with thresholded search in the Sessions selector

Search appears only for larger registries. The selector keeps a stable size while filtering, sorts gateways naturally with the local runtime first, and keeps gateway management outside the scrolling result list.

Filtered Registered gateways settings with the last-used Sessions startup toggle

Settings search stays anchored when the layout has room, then contracts to the true result height without a blank scroll tail. The startup preference follows the registry instead of separating its heading from the gateway list.

Filtered gateway selector with stable geometry

Filtering to two matches preserves the selector geometry, keeps the management action fixed, and avoids layout jumps. All names and endpoints in the screenshots are synthetic.

@alt-glitch alt-glitch added type/feature New feature or request comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 17, 2026
@dokterdok
dokterdok force-pushed the fix/desktop-session-source-scope branch 7 times, most recently from b3ea469 to 4279ad0 Compare August 17, 2026 12:21

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@dokterdok
dokterdok marked this pull request as ready for review August 17, 2026 12:45
@dokterdok

Copy link
Copy Markdown
Contributor Author

Additional Windows verification

Verified PR head 4279ad0 from a clean isolated checkout on Windows 11 (10.0.26300, Node v24.18.0, npm 12.0.2).

  • npm ci passed.
  • Desktop typecheck and ESLint passed.
  • electron/connection-registry.test.ts: 47/47 passed.
  • Production renderer build and unpacked Electron packaging passed, producing a Hermes.exe artifact.
  • Full UI run: 4,597/4,613 passed. Twelve suite-load/time-out failures passed when rerun serially; the four remaining failures are existing en-CH number/currency-format assertions. The source-switcher Settings tests pass in isolation.
  • Platform run: 1,284/1,313 passed, 2 skipped. The remaining failures are in POSIX permission/path expectations plus SSH and git-worktree fixtures, outside the source-switching paths changed here.
  • The NSIS installer step hit an environment-local electron-builder cache EPERM; unpacked Windows packaging itself completed successfully.

Not claimed: packaged-app E2E against multiple live remote gateways on Windows. That remains covered by the macOS packaged-app E2E and the automated registry/routing tests.

@dokterdok
dokterdok force-pushed the fix/desktop-session-source-scope branch from 86f55b9 to 468f02c Compare August 18, 2026 08:33
@dokterdok dokterdok changed the title feat(desktop): switch registered sources from Sessions feat(desktop): switch registered gateways from Sessions Aug 18, 2026
@dokterdok
dokterdok force-pushed the fix/desktop-session-source-scope branch 2 times, most recently from 29f215c to b99aecc Compare August 18, 2026 16:17
@dokterdok
dokterdok force-pushed the fix/desktop-session-source-scope branch 2 times, most recently from 61d6eb6 to 29e87c2 Compare August 18, 2026 18:33
@teknium1

Copy link
Copy Markdown
Collaborator

Merged via PR #89719 (#89719) — all 15 of your commits landed with your authorship preserved via rebase over the 131-commit gap (single conflict in store/profile.ts resolved against #88095). Implements #88307. Thanks for the thorough cross-platform verification on this one.

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

Labels

comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have 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/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants