From 147d0600049ff142b0b7ceea572e81f0e1d0d6b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=91=98=E9=98=BF=E6=B1=9F=28Relakkes?= =?UTF-8?q?=29?= Date: Wed, 6 May 2026 11:44:03 +0800 Subject: [PATCH] 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 --- src/server/__tests__/providers.test.ts | 27 ++++++++++++++++++++++++++ src/server/services/providerService.ts | 11 +++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/server/__tests__/providers.test.ts b/src/server/__tests__/providers.test.ts index 7cd651c6..2a5f01e8 100644 --- a/src/server/__tests__/providers.test.ts +++ b/src/server/__tests__/providers.test.ts @@ -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 + 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' })) diff --git a/src/server/services/providerService.ts b/src/server/services/providerService.ts index fb5739a3..f0d55f33 100644 --- a/src/server/services/providerService.ts +++ b/src/server/services/providerService.ts @@ -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), }),