From 5c6eee331ea6f8018f8b2b7d14b80c006d599a01 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 4 Aug 2026 12:35:25 +0000 Subject: [PATCH] fix(walkthrough): keep unauthenticated models out of the picker Treat an empty allowedProviderIds list as allow-none, disable Generate when no usable model is selected, and mute the button styling so it reads as unavailable rather than actionable. Co-authored-by: Serhii Dziupin --- .../model-picker/ModelPickerList.tsx | 5 ++++- .../views/walkthrough/WalkthroughBlocker.tsx | 2 +- .../views/walkthrough/WalkthroughView.tsx | 18 ++++++++++++------ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/ui/src/components/model-picker/ModelPickerList.tsx b/packages/ui/src/components/model-picker/ModelPickerList.tsx index f06dc190..99080f9c 100644 --- a/packages/ui/src/components/model-picker/ModelPickerList.tsx +++ b/packages/ui/src/components/model-picker/ModelPickerList.tsx @@ -436,7 +436,10 @@ export const ModelPickerList: React.FC = ({ ); const allowedProviderSet = React.useMemo(() => { - if (!allowedProviderIds || allowedProviderIds.length === 0) return null; + // undefined = no restriction; [] = allow none. Treating empty like + // "unrestricted" would resurface providers without a login in pickers that + // intentionally pass the authenticated-only list. + if (!allowedProviderIds) return null; return new Set(allowedProviderIds); }, [allowedProviderIds]); diff --git a/packages/ui/src/components/views/walkthrough/WalkthroughBlocker.tsx b/packages/ui/src/components/views/walkthrough/WalkthroughBlocker.tsx index 2f0af021..a9a620ac 100644 --- a/packages/ui/src/components/views/walkthrough/WalkthroughBlocker.tsx +++ b/packages/ui/src/components/views/walkthrough/WalkthroughBlocker.tsx @@ -150,7 +150,7 @@ export const WalkthroughBlocker = ({ onChange={(providerId, modelId) => { void handleModelChange(providerId, modelId); }} - allowedProviderIds={providers} + allowedProviderIds={providers ?? []} isModelAllowed={isStructuredOutputCapable} /> diff --git a/packages/ui/src/components/views/walkthrough/WalkthroughView.tsx b/packages/ui/src/components/views/walkthrough/WalkthroughView.tsx index 2c53641d..25a19097 100644 --- a/packages/ui/src/components/views/walkthrough/WalkthroughView.tsx +++ b/packages/ui/src/components/views/walkthrough/WalkthroughView.tsx @@ -331,7 +331,9 @@ export const WalkthroughView = ({ directory }: WalkthroughViewProps) => { const providerIsAuthenticated = (providerId: string | undefined) => { if (!providerId) return false; - if (modelProviders === undefined) return true; + // Until the auth list loads, do not present a candidate as selected — + // otherwise an unauthenticated config model flashes in the picker. + if (modelProviders === undefined) return false; return modelProviders.includes(providerId); }; const readinessModelRef = entry.readiness?.model @@ -442,9 +444,9 @@ export const WalkthroughView = ({ directory }: WalkthroughViewProps) => { const blockedRequiredChars = entry.error?.requiredChars ?? entry.readiness?.requiredChars; const blockedAvailableChars = entry.error?.availableChars ?? entry.readiness?.availableChars; - // Not ready means Generate must not look actionable — including when the - // resolved model has no login (reason no-provider-login). - const generateDisabled = Boolean(entry.readiness && !entry.readiness.ready); + // Not ready, or no usable selected model, means Generate must not look + // actionable — including when the resolved model has no login. + const generateDisabled = !activeModel || Boolean(entry.readiness && !entry.readiness.ready); const handleGenerate = useCallback( (force: boolean) => { @@ -571,7 +573,8 @@ export const WalkthroughView = ({ directory }: WalkthroughViewProps) => { onChange={(providerId, modelId) => { selectModel(directory, source, providerId && modelId ? `${providerId}/${modelId}` : null); }} - allowedProviderIds={modelProviders} + // While the auth list is loading, allow none — not every provider. + allowedProviderIds={modelProviders ?? []} isModelAllowed={isStructuredOutputCapable} tooltipsEnabled={false} dropdownPortalToBody @@ -619,7 +622,10 @@ export const WalkthroughView = ({ directory }: WalkthroughViewProps) => { type="button" variant="outline" size="sm" - className={WALKTHROUGH_ACTION_CLASS} + className={cn( + WALKTHROUGH_ACTION_CLASS, + generateDisabled && 'border-border bg-transparent text-muted-foreground hover:bg-transparent hover:text-muted-foreground', + )} disabled={generateDisabled} aria-label={compactHeader ? (view ? t('walkthrough.action.regenerate') : t('walkthrough.action.generate'))