Turbo models (#1249)
<!-- This is an auto-generated description by cubic. --> ## Summary by cubic Adds “Dyad Turbo” models for Pro users and centralizes model/provider constants. Pro users can pick fast, cost‑effective models directly from the ModelPicker, with clearer labels and gating. - **New Features** - Added Dyad Turbo provider in ModelPicker with Qwen3 Coder and Kimi K2 (Pro only). - Turbo options are hidden for non‑Pro users; “Pro only” badge shown where applicable. - “Smart Auto” label now applies only to the Auto model to avoid confusion. - **Refactors** - Moved all model/provider constants into language_model_constants.ts and updated imports (helpers, client, thinking utils). <!-- End of auto-generated description by cubic. -->
This commit is contained in:
@@ -25,6 +25,7 @@ import { LocalModel } from "@/ipc/ipc_types";
|
|||||||
import { useLanguageModelProviders } from "@/hooks/useLanguageModelProviders";
|
import { useLanguageModelProviders } from "@/hooks/useLanguageModelProviders";
|
||||||
import { useSettings } from "@/hooks/useSettings";
|
import { useSettings } from "@/hooks/useSettings";
|
||||||
import { PriceBadge } from "@/components/PriceBadge";
|
import { PriceBadge } from "@/components/PriceBadge";
|
||||||
|
import { TURBO_MODELS } from "@/ipc/shared/language_model_constants";
|
||||||
|
|
||||||
export function ModelPicker() {
|
export function ModelPicker() {
|
||||||
const { settings, updateSettings } = useSettings();
|
const { settings, updateSettings } = useSettings();
|
||||||
@@ -108,6 +109,13 @@ export function ModelPicker() {
|
|||||||
const autoModels =
|
const autoModels =
|
||||||
!loading && modelsByProviders && modelsByProviders["auto"]
|
!loading && modelsByProviders && modelsByProviders["auto"]
|
||||||
? modelsByProviders["auto"].filter((model) => {
|
? modelsByProviders["auto"].filter((model) => {
|
||||||
|
if (
|
||||||
|
settings &&
|
||||||
|
!isDyadProEnabled(settings) &&
|
||||||
|
model.apiName === "turbo"
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
settings &&
|
settings &&
|
||||||
isDyadProEnabled(settings) &&
|
isDyadProEnabled(settings) &&
|
||||||
@@ -144,6 +152,9 @@ export function ModelPicker() {
|
|||||||
const provider = providers?.find((p) => p.id === providerId);
|
const provider = providers?.find((p) => p.id === providerId);
|
||||||
return !(provider && provider.secondary);
|
return !(provider && provider.secondary);
|
||||||
});
|
});
|
||||||
|
if (settings && isDyadProEnabled(settings)) {
|
||||||
|
primaryProviders.unshift(["auto", TURBO_MODELS]);
|
||||||
|
}
|
||||||
const secondaryProviders = providerEntries.filter(([providerId, models]) => {
|
const secondaryProviders = providerEntries.filter(([providerId, models]) => {
|
||||||
if (models.length === 0) return false;
|
if (models.length === 0) return false;
|
||||||
const provider = providers?.find((p) => p.id === providerId);
|
const provider = providers?.find((p) => p.id === providerId);
|
||||||
@@ -220,7 +231,7 @@ export function ModelPicker() {
|
|||||||
<div className="flex justify-between items-start w-full">
|
<div className="flex justify-between items-start w-full">
|
||||||
<span className="flex flex-col items-start">
|
<span className="flex flex-col items-start">
|
||||||
<span>
|
<span>
|
||||||
{isSmartAutoEnabled
|
{isSmartAutoEnabled && model.apiName === "auto"
|
||||||
? "Smart Auto"
|
? "Smart Auto"
|
||||||
: model.displayName}
|
: model.displayName}
|
||||||
</span>
|
</span>
|
||||||
@@ -228,7 +239,7 @@ export function ModelPicker() {
|
|||||||
<div className="flex items-center gap-1.5">
|
<div className="flex items-center gap-1.5">
|
||||||
{isSmartAutoEnabled && (
|
{isSmartAutoEnabled && (
|
||||||
<span className="text-[10px] bg-gradient-to-r from-indigo-600 via-indigo-500 to-indigo-600 bg-[length:200%_100%] animate-[shimmer_5s_ease-in-out_infinite] text-white px-1.5 py-0.5 rounded-full font-medium">
|
<span className="text-[10px] bg-gradient-to-r from-indigo-600 via-indigo-500 to-indigo-600 bg-[length:200%_100%] animate-[shimmer_5s_ease-in-out_infinite] text-white px-1.5 py-0.5 rounded-full font-medium">
|
||||||
Dyad Pro
|
Pro only
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{model.tag && (
|
{model.tag && (
|
||||||
@@ -241,7 +252,7 @@ export function ModelPicker() {
|
|||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent side="right">
|
<TooltipContent side="right">
|
||||||
{isSmartAutoEnabled ? (
|
{isSmartAutoEnabled && model.apiName === "auto" ? (
|
||||||
<p>
|
<p>
|
||||||
<strong>Smart Auto</strong> uses a cheaper model for
|
<strong>Smart Auto</strong> uses a cheaper model for
|
||||||
easier tasks
|
easier tasks
|
||||||
@@ -274,12 +285,16 @@ export function ModelPicker() {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
const provider = providers?.find((p) => p.id === providerId);
|
const provider = providers?.find((p) => p.id === providerId);
|
||||||
|
const providerDisplayName =
|
||||||
|
provider?.id === "auto"
|
||||||
|
? "Dyad Turbo"
|
||||||
|
: (provider?.name ?? providerId);
|
||||||
return (
|
return (
|
||||||
<DropdownMenuSub key={providerId}>
|
<DropdownMenuSub key={providerId}>
|
||||||
<DropdownMenuSubTrigger className="w-full font-normal">
|
<DropdownMenuSubTrigger className="w-full font-normal">
|
||||||
<div className="flex flex-col items-start w-full">
|
<div className="flex flex-col items-start w-full">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span>{provider?.name ?? providerId}</span>
|
<span>{providerDisplayName}</span>
|
||||||
{provider?.type === "cloud" &&
|
{provider?.type === "cloud" &&
|
||||||
!provider?.secondary &&
|
!provider?.secondary &&
|
||||||
isDyadProEnabled(settings) && (
|
isDyadProEnabled(settings) && (
|
||||||
@@ -300,7 +315,7 @@ export function ModelPicker() {
|
|||||||
</DropdownMenuSubTrigger>
|
</DropdownMenuSubTrigger>
|
||||||
<DropdownMenuSubContent className="w-56">
|
<DropdownMenuSubContent className="w-56">
|
||||||
<DropdownMenuLabel>
|
<DropdownMenuLabel>
|
||||||
{(provider?.name ?? providerId) + " Models"}
|
{providerDisplayName + " Models"}
|
||||||
</DropdownMenuLabel>
|
</DropdownMenuLabel>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
{models.map((model) => (
|
{models.map((model) => (
|
||||||
|
|||||||
468
src/ipc/shared/language_model_constants.ts
Normal file
468
src/ipc/shared/language_model_constants.ts
Normal file
@@ -0,0 +1,468 @@
|
|||||||
|
import { LanguageModel } from "../ipc_types";
|
||||||
|
|
||||||
|
export const PROVIDERS_THAT_SUPPORT_THINKING: (keyof typeof MODEL_OPTIONS)[] = [
|
||||||
|
"google",
|
||||||
|
"vertex",
|
||||||
|
"auto",
|
||||||
|
];
|
||||||
|
|
||||||
|
export interface ModelOption {
|
||||||
|
name: string;
|
||||||
|
displayName: string;
|
||||||
|
description: string;
|
||||||
|
dollarSigns?: number;
|
||||||
|
temperature?: number;
|
||||||
|
tag?: string;
|
||||||
|
maxOutputTokens?: number;
|
||||||
|
contextWindow?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MODEL_OPTIONS: Record<string, ModelOption[]> = {
|
||||||
|
openai: [
|
||||||
|
// https://platform.openai.com/docs/models/gpt-5
|
||||||
|
{
|
||||||
|
name: "gpt-5",
|
||||||
|
displayName: "GPT 5",
|
||||||
|
description: "OpenAI's flagship model",
|
||||||
|
// Technically it's 128k but OpenAI errors if you set max_tokens instead of max_completion_tokens
|
||||||
|
maxOutputTokens: undefined,
|
||||||
|
contextWindow: 400_000,
|
||||||
|
// Requires temperature to be default value (1)
|
||||||
|
temperature: 1,
|
||||||
|
dollarSigns: 3,
|
||||||
|
},
|
||||||
|
// https://platform.openai.com/docs/models/gpt-5-mini
|
||||||
|
{
|
||||||
|
name: "gpt-5-mini",
|
||||||
|
displayName: "GPT 5 Mini",
|
||||||
|
description: "OpenAI's lightweight, but intelligent model",
|
||||||
|
// Technically it's 128k but OpenAI errors if you set max_tokens instead of max_completion_tokens
|
||||||
|
maxOutputTokens: undefined,
|
||||||
|
contextWindow: 400_000,
|
||||||
|
// Requires temperature to be default value (1)
|
||||||
|
temperature: 1,
|
||||||
|
dollarSigns: 2,
|
||||||
|
},
|
||||||
|
// https://platform.openai.com/docs/models/gpt-5-nano
|
||||||
|
{
|
||||||
|
name: "gpt-5-nano",
|
||||||
|
displayName: "GPT 5 Nano",
|
||||||
|
description: "Fastest, most cost-efficient version of GPT-5",
|
||||||
|
// Technically it's 128k but OpenAI errors if you set max_tokens instead of max_completion_tokens
|
||||||
|
maxOutputTokens: undefined,
|
||||||
|
contextWindow: 400_000,
|
||||||
|
// Requires temperature to be default value (1)
|
||||||
|
temperature: 1,
|
||||||
|
dollarSigns: 1,
|
||||||
|
},
|
||||||
|
// https://platform.openai.com/docs/models/o4-mini
|
||||||
|
{
|
||||||
|
name: "o4-mini",
|
||||||
|
displayName: "o4 mini",
|
||||||
|
description: "Reasoning model",
|
||||||
|
// Technically the max output tokens is 100k, *however* if the user has a lot of input tokens,
|
||||||
|
// then setting a high max output token will cause the request to fail because
|
||||||
|
// the max output tokens is *included* in the context window limit.
|
||||||
|
maxOutputTokens: 32_000,
|
||||||
|
contextWindow: 200_000,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// https://docs.anthropic.com/en/docs/about-claude/models/all-models#model-comparison-table
|
||||||
|
anthropic: [
|
||||||
|
{
|
||||||
|
name: "claude-sonnet-4-20250514",
|
||||||
|
displayName: "Claude 4 Sonnet",
|
||||||
|
description: "Excellent coder (note: >200k tokens is very expensive!)",
|
||||||
|
// See comment below for Claude 3.7 Sonnet for why we set this to 16k
|
||||||
|
maxOutputTokens: 16_000,
|
||||||
|
contextWindow: 1_000_000,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "claude-3-7-sonnet-latest",
|
||||||
|
displayName: "Claude 3.7 Sonnet",
|
||||||
|
description: "Excellent coder",
|
||||||
|
// Technically the max output tokens is 64k, *however* if the user has a lot of input tokens,
|
||||||
|
// then setting a high max output token will cause the request to fail because
|
||||||
|
// the max output tokens is *included* in the context window limit, see:
|
||||||
|
// https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking#max-tokens-and-context-window-size-with-extended-thinking
|
||||||
|
maxOutputTokens: 16_000,
|
||||||
|
contextWindow: 200_000,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "claude-3-5-sonnet-20241022",
|
||||||
|
displayName: "Claude 3.5 Sonnet",
|
||||||
|
description: "Good coder, excellent at following instructions",
|
||||||
|
maxOutputTokens: 8_000,
|
||||||
|
contextWindow: 200_000,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "claude-3-5-haiku-20241022",
|
||||||
|
displayName: "Claude 3.5 Haiku",
|
||||||
|
description: "Lightweight coder",
|
||||||
|
maxOutputTokens: 8_000,
|
||||||
|
contextWindow: 200_000,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
google: [
|
||||||
|
// https://ai.google.dev/gemini-api/docs/models#gemini-2.5-pro-preview-03-25
|
||||||
|
{
|
||||||
|
name: "gemini-2.5-pro",
|
||||||
|
displayName: "Gemini 2.5 Pro",
|
||||||
|
description: "Google's Gemini 2.5 Pro model",
|
||||||
|
// See Flash 2.5 comment below (go 1 below just to be safe, even though it seems OK now).
|
||||||
|
maxOutputTokens: 65_536 - 1,
|
||||||
|
// Gemini context window = input token + output token
|
||||||
|
contextWindow: 1_048_576,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 3,
|
||||||
|
},
|
||||||
|
// https://ai.google.dev/gemini-api/docs/models#gemini-2.5-flash-preview
|
||||||
|
{
|
||||||
|
name: "gemini-2.5-flash",
|
||||||
|
displayName: "Gemini 2.5 Flash",
|
||||||
|
description: "Google's Gemini 2.5 Flash model (free tier available)",
|
||||||
|
// Weirdly for Vertex AI, the output token limit is *exclusive* of the stated limit.
|
||||||
|
maxOutputTokens: 65_536 - 1,
|
||||||
|
// Gemini context window = input token + output token
|
||||||
|
contextWindow: 1_048_576,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
vertex: [
|
||||||
|
// Vertex Gemini 2.5 Pro
|
||||||
|
{
|
||||||
|
name: "gemini-2.5-pro",
|
||||||
|
displayName: "Gemini 2.5 Pro",
|
||||||
|
description: "Vertex Gemini 2.5 Pro",
|
||||||
|
maxOutputTokens: 65_536 - 1,
|
||||||
|
contextWindow: 1_048_576,
|
||||||
|
temperature: 0,
|
||||||
|
},
|
||||||
|
// Vertex Gemini 2.5 Flash
|
||||||
|
{
|
||||||
|
name: "gemini-2.5-flash",
|
||||||
|
displayName: "Gemini 2.5 Flash",
|
||||||
|
description: "Vertex Gemini 2.5 Flash",
|
||||||
|
maxOutputTokens: 65_536 - 1,
|
||||||
|
contextWindow: 1_048_576,
|
||||||
|
temperature: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
openrouter: [
|
||||||
|
{
|
||||||
|
name: "qwen/qwen3-coder:free",
|
||||||
|
displayName: "Qwen3 Coder (free)",
|
||||||
|
description: "Use for free (data may be used for training)",
|
||||||
|
maxOutputTokens: 32_000,
|
||||||
|
contextWindow: 262_000,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 0,
|
||||||
|
},
|
||||||
|
// https://openrouter.ai/deepseek/deepseek-chat-v3-0324:free
|
||||||
|
{
|
||||||
|
name: "deepseek/deepseek-chat-v3.1:free",
|
||||||
|
displayName: "DeepSeek v3.1 (free)",
|
||||||
|
description: "Use for free (data may be used for training)",
|
||||||
|
maxOutputTokens: 32_000,
|
||||||
|
contextWindow: 128_000,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "deepseek/deepseek-chat-v3-0324:free",
|
||||||
|
displayName: "DeepSeek v3 (free)",
|
||||||
|
description: "Use for free (data may be used for training)",
|
||||||
|
maxOutputTokens: 32_000,
|
||||||
|
contextWindow: 128_000,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "qwen/qwen3-coder",
|
||||||
|
displayName: "Qwen3 Coder",
|
||||||
|
description: "Qwen's best coding model",
|
||||||
|
maxOutputTokens: 32_000,
|
||||||
|
contextWindow: 262_000,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "deepseek/deepseek-chat-v3.1",
|
||||||
|
displayName: "DeepSeek v3.1",
|
||||||
|
description: "Strong cost-effective model with optional thinking",
|
||||||
|
maxOutputTokens: 32_000,
|
||||||
|
contextWindow: 128_000,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 2,
|
||||||
|
},
|
||||||
|
// https://openrouter.ai/moonshotai/kimi-k2
|
||||||
|
{
|
||||||
|
name: "moonshotai/kimi-k2-0905",
|
||||||
|
displayName: "Kimi K2",
|
||||||
|
description: "Powerful cost-effective model (updated to 0905)",
|
||||||
|
maxOutputTokens: 32_000,
|
||||||
|
contextWindow: 256_000,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
auto: [
|
||||||
|
{
|
||||||
|
name: "auto",
|
||||||
|
displayName: "Auto",
|
||||||
|
description: "Automatically selects the best model",
|
||||||
|
tag: "Default",
|
||||||
|
// These are below Gemini 2.5 Pro & Flash limits
|
||||||
|
// which are the ones defaulted to for both regular auto
|
||||||
|
// and smart auto.
|
||||||
|
maxOutputTokens: 32_000,
|
||||||
|
contextWindow: 1_000_000,
|
||||||
|
temperature: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "free",
|
||||||
|
displayName: "Free (OpenRouter)",
|
||||||
|
description: "Selects from one of the free OpenRouter models",
|
||||||
|
tag: "Free",
|
||||||
|
// These are below Gemini 2.5 Pro & Flash limits
|
||||||
|
// which are the ones defaulted to for both regular auto
|
||||||
|
// and smart auto.
|
||||||
|
maxOutputTokens: 32_000,
|
||||||
|
contextWindow: 128_000,
|
||||||
|
temperature: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "turbo",
|
||||||
|
displayName: "Turbo (Pro)",
|
||||||
|
description: "Use very fast open-source frontier models",
|
||||||
|
maxOutputTokens: 32_000,
|
||||||
|
contextWindow: 256_000,
|
||||||
|
temperature: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
azure: [
|
||||||
|
{
|
||||||
|
name: "gpt-5",
|
||||||
|
displayName: "GPT-5",
|
||||||
|
description: "Azure OpenAI GPT-5 model with reasoning capabilities",
|
||||||
|
maxOutputTokens: 128_000,
|
||||||
|
contextWindow: 400_000,
|
||||||
|
temperature: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "gpt-5-mini",
|
||||||
|
displayName: "GPT-5 Mini",
|
||||||
|
description: "Azure OpenAI GPT-5 Mini model",
|
||||||
|
maxOutputTokens: 128_000,
|
||||||
|
contextWindow: 400_000,
|
||||||
|
temperature: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "gpt-5-nano",
|
||||||
|
displayName: "GPT-5 Nano",
|
||||||
|
description: "Azure OpenAI GPT-5 Nano model",
|
||||||
|
maxOutputTokens: 128_000,
|
||||||
|
contextWindow: 400_000,
|
||||||
|
temperature: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "gpt-5-chat",
|
||||||
|
displayName: "GPT-5 Chat",
|
||||||
|
description: "Azure OpenAI GPT-5 Chat model",
|
||||||
|
maxOutputTokens: 16_384,
|
||||||
|
contextWindow: 128_000,
|
||||||
|
temperature: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
xai: [
|
||||||
|
// https://docs.x.ai/docs/models
|
||||||
|
{
|
||||||
|
name: "grok-code-fast-1",
|
||||||
|
displayName: "Grok Code Fast",
|
||||||
|
description: "Fast coding model",
|
||||||
|
maxOutputTokens: 32_000,
|
||||||
|
contextWindow: 256_000,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "grok-4",
|
||||||
|
displayName: "Grok 4",
|
||||||
|
description: "Most capable coding model",
|
||||||
|
maxOutputTokens: 32_000,
|
||||||
|
contextWindow: 256_000,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "grok-3",
|
||||||
|
displayName: "Grok 3",
|
||||||
|
description: "Powerful coding model",
|
||||||
|
maxOutputTokens: 32_000,
|
||||||
|
contextWindow: 131_072,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 4,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
bedrock: [
|
||||||
|
{
|
||||||
|
name: "us.anthropic.claude-sonnet-4-20250514-v1:0",
|
||||||
|
displayName: "Claude 4 Sonnet",
|
||||||
|
description: "Excellent coder (note: >200k tokens is very expensive!)",
|
||||||
|
maxOutputTokens: 16_000,
|
||||||
|
contextWindow: 1_000_000,
|
||||||
|
temperature: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "us.anthropic.claude-3-7-sonnet-20250219-v1:0",
|
||||||
|
displayName: "Claude 3.7 Sonnet",
|
||||||
|
description: "Excellent coder",
|
||||||
|
maxOutputTokens: 16_000,
|
||||||
|
contextWindow: 200_000,
|
||||||
|
temperature: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "us.anthropic.claude-3-5-sonnet-20241022-v2:0",
|
||||||
|
displayName: "Claude 3.5 Sonnet",
|
||||||
|
description: "Good coder, excellent at following instructions",
|
||||||
|
maxOutputTokens: 8_000,
|
||||||
|
contextWindow: 200_000,
|
||||||
|
temperature: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TURBO_MODELS: LanguageModel[] = [
|
||||||
|
{
|
||||||
|
apiName: "qwen3-coder:turbo",
|
||||||
|
displayName: "Qwen3 Coder",
|
||||||
|
description: "Qwen's best coding model (very fast)",
|
||||||
|
maxOutputTokens: 32_000,
|
||||||
|
contextWindow: 131_000,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 2,
|
||||||
|
type: "cloud",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
apiName: "kimi-k2:turbo",
|
||||||
|
displayName: "Kimi K2",
|
||||||
|
description: "Kimi 0905 update (fast)",
|
||||||
|
maxOutputTokens: 16_000,
|
||||||
|
contextWindow: 256_000,
|
||||||
|
temperature: 0,
|
||||||
|
dollarSigns: 2,
|
||||||
|
type: "cloud",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const FREE_OPENROUTER_MODEL_NAMES = MODEL_OPTIONS.openrouter
|
||||||
|
.filter((model) => model.name.endsWith(":free"))
|
||||||
|
.map((model) => model.name);
|
||||||
|
|
||||||
|
export const PROVIDER_TO_ENV_VAR: Record<string, string> = {
|
||||||
|
openai: "OPENAI_API_KEY",
|
||||||
|
anthropic: "ANTHROPIC_API_KEY",
|
||||||
|
google: "GEMINI_API_KEY",
|
||||||
|
openrouter: "OPENROUTER_API_KEY",
|
||||||
|
azure: "AZURE_API_KEY",
|
||||||
|
xai: "XAI_API_KEY",
|
||||||
|
bedrock: "AWS_BEARER_TOKEN_BEDROCK",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CLOUD_PROVIDERS: Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
displayName: string;
|
||||||
|
hasFreeTier?: boolean;
|
||||||
|
websiteUrl?: string;
|
||||||
|
gatewayPrefix: string;
|
||||||
|
secondary?: boolean;
|
||||||
|
}
|
||||||
|
> = {
|
||||||
|
openai: {
|
||||||
|
displayName: "OpenAI",
|
||||||
|
hasFreeTier: false,
|
||||||
|
websiteUrl: "https://platform.openai.com/api-keys",
|
||||||
|
gatewayPrefix: "",
|
||||||
|
},
|
||||||
|
anthropic: {
|
||||||
|
displayName: "Anthropic",
|
||||||
|
hasFreeTier: false,
|
||||||
|
websiteUrl: "https://console.anthropic.com/settings/keys",
|
||||||
|
gatewayPrefix: "anthropic/",
|
||||||
|
},
|
||||||
|
google: {
|
||||||
|
displayName: "Google",
|
||||||
|
hasFreeTier: true,
|
||||||
|
websiteUrl: "https://aistudio.google.com/app/apikey",
|
||||||
|
gatewayPrefix: "gemini/",
|
||||||
|
},
|
||||||
|
vertex: {
|
||||||
|
displayName: "Google Vertex AI",
|
||||||
|
hasFreeTier: false,
|
||||||
|
websiteUrl: "https://console.cloud.google.com/vertex-ai",
|
||||||
|
// Use the same gateway prefix as Google Gemini for Dyad Pro compatibility.
|
||||||
|
gatewayPrefix: "gemini/",
|
||||||
|
secondary: true,
|
||||||
|
},
|
||||||
|
openrouter: {
|
||||||
|
displayName: "OpenRouter",
|
||||||
|
hasFreeTier: true,
|
||||||
|
websiteUrl: "https://openrouter.ai/settings/keys",
|
||||||
|
gatewayPrefix: "openrouter/",
|
||||||
|
},
|
||||||
|
auto: {
|
||||||
|
displayName: "Dyad",
|
||||||
|
websiteUrl: "https://academy.dyad.sh/settings",
|
||||||
|
gatewayPrefix: "dyad/",
|
||||||
|
},
|
||||||
|
azure: {
|
||||||
|
displayName: "Azure OpenAI",
|
||||||
|
hasFreeTier: false,
|
||||||
|
websiteUrl: "https://portal.azure.com/",
|
||||||
|
gatewayPrefix: "",
|
||||||
|
secondary: true,
|
||||||
|
},
|
||||||
|
xai: {
|
||||||
|
displayName: "xAI",
|
||||||
|
hasFreeTier: false,
|
||||||
|
websiteUrl: "https://console.x.ai/",
|
||||||
|
gatewayPrefix: "xai/",
|
||||||
|
secondary: true,
|
||||||
|
},
|
||||||
|
bedrock: {
|
||||||
|
displayName: "AWS Bedrock",
|
||||||
|
hasFreeTier: false,
|
||||||
|
websiteUrl: "https://console.aws.amazon.com/bedrock/",
|
||||||
|
gatewayPrefix: "bedrock/",
|
||||||
|
secondary: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const LOCAL_PROVIDERS: Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
displayName: string;
|
||||||
|
hasFreeTier: boolean;
|
||||||
|
}
|
||||||
|
> = {
|
||||||
|
ollama: {
|
||||||
|
displayName: "Ollama",
|
||||||
|
hasFreeTier: true,
|
||||||
|
},
|
||||||
|
lmstudio: {
|
||||||
|
displayName: "LM Studio",
|
||||||
|
hasFreeTier: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -5,443 +5,12 @@ import {
|
|||||||
} from "@/db/schema";
|
} from "@/db/schema";
|
||||||
import type { LanguageModelProvider, LanguageModel } from "@/ipc/ipc_types";
|
import type { LanguageModelProvider, LanguageModel } from "@/ipc/ipc_types";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
|
import {
|
||||||
export const PROVIDERS_THAT_SUPPORT_THINKING: (keyof typeof MODEL_OPTIONS)[] = [
|
LOCAL_PROVIDERS,
|
||||||
"google",
|
CLOUD_PROVIDERS,
|
||||||
"vertex",
|
MODEL_OPTIONS,
|
||||||
"auto",
|
PROVIDER_TO_ENV_VAR,
|
||||||
];
|
} from "./language_model_constants";
|
||||||
|
|
||||||
export interface ModelOption {
|
|
||||||
name: string;
|
|
||||||
displayName: string;
|
|
||||||
description: string;
|
|
||||||
dollarSigns?: number;
|
|
||||||
temperature?: number;
|
|
||||||
tag?: string;
|
|
||||||
maxOutputTokens?: number;
|
|
||||||
contextWindow?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const MODEL_OPTIONS: Record<string, ModelOption[]> = {
|
|
||||||
openai: [
|
|
||||||
// https://platform.openai.com/docs/models/gpt-5
|
|
||||||
{
|
|
||||||
name: "gpt-5",
|
|
||||||
displayName: "GPT 5",
|
|
||||||
description: "OpenAI's flagship model",
|
|
||||||
// Technically it's 128k but OpenAI errors if you set max_tokens instead of max_completion_tokens
|
|
||||||
maxOutputTokens: undefined,
|
|
||||||
contextWindow: 400_000,
|
|
||||||
// Requires temperature to be default value (1)
|
|
||||||
temperature: 1,
|
|
||||||
dollarSigns: 3,
|
|
||||||
},
|
|
||||||
// https://platform.openai.com/docs/models/gpt-5-mini
|
|
||||||
{
|
|
||||||
name: "gpt-5-mini",
|
|
||||||
displayName: "GPT 5 Mini",
|
|
||||||
description: "OpenAI's lightweight, but intelligent model",
|
|
||||||
// Technically it's 128k but OpenAI errors if you set max_tokens instead of max_completion_tokens
|
|
||||||
maxOutputTokens: undefined,
|
|
||||||
contextWindow: 400_000,
|
|
||||||
// Requires temperature to be default value (1)
|
|
||||||
temperature: 1,
|
|
||||||
dollarSigns: 2,
|
|
||||||
},
|
|
||||||
// https://platform.openai.com/docs/models/gpt-5-nano
|
|
||||||
{
|
|
||||||
name: "gpt-5-nano",
|
|
||||||
displayName: "GPT 5 Nano",
|
|
||||||
description: "Fastest, most cost-efficient version of GPT-5",
|
|
||||||
// Technically it's 128k but OpenAI errors if you set max_tokens instead of max_completion_tokens
|
|
||||||
maxOutputTokens: undefined,
|
|
||||||
contextWindow: 400_000,
|
|
||||||
// Requires temperature to be default value (1)
|
|
||||||
temperature: 1,
|
|
||||||
dollarSigns: 1,
|
|
||||||
},
|
|
||||||
// https://platform.openai.com/docs/models/o4-mini
|
|
||||||
{
|
|
||||||
name: "o4-mini",
|
|
||||||
displayName: "o4 mini",
|
|
||||||
description: "Reasoning model",
|
|
||||||
// Technically the max output tokens is 100k, *however* if the user has a lot of input tokens,
|
|
||||||
// then setting a high max output token will cause the request to fail because
|
|
||||||
// the max output tokens is *included* in the context window limit.
|
|
||||||
maxOutputTokens: 32_000,
|
|
||||||
contextWindow: 200_000,
|
|
||||||
temperature: 0,
|
|
||||||
dollarSigns: 2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
// https://docs.anthropic.com/en/docs/about-claude/models/all-models#model-comparison-table
|
|
||||||
anthropic: [
|
|
||||||
{
|
|
||||||
name: "claude-sonnet-4-20250514",
|
|
||||||
displayName: "Claude 4 Sonnet",
|
|
||||||
description: "Excellent coder (note: >200k tokens is very expensive!)",
|
|
||||||
// See comment below for Claude 3.7 Sonnet for why we set this to 16k
|
|
||||||
maxOutputTokens: 16_000,
|
|
||||||
contextWindow: 1_000_000,
|
|
||||||
temperature: 0,
|
|
||||||
dollarSigns: 5,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "claude-3-7-sonnet-latest",
|
|
||||||
displayName: "Claude 3.7 Sonnet",
|
|
||||||
description: "Excellent coder",
|
|
||||||
// Technically the max output tokens is 64k, *however* if the user has a lot of input tokens,
|
|
||||||
// then setting a high max output token will cause the request to fail because
|
|
||||||
// the max output tokens is *included* in the context window limit, see:
|
|
||||||
// https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking#max-tokens-and-context-window-size-with-extended-thinking
|
|
||||||
maxOutputTokens: 16_000,
|
|
||||||
contextWindow: 200_000,
|
|
||||||
temperature: 0,
|
|
||||||
dollarSigns: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "claude-3-5-sonnet-20241022",
|
|
||||||
displayName: "Claude 3.5 Sonnet",
|
|
||||||
description: "Good coder, excellent at following instructions",
|
|
||||||
maxOutputTokens: 8_000,
|
|
||||||
contextWindow: 200_000,
|
|
||||||
temperature: 0,
|
|
||||||
dollarSigns: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "claude-3-5-haiku-20241022",
|
|
||||||
displayName: "Claude 3.5 Haiku",
|
|
||||||
description: "Lightweight coder",
|
|
||||||
maxOutputTokens: 8_000,
|
|
||||||
contextWindow: 200_000,
|
|
||||||
temperature: 0,
|
|
||||||
dollarSigns: 2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
google: [
|
|
||||||
// https://ai.google.dev/gemini-api/docs/models#gemini-2.5-pro-preview-03-25
|
|
||||||
{
|
|
||||||
name: "gemini-2.5-pro",
|
|
||||||
displayName: "Gemini 2.5 Pro",
|
|
||||||
description: "Google's Gemini 2.5 Pro model",
|
|
||||||
// See Flash 2.5 comment below (go 1 below just to be safe, even though it seems OK now).
|
|
||||||
maxOutputTokens: 65_536 - 1,
|
|
||||||
// Gemini context window = input token + output token
|
|
||||||
contextWindow: 1_048_576,
|
|
||||||
temperature: 0,
|
|
||||||
dollarSigns: 3,
|
|
||||||
},
|
|
||||||
// https://ai.google.dev/gemini-api/docs/models#gemini-2.5-flash-preview
|
|
||||||
{
|
|
||||||
name: "gemini-2.5-flash",
|
|
||||||
displayName: "Gemini 2.5 Flash",
|
|
||||||
description: "Google's Gemini 2.5 Flash model (free tier available)",
|
|
||||||
// Weirdly for Vertex AI, the output token limit is *exclusive* of the stated limit.
|
|
||||||
maxOutputTokens: 65_536 - 1,
|
|
||||||
// Gemini context window = input token + output token
|
|
||||||
contextWindow: 1_048_576,
|
|
||||||
temperature: 0,
|
|
||||||
dollarSigns: 2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
vertex: [
|
|
||||||
// Vertex Gemini 2.5 Pro
|
|
||||||
{
|
|
||||||
name: "gemini-2.5-pro",
|
|
||||||
displayName: "Gemini 2.5 Pro",
|
|
||||||
description: "Vertex Gemini 2.5 Pro",
|
|
||||||
maxOutputTokens: 65_536 - 1,
|
|
||||||
contextWindow: 1_048_576,
|
|
||||||
temperature: 0,
|
|
||||||
},
|
|
||||||
// Vertex Gemini 2.5 Flash
|
|
||||||
{
|
|
||||||
name: "gemini-2.5-flash",
|
|
||||||
displayName: "Gemini 2.5 Flash",
|
|
||||||
description: "Vertex Gemini 2.5 Flash",
|
|
||||||
maxOutputTokens: 65_536 - 1,
|
|
||||||
contextWindow: 1_048_576,
|
|
||||||
temperature: 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
openrouter: [
|
|
||||||
{
|
|
||||||
name: "qwen/qwen3-coder:free",
|
|
||||||
displayName: "Qwen3 Coder (free)",
|
|
||||||
description: "Use for free (data may be used for training)",
|
|
||||||
maxOutputTokens: 32_000,
|
|
||||||
contextWindow: 262_000,
|
|
||||||
temperature: 0,
|
|
||||||
dollarSigns: 0,
|
|
||||||
},
|
|
||||||
// https://openrouter.ai/deepseek/deepseek-chat-v3-0324:free
|
|
||||||
{
|
|
||||||
name: "deepseek/deepseek-chat-v3.1:free",
|
|
||||||
displayName: "DeepSeek v3.1 (free)",
|
|
||||||
description: "Use for free (data may be used for training)",
|
|
||||||
maxOutputTokens: 32_000,
|
|
||||||
contextWindow: 128_000,
|
|
||||||
temperature: 0,
|
|
||||||
dollarSigns: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "deepseek/deepseek-chat-v3-0324:free",
|
|
||||||
displayName: "DeepSeek v3 (free)",
|
|
||||||
description: "Use for free (data may be used for training)",
|
|
||||||
maxOutputTokens: 32_000,
|
|
||||||
contextWindow: 128_000,
|
|
||||||
temperature: 0,
|
|
||||||
dollarSigns: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "qwen/qwen3-coder",
|
|
||||||
displayName: "Qwen3 Coder",
|
|
||||||
description: "Qwen's best coding model",
|
|
||||||
maxOutputTokens: 32_000,
|
|
||||||
contextWindow: 262_000,
|
|
||||||
temperature: 0,
|
|
||||||
dollarSigns: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "deepseek/deepseek-chat-v3.1",
|
|
||||||
displayName: "DeepSeek v3.1",
|
|
||||||
description: "Strong cost-effective model with optional thinking",
|
|
||||||
maxOutputTokens: 32_000,
|
|
||||||
contextWindow: 128_000,
|
|
||||||
temperature: 0,
|
|
||||||
dollarSigns: 2,
|
|
||||||
},
|
|
||||||
// https://openrouter.ai/moonshotai/kimi-k2
|
|
||||||
{
|
|
||||||
name: "moonshotai/kimi-k2-0905",
|
|
||||||
displayName: "Kimi K2",
|
|
||||||
description: "Powerful cost-effective model (updated to 0905)",
|
|
||||||
maxOutputTokens: 32_000,
|
|
||||||
contextWindow: 256_000,
|
|
||||||
temperature: 0,
|
|
||||||
dollarSigns: 2,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
auto: [
|
|
||||||
{
|
|
||||||
name: "auto",
|
|
||||||
displayName: "Auto",
|
|
||||||
description: "Automatically selects the best model",
|
|
||||||
tag: "Default",
|
|
||||||
// These are below Gemini 2.5 Pro & Flash limits
|
|
||||||
// which are the ones defaulted to for both regular auto
|
|
||||||
// and smart auto.
|
|
||||||
maxOutputTokens: 32_000,
|
|
||||||
contextWindow: 1_000_000,
|
|
||||||
temperature: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "free",
|
|
||||||
displayName: "Free (OpenRouter)",
|
|
||||||
description: "Selects from one of the free OpenRouter models",
|
|
||||||
tag: "Free",
|
|
||||||
// These are below Gemini 2.5 Pro & Flash limits
|
|
||||||
// which are the ones defaulted to for both regular auto
|
|
||||||
// and smart auto.
|
|
||||||
maxOutputTokens: 32_000,
|
|
||||||
contextWindow: 128_000,
|
|
||||||
temperature: 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
azure: [
|
|
||||||
{
|
|
||||||
name: "gpt-5",
|
|
||||||
displayName: "GPT-5",
|
|
||||||
description: "Azure OpenAI GPT-5 model with reasoning capabilities",
|
|
||||||
maxOutputTokens: 128_000,
|
|
||||||
contextWindow: 400_000,
|
|
||||||
temperature: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "gpt-5-mini",
|
|
||||||
displayName: "GPT-5 Mini",
|
|
||||||
description: "Azure OpenAI GPT-5 Mini model",
|
|
||||||
maxOutputTokens: 128_000,
|
|
||||||
contextWindow: 400_000,
|
|
||||||
temperature: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "gpt-5-nano",
|
|
||||||
displayName: "GPT-5 Nano",
|
|
||||||
description: "Azure OpenAI GPT-5 Nano model",
|
|
||||||
maxOutputTokens: 128_000,
|
|
||||||
contextWindow: 400_000,
|
|
||||||
temperature: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "gpt-5-chat",
|
|
||||||
displayName: "GPT-5 Chat",
|
|
||||||
description: "Azure OpenAI GPT-5 Chat model",
|
|
||||||
maxOutputTokens: 16_384,
|
|
||||||
contextWindow: 128_000,
|
|
||||||
temperature: 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
xai: [
|
|
||||||
// https://docs.x.ai/docs/models
|
|
||||||
{
|
|
||||||
name: "grok-code-fast-1",
|
|
||||||
displayName: "Grok Code Fast",
|
|
||||||
description: "Fast coding model",
|
|
||||||
maxOutputTokens: 32_000,
|
|
||||||
contextWindow: 256_000,
|
|
||||||
temperature: 0,
|
|
||||||
dollarSigns: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "grok-4",
|
|
||||||
displayName: "Grok 4",
|
|
||||||
description: "Most capable coding model",
|
|
||||||
maxOutputTokens: 32_000,
|
|
||||||
contextWindow: 256_000,
|
|
||||||
temperature: 0,
|
|
||||||
dollarSigns: 4,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "grok-3",
|
|
||||||
displayName: "Grok 3",
|
|
||||||
description: "Powerful coding model",
|
|
||||||
maxOutputTokens: 32_000,
|
|
||||||
contextWindow: 131_072,
|
|
||||||
temperature: 0,
|
|
||||||
dollarSigns: 4,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
bedrock: [
|
|
||||||
{
|
|
||||||
name: "us.anthropic.claude-sonnet-4-20250514-v1:0",
|
|
||||||
displayName: "Claude 4 Sonnet",
|
|
||||||
description: "Excellent coder (note: >200k tokens is very expensive!)",
|
|
||||||
maxOutputTokens: 16_000,
|
|
||||||
contextWindow: 1_000_000,
|
|
||||||
temperature: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "us.anthropic.claude-3-7-sonnet-20250219-v1:0",
|
|
||||||
displayName: "Claude 3.7 Sonnet",
|
|
||||||
description: "Excellent coder",
|
|
||||||
maxOutputTokens: 16_000,
|
|
||||||
contextWindow: 200_000,
|
|
||||||
temperature: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "us.anthropic.claude-3-5-sonnet-20241022-v2:0",
|
|
||||||
displayName: "Claude 3.5 Sonnet",
|
|
||||||
description: "Good coder, excellent at following instructions",
|
|
||||||
maxOutputTokens: 8_000,
|
|
||||||
contextWindow: 200_000,
|
|
||||||
temperature: 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
export const FREE_OPENROUTER_MODEL_NAMES = MODEL_OPTIONS.openrouter
|
|
||||||
.filter((model) => model.name.endsWith(":free"))
|
|
||||||
.map((model) => model.name);
|
|
||||||
|
|
||||||
export const PROVIDER_TO_ENV_VAR: Record<string, string> = {
|
|
||||||
openai: "OPENAI_API_KEY",
|
|
||||||
anthropic: "ANTHROPIC_API_KEY",
|
|
||||||
google: "GEMINI_API_KEY",
|
|
||||||
openrouter: "OPENROUTER_API_KEY",
|
|
||||||
azure: "AZURE_API_KEY",
|
|
||||||
xai: "XAI_API_KEY",
|
|
||||||
bedrock: "AWS_BEARER_TOKEN_BEDROCK",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const CLOUD_PROVIDERS: Record<
|
|
||||||
string,
|
|
||||||
{
|
|
||||||
displayName: string;
|
|
||||||
hasFreeTier?: boolean;
|
|
||||||
websiteUrl?: string;
|
|
||||||
gatewayPrefix: string;
|
|
||||||
secondary?: boolean;
|
|
||||||
}
|
|
||||||
> = {
|
|
||||||
openai: {
|
|
||||||
displayName: "OpenAI",
|
|
||||||
hasFreeTier: false,
|
|
||||||
websiteUrl: "https://platform.openai.com/api-keys",
|
|
||||||
gatewayPrefix: "",
|
|
||||||
},
|
|
||||||
anthropic: {
|
|
||||||
displayName: "Anthropic",
|
|
||||||
hasFreeTier: false,
|
|
||||||
websiteUrl: "https://console.anthropic.com/settings/keys",
|
|
||||||
gatewayPrefix: "anthropic/",
|
|
||||||
},
|
|
||||||
google: {
|
|
||||||
displayName: "Google",
|
|
||||||
hasFreeTier: true,
|
|
||||||
websiteUrl: "https://aistudio.google.com/app/apikey",
|
|
||||||
gatewayPrefix: "gemini/",
|
|
||||||
},
|
|
||||||
vertex: {
|
|
||||||
displayName: "Google Vertex AI",
|
|
||||||
hasFreeTier: false,
|
|
||||||
websiteUrl: "https://console.cloud.google.com/vertex-ai",
|
|
||||||
// Use the same gateway prefix as Google Gemini for Dyad Pro compatibility.
|
|
||||||
gatewayPrefix: "gemini/",
|
|
||||||
secondary: true,
|
|
||||||
},
|
|
||||||
openrouter: {
|
|
||||||
displayName: "OpenRouter",
|
|
||||||
hasFreeTier: true,
|
|
||||||
websiteUrl: "https://openrouter.ai/settings/keys",
|
|
||||||
gatewayPrefix: "openrouter/",
|
|
||||||
},
|
|
||||||
auto: {
|
|
||||||
displayName: "Dyad",
|
|
||||||
websiteUrl: "https://academy.dyad.sh/settings",
|
|
||||||
gatewayPrefix: "dyad/",
|
|
||||||
},
|
|
||||||
azure: {
|
|
||||||
displayName: "Azure OpenAI",
|
|
||||||
hasFreeTier: false,
|
|
||||||
websiteUrl: "https://portal.azure.com/",
|
|
||||||
gatewayPrefix: "",
|
|
||||||
secondary: true,
|
|
||||||
},
|
|
||||||
xai: {
|
|
||||||
displayName: "xAI",
|
|
||||||
hasFreeTier: false,
|
|
||||||
websiteUrl: "https://console.x.ai/",
|
|
||||||
gatewayPrefix: "xai/",
|
|
||||||
secondary: true,
|
|
||||||
},
|
|
||||||
bedrock: {
|
|
||||||
displayName: "AWS Bedrock",
|
|
||||||
hasFreeTier: false,
|
|
||||||
websiteUrl: "https://console.aws.amazon.com/bedrock/",
|
|
||||||
gatewayPrefix: "bedrock/",
|
|
||||||
secondary: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const LOCAL_PROVIDERS: Record<
|
|
||||||
string,
|
|
||||||
{
|
|
||||||
displayName: string;
|
|
||||||
hasFreeTier: boolean;
|
|
||||||
}
|
|
||||||
> = {
|
|
||||||
ollama: {
|
|
||||||
displayName: "Ollama",
|
|
||||||
hasFreeTier: true,
|
|
||||||
},
|
|
||||||
lmstudio: {
|
|
||||||
displayName: "LM Studio",
|
|
||||||
hasFreeTier: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches language model providers from both the database (custom) and hardcoded constants (cloud),
|
* Fetches language model providers from both the database (custom) and hardcoded constants (cloud),
|
||||||
* merging them with custom providers taking precedence.
|
* merging them with custom providers taking precedence.
|
||||||
|
|||||||
@@ -15,10 +15,8 @@ import type {
|
|||||||
} from "../../lib/schemas";
|
} from "../../lib/schemas";
|
||||||
import { getEnvVar } from "./read_env";
|
import { getEnvVar } from "./read_env";
|
||||||
import log from "electron-log";
|
import log from "electron-log";
|
||||||
import {
|
import { FREE_OPENROUTER_MODEL_NAMES } from "../shared/language_model_constants";
|
||||||
FREE_OPENROUTER_MODEL_NAMES,
|
import { getLanguageModelProviders } from "../shared/language_model_helpers";
|
||||||
getLanguageModelProviders,
|
|
||||||
} from "../shared/language_model_helpers";
|
|
||||||
import { LanguageModelProvider } from "../ipc_types";
|
import { LanguageModelProvider } from "../ipc_types";
|
||||||
import { createDyadEngine } from "./llm_engine_provider";
|
import { createDyadEngine } from "./llm_engine_provider";
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { PROVIDERS_THAT_SUPPORT_THINKING } from "../shared/language_model_helpers";
|
import { PROVIDERS_THAT_SUPPORT_THINKING } from "../shared/language_model_constants";
|
||||||
import type { UserSettings } from "../../lib/schemas";
|
import type { UserSettings } from "../../lib/schemas";
|
||||||
|
|
||||||
function getThinkingBudgetTokens(
|
function getThinkingBudgetTokens(
|
||||||
|
|||||||
Reference in New Issue
Block a user