mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
fix(web): gate Claude model interactions during restore
via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import type { ApiClient } from '@/api/client'
|
||||
import type { Machine } from '@/types/api'
|
||||
import { saveNewSessionFormDraft } from './newSessionFormDraft'
|
||||
@@ -156,10 +156,17 @@ vi.mock('./ModelSelector', () => ({
|
||||
ModelSelector: (props: {
|
||||
model: string
|
||||
options?: Array<{ value: string; label: string }>
|
||||
isDisabled: boolean
|
||||
isLoading?: boolean
|
||||
onModelChange: (model: string) => void
|
||||
}) => (
|
||||
<>
|
||||
<button type="button" data-testid="model" onClick={() => props.onModelChange('gpt-5.6-terra')}>
|
||||
<button
|
||||
type="button"
|
||||
data-testid="model"
|
||||
disabled={props.isDisabled || props.isLoading}
|
||||
onClick={() => props.onModelChange('gpt-5.6-terra')}
|
||||
>
|
||||
{props.model}
|
||||
</button>
|
||||
<div data-testid="model-options">{props.options?.map((option) => option.label).join(',')}</div>
|
||||
@@ -309,6 +316,52 @@ describe('NewSession launch preferences', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('blocks model changes and creation until custom Claude models load', async () => {
|
||||
savePreferredAgent('claude')
|
||||
savePreferredLaunchSettings('machine-1', 'claude', {
|
||||
model: 'deepseek-v4-flash[1m]',
|
||||
cursorSelectedBase: 'auto',
|
||||
effort: 'high',
|
||||
modelReasoningEffort: 'default'
|
||||
})
|
||||
let resolveModels!: (value: { models: string[] }) => void
|
||||
const claudeApi = {
|
||||
getClaudeCustomModels: vi.fn().mockReturnValue(new Promise((resolve) => {
|
||||
resolveModels = resolve
|
||||
}))
|
||||
} as unknown as ApiClient
|
||||
|
||||
render(
|
||||
<NewSession
|
||||
api={claudeApi}
|
||||
machines={[machine]}
|
||||
initialMachineId="machine-1"
|
||||
initialDirectory="C:\\repo"
|
||||
onSuccess={mocks.onSuccess}
|
||||
onCancel={() => {}}
|
||||
/>
|
||||
)
|
||||
|
||||
const model = screen.getByTestId('model')
|
||||
const create = screen.getByTestId('create')
|
||||
expect(model).toBeDisabled()
|
||||
expect(create).toBeDisabled()
|
||||
fireEvent.click(model)
|
||||
fireEvent.click(create)
|
||||
expect(model).toHaveTextContent('auto')
|
||||
expect(mocks.spawnSession).not.toHaveBeenCalled()
|
||||
|
||||
await act(async () => {
|
||||
resolveModels({ models: ['deepseek-v4-flash[1m]'] })
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(model).toHaveTextContent('deepseek-v4-flash[1m]')
|
||||
expect(model).toBeEnabled()
|
||||
expect(create).toBeEnabled()
|
||||
})
|
||||
})
|
||||
|
||||
it.each([
|
||||
['model', 'gpt-5.6-sol', 'default'],
|
||||
['reasoning effort', 'auto', 'xhigh']
|
||||
|
||||
@@ -308,7 +308,8 @@ export function NewSession(props: {
|
||||
() => agent === 'claude' ? claudeModelOptions.map((option) => option.value) : null,
|
||||
[agent, claudeModelOptions]
|
||||
)
|
||||
const preferredModelCatalogReady = agent !== 'claude' || claudeModelsLoaded
|
||||
const claudeModelsLoading = agent === 'claude' && !claudeModelsLoaded
|
||||
const preferredModelCatalogReady = !claudeModelsLoading
|
||||
const runnerSpawnError = useMemo(
|
||||
() => formatRunnerSpawnError(selectedMachine),
|
||||
[selectedMachine]
|
||||
@@ -1342,7 +1343,8 @@ export function NewSession(props: {
|
||||
}
|
||||
|
||||
const isLaunchPreferenceValidationPending =
|
||||
(agent === 'codex'
|
||||
claudeModelsLoading
|
||||
|| (agent === 'codex'
|
||||
&& (model !== 'auto' || modelReasoningEffort !== 'default')
|
||||
&& codexModelsState.isLoading)
|
||||
|| (agent === 'agy'
|
||||
@@ -1522,7 +1524,8 @@ export function NewSession(props: {
|
||||
|| (agent === 'grok' && Boolean(grokModelsState.error))
|
||||
|| (agent === 'copilot' && Boolean(copilotModelsState.error))
|
||||
}
|
||||
isLoading={(agent === 'codex' && codexModelsState.isLoading)
|
||||
isLoading={claudeModelsLoading
|
||||
|| (agent === 'codex' && codexModelsState.isLoading)
|
||||
|| (agent === 'grok' && grokModelsState.isLoading)
|
||||
|| (agent === 'copilot' && copilotModelsState.isLoading)}
|
||||
error={agent === 'codex' && codexModelsState.error
|
||||
|
||||
Reference in New Issue
Block a user