fix: preserve custom provider thinking settings

Custom providers can point at user-defined model IDs that the CLI cannot
classify by built-in model tables. Declare the existing tier capability
overrides for custom provider roles so explicit thinking and effort settings
survive request construction.

Constraint: Issue #285 reports local proxy logs dropping user-defined model thinking and effort as passthrough with no config.
Rejected: Disable model capability checks globally | would relax behavior for built-in presets and non-custom providers.
Confidence: high
Scope-risk: narrow
Directive: Keep this scoped to custom providers unless each preset has explicit capability semantics.
Tested: bun test src/server/__tests__/providers.test.ts src/server/__tests__/provider-presets.test.ts src/utils/__tests__/thinking.test.ts
Tested: bun run check:server
Tested: bun run quality:pr
Tested: bun run quality:gate --mode baseline --allow-live --provider-model custom:main:custom-main
Tested: agent-browser custom provider UI smoke with request log showing thinking adaptive and effort max
Related: https://github.com/NanmiCoder/cc-haha/issues/285
This commit is contained in:
程序员阿江(Relakkes) 2026-05-06 11:44:03 +08:00
parent 4e9c6dbda1
commit 147d060004
2 changed files with 38 additions and 0 deletions

View File

@ -137,6 +137,33 @@ describe('ProviderService', () => {
await expect(fs.readFile(path.join(tmpDir, 'cc-haha', 'settings.json'), 'utf-8')).rejects.toThrow()
})
test('custom providers declare thinking and effort capability passthrough for user-defined models', async () => {
const svc = new ProviderService()
const provider = await svc.addProvider(sampleInput({
models: {
main: 'deepseek-ai/DeepSeek-V4-Pro',
haiku: 'deepseek-ai/DeepSeek-V4-Pro',
sonnet: 'deepseek-ai/DeepSeek-V4-Pro',
opus: 'deepseek-ai/DeepSeek-V4-Pro',
},
}))
await svc.activateProvider(provider.id)
const settings = await readSettings()
const env = settings.env as Record<string, string>
expect(env.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('deepseek-ai/DeepSeek-V4-Pro')
expect(env.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES).toBe(
'thinking,effort,adaptive_thinking,max_effort',
)
expect(env.ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES).toBe(
'thinking,effort,adaptive_thinking,max_effort',
)
expect(env.ANTHROPIC_DEFAULT_OPUS_MODEL_SUPPORTED_CAPABILITIES).toBe(
'thinking,effort,adaptive_thinking,max_effort',
)
})
test('adding additional providers should keep activeId unchanged', async () => {
const svc = new ProviderService()
await svc.addProvider(sampleInput({ name: 'First' }))

View File

@ -44,6 +44,8 @@ const MANAGED_ENV_KEYS = [
MODEL_CONTEXT_WINDOWS_ENV_KEY,
] as const
const CUSTOM_PROVIDER_MODEL_CAPABILITIES = 'thinking,effort,adaptive_thinking,max_effort'
const DEFAULT_INDEX: ProvidersIndex = { activeId: null, providers: [] }
const AUTH_ENV_KEYS = new Set(['ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN'])
@ -317,9 +319,18 @@ export class ProviderService {
}
const presetDefaultEnv = getPresetDefaultEnv(provider.presetId)
const customProviderCapabilityEnv =
provider.presetId === 'custom'
? {
ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES: CUSTOM_PROVIDER_MODEL_CAPABILITIES,
ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES: CUSTOM_PROVIDER_MODEL_CAPABILITIES,
ANTHROPIC_DEFAULT_OPUS_MODEL_SUPPORTED_CAPABILITIES: CUSTOM_PROVIDER_MODEL_CAPABILITIES,
}
: {}
return {
...omitAuthEnv(presetDefaultEnv),
...customProviderCapabilityEnv,
...(provider.autoCompactWindow !== undefined && {
CLAUDE_CODE_AUTO_COMPACT_WINDOW: String(provider.autoCompactWindow),
}),