diff --git a/src/server/__tests__/provider-presets.test.ts b/src/server/__tests__/provider-presets.test.ts index 8f0737da..af88b74c 100644 --- a/src/server/__tests__/provider-presets.test.ts +++ b/src/server/__tests__/provider-presets.test.ts @@ -79,25 +79,29 @@ describe('provider presets API', () => { expect(ollama?.authStrategy).toBe('auth_token_empty_api_key') expect(ollama?.defaultModels.main).toBe('qwen3.6:27b') expect(deepseek?.authStrategy).toBe('auth_token') - expect(deepseek?.defaultModels.main).toBe('deepseek-v4-pro') + expect(deepseek?.defaultModels.main).toBe('deepseek-v4-pro[1m]') expect(deepseek?.defaultModels.haiku).toBe('deepseek-v4-flash') - expect(deepseek?.defaultModels.sonnet).toBe('deepseek-v4-pro') - expect(deepseek?.defaultModels.opus).toBe('deepseek-v4-pro') + expect(deepseek?.defaultModels.sonnet).toBe('deepseek-v4-pro[1m]') + expect(deepseek?.defaultModels.opus).toBe('deepseek-v4-pro[1m]') expect(deepseek?.defaultEnv?.CC_HAHA_SEND_DISABLED_THINKING).toBeUndefined() expect(deepseek?.defaultEnv?.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES).toBe( 'thinking,effort,adaptive_thinking,max_effort', ) expect(zhipu?.authStrategy).toBe('auth_token') - expect(zhipu?.defaultModels.main).toBe('glm-5.1') - expect(zhipu?.defaultModels.haiku).toBe('glm-4.5-air') - expect(zhipu?.defaultModels.sonnet).toBe('glm-5-turbo') - expect(zhipu?.defaultModels.opus).toBe('glm-5.1') - expect(kimi?.baseUrl).toBe('https://api.kimi.com/coding') + expect(zhipu?.defaultModels.main).toBe('glm-5.2[1m]') + expect(zhipu?.defaultModels.haiku).toBe('glm-4.7') + expect(zhipu?.defaultModels.sonnet).toBe('glm-5.2[1m]') + expect(zhipu?.defaultModels.opus).toBe('glm-5.2[1m]') + expect(zhipu?.defaultEnv?.CLAUDE_CODE_AUTO_COMPACT_WINDOW).toBe('1000000') + expect(kimi?.baseUrl).toBe('https://api.moonshot.cn/anthropic') expect(kimi?.authStrategy).toBe('auth_token') - expect(kimi?.defaultModels.main).toBe('kimi-k2.6') - expect(kimi?.defaultEnv?.CC_HAHA_SEND_DISABLED_THINKING).toBe('1') + expect(kimi?.defaultModels.main).toBe('kimi-k2.7-code') + expect(kimi?.defaultEnv?.CC_HAHA_SEND_DISABLED_THINKING).toBeUndefined() + expect(kimi?.defaultEnv?.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES).toBe('thinking') expect(minimax?.authStrategy).toBe('auth_token') - expect(minimax?.defaultModels.main).toBe('MiniMax-M3') + expect(minimax?.defaultModels.main).toBe('MiniMax-M3[1m]') + expect(minimax?.defaultEnv?.CLAUDE_CODE_AUTO_COMPACT_WINDOW).toBe('1000000') + expect(minimax?.defaultEnv?.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES).toBe('thinking,adaptive_thinking') expect(minimax?.modelContextWindows?.['MiniMax-M3']).toBe(1000000) expect(jiekouai?.baseUrl).toBe('https://api.jiekou.ai/anthropic') expect(jiekouai?.authStrategy).toBe('auth_token') @@ -140,11 +144,14 @@ describe('provider presets API', () => { expect(deepseek?.modelContextWindows?.['deepseek-v4-flash']).toBe(1000000) expect(zhipu?.apiKeyUrl).toBe('https://www.bigmodel.cn/invite?icode=d41B2qi8Z5xNwTGLNPPF3OZLO2QH3C0EBTSr%2BArzMw4%3D') expect(zhipu?.promoText).toContain('cc-haha') - expect(zhipu?.defaultEnv?.CC_HAHA_SEND_DISABLED_THINKING).toBe('1') - expect(zhipu?.modelContextWindows?.['glm-5.2']).toBe(200000) + expect(zhipu?.defaultEnv?.CC_HAHA_SEND_DISABLED_THINKING).toBeUndefined() + expect(zhipu?.modelContextWindows?.['glm-5.2']).toBe(1000000) expect(zhipu?.modelContextWindows?.['glm-5.1']).toBe(200000) + expect(zhipu?.modelContextWindows?.['glm-4.7']).toBe(200000) expect(zhipu?.modelContextWindows?.['glm-4.5-air']).toBe(128000) expect(kimi?.apiKeyUrl).toBe('https://platform.kimi.com/console/api-keys') + expect(kimi?.modelContextWindows?.['kimi-k2.7-code']).toBe(262144) + expect(kimi?.modelContextWindows?.['kimi-k2.7-code-highspeed']).toBe(262144) expect(kimi?.modelContextWindows?.['kimi-k2.6']).toBe(262144) expect(minimax?.apiKeyUrl).toBe('https://platform.minimaxi.com/subscribe/token-plan?code=1TG2Cseab2&source=link') expect(jiekouai?.apiKeyUrl).toBe('https://jiekou.ai/referral?invited_code=OBNU3K') diff --git a/src/server/__tests__/provider-runtime-env.test.ts b/src/server/__tests__/provider-runtime-env.test.ts index 5f12b485..9bd7ca3c 100644 --- a/src/server/__tests__/provider-runtime-env.test.ts +++ b/src/server/__tests__/provider-runtime-env.test.ts @@ -189,4 +189,72 @@ describe('providerRuntimeEnv', () => { expect(env.ENABLE_TOOL_SEARCH).toBeUndefined() }) + + test('applies updated docs-backed preset env for domestic Anthropic-compatible providers', async () => { + await writeJson(path.join(tmpDir, 'cc-haha', 'providers.json'), { + activeId: 'provider-kimi', + providers: [ + { + id: 'provider-kimi', + presetId: 'kimi', + name: 'Kimi', + apiKey: 'sk-kimi', + authStrategy: 'auth_token', + baseUrl: 'https://api.moonshot.cn/anthropic', + apiFormat: 'anthropic', + models: { + main: 'kimi-k2.7-code', + haiku: 'kimi-k2.7-code', + sonnet: 'kimi-k2.7-code', + opus: 'kimi-k2.7-code', + }, + }, + ], + }) + + const kimiEnv = readActiveProviderManagedEnv(tmpDir) + + expect(kimiEnv).toMatchObject({ + ANTHROPIC_BASE_URL: 'https://api.moonshot.cn/anthropic', + ANTHROPIC_MODEL: 'kimi-k2.7-code', + ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES: 'thinking', + }) + expect(JSON.parse(kimiEnv!.CLAUDE_CODE_MODEL_CONTEXT_WINDOWS)).toMatchObject({ + 'kimi-k2.7-code': 262144, + 'kimi-k2.7-code-highspeed': 262144, + }) + + await writeJson(path.join(tmpDir, 'cc-haha', 'providers.json'), { + activeId: 'provider-zhipu', + providers: [ + { + id: 'provider-zhipu', + presetId: 'zhipuglm', + name: 'Zhipu GLM', + apiKey: 'sk-zhipu', + authStrategy: 'auth_token', + baseUrl: 'https://open.bigmodel.cn/api/anthropic', + apiFormat: 'anthropic', + models: { + main: 'glm-5.2[1m]', + haiku: 'glm-4.7', + sonnet: 'glm-5.2[1m]', + opus: 'glm-5.2[1m]', + }, + }, + ], + }) + + const zhipuEnv = readActiveProviderManagedEnv(tmpDir) + + expect(zhipuEnv).toMatchObject({ + ANTHROPIC_MODEL: 'glm-5.2[1m]', + ANTHROPIC_DEFAULT_HAIKU_MODEL: 'glm-4.7', + CLAUDE_CODE_AUTO_COMPACT_WINDOW: '1000000', + }) + expect(JSON.parse(zhipuEnv!.CLAUDE_CODE_MODEL_CONTEXT_WINDOWS)).toMatchObject({ + 'glm-5.2[1m]': 1000000, + 'glm-4.7': 200000, + }) + }) }) diff --git a/src/server/config/providerPresets.json b/src/server/config/providerPresets.json index 2cf21e80..5ad1bc6c 100644 --- a/src/server/config/providerPresets.json +++ b/src/server/config/providerPresets.json @@ -19,21 +19,23 @@ "baseUrl": "https://api.deepseek.com/anthropic", "apiFormat": "anthropic", "defaultModels": { - "main": "deepseek-v4-pro", + "main": "deepseek-v4-pro[1m]", "haiku": "deepseek-v4-flash", - "sonnet": "deepseek-v4-pro", - "opus": "deepseek-v4-pro" + "sonnet": "deepseek-v4-pro[1m]", + "opus": "deepseek-v4-pro[1m]" }, "needsApiKey": true, "websiteUrl": "https://platform.deepseek.com", "apiKeyUrl": "https://platform.deepseek.com/api_keys", "authStrategy": "auth_token", "defaultEnv": { + "CLAUDE_CODE_AUTO_COMPACT_WINDOW": "1000000", "ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES": "thinking,effort,adaptive_thinking,max_effort", "ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES": "thinking,effort,adaptive_thinking,max_effort", "ANTHROPIC_DEFAULT_OPUS_MODEL_SUPPORTED_CAPABILITIES": "thinking,effort,adaptive_thinking,max_effort" }, "modelContextWindows": { + "deepseek-v4-pro[1m]": 1000000, "deepseek-v4-pro": 1000000, "deepseek-v4-flash": 1000000, "deepseek-chat": 1000000, @@ -46,10 +48,10 @@ "baseUrl": "https://open.bigmodel.cn/api/anthropic", "apiFormat": "anthropic", "defaultModels": { - "main": "glm-5.1", - "haiku": "glm-4.5-air", - "sonnet": "glm-5-turbo", - "opus": "glm-5.1" + "main": "glm-5.2[1m]", + "haiku": "glm-4.7", + "sonnet": "glm-5.2[1m]", + "opus": "glm-5.2[1m]" }, "needsApiKey": true, "websiteUrl": "https://open.bigmodel.cn", @@ -57,40 +59,42 @@ "promoText": "智谱 GLM 为 cc-haha 用户准备了专属邀请福利,使用此链接注册后可领取新用户权益。", "authStrategy": "auth_token", "defaultEnv": { - "CC_HAHA_SEND_DISABLED_THINKING": "1" + "CLAUDE_CODE_AUTO_COMPACT_WINDOW": "1000000" }, "modelContextWindows": { - "glm-5.2": 200000, + "glm-5.2[1m]": 1000000, + "glm-5.2": 1000000, "glm-5.1": 200000, "glm-5-turbo": 200000, + "glm-4.7": 200000, "glm-4.5-air": 128000 } }, { "id": "kimi", "name": "Kimi", - "baseUrl": "https://api.kimi.com/coding", + "baseUrl": "https://api.moonshot.cn/anthropic", "apiFormat": "anthropic", "defaultModels": { - "main": "kimi-k2.6", - "haiku": "kimi-k2.6", - "sonnet": "kimi-k2.6", - "opus": "kimi-k2.6" + "main": "kimi-k2.7-code", + "haiku": "kimi-k2.7-code", + "sonnet": "kimi-k2.7-code", + "opus": "kimi-k2.7-code" }, "needsApiKey": true, - "websiteUrl": "https://platform.moonshot.cn", + "websiteUrl": "https://platform.kimi.com", "apiKeyUrl": "https://platform.kimi.com/console/api-keys", "authStrategy": "auth_token", "defaultEnv": { - "CC_HAHA_SEND_DISABLED_THINKING": "1" + "ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES": "thinking", + "ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES": "thinking", + "ANTHROPIC_DEFAULT_OPUS_MODEL_SUPPORTED_CAPABILITIES": "thinking" }, "modelContextWindows": { + "kimi-k2.7-code": 262144, + "kimi-k2.7-code-highspeed": 262144, "kimi-k2.6": 262144, - "kimi-k2.5": 262144, - "kimi-k2-0905-preview": 262144, - "kimi-k2-turbo-preview": 262144, - "kimi-k2-thinking": 262144, - "kimi-k2-thinking-turbo": 262144 + "kimi-k2.5": 262144 } }, { @@ -99,16 +103,23 @@ "baseUrl": "https://api.minimaxi.com/anthropic", "apiFormat": "anthropic", "defaultModels": { - "main": "MiniMax-M3", - "haiku": "MiniMax-M3", - "sonnet": "MiniMax-M3", - "opus": "MiniMax-M3" + "main": "MiniMax-M3[1m]", + "haiku": "MiniMax-M3[1m]", + "sonnet": "MiniMax-M3[1m]", + "opus": "MiniMax-M3[1m]" }, "needsApiKey": true, "websiteUrl": "https://platform.minimaxi.com", "apiKeyUrl": "https://platform.minimaxi.com/subscribe/token-plan?code=1TG2Cseab2&source=link", "authStrategy": "auth_token", + "defaultEnv": { + "CLAUDE_CODE_AUTO_COMPACT_WINDOW": "1000000", + "ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES": "thinking,adaptive_thinking", + "ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES": "thinking,adaptive_thinking", + "ANTHROPIC_DEFAULT_OPUS_MODEL_SUPPORTED_CAPABILITIES": "thinking,adaptive_thinking" + }, "modelContextWindows": { + "MiniMax-M3[1m]": 1000000, "MiniMax-M3": 1000000, "MiniMax-M2.7": 204800, "MiniMax-M2.7-highspeed": 204800 diff --git a/src/utils/__tests__/thinking.test.ts b/src/utils/__tests__/thinking.test.ts index a79f4c25..3dfec9a3 100644 --- a/src/utils/__tests__/thinking.test.ts +++ b/src/utils/__tests__/thinking.test.ts @@ -93,16 +93,29 @@ describe('provider-aware thinking support', () => { expect(shouldSendExplicitDisabledThinking()).toBe(false) }) - test('MiniMax preset models declare thinking support without effort passthrough', () => { + test('MiniMax preset models declare adaptive thinking without effort passthrough', () => { process.env.ANTHROPIC_BASE_URL = 'https://api.minimaxi.com/anthropic' - process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'MiniMax-M3' - delete process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES + process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'MiniMax-M3[1m]' + process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES = + 'thinking,adaptive_thinking' clearCapabilityCache() - expect(modelSupportsThinking('MiniMax-M3')).toBe(true) - expect(modelSupportsAdaptiveThinking('MiniMax-M3')).toBe(false) - expect(modelSupportsEffort('MiniMax-M3')).toBe(false) - expect(modelSupportsMaxEffort('MiniMax-M3')).toBe(false) + expect(modelSupportsThinking('MiniMax-M3[1m]')).toBe(true) + expect(modelSupportsAdaptiveThinking('MiniMax-M3[1m]')).toBe(true) + expect(modelSupportsEffort('MiniMax-M3[1m]')).toBe(false) + expect(modelSupportsMaxEffort('MiniMax-M3[1m]')).toBe(false) + }) + + test('Kimi preset models declare thinking without effort passthrough', () => { + process.env.ANTHROPIC_BASE_URL = 'https://api.moonshot.cn/anthropic' + process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'kimi-k2.7-code' + process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES = 'thinking' + clearCapabilityCache() + + expect(modelSupportsThinking('kimi-k2.7-code')).toBe(true) + expect(modelSupportsAdaptiveThinking('kimi-k2.7-code')).toBe(false) + expect(modelSupportsEffort('kimi-k2.7-code')).toBe(false) + expect(modelSupportsMaxEffort('kimi-k2.7-code')).toBe(false) }) test('third-party base URLs do not default unknown model names to effort support', () => { diff --git a/src/utils/model/modelContextWindows.test.ts b/src/utils/model/modelContextWindows.test.ts new file mode 100644 index 00000000..3789e43d --- /dev/null +++ b/src/utils/model/modelContextWindows.test.ts @@ -0,0 +1,31 @@ +import { describe, expect, test } from 'bun:test' + +import { + getConfiguredOrBuiltInModelContextWindow, + getModelContextWindowFromEnvValue, +} from './modelContextWindows.js' + +describe('model context windows', () => { + test('recognizes updated domestic coding model context windows', () => { + expect(getConfiguredOrBuiltInModelContextWindow('kimi-k2.7-code')).toBe(262_144) + expect(getConfiguredOrBuiltInModelContextWindow('kimi-k2.7-code-highspeed')).toBe(262_144) + expect(getConfiguredOrBuiltInModelContextWindow('glm-5.2')).toBe(1_000_000) + expect(getConfiguredOrBuiltInModelContextWindow('glm-4.7')).toBe(200_000) + expect(getConfiguredOrBuiltInModelContextWindow('qwen/qwen3.6-27b')).toBe(262_144) + expect(getConfiguredOrBuiltInModelContextWindow('qwen3.6:27b')).toBe(262_144) + expect(getConfiguredOrBuiltInModelContextWindow('qwen3.7-plus-2026-02-15')).toBe(1_000_000) + expect(getConfiguredOrBuiltInModelContextWindow('qwen3-coder-plus')).toBe(1_000_000) + expect(getConfiguredOrBuiltInModelContextWindow('qwen3-coder-next')).toBe(262_144) + }) + + test('matches configured base model windows for Claude Code 1m aliases', () => { + expect(getModelContextWindowFromEnvValue( + 'MiniMax-M3[1m]', + JSON.stringify({ 'MiniMax-M3': 1_000_000 }), + )).toBe(1_000_000) + expect(getModelContextWindowFromEnvValue( + 'glm-5.2[1m]', + JSON.stringify({ 'glm-5.2': 1_000_000 }), + )).toBe(1_000_000) + }) +}) diff --git a/src/utils/model/modelContextWindows.ts b/src/utils/model/modelContextWindows.ts index 421e2ba3..23810bce 100644 --- a/src/utils/model/modelContextWindows.ts +++ b/src/utils/model/modelContextWindows.ts @@ -10,6 +10,8 @@ const DIRECT_MODEL_CONTEXT_WINDOWS: Record = { 'deepseek-v4-flash': 1_000_000, 'deepseek-chat': 1_000_000, 'deepseek-reasoner': 1_000_000, + 'kimi-k2.7-code': 262_144, + 'kimi-k2.7-code-highspeed': 262_144, 'kimi-k2.6': 262_144, 'kimi-k2.5': 262_144, 'kimi-k2-0905-preview': 262_144, @@ -19,7 +21,9 @@ const DIRECT_MODEL_CONTEXT_WINDOWS: Record = { 'minimax-m3': 1_000_000, 'minimax-m2.7': 204_800, 'minimax-m2.7-highspeed': 204_800, - 'glm-5.2': 200_000, + 'qwen/qwen3.6-27b': 262_144, + 'qwen3.6:27b': 262_144, + 'glm-5.2': 1_000_000, 'glm-5.1': 200_000, 'glm-5': 200_000, 'glm-5-turbo': 200_000, @@ -37,11 +41,14 @@ const PATTERN_MODEL_CONTEXT_WINDOWS: Array<[RegExp, number]> = [ [/^openai\/gpt-5(?:[.-]\d+)?\b/i, 400_000], [/^google\/gemini-(?:2\.0|2\.5|3)/i, 1_048_576], [/^gemini-(?:2\.0|2\.5|3)/i, 1_048_576], - [/^zai-org\/glm-5\.2\b/i, 200_000], - [/^qwen\/qwen3\.5-(?:plus|flash)\b/i, 1_000_000], - [/^qwen3\.5-(?:plus|flash)\b/i, 1_000_000], - [/^qwen\/qwen3-max\b/i, 262_144], - [/^qwen3-max\b/i, 262_144], + [/^zai-org\/glm-5\.2\b/i, 1_000_000], + [/^(?:qwen\/)?qwen3\.7-(?:max|plus)(?:[-.][\w.-]+)?\b/i, 1_000_000], + [/^(?:qwen\/)?qwen3\.6-(?:plus|flash)(?:[-.][\w.-]+)?\b/i, 1_000_000], + [/^(?:qwen\/)?qwen3\.6-max-preview\b/i, 262_144], + [/^(?:qwen\/)?qwen3\.5-(?:plus|flash)(?:[-.][\w.-]+)?\b/i, 1_000_000], + [/^(?:qwen\/)?qwen3-max(?:[-.][\w.-]+)?\b/i, 262_144], + [/^(?:qwen\/)?qwen3-coder-plus(?:[-.][\w.-]+)?\b/i, 1_000_000], + [/^(?:qwen\/)?qwen3-coder-next(?:[-.][\w.-]+)?\b/i, 262_144], [/qwen-long/i, 10_000_000], ]