diff --git a/apps/desktop/src/store/profile.ts b/apps/desktop/src/store/profile.ts index 67b708fb219..4c8ffc3540f 100644 --- a/apps/desktop/src/store/profile.ts +++ b/apps/desktop/src/store/profile.ts @@ -12,6 +12,7 @@ import { storedStringRecord } from '@/lib/storage' import { $gateway, ensureGatewayForProfile } from '@/store/gateway' +import { setConnection } from '@/store/session' import type { ProfileInfo } from '@/types/hermes' // Canonical key for a profile: trimmed, empty → "default". Used everywhere we @@ -178,6 +179,32 @@ export const $gatewaySwapTarget = atom(null) let gatewaySwitch: Promise | null = null +// Keep the renderer's $connection (mode / baseUrl / profile) in lockstep with +// the profile the live gateway is now on. $connection seeds from the PRIMARY +// (window) backend at boot and otherwise only refreshes on a sleep/wake +// reconnect — so activating a *background* profile left $connection describing +// the primary, with the wrong `mode` for everything that branches on +// local-vs-remote. Headline symptom: with a local primary and a remote pool +// profile active, image attachments went out via the path-based `image.attach` +// instead of `image.attach_bytes`, handing the remote gateway a client-only +// path it can't resolve ("image not found: C:\…"), while the /api/fs/* file +// browser and /api/media fetches targeted the wrong machine (#46651). +// Best-effort: a failed descriptor fetch leaves the prior connection intact for +// boot/reconnect to resync. +async function syncConnectionToActiveProfile(profile: string): Promise { + const getConnection = window.hermesDesktop?.getConnection + + if (!getConnection) { + return + } + + try { + setConnection(await getConnection(profile)) + } catch { + // Leave the prior connection in place; boot/reconnect resyncs it later. + } +} + // Make `profile`'s backend the active gateway, lazily opening its socket if it // isn't live yet. Unlike the old single-socket swap, background profiles keep // their sockets — so their sessions keep streaming concurrently. A null/empty @@ -218,6 +245,9 @@ export async function ensureGatewayProfile(profile: string | null | undefined): // the active gateway at it — without closing the profile you came from. await ensureGatewayForProfile(target) $activeGatewayProfile.set(target) + // The active backend just changed; resync $connection so remote-aware + // paths (image.attach_bytes vs image.attach, /api/fs/*, /api/media) follow. + await syncConnectionToActiveProfile(target) })() try {