mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
fix(web): preserve draft Claude model options
via [HAPI](https://hapi.run) Co-Authored-By: HAPI <noreply@hapi.run>
This commit is contained in:
@@ -170,7 +170,11 @@ vi.mock('./ModelSelector', () => ({
|
||||
isDisabled: boolean
|
||||
isLoading?: boolean
|
||||
onModelChange: (model: string) => void
|
||||
}) => (
|
||||
}) => {
|
||||
const displayedModel = props.options && !props.options.some((option) => option.value === props.model)
|
||||
? props.options[0]?.value ?? props.model
|
||||
: props.model
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
@@ -178,11 +182,12 @@ vi.mock('./ModelSelector', () => ({
|
||||
disabled={props.isDisabled || props.isLoading}
|
||||
onClick={() => props.onModelChange('gpt-5.6-terra')}
|
||||
>
|
||||
{props.model}
|
||||
{displayedModel}
|
||||
</button>
|
||||
<div data-testid="model-options">{props.options?.map((option) => option.label).join(',')}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
}))
|
||||
vi.mock('./ReasoningEffortSelector', () => ({
|
||||
ReasoningEffortSelector: (props: { value: string; onChange: (effort: string) => void }) => (
|
||||
@@ -631,4 +636,49 @@ describe('NewSession launch preferences', () => {
|
||||
expect(screen.getByTestId('reasoning')).toHaveTextContent('max')
|
||||
})
|
||||
})
|
||||
|
||||
it('keeps a browse-return custom Claude model visible when it is no longer configured', async () => {
|
||||
savePreferredAgent('claude')
|
||||
saveNewSessionFormDraft({
|
||||
agent: 'claude',
|
||||
model: 'deepseek-v4-flash[1m]',
|
||||
cursorSelectedBase: 'auto',
|
||||
machineId: 'machine-1',
|
||||
effort: 'high',
|
||||
modelReasoningEffort: 'default',
|
||||
serviceTier: 'standard',
|
||||
collaborationMode: 'default',
|
||||
copilotAgentMode: 'interactive',
|
||||
yoloMode: false,
|
||||
codexFamilyPermissionMode: 'default',
|
||||
grokPermissionMode: 'default',
|
||||
sessionType: 'simple',
|
||||
worktreeName: ''
|
||||
})
|
||||
mocks.spawnSession.mockResolvedValue({ type: 'success', sessionId: 'session-1' })
|
||||
const claudeApi = {
|
||||
getClaudeCustomModels: vi.fn().mockResolvedValue({ models: [] })
|
||||
} as unknown as ApiClient
|
||||
|
||||
render(
|
||||
<NewSession
|
||||
api={claudeApi}
|
||||
machines={[machine]}
|
||||
initialMachineId="machine-1"
|
||||
initialDirectory="C:\\repo"
|
||||
onSuccess={mocks.onSuccess}
|
||||
onCancel={() => {}}
|
||||
/>
|
||||
)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('model')).toHaveTextContent('deepseek-v4-flash[1m]')
|
||||
expect(screen.getByTestId('create')).toBeEnabled()
|
||||
})
|
||||
fireEvent.click(screen.getByTestId('create'))
|
||||
|
||||
await waitFor(() => expect(mocks.spawnSession).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ model: 'deepseek-v4-flash[1m]' })
|
||||
))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -302,11 +302,20 @@ export function NewSession(props: {
|
||||
options.push({ value: modelName, label: modelName })
|
||||
}
|
||||
}
|
||||
if (
|
||||
agent === 'claude'
|
||||
&& model !== 'auto'
|
||||
&& !options.some((option) => option.value === model)
|
||||
) {
|
||||
options.splice(1, 0, { value: model, label: model })
|
||||
}
|
||||
return options
|
||||
}, [claudeCustomModels])
|
||||
}, [agent, claudeCustomModels, model])
|
||||
const claudePreferredModelValues = useMemo(
|
||||
() => agent === 'claude' ? claudeModelOptions.map((option) => option.value) : null,
|
||||
[agent, claudeModelOptions]
|
||||
() => agent === 'claude'
|
||||
? [...MODEL_OPTIONS.claude.map((option) => option.value), ...claudeCustomModels]
|
||||
: null,
|
||||
[agent, claudeCustomModels]
|
||||
)
|
||||
const claudeModelsLoading = agent === 'claude' && !claudeModelsLoaded
|
||||
const preferredModelCatalogReady = !claudeModelsLoading
|
||||
|
||||
Reference in New Issue
Block a user