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), }),