Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions apps/desktop/src/app/contrib/hooks/use-background-sync.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { renderHook } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'

import { useBackgroundSync } from './use-background-sync'

describe('useBackgroundSync', () => {
it('force-reseeds the profile default for a fresh new-session draft', () => {
const refreshCurrentModel = vi.fn()

renderHook(() =>
useBackgroundSync({
activeIsMessaging: false,
activeSessionId: null,
freshDraftReady: true,
gatewayState: 'open',
refreshActiveMessagingTranscript: vi.fn(),
refreshCronJobs: vi.fn(),
refreshCurrentModel,
refreshHermesConfig: vi.fn(),
refreshMessagingSessions: vi.fn(),
refreshSessions: vi.fn(),
requestGateway: vi.fn()
})
)

expect(refreshCurrentModel).toHaveBeenCalledWith(true)
})

it('does not reseed the profile default while a live session is active', () => {
const refreshCurrentModel = vi.fn()

renderHook(() =>
useBackgroundSync({
activeIsMessaging: false,
activeSessionId: 'runtime-1',
freshDraftReady: true,
gatewayState: 'open',
refreshActiveMessagingTranscript: vi.fn(),
refreshCronJobs: vi.fn(),
refreshCurrentModel,
refreshHermesConfig: vi.fn(),
refreshMessagingSessions: vi.fn(),
refreshSessions: vi.fn(),
requestGateway: vi.fn()
})
)

expect(refreshCurrentModel).not.toHaveBeenCalledWith(true)
})
})
2 changes: 1 addition & 1 deletion apps/desktop/src/app/contrib/hooks/use-background-sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ export function useBackgroundSync({
// model + config so the composer pill reflects the profile default.
useEffect(() => {
if (gatewayState === 'open' && !activeSessionId && freshDraftReady) {
void refreshCurrentModel()
void refreshCurrentModel(true)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true overrides the deliberate sticky-composer contract: startFreshSessionDraft keeps the previous model/provider for new chats (apps/desktop/src/app/session/hooks/use-session-actions/index.ts:210-215), and refreshCurrentModel reserves force for profile swaps (apps/desktop/src/app/session/hooks/use-model-controls.ts:38-56). Please retain the non-forced call unless that product behavior is intentionally being changed.

void refreshHermesConfig()
}
}, [activeSessionId, freshDraftReady, gatewayState, refreshCurrentModel, refreshHermesConfig])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,10 @@ describe('useModelControls', () => {
await result.current.refreshCurrentModel()
expect($currentModel.get()).toBe('anthropic/claude-sonnet-4.6')

// A profile swap forces a reseed to the new profile's default.
// A fresh new chat (or profile swap) explicitly reseeds from the profile
// default instead of inheriting the prior sticky composer selection.
await result.current.refreshCurrentModel(true)
expect($currentModel.get()).toBe('openai/gpt-5.5')
expect($currentProvider.get()).toBe('openai-codex')
})
})