From 584d3ae532a07f77c38d24d47a420fadbfb5f29e Mon Sep 17 00:00:00 2001 From: Tranquil-Flow <66773372+Tranquil-Flow@users.noreply.github.com> Date: Thu, 18 Jun 2026 18:10:50 +0200 Subject: [PATCH] fix(desktop): extend profile startup REST timeouts (#48504) --- apps/desktop/src/hermes.test.ts | 44 ++++++++++++++++++++++++++++++- apps/desktop/src/hermes.ts | 4 ++- apps/desktop/src/store/profile.ts | 7 +++-- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/apps/desktop/src/hermes.test.ts b/apps/desktop/src/hermes.test.ts index 290f6aac96d..a32a91f3b11 100644 --- a/apps/desktop/src/hermes.test.ts +++ b/apps/desktop/src/hermes.test.ts @@ -1,6 +1,12 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { getSessionMessages, listAllProfileSessions, listSessions } from './hermes' +import { + getProfiles, + getSessionMessages, + listAllProfileSessions, + listSessions +} from './hermes' +import { refreshActiveProfile } from './store/profile' const emptySessionsResponse = { limit: 0, @@ -47,6 +53,42 @@ describe('Hermes REST session helpers', () => { ) }) + it('uses a longer timeout for profile listing during desktop startup', async () => { + api.mockResolvedValue({ profiles: [] }) + + await getProfiles() + + expect(api).toHaveBeenCalledWith( + expect.objectContaining({ + path: '/api/profiles', + timeoutMs: 60_000 + }) + ) + }) + + it('uses a longer timeout for active profile refresh during desktop startup', async () => { + api + .mockResolvedValueOnce({ current: 'default' }) + .mockResolvedValueOnce({ profiles: [] }) + + await refreshActiveProfile() + + expect(api).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + path: '/api/profiles/active', + timeoutMs: 60_000 + }) + ) + expect(api).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + path: '/api/profiles', + timeoutMs: 60_000 + }) + ) + }) + it('tags cross-profile message reads for Electron routing and backend lookup', async () => { api.mockResolvedValue({ messages: [], session_id: 'session-1' }) diff --git a/apps/desktop/src/hermes.ts b/apps/desktop/src/hermes.ts index 5006ce417ed..1c248c05fd2 100644 --- a/apps/desktop/src/hermes.ts +++ b/apps/desktop/src/hermes.ts @@ -47,6 +47,7 @@ import type { ToolsetInfo } from '@/types/hermes' +export const STARTUP_PROFILE_REQUEST_TIMEOUT_MS = 60_000 const DEFAULT_GATEWAY_REQUEST_TIMEOUT_MS = 30_000 const SESSION_LIST_REQUEST_TIMEOUT_MS = 60_000 // prompt.submit is effectively fire-and-forget: turn completion is signaled by @@ -702,7 +703,8 @@ export function deleteCronJob(jobId: string): Promise<{ ok: boolean }> { export function getProfiles(): Promise { return window.hermesDesktop.api({ - path: '/api/profiles' + path: '/api/profiles', + timeoutMs: STARTUP_PROFILE_REQUEST_TIMEOUT_MS }) } diff --git a/apps/desktop/src/store/profile.ts b/apps/desktop/src/store/profile.ts index 8c13c10669d..38ec723e54b 100644 --- a/apps/desktop/src/store/profile.ts +++ b/apps/desktop/src/store/profile.ts @@ -1,6 +1,6 @@ import { atom, computed } from 'nanostores' -import { getProfiles, setApiRequestProfile } from '@/hermes' +import { getProfiles, setApiRequestProfile, STARTUP_PROFILE_REQUEST_TIMEOUT_MS } from '@/hermes' import { queryClient } from '@/lib/query-client' import { arraysEqual, @@ -110,7 +110,10 @@ interface ActiveProfileResponse { // Best-effort: failures (backend not up yet) leave the prior values intact. export async function refreshActiveProfile(): Promise { try { - const res = await window.hermesDesktop.api({ path: '/api/profiles/active' }) + const res = await window.hermesDesktop.api({ + path: '/api/profiles/active', + timeoutMs: STARTUP_PROFILE_REQUEST_TIMEOUT_MS + }) setActiveProfile(res.current || 'default') } catch {