From 35f17e9e96be0ca5ef6a940bf7c95d45859ea57f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 4 Aug 2026 12:22:54 +0000 Subject: [PATCH] fix(walkthrough): hide unauthenticated models and disable Generate Do not present a provider without a login as the selected walkthrough model, and grey out Generate when readiness is false instead of showing a login-error blocker or raw auth banner. Co-authored-by: Serhii Dziupin --- .../views/walkthrough/WalkthroughBlocker.tsx | 9 +--- .../views/walkthrough/WalkthroughView.tsx | 46 +++++++++++++++---- packages/ui/src/lib/i18n/messages/de.ts | 3 -- packages/ui/src/lib/i18n/messages/en.ts | 3 -- packages/ui/src/lib/i18n/messages/es.ts | 3 -- packages/ui/src/lib/i18n/messages/fr.ts | 3 -- packages/ui/src/lib/i18n/messages/ja.ts | 3 -- packages/ui/src/lib/i18n/messages/ko.ts | 3 -- packages/ui/src/lib/i18n/messages/pl.ts | 3 -- packages/ui/src/lib/i18n/messages/pt-BR.ts | 3 -- packages/ui/src/lib/i18n/messages/uk.ts | 3 -- packages/ui/src/lib/i18n/messages/zh-CN.ts | 3 -- packages/ui/src/lib/i18n/messages/zh-TW.ts | 3 -- packages/ui/src/lib/walkthrough/types.ts | 2 + .../server/lib/walkthrough/DOCUMENTATION.md | 7 +-- packages/web/server/lib/walkthrough/index.js | 5 +- .../lib/walkthrough/reproduce-2607.test.js | 7 +-- 17 files changed, 49 insertions(+), 60 deletions(-) diff --git a/packages/ui/src/components/views/walkthrough/WalkthroughBlocker.tsx b/packages/ui/src/components/views/walkthrough/WalkthroughBlocker.tsx index f23696be..2f0af021 100644 --- a/packages/ui/src/components/views/walkthrough/WalkthroughBlocker.tsx +++ b/packages/ui/src/components/views/walkthrough/WalkthroughBlocker.tsx @@ -41,8 +41,7 @@ export const WalkthroughBlocker = ({ // Settings. const canChooseModel = reason === 'context-too-small' || reason === 'structured-output-unsupported' - || reason === 'output-exhausted' - || reason === 'no-provider-login'; + || reason === 'output-exhausted'; useEffect(() => { if (!canChooseModel || providers !== undefined) return; @@ -101,11 +100,6 @@ export const WalkthroughBlocker = ({ const description = () => { if (reason === 'no-model') return t('walkthrough.blocked.noModel.description'); - if (reason === 'no-provider-login') { - return label - ? t('walkthrough.blocked.noProviderLogin.description', { model: label }) - : t('walkthrough.blocked.noProviderLogin.descriptionUnknownModel'); - } if (reason === 'empty-diff') return t('walkthrough.blocked.emptyDiff.description'); if (reason === 'only-generated') return t('walkthrough.blocked.onlyGenerated.description'); if (reason === 'output-exhausted') { @@ -129,7 +123,6 @@ export const WalkthroughBlocker = ({ const title = () => { if (reason === 'no-model') return t('walkthrough.blocked.noModel.title'); - if (reason === 'no-provider-login') return t('walkthrough.blocked.noProviderLogin.title'); if (reason === 'empty-diff') return t('walkthrough.blocked.emptyDiff.title'); if (reason === 'only-generated') return t('walkthrough.blocked.onlyGenerated.title'); if (reason === 'output-exhausted') return t('walkthrough.blocked.outputExhausted.title'); diff --git a/packages/ui/src/components/views/walkthrough/WalkthroughView.tsx b/packages/ui/src/components/views/walkthrough/WalkthroughView.tsx index 15b9baa8..2c53641d 100644 --- a/packages/ui/src/components/views/walkthrough/WalkthroughView.tsx +++ b/packages/ui/src/components/views/walkthrough/WalkthroughView.tsx @@ -323,15 +323,34 @@ export const WalkthroughView = ({ directory }: WalkthroughViewProps) => { // Explicit pick first, then the model that actually produced what is on // screen, then whatever settings resolve to. The middle step is what makes // reopening a review show the model behind it rather than the default. - const activeModel = selectedModel - ?? (entry.result?.model ? `${entry.result.model.providerID}/${entry.result.model.modelID}` : undefined) - ?? (entry.readiness?.model ? `${entry.readiness.model.providerID}/${entry.readiness.model.modelID}` : undefined); - const [activeProviderId, ...activeModelParts] = (activeModel ?? '').split('/'); - const activeModelId = activeModelParts.join('/'); - + // Never present a provider without a usable login as the current selection — + // the picker already hides them from the menu; showing one as selected was + // the whole "why say so?" failure mode. const modelsMetadata = useConfigStore((state) => state.modelsMetadata); const [modelProviders, setModelProviders] = useState(undefined); + const providerIsAuthenticated = (providerId: string | undefined) => { + if (!providerId) return false; + if (modelProviders === undefined) return true; + return modelProviders.includes(providerId); + }; + const readinessModelRef = entry.readiness?.model + && entry.readiness.model.hasLogin !== false + && providerIsAuthenticated(entry.readiness.model.providerID) + ? `${entry.readiness.model.providerID}/${entry.readiness.model.modelID}` + : undefined; + const resultModelRef = entry.result?.model + && providerIsAuthenticated(entry.result.model.providerID) + ? `${entry.result.model.providerID}/${entry.result.model.modelID}` + : undefined; + const selectedModelUsable = selectedModel + && providerIsAuthenticated(selectedModel.split('/')[0]) + ? selectedModel + : undefined; + const activeModel = selectedModelUsable ?? resultModelRef ?? readinessModelRef; + const [activeProviderId, ...activeModelParts] = (activeModel ?? '').split('/'); + const activeModelId = activeModelParts.join('/'); + useEffect(() => { if (modelProviders !== undefined) return; let cancelled = false; @@ -403,15 +422,17 @@ export const WalkthroughView = ({ directory }: WalkthroughViewProps) => { const showStages = startedFromEmptyRef.current && (entry.status === 'generating' || stageProgress.holding); + // Auth/login gaps are not a full-panel blocker: hide the unusable model and + // disable Generate instead of explaining a raw provider error. const blockedReason = entry.error?.code === 'context-too-small' || entry.error?.code === 'structured-output-unsupported' || entry.error?.code === 'no-model' - || entry.error?.code === 'no-provider-login' || entry.error?.code === 'empty-diff' || entry.error?.code === 'only-generated' || entry.error?.code === 'output-exhausted' ? entry.error.code : entry.readiness && !entry.readiness.ready && !view + && entry.readiness.reason !== 'no-provider-login' ? entry.readiness.reason : undefined; @@ -421,11 +442,16 @@ 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); + const handleGenerate = useCallback( (force: boolean) => { + if (generateDisabled) return; void generate(directory, source, { force, language: activeLanguage }); }, - [activeLanguage, directory, generate, source] + [activeLanguage, directory, generate, generateDisabled, source] ); return ( @@ -594,6 +620,7 @@ export const WalkthroughView = ({ directory }: WalkthroughViewProps) => { variant="outline" size="sm" className={WALKTHROUGH_ACTION_CLASS} + disabled={generateDisabled} aria-label={compactHeader ? (view ? t('walkthrough.action.regenerate') : t('walkthrough.action.generate')) : undefined} @@ -647,6 +674,7 @@ export const WalkthroughView = ({ directory }: WalkthroughViewProps) => { variant="ghost" size="xs" className="ml-auto" + disabled={generateDisabled} // Not forced: if an entry for this exact request existed the banner // would not be here, and a forced run would refuse the cache it may // find on the way. @@ -678,7 +706,7 @@ export const WalkthroughView = ({ directory }: WalkthroughViewProps) => { )} - {entry.error && !blockedReason && ( + {entry.error && !blockedReason && entry.error.code !== 'no-provider-login' && (
{/* Provider errors arrive as raw JSON bodies. Show a readable amount diff --git a/packages/ui/src/lib/i18n/messages/de.ts b/packages/ui/src/lib/i18n/messages/de.ts index 4f353026..0db76c86 100644 --- a/packages/ui/src/lib/i18n/messages/de.ts +++ b/packages/ui/src/lib/i18n/messages/de.ts @@ -2866,9 +2866,6 @@ export const dict = { 'walkthrough.importance.context': 'Kontext', 'walkthrough.blocked.noModel.title': 'Kein Modell ausgewählt', 'walkthrough.blocked.noModel.description': 'Wählen Sie zuerst ein Modell aus.', - 'walkthrough.blocked.noProviderLogin.title': 'Dieser Anbieter ist nicht angemeldet', - 'walkthrough.blocked.noProviderLogin.description': '{model} braucht eine Anmeldung bei seinem Anbieter. Melde dich an oder wähle ein Modell eines Anbieters, den du bereits nutzt.', - 'walkthrough.blocked.noProviderLogin.descriptionUnknownModel': 'Das ausgewählte Modell braucht eine Anmeldung bei seinem Anbieter. Melde dich an oder wähle ein Modell eines Anbieters, den du bereits nutzt.', 'walkthrough.blocked.emptyDiff.title': 'Kein Diff vorhanden', 'walkthrough.blocked.emptyDiff.description': 'Es gibt keine Änderungen, die zusammengefasst werden können.', 'walkthrough.blocked.contextTooSmall.title': 'Kontext zu klein', diff --git a/packages/ui/src/lib/i18n/messages/en.ts b/packages/ui/src/lib/i18n/messages/en.ts index 53929a2f..17d137e5 100644 --- a/packages/ui/src/lib/i18n/messages/en.ts +++ b/packages/ui/src/lib/i18n/messages/en.ts @@ -1147,9 +1147,6 @@ export const dict = { 'walkthrough.importance.context': 'Context', 'walkthrough.blocked.noModel.title': 'No small model available', 'walkthrough.blocked.noModel.description': 'Sign in to a model provider to generate a review.', - 'walkthrough.blocked.noProviderLogin.title': 'This provider is not signed in', - 'walkthrough.blocked.noProviderLogin.description': '{model} needs a login for its provider. Sign in, or choose a model from a provider you already use.', - 'walkthrough.blocked.noProviderLogin.descriptionUnknownModel': 'The selected model needs a login for its provider. Sign in, or choose a model from a provider you already use.', 'walkthrough.blocked.emptyDiff.title': 'Nothing to review', 'walkthrough.blocked.emptyDiff.description': 'There are no changes in this scope yet.', 'walkthrough.blocked.contextTooSmall.title': 'This diff is too large for the current model', diff --git a/packages/ui/src/lib/i18n/messages/es.ts b/packages/ui/src/lib/i18n/messages/es.ts index 140e686e..ea5086d0 100644 --- a/packages/ui/src/lib/i18n/messages/es.ts +++ b/packages/ui/src/lib/i18n/messages/es.ts @@ -1148,9 +1148,6 @@ export const dict: Record = { "walkthrough.importance.context": "Contexto", "walkthrough.blocked.noModel.title": "No hay ningún modelo pequeño disponible", "walkthrough.blocked.noModel.description": "Inicia sesión en un proveedor de modelos para generar una revisión.", - "walkthrough.blocked.noProviderLogin.title": "Este proveedor no tiene sesión iniciada", - "walkthrough.blocked.noProviderLogin.description": "{model} necesita un inicio de sesión en su proveedor. Inicia sesión o elige un modelo de un proveedor que ya uses.", - "walkthrough.blocked.noProviderLogin.descriptionUnknownModel": "El modelo seleccionado necesita un inicio de sesión en su proveedor. Inicia sesión o elige un modelo de un proveedor que ya uses.", "walkthrough.blocked.emptyDiff.title": "Nada que revisar", "walkthrough.blocked.emptyDiff.description": "Todavía no hay cambios en este ámbito.", "walkthrough.blocked.contextTooSmall.title": "Este diff es demasiado grande para el modelo actual", diff --git a/packages/ui/src/lib/i18n/messages/fr.ts b/packages/ui/src/lib/i18n/messages/fr.ts index 479033dc..3a625450 100644 --- a/packages/ui/src/lib/i18n/messages/fr.ts +++ b/packages/ui/src/lib/i18n/messages/fr.ts @@ -972,9 +972,6 @@ export const dict = { 'walkthrough.importance.context': 'Contexte', 'walkthrough.blocked.noModel.title': 'Aucun petit modèle disponible', 'walkthrough.blocked.noModel.description': 'Connectez-vous à un fournisseur de modèles pour générer une revue.', - 'walkthrough.blocked.noProviderLogin.title': 'Ce fournisseur n’est pas connecté', - 'walkthrough.blocked.noProviderLogin.description': '{model} nécessite une connexion à son fournisseur. Connectez-vous, ou choisissez un modèle d’un fournisseur que vous utilisez déjà.', - 'walkthrough.blocked.noProviderLogin.descriptionUnknownModel': 'Le modèle sélectionné nécessite une connexion à son fournisseur. Connectez-vous, ou choisissez un modèle d’un fournisseur que vous utilisez déjà.', 'walkthrough.blocked.emptyDiff.title': 'Rien à examiner', 'walkthrough.blocked.emptyDiff.description': 'Il n’y a encore aucune modification dans cette portée.', 'walkthrough.blocked.contextTooSmall.title': 'Ce diff est trop volumineux pour le modèle actuel', diff --git a/packages/ui/src/lib/i18n/messages/ja.ts b/packages/ui/src/lib/i18n/messages/ja.ts index ed810851..181ec3e9 100644 --- a/packages/ui/src/lib/i18n/messages/ja.ts +++ b/packages/ui/src/lib/i18n/messages/ja.ts @@ -1144,9 +1144,6 @@ export const dict: Record = { 'walkthrough.importance.context': '補足', 'walkthrough.blocked.noModel.title': '利用できるスモールモデルがありません', 'walkthrough.blocked.noModel.description': 'レビューを生成するにはモデルプロバイダーにサインインしてください。', - 'walkthrough.blocked.noProviderLogin.title': 'このプロバイダーにはサインインしていません', - 'walkthrough.blocked.noProviderLogin.description': '{model} にはプロバイダーへのログインが必要です。サインインするか、すでに使っているプロバイダーのモデルを選んでください。', - 'walkthrough.blocked.noProviderLogin.descriptionUnknownModel': '選択したモデルにはプロバイダーへのログインが必要です。サインインするか、すでに使っているプロバイダーのモデルを選んでください。', 'walkthrough.blocked.emptyDiff.title': 'レビュー対象がありません', 'walkthrough.blocked.emptyDiff.description': 'この範囲にはまだ変更がありません。', 'walkthrough.blocked.contextTooSmall.title': 'この差分は現在のモデルには大きすぎます', diff --git a/packages/ui/src/lib/i18n/messages/ko.ts b/packages/ui/src/lib/i18n/messages/ko.ts index d9d68816..150a56ce 100644 --- a/packages/ui/src/lib/i18n/messages/ko.ts +++ b/packages/ui/src/lib/i18n/messages/ko.ts @@ -1148,9 +1148,6 @@ export const dict: Record = { 'walkthrough.importance.context': '참고', 'walkthrough.blocked.noModel.title': '사용할 수 있는 스몰 모델이 없습니다', 'walkthrough.blocked.noModel.description': '리뷰를 생성하려면 모델 제공자에 로그인하세요.', - 'walkthrough.blocked.noProviderLogin.title': '이 제공자에 로그인되어 있지 않습니다', - 'walkthrough.blocked.noProviderLogin.description': '{model}을(를) 쓰려면 해당 제공자에 로그인해야 합니다. 로그인하거나, 이미 사용 중인 제공자의 모델을 선택하세요.', - 'walkthrough.blocked.noProviderLogin.descriptionUnknownModel': '선택한 모델을 쓰려면 해당 제공자에 로그인해야 합니다. 로그인하거나, 이미 사용 중인 제공자의 모델을 선택하세요.', 'walkthrough.blocked.emptyDiff.title': '리뷰할 내용이 없습니다', 'walkthrough.blocked.emptyDiff.description': '이 범위에는 아직 변경 사항이 없습니다.', 'walkthrough.blocked.contextTooSmall.title': '이 diff는 현재 모델에 너무 큽니다', diff --git a/packages/ui/src/lib/i18n/messages/pl.ts b/packages/ui/src/lib/i18n/messages/pl.ts index 949b745f..8f93e1f6 100644 --- a/packages/ui/src/lib/i18n/messages/pl.ts +++ b/packages/ui/src/lib/i18n/messages/pl.ts @@ -1460,9 +1460,6 @@ export const dict: Record = { 'walkthrough.importance.context': 'Kontekst', 'walkthrough.blocked.noModel.title': 'Brak dostępnego małego modelu', 'walkthrough.blocked.noModel.description': 'Zaloguj się u dostawcy modeli, aby wygenerować przegląd.', - 'walkthrough.blocked.noProviderLogin.title': 'Ten dostawca nie jest zalogowany', - 'walkthrough.blocked.noProviderLogin.description': '{model} wymaga logowania u swojego dostawcy. Zaloguj się albo wybierz model u dostawcy, którego już używasz.', - 'walkthrough.blocked.noProviderLogin.descriptionUnknownModel': 'Wybrany model wymaga logowania u swojego dostawcy. Zaloguj się albo wybierz model u dostawcy, którego już używasz.', 'walkthrough.blocked.emptyDiff.title': 'Nie ma czego przeglądać', 'walkthrough.blocked.emptyDiff.description': 'W tym zakresie nie ma jeszcze zmian.', 'walkthrough.blocked.contextTooSmall.title': 'Te różnice są za duże dla bieżącego modelu', diff --git a/packages/ui/src/lib/i18n/messages/pt-BR.ts b/packages/ui/src/lib/i18n/messages/pt-BR.ts index 6c79996a..44fef67a 100644 --- a/packages/ui/src/lib/i18n/messages/pt-BR.ts +++ b/packages/ui/src/lib/i18n/messages/pt-BR.ts @@ -1148,9 +1148,6 @@ export const dict: Record = { "walkthrough.importance.context": "Contexto", "walkthrough.blocked.noModel.title": "Nenhum modelo pequeno disponível", "walkthrough.blocked.noModel.description": "Entre em um provedor de modelos para gerar uma revisão.", - "walkthrough.blocked.noProviderLogin.title": "Este provedor não está conectado", - "walkthrough.blocked.noProviderLogin.description": "{model} precisa de login no provedor. Entre na conta ou escolha um modelo de um provedor que você já usa.", - "walkthrough.blocked.noProviderLogin.descriptionUnknownModel": "O modelo selecionado precisa de login no provedor. Entre na conta ou escolha um modelo de um provedor que você já usa.", "walkthrough.blocked.emptyDiff.title": "Nada para revisar", "walkthrough.blocked.emptyDiff.description": "Ainda não há mudanças neste escopo.", "walkthrough.blocked.contextTooSmall.title": "Este diff é grande demais para o modelo atual", diff --git a/packages/ui/src/lib/i18n/messages/uk.ts b/packages/ui/src/lib/i18n/messages/uk.ts index 6005df66..c8663cea 100644 --- a/packages/ui/src/lib/i18n/messages/uk.ts +++ b/packages/ui/src/lib/i18n/messages/uk.ts @@ -1148,9 +1148,6 @@ export const dict: Record = { "walkthrough.importance.context": "Контекст", "walkthrough.blocked.noModel.title": "Немає доступної small model", "walkthrough.blocked.noModel.description": "Увійдіть до провайдера моделей, щоб створити розбір.", - "walkthrough.blocked.noProviderLogin.title": "У цей провайдер не ввійшли", - "walkthrough.blocked.noProviderLogin.description": "{model} потребує входу в його провайдер. Увійдіть або виберіть модель у провайдера, яким ви вже користуєтесь.", - "walkthrough.blocked.noProviderLogin.descriptionUnknownModel": "Вибрана модель потребує входу в її провайдер. Увійдіть або виберіть модель у провайдера, яким ви вже користуєтесь.", "walkthrough.blocked.emptyDiff.title": "Немає що оглядати", "walkthrough.blocked.emptyDiff.description": "У цій області поки що немає змін.", "walkthrough.blocked.contextTooSmall.title": "Цей diff завеликий для поточної моделі", diff --git a/packages/ui/src/lib/i18n/messages/zh-CN.ts b/packages/ui/src/lib/i18n/messages/zh-CN.ts index 551b95cf..76ffac2f 100644 --- a/packages/ui/src/lib/i18n/messages/zh-CN.ts +++ b/packages/ui/src/lib/i18n/messages/zh-CN.ts @@ -1148,9 +1148,6 @@ export const dict: Record = { 'walkthrough.importance.context': '背景', 'walkthrough.blocked.noModel.title': '没有可用的小模型', 'walkthrough.blocked.noModel.description': '请登录模型提供方后再生成评审。', - 'walkthrough.blocked.noProviderLogin.title': '尚未登录此提供方', - 'walkthrough.blocked.noProviderLogin.description': '{model} 需要登录其提供方。请先登录,或改选你已在使用的提供方中的模型。', - 'walkthrough.blocked.noProviderLogin.descriptionUnknownModel': '所选模型需要登录其提供方。请先登录,或改选你已在使用的提供方中的模型。', 'walkthrough.blocked.emptyDiff.title': '没有可评审的内容', 'walkthrough.blocked.emptyDiff.description': '该范围内暂无改动。', 'walkthrough.blocked.contextTooSmall.title': '当前模型无法容纳这份差异', diff --git a/packages/ui/src/lib/i18n/messages/zh-TW.ts b/packages/ui/src/lib/i18n/messages/zh-TW.ts index 95b0af8b..3538d59c 100644 --- a/packages/ui/src/lib/i18n/messages/zh-TW.ts +++ b/packages/ui/src/lib/i18n/messages/zh-TW.ts @@ -1160,9 +1160,6 @@ export const dict: Record = { 'walkthrough.importance.context': '背景', 'walkthrough.blocked.noModel.title': '沒有可用的小模型', 'walkthrough.blocked.noModel.description': '請先登入模型供應商再產生審閱。', - 'walkthrough.blocked.noProviderLogin.title': '尚未登入此供應商', - 'walkthrough.blocked.noProviderLogin.description': '{model} 需要登入其供應商。請先登入,或改選你已在使用的供應商中的模型。', - 'walkthrough.blocked.noProviderLogin.descriptionUnknownModel': '所選模型需要登入其供應商。請先登入,或改選你已在使用的供應商中的模型。', 'walkthrough.blocked.emptyDiff.title': '沒有可審閱的內容', 'walkthrough.blocked.emptyDiff.description': '此範圍目前沒有變更。', 'walkthrough.blocked.contextTooSmall.title': '目前模型無法容納這份差異', diff --git a/packages/ui/src/lib/walkthrough/types.ts b/packages/ui/src/lib/walkthrough/types.ts index 40bfd62e..5f8ef80a 100644 --- a/packages/ui/src/lib/walkthrough/types.ts +++ b/packages/ui/src/lib/walkthrough/types.ts @@ -105,6 +105,8 @@ export interface WalkthroughReadiness { inputCharBudget?: number; contextTokens?: number; structuredOutput?: boolean | null; + /** False when the resolved provider has no usable OpenCode login. */ + hasLogin?: boolean; }; requiredChars?: number; availableChars?: number; diff --git a/packages/web/server/lib/walkthrough/DOCUMENTATION.md b/packages/web/server/lib/walkthrough/DOCUMENTATION.md index 63997184..0f23fac5 100644 --- a/packages/web/server/lib/walkthrough/DOCUMENTATION.md +++ b/packages/web/server/lib/walkthrough/DOCUMENTATION.md @@ -121,9 +121,10 @@ silently changes the model behind commit messages. A settings or `opencode.json` `small_model` override can still name a provider with no usable login (neither `auth.json` nor `provider..options.apiKey`). `describeSmallModel` reports that as `hasLogin: false`, readiness refuses with -`code: 'no-provider-login'`, and generation maps the same code to HTTP 401 — -so the panel shows a blocker with a model picker instead of looking ready and -then dumping the raw `No OpenCode login found for provider "…"` string. +`reason: 'no-provider-login'` and omits the unusable model so the panel cannot +present it as selected, and generation maps the same code to HTTP 401. The UI +disables Generate and keeps the picker on authenticated providers only — it does +not surface a raw auth error or a special login blocker for this case. ## Output language diff --git a/packages/web/server/lib/walkthrough/index.js b/packages/web/server/lib/walkthrough/index.js index 057a2c58..f65d3e2f 100644 --- a/packages/web/server/lib/walkthrough/index.js +++ b/packages/web/server/lib/walkthrough/index.js @@ -334,9 +334,10 @@ function computeReadiness({ model, digest, files, fileCount, hunkCount, generate } // A resolved override/config model can still have no usable login. Refuse up - // front so the panel does not look ready and then dump a raw auth error. + // front and omit the model — offering an unauthenticated selection in the + // picker is what made the old raw auth error feel like a product bug. if (model.hasLogin === false) { - return { ready: false, reason: 'no-provider-login', model }; + return { ready: false, reason: 'no-provider-login' }; } // Built with the same language the generation would use: the instruction is diff --git a/packages/web/server/lib/walkthrough/reproduce-2607.test.js b/packages/web/server/lib/walkthrough/reproduce-2607.test.js index 7ef6c15c..8cca6e55 100644 --- a/packages/web/server/lib/walkthrough/reproduce-2607.test.js +++ b/packages/web/server/lib/walkthrough/reproduce-2607.test.js @@ -90,11 +90,8 @@ describe('issue 2607 — walkthrough blocks unauthenticated providers', () => { expect(result.readiness.ready).toBe(false); expect(result.readiness.reason).toBe('no-provider-login'); - expect(result.readiness.model).toMatchObject({ - providerID: 'deepseek', - modelID: 'deepseek-v4-flash', - hasLogin: false, - }); + // Unusable models must not be offered as the current selection. + expect(result.readiness.model).toBeUndefined(); }); it('callSmallModel throws a structured no-provider-login error', async () => {