More free models (#1244)
<!-- This is an auto-generated description by cubic. --> ## Summary by cubic Adds support for free OpenRouter models and a new “Free (OpenRouter)” auto option that fails over across free models for reliability. Improves setup flow and UI with provider cards, a “Free” price badge, and an OpenRouter setup prompt in chat. - **New Features** - Added OpenRouter free models: Qwen3 Coder (free), DeepSeek v3 (free), DeepSeek v3.1 (free), marked with dollarSigns=0 and a “Free” badge. - New auto model: “Free (OpenRouter)” that uses a fallback client to cycle through free models with smart retry on transient errors. - New SetupProviderCard component and updated SetupBanner with dedicated Google and OpenRouter setup cards. - Chat shows an OpenRouter setup prompt when “Free (OpenRouter)” is selected and OpenRouter isn’t configured. - New PriceBadge component in ModelPicker to display “Free” or price tier. - E2E: added setup flow test and option to show the setup screen in tests. - Model updates: added DeepSeek v3.1, updated Kimi K2 to kimi-k2-0905, migrated providers to LanguageModelV2. <!-- End of auto-generated description by cubic. -->
This commit is contained in:
@@ -24,6 +24,7 @@ import { useLanguageModelsByProviders } from "@/hooks/useLanguageModelsByProvide
|
||||
import { LocalModel } from "@/ipc/ipc_types";
|
||||
import { useLanguageModelProviders } from "@/hooks/useLanguageModelProviders";
|
||||
import { useSettings } from "@/hooks/useSettings";
|
||||
import { PriceBadge } from "@/components/PriceBadge";
|
||||
|
||||
export function ModelPicker() {
|
||||
const { settings, updateSettings } = useSettings();
|
||||
@@ -106,7 +107,16 @@ export function ModelPicker() {
|
||||
// Get auto provider models (if any)
|
||||
const autoModels =
|
||||
!loading && modelsByProviders && modelsByProviders["auto"]
|
||||
? modelsByProviders["auto"]
|
||||
? modelsByProviders["auto"].filter((model) => {
|
||||
if (
|
||||
settings &&
|
||||
isDyadProEnabled(settings) &&
|
||||
model.apiName === "free"
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
: [];
|
||||
|
||||
// Determine availability of local models
|
||||
@@ -251,6 +261,18 @@ export function ModelPicker() {
|
||||
|
||||
{/* Primary providers as submenus */}
|
||||
{primaryProviders.map(([providerId, models]) => {
|
||||
models = models.filter((model) => {
|
||||
// Don't show free models if Dyad Pro is enabled because
|
||||
// we will use the paid models (in Dyad Pro backend) which
|
||||
// don't have the free limitations.
|
||||
if (
|
||||
isDyadProEnabled(settings) &&
|
||||
model.apiName.endsWith(":free")
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
const provider = providers?.find((p) => p.id === providerId);
|
||||
return (
|
||||
<DropdownMenuSub key={providerId}>
|
||||
@@ -304,11 +326,7 @@ export function ModelPicker() {
|
||||
>
|
||||
<div className="flex justify-between items-start w-full">
|
||||
<span>{model.displayName}</span>
|
||||
{model.dollarSigns && (
|
||||
<span className="text-[10px] bg-primary/10 text-primary px-1.5 py-0.5 rounded-full font-medium">
|
||||
{"$".repeat(model.dollarSigns)}
|
||||
</span>
|
||||
)}
|
||||
<PriceBadge dollarSigns={model.dollarSigns} />
|
||||
{model.tag && (
|
||||
<span className="text-[10px] bg-primary/10 text-primary px-1.5 py-0.5 rounded-full font-medium">
|
||||
{model.tag}
|
||||
|
||||
Reference in New Issue
Block a user