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:
@@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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)}
|
||||||
|
|||||||
@@ -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: "",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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]);
|
||||||
|
|||||||
Reference in New Issue
Block a user