import { afterEach, describe, expect, it, vi } from 'vitest' import { getGlobalModelOptions } from '@/hermes' import { manualPickRemoved, requestModelOptions } from './model-options' const globalOptions = { model: 'hermes-4', provider: 'nous', providers: [] } vi.mock('@/hermes', () => ({ getGlobalModelOptions: vi.fn(() => Promise.resolve(globalOptions)) })) describe('requestModelOptions', () => { afterEach(() => { vi.clearAllMocks() }) it('uses the connected gateway even before a session exists', async () => { const gatewayPayload = { model: 'BeastMode', provider: 'moa', providers: [] } const gateway = { request: vi.fn(() => Promise.resolve(gatewayPayload)) } await expect(requestModelOptions({ gateway: gateway as never, sessionId: null })).resolves.toBe(gatewayPayload) expect(gateway.request).toHaveBeenCalledWith('model.options', { explicit_only: true }) expect(getGlobalModelOptions).not.toHaveBeenCalled() }) it('passes the active session id and refresh flag through the gateway', async () => { const gateway = { request: vi.fn(() => Promise.resolve(globalOptions)) } await requestModelOptions({ gateway: gateway as never, refresh: true, sessionId: 'session-1' }) expect(gateway.request).toHaveBeenCalledWith('model.options', { explicit_only: true, refresh: true, session_id: 'session-1' }) }) it('falls back to REST when no gateway is connected', async () => { await requestModelOptions({ refresh: true }) expect(getGlobalModelOptions).toHaveBeenCalledWith({ explicitOnly: true, refresh: true }) }) }) describe('manualPickRemoved', () => { const providers = [ { name: 'OpenRouter', slug: 'openrouter', models: ['owl-alpha', 'gpt-5.5'] }, { name: 'Nous', slug: 'nous', models: [] } // present but unconfigured / re-auth ] it('flags a pick whose model was dropped from a populated provider', () => { expect(manualPickRemoved(providers, 'openrouter', 'nemotron-removed')).toBe(true) }) it('keeps a pick that is still in the catalog', () => { expect(manualPickRemoved(providers, 'openrouter', 'gpt-5.5')).toBe(false) }) it('matches the provider by name as well as slug', () => { expect(manualPickRemoved(providers, 'OpenRouter', 'gpt-5.5')).toBe(false) expect(manualPickRemoved(providers, 'OpenRouter', 'gone')).toBe(true) }) it('never clobbers when the provider is absent (ambiguous / deauth)', () => { expect(manualPickRemoved(providers, 'anthropic', 'claude-sonnet-4.6')).toBe(false) }) it('never clobbers when the provider has an empty model list (re-auth)', () => { expect(manualPickRemoved(providers, 'nous', 'hermes-4')).toBe(false) }) it('never clobbers on a not-yet-loaded or empty catalog', () => { expect(manualPickRemoved(undefined, 'openrouter', 'gpt-5.5')).toBe(false) expect(manualPickRemoved([], 'openrouter', 'gpt-5.5')).toBe(false) }) it('never clobbers when there is no pick', () => { expect(manualPickRemoved(providers, '', '')).toBe(false) }) })