Browse Source

fix: show provider filter icons for env-configured providers too

The ModelSearchDialog only checked client-side localStorage keys to
determine available providers, missing providers configured via .env
server-side vars. Now the /api/models endpoint returns an
availableProviders array and the dialog merges both sources.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 4 months ago
parent
commit
0a7210d337
  1. 9
      src/app/api/models/route.ts
  2. 16
      src/components/modals/ModelSearchDialog.tsx

9
src/app/api/models/route.ts

@ -499,6 +499,8 @@ interface ModelsSuccessResponse {
models: ProviderModel[];
cached: boolean;
providers: Record<string, ProviderResult>;
/** All providers that have API keys configured (env or client header) */
availableProviders: string[];
errors?: string[];
}
@ -952,6 +954,12 @@ export async function GET(
const kieKey = request.headers.get("X-Kie-Key") || process.env.KIE_API_KEY || null;
const wavespeedKey = request.headers.get("X-WaveSpeed-Key") || process.env.WAVESPEED_API_KEY || null;
// Build list of all available providers (have keys from env or client headers)
const availableProviders: string[] = ["gemini", "fal"]; // Always available
if (replicateKey) availableProviders.push("replicate");
if (kieKey) availableProviders.push("kie");
if (wavespeedKey) availableProviders.push("wavespeed");
// Determine which providers to fetch from (excluding gemini/kie - handled separately as hardcoded)
const providersToFetch: ProviderType[] = [];
let includeGemini = false;
@ -1160,6 +1168,7 @@ export async function GET(
models: filteredModels,
cached: anyFromCache && allFromCache,
providers: providerResults,
availableProviders,
};
if (errors.length > 0) {

16
src/components/modals/ModelSearchDialog.tsx

@ -95,6 +95,8 @@ type CapabilityFilter = "all" | "image" | "video" | "3d" | "audio";
interface ModelsResponse {
success: boolean;
models?: ProviderModel[];
/** Providers with API keys configured (env or client header) */
availableProviders?: string[];
error?: string;
}
@ -138,6 +140,7 @@ export function ModelSearchDialog({
const [isLoading, setIsLoading] = useState(false);
const [isRefreshing, setIsRefreshing] = useState(false);
const [error, setError] = useState<string | null>(null);
const [serverAvailableProviders, setServerAvailableProviders] = useState<string[]>([]);
// Refs
const searchInputRef = useRef<HTMLInputElement>(null);
@ -241,6 +244,10 @@ export function ModelSearchDialog({
setModels(data.models);
// Cache the successful result
setCachedModels(cacheKey, data.models);
// Update server-reported available providers
if (data.availableProviders) {
setServerAvailableProviders(data.availableProviders);
}
} else {
setError(data.error || "Failed to fetch models");
setModels([]);
@ -405,14 +412,19 @@ export function ModelSearchDialog({
}
};
// Compute which providers are available based on API keys
// Compute which providers are available based on client API keys + server env vars
const availableProviders = useMemo(() => {
const providers = new Set<ProviderType>(["gemini", "fal"]); // Always available
// Client-side keys (from localStorage/provider settings)
if (replicateApiKey) providers.add("replicate");
if (kieApiKey) providers.add("kie");
if (wavespeedApiKey) providers.add("wavespeed");
// Server-side keys (from env vars, reported by /api/models)
for (const p of serverAvailableProviders) {
providers.add(p as ProviderType);
}
return providers;
}, [replicateApiKey, kieApiKey, wavespeedApiKey]);
}, [replicateApiKey, kieApiKey, wavespeedApiKey, serverAvailableProviders]);
// Reset provider filter if current selection becomes unavailable
useEffect(() => {

Loading…
Cancel
Save