feat: add DeepSeek Harness runtime

This commit is contained in:
lofyer
2026-08-14 10:04:34 +08:00
parent fca9888f83
commit 8286e120a1
69 changed files with 13660 additions and 351 deletions
+199 -5
View File
@@ -42,6 +42,7 @@ function settings(
continueBinaryPath: '',
continueConfigPath: '',
continueMode: 'chat',
deepseekHarnessModelSource: { kind: 'platform' },
runtimeSandboxMode: 'auto',
knowledgeEmbeddingEnabled: false,
knowledgeEmbeddingBaseUrl:
@@ -103,6 +104,199 @@ describe('RuntimeSettingsStore', () => {
})
})
it('migrates DeepSeek Harness to controlled platform mode and stores an official profile', async () => {
const { filePath, store } = await createStore()
await store.update(settings())
const versionFourteen = JSON.parse(
await readFile(filePath, 'utf8')
) as Record<string, unknown>
versionFourteen.version = 14
delete versionFourteen.deepseekHarnessModelSource
delete versionFourteen.deepseekHarnessBinaryPath
await writeFile(filePath, JSON.stringify(versionFourteen), 'utf8')
const migrated = new RuntimeSettingsStore(filePath, cipher, {})
await expect(migrated.getResolvedSettings()).resolves.toMatchObject({
deepseekHarnessModelProfile: undefined
})
const profileId = '00000000-0000-4000-8000-000000000044'
await migrated.update(
settings({
provider: 'deepseek-harness',
modelProfiles: [
{
id: profileId,
name: 'DeepSeek',
baseUrl: 'https://api.deepseek.com',
modelName: 'deepseek-chat',
protocol: 'openai-chat-completions',
authentication: 'api-key',
imageGenerationQuality: 'auto',
apiKey: { action: 'replace', value: 'deepseek-secret' }
}
],
defaultModelProfileId: profileId,
deepseekHarnessModelSource: { kind: 'profile', profileId }
})
)
await expect(migrated.getResolvedSettings()).resolves.toMatchObject({
provider: 'deepseek-harness',
deepseekHarnessModelProfile: {
id: profileId,
apiKey: 'deepseek-secret'
}
})
})
it('resolves a controlled platform DeepSeek profile without exposing its credential', async () => {
const apiKey = 'platform-deepseek-secret'
const { store } = await createStore({
GOODBUDDY_MODEL_API_KEY: apiKey,
GOODBUDDY_MODEL_BASE_URL: 'https://api.deepseek.com/',
GOODBUDDY_MODEL_NAME: 'deepseek-v4-flash'
})
await expect(store.getResolvedSettings()).resolves.toMatchObject({
modelProtocol: 'anthropic-messages',
deepseekHarnessModelProfile: {
id: 'goodbuddy-platform-deepseek',
name: '平台 DeepSeek',
baseUrl: 'https://api.deepseek.com/',
modelName: 'deepseek-v4-flash',
protocol: 'openai-chat-completions',
authentication: 'api-key',
supportsImageInput: false,
imageGenerationQuality: 'auto',
apiKey
}
})
const publicSettings = await store.getPublicSettings()
expect(JSON.stringify(publicSettings)).not.toContain(apiKey)
expect(publicSettings.modelProtocol).toBe('anthropic-messages')
})
it.each([
[
'a non-DeepSeek endpoint',
{
GOODBUDDY_MODEL_API_KEY: 'platform-key',
GOODBUDDY_MODEL_BASE_URL: 'https://deepseek.example',
GOODBUDDY_MODEL_NAME: 'deepseek-chat'
}
],
[
'an insecure DeepSeek endpoint',
{
GOODBUDDY_MODEL_API_KEY: 'platform-key',
GOODBUDDY_MODEL_BASE_URL: 'http://api.deepseek.com',
GOODBUDDY_MODEL_NAME: 'deepseek-chat'
}
],
[
'a DeepSeek endpoint path',
{
GOODBUDDY_MODEL_API_KEY: 'platform-key',
GOODBUDDY_MODEL_BASE_URL: 'https://api.deepseek.com/v1',
GOODBUDDY_MODEL_NAME: 'deepseek-chat'
}
],
[
'a missing API key',
{
GOODBUDDY_MODEL_BASE_URL: 'https://api.deepseek.com',
GOODBUDDY_MODEL_NAME: 'deepseek-chat'
}
]
])('does not resolve platform DeepSeek from %s', async (_, environment) => {
const { store } = await createStore(environment)
await expect(store.getResolvedSettings()).resolves.toMatchObject({
deepseekHarnessModelProfile: undefined
})
})
it('drops the legacy custom Harness Host path and ignores its environment override', async () => {
const { filePath, store } = await createStore()
await store.update(settings())
const versionFifteen = JSON.parse(
await readFile(filePath, 'utf8')
) as Record<string, unknown>
versionFifteen.version = 15
versionFifteen.deepseekHarnessBinaryPath =
'C:\\untrusted\\custom-harness.js'
await writeFile(filePath, JSON.stringify(versionFifteen), 'utf8')
const migrated = new RuntimeSettingsStore(filePath, cipher, {
GOODBUDDY_DEEPSEEK_HARNESS_BINARY:
'C:\\environment\\custom-harness.js'
})
const publicSettings = await migrated.getPublicSettings()
const resolvedSettings = await migrated.getResolvedSettings()
expect(publicSettings).not.toHaveProperty(
'deepseekHarnessBinaryPath'
)
expect(publicSettings.configured).not.toHaveProperty(
'deepseekHarnessBinaryPath'
)
expect(resolvedSettings).not.toHaveProperty(
'deepseekHarnessBinaryPath'
)
await migrated.update(settings())
const persisted = JSON.parse(
await readFile(filePath, 'utf8')
) as Record<string, unknown>
expect(persisted.version).toBe(16)
expect(persisted).not.toHaveProperty(
'deepseekHarnessBinaryPath'
)
})
it('rejects incompatible DeepSeek Harness model profiles', () => {
const profileId = '00000000-0000-4000-8000-000000000045'
expect(
runtimeSettingsInputSchema.safeParse(
settings({
modelProfiles: [
{
id: profileId,
name: 'Other compatible API',
baseUrl: 'https://other.example/v1',
modelName: 'deepseek-chat',
protocol: 'openai-chat-completions',
authentication: 'api-key',
imageGenerationQuality: 'auto',
apiKey: { action: 'keep' }
}
],
defaultModelProfileId: profileId,
deepseekHarnessModelSource: { kind: 'profile', profileId }
})
).success
).toBe(false)
expect(
runtimeSettingsInputSchema.safeParse(
settings({
modelProfiles: [
{
id: profileId,
name: 'DeepSeek without API key',
baseUrl: 'https://api.deepseek.com',
modelName: 'deepseek-chat',
protocol: 'openai-chat-completions',
authentication: 'none',
imageGenerationQuality: 'auto',
apiKey: { action: 'clear' }
}
],
defaultModelProfileId: profileId,
deepseekHarnessModelSource: { kind: 'profile', profileId }
})
).success
).toBe(false)
})
it('always enables bundled OpenCode when the Server address is blank', async () => {
const { filePath, store } = await createStore({
GOODBUDDY_OPENCODE_EMBEDDED: 'false'
@@ -331,7 +525,7 @@ describe('RuntimeSettingsStore', () => {
const persisted = JSON.parse(await readFile(filePath, 'utf8')) as {
version: number
}
expect(persisted.version).toBe(14)
expect(persisted.version).toBe(16)
})
it('migrates version 11 and removes the obsolete intranet toggle', async () => {
@@ -351,7 +545,7 @@ describe('RuntimeSettingsStore', () => {
version: number
intranetCompatibilityEnabled?: boolean
}
expect(persisted.version).toBe(14)
expect(persisted.version).toBe(16)
expect(persisted).not.toHaveProperty('intranetCompatibilityEnabled')
})
@@ -940,7 +1134,7 @@ describe('RuntimeSettingsStore', () => {
version: number
modelProfiles: Array<Record<string, unknown>>
}
expect(persisted.version).toBe(14)
expect(persisted.version).toBe(16)
expect(persisted.modelProfiles).toContainEqual(
expect.objectContaining({
id: imageId,
@@ -1186,7 +1380,7 @@ describe('RuntimeSettingsStore', () => {
unknown
>
expect(saved).toMatchObject({
version: 14,
version: 16,
provider: 'model',
continueBinaryPath: '',
continueMode: 'chat',
@@ -1465,7 +1659,7 @@ describe('RuntimeSettingsStore', () => {
version: number
modelProfiles: Array<Record<string, unknown>>
}
expect(persisted.version).toBe(14)
expect(persisted.version).toBe(16)
expect(persisted.modelProfiles[0]).not.toHaveProperty('credential')
})