Unverified 提交 5d678c2e authored 作者: Will Chen's avatar Will Chen 提交者: GitHub

Smart auto (#476)

上级 30415638
......@@ -34,10 +34,29 @@ testSkipIfWindows(
},
);
testSkipIfWindows("auto should send message to engine", async ({ po }) => {
testSkipIfWindows(
"smart auto should send message to engine",
async ({ po }) => {
await po.setUpDyadPro();
await po.sendPrompt("[dump] tc=turbo-edits");
await po.snapshotServerDump("request");
await po.snapshotMessages({ replaceDumpPath: true });
});
},
);
testSkipIfWindows(
"regular auto should send message to engine",
async ({ po }) => {
await po.setUpDyadPro();
const proModesDialog = await po.openProModesDialog({
location: "home-chat-input-container",
});
await proModesDialog.toggleSmartContext();
await proModesDialog.close();
await po.sendPrompt("[dump] tc=turbo-edits");
await po.snapshotServerDump("request");
await po.snapshotMessages({ replaceDumpPath: true });
},
);
- paragraph: "[dump] tc=turbo-edits"
- paragraph: "[[dyad-dump-path=*]]"
- button "Retry":
- img
\ No newline at end of file
{
"body": {
"model": "gemini/gemini-2.5-flash",
"max_tokens": 8000,
"model": "dyad/auto",
"max_tokens": 32000,
"temperature": 0,
"messages": [
{
......
import type { LargeLanguageModel } from "@/lib/schemas";
import { isDyadProEnabled, type LargeLanguageModel } from "@/lib/schemas";
import { Button } from "@/components/ui/button";
import {
Tooltip,
......@@ -119,6 +119,8 @@ export function ModelPicker() {
return null;
}
const selectedModel = settings?.selectedModel;
const isSmartAutoEnabled =
settings.enableProSmartFilesContextMode && isDyadProEnabled(settings);
const modelDisplayName = getModelDisplayName();
return (
......@@ -190,21 +192,37 @@ export function ModelPicker() {
>
<div className="flex justify-between items-start w-full">
<span className="flex flex-col items-start">
<span>{model.displayName}</span>
<span className="text-xs text-muted-foreground">
auto
<span>
{isSmartAutoEnabled
? "Smart Auto"
: model.displayName}
</span>
</span>
<div className="flex items-center gap-1.5">
{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">
Dyad Pro
</span>
)}
{model.tag && (
<span className="text-[10px] bg-primary/10 text-primary px-1.5 py-0.5 rounded-full font-medium">
{model.tag}
</span>
)}
</div>
</div>
</DropdownMenuItem>
</TooltipTrigger>
<TooltipContent side="right">
{model.description}
{isSmartAutoEnabled ? (
<p>
<strong>Smart Auto</strong> uses a cheaper model for
easier tasks
<br /> and a flagship model for harder tasks
</p>
) : (
model.description
)}
</TooltipContent>
</Tooltip>
))}
......
......@@ -8,6 +8,7 @@ import { eq } from "drizzle-orm";
export const PROVIDERS_THAT_SUPPORT_THINKING: (keyof typeof MODEL_OPTIONS)[] = [
"google",
"auto",
];
export interface ModelOption {
......@@ -139,6 +140,11 @@ export const MODEL_OPTIONS: Record<string, ModelOption[]> = {
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,
},
],
};
......@@ -186,7 +192,7 @@ export const CLOUD_PROVIDERS: Record<
auto: {
displayName: "Dyad",
websiteUrl: "https://academy.dyad.sh/settings",
gatewayPrefix: "",
gatewayPrefix: "dyad/",
},
};
......
......@@ -54,39 +54,6 @@ export async function getModelClient(
const allProviders = await getLanguageModelProviders();
const dyadApiKey = settings.providerSettings?.auto?.apiKey?.value;
// Handle 'auto' provider by trying each model in AUTO_MODELS until one works
if (model.provider === "auto") {
for (const autoModel of AUTO_MODELS) {
const providerInfo = allProviders.find(
(p) => p.id === autoModel.provider,
);
const envVarName = providerInfo?.envVarName;
const apiKey =
dyadApiKey ||
settings.providerSettings?.[autoModel.provider]?.apiKey?.value ||
(envVarName ? getEnvVar(envVarName) : undefined);
if (apiKey) {
logger.log(
`Using provider: ${autoModel.provider} model: ${autoModel.name}`,
);
// Recursively call with the specific model found
return await getModelClient(
{
provider: autoModel.provider,
name: autoModel.name,
},
settings,
files,
);
}
}
// If no models have API keys, throw an error
throw new Error(
"No API keys available for any model supported by the 'auto' provider.",
);
}
// --- Handle specific provider ---
const providerConfig = allProviders.find((p) => p.id === model.provider);
......@@ -161,6 +128,38 @@ export async function getModelClient(
// Fall through to regular provider logic if gateway prefix is missing
}
}
// Handle 'auto' provider by trying each model in AUTO_MODELS until one works
if (model.provider === "auto") {
for (const autoModel of AUTO_MODELS) {
const providerInfo = allProviders.find(
(p) => p.id === autoModel.provider,
);
const envVarName = providerInfo?.envVarName;
const apiKey =
settings.providerSettings?.[autoModel.provider]?.apiKey?.value ||
(envVarName ? getEnvVar(envVarName) : undefined);
if (apiKey) {
logger.log(
`Using provider: ${autoModel.provider} model: ${autoModel.name}`,
);
// Recursively call with the specific model found
return await getModelClient(
{
provider: autoModel.provider,
name: autoModel.name,
},
settings,
files,
);
}
}
// If no models have API keys, throw an error
throw new Error(
"No API keys available for any model supported by the 'auto' provider.",
);
}
return getRegularModelClient(model, settings, providerConfig);
}
......
......@@ -168,6 +168,13 @@ export const UserSettingsSchema = z.object({
*/
export type UserSettings = z.infer<typeof UserSettingsSchema>;
export function isDyadProEnabled(settings: UserSettings): boolean {
return (
settings.enableDyadPro === true &&
!!settings.providerSettings?.auto?.apiKey?.value
);
}
// Define interfaces for the props
export interface SecurityRisk {
type: "warning" | "danger";
......
......@@ -290,6 +290,15 @@
}
}
@keyframes shimmer {
0% {
background-position: -200% 0;
}
100% {
background-position: 200% 0;
}
}
.animate-marquee {
animation: marquee 2s linear infinite;
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论