fix: clarify model refresh and onboarding providers

OpenCode is now a supported chat provider, but first-run onboarding still only offered
Claude, Cursor, Codex, and Gemini. That made OpenCode harder to discover and
forced users to finish setup before finding the provider in settings or chat.
Adding it to onboarding keeps first-run setup aligned with the providers the
application already supports elsewhere.

The model refresh control was also doing too much visual work. In the new chat
model picker, the previous Hard Refresh label looked like the dialog heading,
which made the primary task unclear. Users open that dialog to choose a model;
refreshing catalogs is only a secondary maintenance action for stale cached
provider model lists.

Rename and reposition the refresh affordance so the model picker reads as a
model picker first. The copy now explains why catalogs are cached, when a refresh
is useful, and that the refresh checks every provider. The /models modal gets the
same clarification so both model-selection surfaces describe the cache behavior
consistently.
This commit is contained in:
Haileyesus
2026-05-22 16:49:40 +03:00
parent 117f7f662d
commit 6ca0d38fa4
3 changed files with 56 additions and 34 deletions

View File

@@ -346,7 +346,7 @@ function ModelsContent({
return (
<div className="flex h-full min-h-0 flex-col gap-2.5">
<div className="rounded-2xl border border-border/70 bg-muted/20 p-2.5">
<div className="grid gap-2.5 lg:grid-cols-[minmax(0,1.75fr)_minmax(13rem,0.75fr)_auto] lg:items-start">
<div className="grid gap-2.5 lg:grid-cols-[minmax(0,1.55fr)_minmax(12rem,0.7fr)_minmax(15rem,0.9fr)] lg:items-start">
<div className="min-w-0">
<div className="flex flex-wrap items-center gap-2">
<Badge variant="secondary" className="rounded-lg border border-primary/20 bg-primary/10 px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.18em] text-primary">
@@ -387,17 +387,31 @@ function ModelsContent({
</div>
</div>
<Button
type="button"
variant="outline"
size="sm"
onClick={onHardRefreshProviderModels}
disabled={providerModelsRefreshing}
className="h-8 shrink-0 rounded-xl px-3 lg:self-start"
>
<RefreshCw className={providerModelsRefreshing ? 'animate-spin' : ''} />
{providerModelsRefreshing ? 'Refreshing...' : 'Hard Refresh'}
</Button>
<div className="rounded-xl border border-border/60 bg-background/55 p-2.5">
<div className="flex flex-wrap items-center gap-1.5">
<p className="text-[10px] font-bold uppercase tracking-[0.18em] text-foreground/80">
Catalog Refresh
</p>
<Badge variant="secondary" className="rounded-md px-1.5 py-0 text-[9px] uppercase tracking-[0.14em]">
All providers
</Badge>
</div>
<p className="mt-1.5 text-[11px] leading-4 text-muted-foreground">
Model lists are cached for 3 days. Refresh after CLI, auth, or config changes,
or when a new model is missing.
</p>
<Button
type="button"
variant="outline"
size="sm"
onClick={onHardRefreshProviderModels}
disabled={providerModelsRefreshing}
className="mt-2 h-8 w-full rounded-xl px-3"
>
<RefreshCw className={providerModelsRefreshing ? 'animate-spin' : ''} />
{providerModelsRefreshing ? 'Refreshing catalogs...' : 'Refresh from providers'}
</Button>
</div>
</div>
<div className="mt-2 border-t border-border/50 pt-1.5 text-[11px] text-muted-foreground">

View File

@@ -265,29 +265,29 @@ export default function ProviderSelectionEmptyState({
<DialogContent className="max-w-md overflow-hidden p-0">
<DialogTitle>Model Selector</DialogTitle>
<div className="border-b border-border/60 bg-muted/20 px-4 py-3">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<p className="text-sm font-semibold text-foreground">
Hard refresh model catalogs
</p>
<p className="mt-1 text-xs leading-5 text-muted-foreground">
Bypasses the 3-day backend cache and re-fetches models for every provider.
</p>
<p className="mt-1 text-[11px] text-muted-foreground">
Last updated for {getProviderDisplayName(provider)}: {formatUpdatedAt(currentProviderCache?.updatedAt)}
</p>
<div className="space-y-2">
<div className="flex flex-wrap items-start justify-between gap-3">
<div className="min-w-0 flex-1">
<p className="text-sm font-semibold text-foreground">Choose a model</p>
<p className="mt-0.5 text-xs leading-5 text-muted-foreground">
Catalogs are cached for 3 days. Refresh after CLI/auth changes or if a model is missing.
</p>
</div>
<Button
type="button"
variant="outline"
size="sm"
onClick={onHardRefreshProviderModels}
disabled={providerModelsRefreshing}
className="shrink-0 rounded-xl"
>
<RefreshCw className={providerModelsRefreshing ? "animate-spin" : ""} />
{providerModelsRefreshing ? "Refreshing..." : "Refresh"}
</Button>
</div>
<Button
type="button"
variant="outline"
size="sm"
onClick={onHardRefreshProviderModels}
disabled={providerModelsRefreshing}
className="shrink-0 rounded-xl"
>
<RefreshCw className={providerModelsRefreshing ? "animate-spin" : ""} />
{providerModelsRefreshing ? "Refreshing..." : "Hard Refresh"}
</Button>
<p className="text-[11px] text-muted-foreground">
Refresh checks every provider and replaces the cached catalogs. Last updated for {getProviderDisplayName(provider)}: {formatUpdatedAt(currentProviderCache?.updatedAt)}
</p>
</div>
</div>
<Command>

View File

@@ -1,5 +1,6 @@
import type { LLMProvider } from '../../../../types/app';
import type { ProviderAuthStatusMap } from '../../../provider-auth/types';
import AgentConnectionCard from './AgentConnectionCard';
type AgentConnectionsStepProps = {
@@ -36,6 +37,13 @@ const providerCards = [
iconContainerClassName: 'bg-teal-100 dark:bg-teal-900/30',
loginButtonClassName: 'bg-teal-600 hover:bg-teal-700',
},
{
provider: 'opencode' as const,
title: 'OpenCode',
connectedClassName: 'bg-zinc-100 dark:bg-zinc-800/50 border-zinc-300 dark:border-zinc-600',
iconContainerClassName: 'bg-zinc-100 dark:bg-zinc-800',
loginButtonClassName: 'bg-zinc-800 hover:bg-zinc-900 dark:bg-zinc-700 dark:hover:bg-zinc-600',
},
];
export default function AgentConnectionsStep({