feat: simplify DeepSeek Harness model selection
- replace competing model-source choices with one DeepSeek connection picker - keep administrator-provided environment settings compatible without exposing them as a selectable UI source - update bilingual guidance, tests, and runtime design documentation
This commit is contained in:
@@ -403,6 +403,7 @@ DeepSeek Harness 首版只使用 GoodBuddy 模型连接:
|
||||
- 服务地址必须是 `https://api.deepseek.com`,且不得包含用户信息。
|
||||
- 模型名称和服务地址由 Main 传入受控 Host。
|
||||
- API Key 继续保存在 GoodBuddy 加密设置中。
|
||||
- 启动环境提供的部署连接只由 Main 自动解析,不在 Renderer 中显示为可选来源。
|
||||
|
||||
不允许选择 Harness 自有的用户配置文件或自定义 Host。Runtime 始终使用随当前 GoodBuddy 版本发布的内置 Host,并通过完整内部能力握手。
|
||||
|
||||
|
||||
@@ -1372,7 +1372,7 @@ describe('SettingsPanel runtime files', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('configures DeepSeek Harness only with Chat Completions or platform settings', async () => {
|
||||
it('configures DeepSeek Harness with a compatible GoodBuddy connection', async () => {
|
||||
const harnessProfileId =
|
||||
'00000000-0000-4000-8000-000000000051'
|
||||
getRuntime.mockResolvedValueOnce({
|
||||
@@ -1451,8 +1451,12 @@ describe('SettingsPanel runtime files', () => {
|
||||
})
|
||||
).not.toBeInTheDocument()
|
||||
const source = screen.getByLabelText(
|
||||
'DeepSeek Harness GoodBuddy 模型连接'
|
||||
'DeepSeek Harness DeepSeek 模型连接'
|
||||
)
|
||||
expect(screen.queryByRole('radio')).not.toBeInTheDocument()
|
||||
expect(
|
||||
screen.queryByText('使用平台 DeepSeek 环境配置')
|
||||
).not.toBeInTheDocument()
|
||||
expect(
|
||||
within(source).getByRole('option', { name: '默认模型(不兼容)' })
|
||||
).toBeDisabled()
|
||||
@@ -1460,22 +1464,20 @@ describe('SettingsPanel runtime files', () => {
|
||||
within(source).getByRole('option', { name: 'DeepSeek Chat' })
|
||||
).not.toBeDisabled()
|
||||
|
||||
fireEvent.click(
|
||||
screen.getByRole('radio', {
|
||||
name: /使用平台 DeepSeek 环境配置/
|
||||
})
|
||||
)
|
||||
fireEvent.click(screen.getByRole('button', { name: '保存设置' }))
|
||||
await waitFor(() =>
|
||||
expect(updateRuntime).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
deepseekHarnessModelSource: { kind: 'platform' }
|
||||
deepseekHarnessModelSource: {
|
||||
kind: 'profile',
|
||||
profileId: harnessProfileId
|
||||
}
|
||||
})
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
it('normalizes an environment-managed DeepSeek profile to the platform source when saving', async () => {
|
||||
it('keeps an environment-managed source compatible without exposing it as an option', async () => {
|
||||
getRuntime.mockResolvedValueOnce({
|
||||
...runtimeSettings,
|
||||
modelBaseUrl: 'https://api.deepseek.com',
|
||||
@@ -1527,11 +1529,17 @@ describe('SettingsPanel runtime files', () => {
|
||||
name: 'DeepSeek Harness(预览)'
|
||||
})
|
||||
)
|
||||
fireEvent.click(
|
||||
screen.getByRole('radio', {
|
||||
name: /使用 GoodBuddy 模型连接/
|
||||
})
|
||||
expect(screen.queryByRole('radio')).not.toBeInTheDocument()
|
||||
expect(
|
||||
screen.getByText('管理员预置的 DeepSeek 连接')
|
||||
).toBeInTheDocument()
|
||||
const source = screen.getByLabelText(
|
||||
'DeepSeek Harness DeepSeek 模型连接'
|
||||
)
|
||||
expect(source).toHaveValue('')
|
||||
fireEvent.change(source, {
|
||||
target: { value: runtimeSettings.modelProfiles[0]!.id }
|
||||
})
|
||||
fireEvent.click(screen.getByRole('button', { name: '保存设置' }))
|
||||
|
||||
await waitFor(() =>
|
||||
|
||||
@@ -1981,7 +1981,7 @@ export function SettingsPanel({
|
||||
detecting={detecting}
|
||||
modelConfiguration={
|
||||
activeRuntimeModelSource.kind === 'platform'
|
||||
? t('runtime.deepseekHarness.platformSource')
|
||||
? t('runtime.deepseekHarness.managedSource')
|
||||
: activeRuntimeModelProfile
|
||||
? t('runtime.followGoodBuddy', {
|
||||
name: modelProfileDisplayName(
|
||||
@@ -1998,100 +1998,48 @@ export function SettingsPanel({
|
||||
runtime: 'DeepSeek Harness'
|
||||
})}
|
||||
/>
|
||||
<fieldset className="runtime-source-options">
|
||||
<legend>{t('runtime.sourceLegend')}</legend>
|
||||
<label>
|
||||
<input
|
||||
checked={
|
||||
deepseekHarnessModelSource.kind === 'profile'
|
||||
}
|
||||
disabled={!defaultDeepseekHarnessModelProfile}
|
||||
name="deepseek-harness-model-source"
|
||||
onChange={() => {
|
||||
if (defaultDeepseekHarnessModelProfile) {
|
||||
setDeepseekHarnessModelSource({
|
||||
kind: 'profile',
|
||||
profileId:
|
||||
defaultDeepseekHarnessModelProfile.id
|
||||
})
|
||||
}
|
||||
}}
|
||||
type="radio"
|
||||
/>
|
||||
<span>
|
||||
<strong>
|
||||
{t(
|
||||
'runtime.deepseekHarness.goodBuddySource'
|
||||
)}
|
||||
</strong>
|
||||
<small>
|
||||
{t(
|
||||
'runtime.deepseekHarness.goodBuddySourceDescription'
|
||||
)}
|
||||
</small>
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
checked={
|
||||
deepseekHarnessModelSource.kind === 'platform'
|
||||
}
|
||||
name="deepseek-harness-model-source"
|
||||
onChange={() =>
|
||||
setDeepseekHarnessModelSource({
|
||||
kind: 'platform'
|
||||
})
|
||||
}
|
||||
type="radio"
|
||||
/>
|
||||
<span>
|
||||
<strong>
|
||||
{t('runtime.deepseekHarness.platformSource')}
|
||||
</strong>
|
||||
<small>
|
||||
{t(
|
||||
'runtime.deepseekHarness.platformSourceDescription'
|
||||
)}
|
||||
</small>
|
||||
</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
{deepseekHarnessModelSource.kind === 'profile' && (
|
||||
<label className="field">
|
||||
<span>{t('runtime.goodBuddyConnection')}</span>
|
||||
<select
|
||||
aria-label={`DeepSeek Harness ${t(
|
||||
'runtime.goodBuddyConnection'
|
||||
)}`}
|
||||
onChange={(event) =>
|
||||
setDeepseekHarnessModelSource(
|
||||
parseModelSource(event.target.value)
|
||||
)
|
||||
}
|
||||
value={deepseekHarnessModelSource.profileId}
|
||||
>
|
||||
{modelProfiles.map((profile) => (
|
||||
<option
|
||||
disabled={
|
||||
!isDeepseekHarnessCompatible(profile)
|
||||
}
|
||||
key={profile.id}
|
||||
value={profile.id}
|
||||
>
|
||||
{modelProfileDisplayName(profile)}
|
||||
{isDeepseekHarnessCompatible(profile)
|
||||
? ''
|
||||
: t('runtime.incompatibleSuffix')}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<small>
|
||||
<label className="field">
|
||||
<span>{t('runtime.deepseekHarness.connection')}</span>
|
||||
<select
|
||||
aria-label={`DeepSeek Harness ${t(
|
||||
'runtime.deepseekHarness.connection'
|
||||
)}`}
|
||||
disabled={!defaultDeepseekHarnessModelProfile}
|
||||
onChange={(event) =>
|
||||
setDeepseekHarnessModelSource(
|
||||
parseModelSource(event.target.value)
|
||||
)
|
||||
}
|
||||
value={
|
||||
deepseekHarnessModelSource.kind === 'profile'
|
||||
? deepseekHarnessModelSource.profileId
|
||||
: ''
|
||||
}
|
||||
>
|
||||
<option disabled value="">
|
||||
{t(
|
||||
'runtime.deepseekHarness.connectionDescription'
|
||||
'runtime.deepseekHarness.connectionPlaceholder'
|
||||
)}
|
||||
</small>
|
||||
</label>
|
||||
)}
|
||||
</option>
|
||||
{modelProfiles.map((profile) => (
|
||||
<option
|
||||
disabled={!isDeepseekHarnessCompatible(profile)}
|
||||
key={profile.id}
|
||||
value={profile.id}
|
||||
>
|
||||
{modelProfileDisplayName(profile)}
|
||||
{isDeepseekHarnessCompatible(profile)
|
||||
? ''
|
||||
: t('runtime.incompatibleSuffix')}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<small>
|
||||
{t(
|
||||
'runtime.deepseekHarness.connectionDescription'
|
||||
)}
|
||||
</small>
|
||||
</label>
|
||||
<details className="settings-section">
|
||||
<summary>{t('runtime.advanced')}</summary>
|
||||
<p className="settings-panel__description">
|
||||
|
||||
@@ -242,14 +242,11 @@ export const settings = {
|
||||
'DeepSeek Harness currently supports DeepSeek models only and is not intended for other model providers.',
|
||||
description:
|
||||
'GoodBuddy maintains the fixed Host and control protocol internally and uses pinned Harness libraries underneath. Execute tool calls receive automatic one-time authorization, Ask remains read-only, and cancellation and workspace safety boundaries remain in place. It does not integrate with the DSH plugin or marketplace mechanisms.',
|
||||
goodBuddySource: 'Use a GoodBuddy model connection',
|
||||
goodBuddySourceDescription:
|
||||
'Only OpenAI-compatible Chat Completions connections are available. The connection must point to a DeepSeek model.',
|
||||
platformSource: 'Use platform DeepSeek environment settings',
|
||||
platformSourceDescription:
|
||||
'Reads platform-managed DeepSeek settings from the launch environment without exposing credentials to the renderer.',
|
||||
managedSource: 'Administrator-provided DeepSeek connection',
|
||||
connection: 'DeepSeek model connection',
|
||||
connectionPlaceholder: 'Select a DeepSeek model connection',
|
||||
connectionDescription:
|
||||
'The internal GoodBuddy Harness Runtime currently accepts only the OpenAI-compatible Chat Completions protocol.',
|
||||
'Choose a GoodBuddy model connection. Only OpenAI-compatible Chat Completions connections that point to DeepSeek are supported.',
|
||||
advancedDescription:
|
||||
'This Runtime always uses GoodBuddy’s bundled, version-pinned Host. It does not load external DSH plugins, marketplace packages, user profiles, or custom Hosts.'
|
||||
}
|
||||
|
||||
@@ -220,14 +220,11 @@ export const settings = {
|
||||
'DeepSeek Harness 当前仅支持 DeepSeek 模型,不适用于其他模型提供商。',
|
||||
description:
|
||||
'由 GoodBuddy 内部维护固定 Host 与控制协议,复用锁定的 Harness 底层库;Execute 工具调用自动单次授权,Ask 保持只读,并保留取消和工作区安全边界;不接入 DSH 插件或市场机制。',
|
||||
goodBuddySource: '使用 GoodBuddy 模型连接',
|
||||
goodBuddySourceDescription:
|
||||
'只能选择 OpenAI 兼容 Chat Completions 连接;该连接必须指向 DeepSeek 模型。',
|
||||
platformSource: '使用平台 DeepSeek 环境配置',
|
||||
platformSourceDescription:
|
||||
'从启动环境读取平台管理的 DeepSeek 配置,不会在渲染进程中显示凭据。',
|
||||
managedSource: '管理员预置的 DeepSeek 连接',
|
||||
connection: 'DeepSeek 模型连接',
|
||||
connectionPlaceholder: '选择 DeepSeek 模型连接',
|
||||
connectionDescription:
|
||||
'GoodBuddy 内部 Harness Runtime 目前仅接受 OpenAI 兼容 Chat Completions 协议。',
|
||||
'从 GoodBuddy 模型连接中选择;仅支持指向 DeepSeek 的 OpenAI 兼容 Chat Completions 连接。',
|
||||
advancedDescription:
|
||||
'该 Runtime 始终使用 GoodBuddy 内置并固定版本的 Host,不加载外部 DSH 插件、市场包、用户 profile 或自定义 Host。'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user