- {provider?.name ?? providerId}
+ {providerDisplayName}
{provider?.type === "cloud" &&
!provider?.secondary &&
isDyadProEnabled(settings) && (
@@ -300,7 +315,7 @@ export function ModelPicker() {
- {(provider?.name ?? providerId) + " Models"}
+ {providerDisplayName + " Models"}
{models.map((model) => (
diff --git a/src/ipc/shared/language_model_constants.ts b/src/ipc/shared/language_model_constants.ts
new file mode 100644
index 0000000..be3945a
--- /dev/null
+++ b/src/ipc/shared/language_model_constants.ts
@@ -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 = {
+ 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 = {
+ 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,
+ },
+};
diff --git a/src/ipc/shared/language_model_helpers.ts b/src/ipc/shared/language_model_helpers.ts
index 911a975..62a8ef7 100644
--- a/src/ipc/shared/language_model_helpers.ts
+++ b/src/ipc/shared/language_model_helpers.ts
@@ -5,443 +5,12 @@ import {
} from "@/db/schema";
import type { LanguageModelProvider, LanguageModel } from "@/ipc/ipc_types";
import { eq } from "drizzle-orm";
-
-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 = {
- 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 = {
- 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,
- },
-};
-
+import {
+ LOCAL_PROVIDERS,
+ CLOUD_PROVIDERS,
+ MODEL_OPTIONS,
+ PROVIDER_TO_ENV_VAR,
+} from "./language_model_constants";
/**
* Fetches language model providers from both the database (custom) and hardcoded constants (cloud),
* merging them with custom providers taking precedence.
diff --git a/src/ipc/utils/get_model_client.ts b/src/ipc/utils/get_model_client.ts
index 33d90bf..57f66c4 100644
--- a/src/ipc/utils/get_model_client.ts
+++ b/src/ipc/utils/get_model_client.ts
@@ -15,10 +15,8 @@ import type {
} from "../../lib/schemas";
import { getEnvVar } from "./read_env";
import log from "electron-log";
-import {
- FREE_OPENROUTER_MODEL_NAMES,
- getLanguageModelProviders,
-} from "../shared/language_model_helpers";
+import { FREE_OPENROUTER_MODEL_NAMES } from "../shared/language_model_constants";
+import { getLanguageModelProviders } from "../shared/language_model_helpers";
import { LanguageModelProvider } from "../ipc_types";
import { createDyadEngine } from "./llm_engine_provider";
diff --git a/src/ipc/utils/thinking_utils.ts b/src/ipc/utils/thinking_utils.ts
index c27f8f2..d475f9f 100644
--- a/src/ipc/utils/thinking_utils.ts
+++ b/src/ipc/utils/thinking_utils.ts
@@ -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";
function getThinkingBudgetTokens(