Support LLM gateway with Dyad API key (#23)

* Do not make API key input (password) - hurts usability
* Support LLM gateway (and add GPT 4.1 mini model)
* Show Dyad Pro button
* Fix to use auto (not dyad) for detecting dyad pro
* Fix description of gpt 4.1-mini
This commit is contained in:
Will Chen
2025-04-26 08:52:08 -07:00
committed by GitHub
parent 0dcbb44e2b
commit 2ad10ba039
4 changed files with 49 additions and 9 deletions

View File

@@ -6,6 +6,7 @@ import { useSettings } from "@/hooks/useSettings";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
// @ts-ignore // @ts-ignore
import logo from "../../assets/logo_transparent.png"; import logo from "../../assets/logo_transparent.png";
import { providerSettingsRoute } from "@/routes/settings/providers/$provider";
export const TitleBar = () => { export const TitleBar = () => {
const [selectedAppId] = useAtom(selectedAppIdAtom); const [selectedAppId] = useAtom(selectedAppIdAtom);
@@ -25,6 +26,8 @@ export const TitleBar = () => {
} }
}; };
const isDyadPro = !!settings?.providerSettings?.auto?.apiKey?.value;
return ( return (
<div className="@container z-11 w-full h-11 bg-(--sidebar) absolute top-0 left-0 app-region-drag flex items-center"> <div className="@container z-11 w-full h-11 bg-(--sidebar) absolute top-0 left-0 app-region-drag flex items-center">
<div className="pl-20"></div> <div className="pl-20"></div>
@@ -39,6 +42,21 @@ export const TitleBar = () => {
> >
{displayText} {displayText}
</Button> </Button>
{isDyadPro && (
<Button
onClick={() => {
navigate({
to: providerSettingsRoute.id,
params: { provider: "auto" },
});
}}
variant="outline"
className="ml-4 no-app-region-drag h-7 bg-indigo-600 text-white dark:bg-indigo-600 dark:text-white"
size="sm"
>
Dyad Pro
</Button>
)}
</div> </div>
); );
}; };

View File

@@ -273,7 +273,6 @@ export function ProviderSettingsPage({ provider }: ProviderSettingsPageProps) {
</label> </label>
<div className="flex items-start space-x-2"> <div className="flex items-start space-x-2">
<Input <Input
type="password"
id="apiKeyInput" id="apiKeyInput"
value={apiKeyInput} value={apiKeyInput}
onChange={(e) => setApiKeyInput(e.target.value)} onChange={(e) => setApiKeyInput(e.target.value)}

View File

@@ -14,6 +14,11 @@ export const MODEL_OPTIONS: Record<RegularModelProvider, ModelOption[]> = {
displayName: "GPT 4.1", displayName: "GPT 4.1",
description: "OpenAI's flagship model", description: "OpenAI's flagship model",
}, },
{
name: "gpt-4.1-mini",
displayName: "GPT 4.1 Mini",
description: "OpenAI's lightweight, but intelligent model",
},
{ {
name: "o3-mini", name: "o3-mini",
displayName: "o3 mini", displayName: "o3 mini",
@@ -55,40 +60,40 @@ export const MODEL_OPTIONS: Record<RegularModelProvider, ModelOption[]> = {
export const PROVIDERS: Record< export const PROVIDERS: Record<
RegularModelProvider, RegularModelProvider,
{ {
name: string;
displayName: string; displayName: string;
hasFreeTier?: boolean; hasFreeTier?: boolean;
websiteUrl?: string; websiteUrl?: string;
gatewayPrefix: string;
} }
> = { > = {
openai: { openai: {
name: "openai",
displayName: "OpenAI", displayName: "OpenAI",
hasFreeTier: false, hasFreeTier: false,
websiteUrl: "https://platform.openai.com/api-keys", websiteUrl: "https://platform.openai.com/api-keys",
gatewayPrefix: "",
}, },
anthropic: { anthropic: {
name: "anthropic",
displayName: "Anthropic", displayName: "Anthropic",
hasFreeTier: false, hasFreeTier: false,
websiteUrl: "https://console.anthropic.com/settings/keys", websiteUrl: "https://console.anthropic.com/settings/keys",
gatewayPrefix: "anthropic/",
}, },
google: { google: {
name: "google",
displayName: "Google", displayName: "Google",
hasFreeTier: true, hasFreeTier: true,
websiteUrl: "https://aistudio.google.com/app/apikey", websiteUrl: "https://aistudio.google.com/app/apikey",
gatewayPrefix: "gemini/",
}, },
openrouter: { openrouter: {
name: "openrouter",
displayName: "OpenRouter", displayName: "OpenRouter",
hasFreeTier: true, hasFreeTier: true,
websiteUrl: "https://openrouter.ai/settings/keys", websiteUrl: "https://openrouter.ai/settings/keys",
gatewayPrefix: "openrouter/",
}, },
auto: { auto: {
name: "auto",
displayName: "Dyad", displayName: "Dyad",
websiteUrl: "https://academy.dyad.sh/settings", websiteUrl: "https://academy.dyad.sh/settings",
gatewayPrefix: "",
}, },
}; };

View File

@@ -1,12 +1,19 @@
import { createOpenAI } from "@ai-sdk/openai"; import { createOpenAI, OpenAIProvider } from "@ai-sdk/openai";
import { createGoogleGenerativeAI as createGoogle } from "@ai-sdk/google"; import { createGoogleGenerativeAI as createGoogle } from "@ai-sdk/google";
import { createAnthropic } from "@ai-sdk/anthropic"; import { createAnthropic } from "@ai-sdk/anthropic";
import { createOpenRouter } from "@openrouter/ai-sdk-provider"; import { createOpenRouter } from "@openrouter/ai-sdk-provider";
import { createOllama } from "ollama-ai-provider"; import { createOllama } from "ollama-ai-provider";
import type { LargeLanguageModel, UserSettings } from "../../lib/schemas"; import type { LargeLanguageModel, UserSettings } from "../../lib/schemas";
import { PROVIDER_TO_ENV_VAR, AUTO_MODELS } from "../../constants/models"; import {
PROVIDER_TO_ENV_VAR,
AUTO_MODELS,
PROVIDERS,
} from "../../constants/models";
import { getEnvVar } from "./read_env"; import { getEnvVar } from "./read_env";
import log from "electron-log";
const logger = log.scope("getModelClient");
export function getModelClient( export function getModelClient(
model: LargeLanguageModel, model: LargeLanguageModel,
settings: UserSettings settings: UserSettings
@@ -38,6 +45,17 @@ export function getModelClient(
throw new Error("No API keys available for any model in AUTO_MODELS"); throw new Error("No API keys available for any model in AUTO_MODELS");
} }
const dyadApiKey = settings.providerSettings?.auto?.apiKey?.value;
if (dyadApiKey) {
const provider = createOpenAI({
apiKey: dyadApiKey,
baseURL: "https://llm-gateway.dyad.sh/v1",
});
const providerInfo = PROVIDERS[model.provider as keyof typeof PROVIDERS];
logger.info("Using Dyad Pro API key");
return provider(`${providerInfo.gatewayPrefix}${model.name}`);
}
const apiKey = const apiKey =
settings.providerSettings?.[model.provider]?.apiKey?.value || settings.providerSettings?.[model.provider]?.apiKey?.value ||
getEnvVar(PROVIDER_TO_ENV_VAR[model.provider]); getEnvVar(PROVIDER_TO_ENV_VAR[model.provider]);