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:
lofyer
2026-08-14 10:30:53 +08:00
parent 8286e120a1
commit 36e05d45fa
5 changed files with 71 additions and 120 deletions
+1
View File
@@ -403,6 +403,7 @@ DeepSeek Harness 首版只使用 GoodBuddy 模型连接:
- 服务地址必须是 `https://api.deepseek.com`,且不得包含用户信息。 - 服务地址必须是 `https://api.deepseek.com`,且不得包含用户信息。
- 模型名称和服务地址由 Main 传入受控 Host。 - 模型名称和服务地址由 Main 传入受控 Host。
- API Key 继续保存在 GoodBuddy 加密设置中。 - API Key 继续保存在 GoodBuddy 加密设置中。
- 启动环境提供的部署连接只由 Main 自动解析,不在 Renderer 中显示为可选来源。
不允许选择 Harness 自有的用户配置文件或自定义 Host。Runtime 始终使用随当前 GoodBuddy 版本发布的内置 Host,并通过完整内部能力握手。 不允许选择 Harness 自有的用户配置文件或自定义 Host。Runtime 始终使用随当前 GoodBuddy 版本发布的内置 Host,并通过完整内部能力握手。
+21 -13
View File
@@ -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 = const harnessProfileId =
'00000000-0000-4000-8000-000000000051' '00000000-0000-4000-8000-000000000051'
getRuntime.mockResolvedValueOnce({ getRuntime.mockResolvedValueOnce({
@@ -1451,8 +1451,12 @@ describe('SettingsPanel runtime files', () => {
}) })
).not.toBeInTheDocument() ).not.toBeInTheDocument()
const source = screen.getByLabelText( const source = screen.getByLabelText(
'DeepSeek Harness GoodBuddy 模型连接' 'DeepSeek Harness DeepSeek 模型连接'
) )
expect(screen.queryByRole('radio')).not.toBeInTheDocument()
expect(
screen.queryByText('使用平台 DeepSeek 环境配置')
).not.toBeInTheDocument()
expect( expect(
within(source).getByRole('option', { name: '默认模型(不兼容)' }) within(source).getByRole('option', { name: '默认模型(不兼容)' })
).toBeDisabled() ).toBeDisabled()
@@ -1460,22 +1464,20 @@ describe('SettingsPanel runtime files', () => {
within(source).getByRole('option', { name: 'DeepSeek Chat' }) within(source).getByRole('option', { name: 'DeepSeek Chat' })
).not.toBeDisabled() ).not.toBeDisabled()
fireEvent.click(
screen.getByRole('radio', {
name: /使用平台 DeepSeek 环境配置/
})
)
fireEvent.click(screen.getByRole('button', { name: '保存设置' })) fireEvent.click(screen.getByRole('button', { name: '保存设置' }))
await waitFor(() => await waitFor(() =>
expect(updateRuntime).toHaveBeenCalledWith( expect(updateRuntime).toHaveBeenCalledWith(
expect.objectContaining({ 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({ getRuntime.mockResolvedValueOnce({
...runtimeSettings, ...runtimeSettings,
modelBaseUrl: 'https://api.deepseek.com', modelBaseUrl: 'https://api.deepseek.com',
@@ -1527,11 +1529,17 @@ describe('SettingsPanel runtime files', () => {
name: 'DeepSeek Harness(预览)' name: 'DeepSeek Harness(预览)'
}) })
) )
fireEvent.click( expect(screen.queryByRole('radio')).not.toBeInTheDocument()
screen.getByRole('radio', { expect(
name: /使用 GoodBuddy 模型连接/ 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: '保存设置' })) fireEvent.click(screen.getByRole('button', { name: '保存设置' }))
await waitFor(() => await waitFor(() =>
+41 -93
View File
@@ -1981,7 +1981,7 @@ export function SettingsPanel({
detecting={detecting} detecting={detecting}
modelConfiguration={ modelConfiguration={
activeRuntimeModelSource.kind === 'platform' activeRuntimeModelSource.kind === 'platform'
? t('runtime.deepseekHarness.platformSource') ? t('runtime.deepseekHarness.managedSource')
: activeRuntimeModelProfile : activeRuntimeModelProfile
? t('runtime.followGoodBuddy', { ? t('runtime.followGoodBuddy', {
name: modelProfileDisplayName( name: modelProfileDisplayName(
@@ -1998,100 +1998,48 @@ export function SettingsPanel({
runtime: 'DeepSeek Harness' runtime: 'DeepSeek Harness'
})} })}
/> />
<fieldset className="runtime-source-options"> <label className="field">
<legend>{t('runtime.sourceLegend')}</legend> <span>{t('runtime.deepseekHarness.connection')}</span>
<label> <select
<input aria-label={`DeepSeek Harness ${t(
checked={ 'runtime.deepseekHarness.connection'
deepseekHarnessModelSource.kind === 'profile' )}`}
} disabled={!defaultDeepseekHarnessModelProfile}
disabled={!defaultDeepseekHarnessModelProfile} onChange={(event) =>
name="deepseek-harness-model-source" setDeepseekHarnessModelSource(
onChange={() => { parseModelSource(event.target.value)
if (defaultDeepseekHarnessModelProfile) { )
setDeepseekHarnessModelSource({ }
kind: 'profile', value={
profileId: deepseekHarnessModelSource.kind === 'profile'
defaultDeepseekHarnessModelProfile.id ? deepseekHarnessModelSource.profileId
}) : ''
} }
}} >
type="radio" <option disabled value="">
/>
<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>
{t( {t(
'runtime.deepseekHarness.connectionDescription' 'runtime.deepseekHarness.connectionPlaceholder'
)} )}
</small> </option>
</label> {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"> <details className="settings-section">
<summary>{t('runtime.advanced')}</summary> <summary>{t('runtime.advanced')}</summary>
<p className="settings-panel__description"> <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.', 'DeepSeek Harness currently supports DeepSeek models only and is not intended for other model providers.',
description: 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.', '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', managedSource: 'Administrator-provided DeepSeek connection',
goodBuddySourceDescription: connection: 'DeepSeek model connection',
'Only OpenAI-compatible Chat Completions connections are available. The connection must point to a DeepSeek model.', connectionPlaceholder: 'Select a DeepSeek model connection',
platformSource: 'Use platform DeepSeek environment settings',
platformSourceDescription:
'Reads platform-managed DeepSeek settings from the launch environment without exposing credentials to the renderer.',
connectionDescription: 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: advancedDescription:
'This Runtime always uses GoodBuddys bundled, version-pinned Host. It does not load external DSH plugins, marketplace packages, user profiles, or custom Hosts.' 'This Runtime always uses GoodBuddys 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 模型,不适用于其他模型提供商。', 'DeepSeek Harness 当前仅支持 DeepSeek 模型,不适用于其他模型提供商。',
description: description:
'由 GoodBuddy 内部维护固定 Host 与控制协议,复用锁定的 Harness 底层库;Execute 工具调用自动单次授权,Ask 保持只读,并保留取消和工作区安全边界;不接入 DSH 插件或市场机制。', '由 GoodBuddy 内部维护固定 Host 与控制协议,复用锁定的 Harness 底层库;Execute 工具调用自动单次授权,Ask 保持只读,并保留取消和工作区安全边界;不接入 DSH 插件或市场机制。',
goodBuddySource: '使用 GoodBuddy 模型连接', managedSource: '管理员预置的 DeepSeek 连接',
goodBuddySourceDescription: connection: 'DeepSeek 模型连接',
'只能选择 OpenAI 兼容 Chat Completions 连接;该连接必须指向 DeepSeek 模型', connectionPlaceholder: '选择 DeepSeek 模型连接',
platformSource: '使用平台 DeepSeek 环境配置',
platformSourceDescription:
'从启动环境读取平台管理的 DeepSeek 配置,不会在渲染进程中显示凭据。',
connectionDescription: connectionDescription:
'GoodBuddy 内部 Harness Runtime 目前仅接受 OpenAI 兼容 Chat Completions 协议。', 'GoodBuddy 模型连接中选择;仅支持指向 DeepSeek 的 OpenAI 兼容 Chat Completions 连接。',
advancedDescription: advancedDescription:
'该 Runtime 始终使用 GoodBuddy 内置并固定版本的 Host,不加载外部 DSH 插件、市场包、用户 profile 或自定义 Host。' '该 Runtime 始终使用 GoodBuddy 内置并固定版本的 Host,不加载外部 DSH 插件、市场包、用户 profile 或自定义 Host。'
} }