diff --git a/apps/web/src/components/chat/modelPickerEmptyState.ts b/apps/web/src/components/chat/modelPickerEmptyState.ts index 868fcd69a..1cb3a9290 100644 --- a/apps/web/src/components/chat/modelPickerEmptyState.ts +++ b/apps/web/src/components/chat/modelPickerEmptyState.ts @@ -105,12 +105,11 @@ export function resolveModelPickerEmptyState(input: { }; } - if (input.activeTabKind === "favorites") { - return { lines: ["No favorite models"], showSettingsAction: false }; - } - // Nothing to pick and every provider the user enabled is unusable: name - // each one instead of leaving them to guess which is broken. + // each one instead of leaving them to guess which is broken. This wins + // over the Favorites empty text because a cold install has no usable + // provider tabs at all, so Favorites is the only tab the picker can open + // on and its bare "No favorite models" would hide the one actionable fact. const enabledProviders = input.providers.filter((provider) => provider.enabled); const unavailableProviders = enabledProviders.filter( (provider) => getModelPickerProviderAvailability(provider.snapshot) !== "available", @@ -124,5 +123,9 @@ export function resolveModelPickerEmptyState(input: { }; } + if (input.activeTabKind === "favorites") { + return { lines: ["No favorite models"], showSettingsAction: false }; + } + return { lines: ["No models available"], showSettingsAction: false }; } diff --git a/apps/web/src/components/chat/modelPickerSearch.test.ts b/apps/web/src/components/chat/modelPickerSearch.test.ts index b44bb0512..c017e77b1 100644 --- a/apps/web/src/components/chat/modelPickerSearch.test.ts +++ b/apps/web/src/components/chat/modelPickerSearch.test.ts @@ -246,13 +246,34 @@ describe("resolveModelPickerEmptyState", () => { ).toEqual({ lines: ["No models available"], showSettingsAction: false }); }); - it("keeps the favorites tab message provider-agnostic", () => { + it("keeps the favorites tab message while a provider is still usable", () => { expect( resolveModelPickerEmptyState({ searchQuery: "", activeTabKind: "favorites", - providers: [CLAUDE_MISSING], + providers: [CODEX_READY, CLAUDE_MISSING], }), ).toEqual({ lines: ["No favorite models"], showSettingsAction: false }); }); + + it("explains providers from the favorites tab on a cold install", () => { + // A cold install has no usable provider tabs, so Favorites is the only + // tab the picker can open on; the provider guidance must win there too. + expect( + resolveModelPickerEmptyState({ + searchQuery: "", + activeTabKind: "favorites", + providers: [ + makeProvider("codex", "Codex", { + status: "warning", + auth: { status: "unauthenticated" }, + }), + CLAUDE_MISSING, + ], + }), + ).toEqual({ + lines: ["Codex · Not authenticated", "Claude · Not found"], + showSettingsAction: true, + }); + }); });