Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
B
bit-pm
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
燕伟桐
bit-pm
Commits
5d678c2e
Unverified
提交
5d678c2e
authored
6月 24, 2025
作者:
Will Chen
提交者:
GitHub
6月 24, 2025
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Smart auto (#476)
上级
30415638
全部展开
显示空白字符变更
内嵌
并排
正在显示
10 个修改的文件
包含
106 行增加
和
43 行删除
+106
-43
engine.spec.ts
e2e-tests/engine.spec.ts
+21
-2
engine.spec.ts_regular-auto-should-send-message-to-engine-1.aria.yml
....ts_regular-auto-should-send-message-to-engine-1.aria.yml
+0
-0
engine.spec.ts_regular-auto-should-send-message-to-engine-1.txt
....spec.ts_regular-auto-should-send-message-to-engine-1.txt
+0
-0
engine.spec.ts_smart-auto-should-send-message-to-engine-1.aria.yml
...ec.ts_smart-auto-should-send-message-to-engine-1.aria.yml
+5
-0
engine.spec.ts_smart-auto-should-send-message-to-engine-1.txt
...ne.spec.ts_smart-auto-should-send-message-to-engine-1.txt
+2
-2
ModelPicker.tsx
src/components/ModelPicker.tsx
+23
-5
language_model_helpers.ts
src/ipc/shared/language_model_helpers.ts
+7
-1
get_model_client.ts
src/ipc/utils/get_model_client.ts
+32
-33
schemas.ts
src/lib/schemas.ts
+7
-0
globals.css
src/styles/globals.css
+9
-0
没有找到文件。
e2e-tests/engine.spec.ts
浏览文件 @
5d678c2e
...
@@ -34,10 +34,29 @@ testSkipIfWindows(
...
@@ -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
.
setUpDyadPro
();
await
po
.
sendPrompt
(
"[dump] tc=turbo-edits"
);
await
po
.
sendPrompt
(
"[dump] tc=turbo-edits"
);
await
po
.
snapshotServerDump
(
"request"
);
await
po
.
snapshotServerDump
(
"request"
);
await
po
.
snapshotMessages
({
replaceDumpPath
:
true
});
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
});
},
);
e2e-tests/snapshots/engine.spec.ts_auto-should-send-message-to-engine-1.aria.yml
→
e2e-tests/snapshots/engine.spec.ts_
regular-
auto-should-send-message-to-engine-1.aria.yml
浏览文件 @
5d678c2e
File moved
e2e-tests/snapshots/engine.spec.ts_regular-auto-should-send-message-to-engine-1.txt
0 → 100644
浏览文件 @
5d678c2e
差异被折叠。
点击展开。
e2e-tests/snapshots/engine.spec.ts_smart-auto-should-send-message-to-engine-1.aria.yml
0 → 100644
浏览文件 @
5d678c2e
-
paragraph
:
"
[dump]
tc=turbo-edits"
-
paragraph
:
"
[[dyad-dump-path=*]]"
-
button "Retry"
:
-
img
\ No newline at end of file
e2e-tests/snapshots/engine.spec.ts_auto-should-send-message-to-engine-1.txt
→
e2e-tests/snapshots/engine.spec.ts_
smart-
auto-should-send-message-to-engine-1.txt
浏览文件 @
5d678c2e
{
{
"body": {
"body": {
"model": "
gemini/gemini-2.5-flash
",
"model": "
dyad/auto
",
"max_tokens":
8
000,
"max_tokens":
32
000,
"temperature": 0,
"temperature": 0,
"messages": [
"messages": [
{
{
...
...
src/components/ModelPicker.tsx
浏览文件 @
5d678c2e
import
type
{
LargeLanguageModel
}
from
"@/lib/schemas"
;
import
{
isDyadProEnabled
,
type
LargeLanguageModel
}
from
"@/lib/schemas"
;
import
{
Button
}
from
"@/components/ui/button"
;
import
{
Button
}
from
"@/components/ui/button"
;
import
{
import
{
Tooltip
,
Tooltip
,
...
@@ -119,6 +119,8 @@ export function ModelPicker() {
...
@@ -119,6 +119,8 @@ export function ModelPicker() {
return
null
;
return
null
;
}
}
const
selectedModel
=
settings
?.
selectedModel
;
const
selectedModel
=
settings
?.
selectedModel
;
const
isSmartAutoEnabled
=
settings
.
enableProSmartFilesContextMode
&&
isDyadProEnabled
(
settings
);
const
modelDisplayName
=
getModelDisplayName
();
const
modelDisplayName
=
getModelDisplayName
();
return
(
return
(
...
@@ -190,21 +192,37 @@ export function ModelPicker() {
...
@@ -190,21 +192,37 @@ 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
>
{
model
.
displayName
}
</
span
>
<
span
>
<
span
className=
"text-xs text-muted-foreground"
>
{
isSmartAutoEnabled
auto
?
"Smart Auto"
:
model
.
displayName
}
</
span
>
</
span
>
</
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
&&
(
{
model
.
tag
&&
(
<
span
className=
"text-[10px] bg-primary/10 text-primary px-1.5 py-0.5 rounded-full font-medium"
>
<
span
className=
"text-[10px] bg-primary/10 text-primary px-1.5 py-0.5 rounded-full font-medium"
>
{
model
.
tag
}
{
model
.
tag
}
</
span
>
</
span
>
)
}
)
}
</
div
>
</
div
>
</
div
>
</
DropdownMenuItem
>
</
DropdownMenuItem
>
</
TooltipTrigger
>
</
TooltipTrigger
>
<
TooltipContent
side=
"right"
>
<
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
>
</
TooltipContent
>
</
Tooltip
>
</
Tooltip
>
))
}
))
}
...
...
src/ipc/shared/language_model_helpers.ts
浏览文件 @
5d678c2e
...
@@ -8,6 +8,7 @@ import { eq } from "drizzle-orm";
...
@@ -8,6 +8,7 @@ import { eq } from "drizzle-orm";
export
const
PROVIDERS_THAT_SUPPORT_THINKING
:
(
keyof
typeof
MODEL_OPTIONS
)[]
=
[
export
const
PROVIDERS_THAT_SUPPORT_THINKING
:
(
keyof
typeof
MODEL_OPTIONS
)[]
=
[
"google"
,
"google"
,
"auto"
,
];
];
export
interface
ModelOption
{
export
interface
ModelOption
{
...
@@ -139,6 +140,11 @@ export const MODEL_OPTIONS: Record<string, ModelOption[]> = {
...
@@ -139,6 +140,11 @@ export const MODEL_OPTIONS: Record<string, ModelOption[]> = {
displayName
:
"Auto"
,
displayName
:
"Auto"
,
description
:
"Automatically selects the best model"
,
description
:
"Automatically selects the best model"
,
tag
:
"Default"
,
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<
...
@@ -186,7 +192,7 @@ export const CLOUD_PROVIDERS: Record<
auto
:
{
auto
:
{
displayName
:
"Dyad"
,
displayName
:
"Dyad"
,
websiteUrl
:
"https://academy.dyad.sh/settings"
,
websiteUrl
:
"https://academy.dyad.sh/settings"
,
gatewayPrefix
:
""
,
gatewayPrefix
:
"
dyad/
"
,
},
},
};
};
...
...
src/ipc/utils/get_model_client.ts
浏览文件 @
5d678c2e
...
@@ -54,39 +54,6 @@ export async function getModelClient(
...
@@ -54,39 +54,6 @@ export async function getModelClient(
const
allProviders
=
await
getLanguageModelProviders
();
const
allProviders
=
await
getLanguageModelProviders
();
const
dyadApiKey
=
settings
.
providerSettings
?.
auto
?.
apiKey
?.
value
;
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 ---
// --- Handle specific provider ---
const
providerConfig
=
allProviders
.
find
((
p
)
=>
p
.
id
===
model
.
provider
);
const
providerConfig
=
allProviders
.
find
((
p
)
=>
p
.
id
===
model
.
provider
);
...
@@ -161,6 +128,38 @@ export async function getModelClient(
...
@@ -161,6 +128,38 @@ export async function getModelClient(
// Fall through to regular provider logic if gateway prefix is missing
// 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);
return getRegularModelClient(model, settings, providerConfig);
}
}
...
...
src/lib/schemas.ts
浏览文件 @
5d678c2e
...
@@ -168,6 +168,13 @@ export const UserSettingsSchema = z.object({
...
@@ -168,6 +168,13 @@ export const UserSettingsSchema = z.object({
*/
*/
export
type
UserSettings
=
z
.
infer
<
typeof
UserSettingsSchema
>
;
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
// Define interfaces for the props
export
interface
SecurityRisk
{
export
interface
SecurityRisk
{
type
:
"warning"
|
"danger"
;
type
:
"warning"
|
"danger"
;
...
...
src/styles/globals.css
浏览文件 @
5d678c2e
...
@@ -290,6 +290,15 @@
...
@@ -290,6 +290,15 @@
}
}
}
}
@keyframes
shimmer
{
0
%
{
background-position
:
-200%
0
;
}
100
%
{
background-position
:
200%
0
;
}
}
.animate-marquee
{
.animate-marquee
{
animation
:
marquee
2s
linear
infinite
;
animation
:
marquee
2s
linear
infinite
;
}
}
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论