From 71dc2fd4cf8057a298fd148a4eb5da8019d484d6 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: Mon, 20 Jul 2026 19:25:05 +0800 Subject: [PATCH] fix(provider): update Kimi Code preset to K3 --- src/server/__tests__/provider-presets.test.ts | 16 +++---- .../__tests__/provider-runtime-env.test.ts | 47 ++++++++++++++++--- src/server/config/providerPresets.json | 25 +++++----- src/server/services/providerRuntimeEnv.ts | 47 +++++++++++++++---- .../api/claudeRequiredThinking.test.ts | 24 +++++----- src/services/compact/autoCompact.test.ts | 2 + src/utils/__tests__/thinking.test.ts | 22 ++++----- src/utils/model/modelContextWindows.test.ts | 4 ++ src/utils/model/modelContextWindows.ts | 3 ++ 9 files changed, 132 insertions(+), 58 deletions(-) diff --git a/src/server/__tests__/provider-presets.test.ts b/src/server/__tests__/provider-presets.test.ts index f4f79126..8a06966e 100644 --- a/src/server/__tests__/provider-presets.test.ts +++ b/src/server/__tests__/provider-presets.test.ts @@ -94,12 +94,12 @@ describe('provider presets API', () => { 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.7-code') + expect(kimi?.baseUrl).toBe('https://api.kimi.com/coding/') + expect(kimi?.authStrategy).toBe('api_key') + expect(kimi?.defaultModels.main).toBe('k3') expect(kimi?.defaultEnv?.CC_HAHA_SEND_DISABLED_THINKING).toBeUndefined() expect(kimi?.defaultEnv?.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES).toBe( - 'thinking,required_thinking', + 'thinking,required_thinking,effort,max_effort', ) expect(minimax?.authStrategy).toBe('auth_token') expect(minimax?.defaultModels.main).toBe('MiniMax-M3[1m]') @@ -161,10 +161,10 @@ describe('provider presets API', () => { 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(kimi?.apiKeyUrl).toBe('https://www.kimi.com/code/console') + expect(kimi?.modelContextWindows?.k3).toBe(262144) + expect(kimi?.modelContextWindows?.['kimi-for-coding']).toBe(262144) + expect(kimi?.modelContextWindows?.['kimi-for-coding-highspeed']).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') expect(jiekouai?.promoText).toContain('官方 8 折') diff --git a/src/server/__tests__/provider-runtime-env.test.ts b/src/server/__tests__/provider-runtime-env.test.ts index 19b78321..d8e2e59f 100644 --- a/src/server/__tests__/provider-runtime-env.test.ts +++ b/src/server/__tests__/provider-runtime-env.test.ts @@ -271,6 +271,43 @@ describe('providerRuntimeEnv', () => { presetId: 'kimi', name: 'Kimi', apiKey: 'sk-kimi', + authStrategy: 'api_key', + baseUrl: 'https://api.kimi.com/coding/', + apiFormat: 'anthropic', + models: { + main: 'k3', + haiku: 'k3', + sonnet: 'k3', + opus: 'k3', + }, + }, + ], + }) + + const kimiEnv = readActiveProviderManagedEnv(tmpDir) + + expect(kimiEnv).toMatchObject({ + ANTHROPIC_BASE_URL: 'https://api.kimi.com/coding/', + ANTHROPIC_API_KEY: 'sk-kimi', + ANTHROPIC_MODEL: 'k3', + ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES: + 'thinking,required_thinking,effort,max_effort', + }) + expect(kimiEnv?.ANTHROPIC_AUTH_TOKEN).toBeUndefined() + expect(JSON.parse(kimiEnv!.CLAUDE_CODE_MODEL_CONTEXT_WINDOWS)).toMatchObject({ + k3: 262144, + 'kimi-for-coding': 262144, + 'kimi-for-coding-highspeed': 262144, + }) + + await writeJson(path.join(tmpDir, 'cc-haha', 'providers.json'), { + activeId: 'provider-kimi-legacy', + providers: [ + { + id: 'provider-kimi-legacy', + presetId: 'kimi', + name: 'Kimi Open Platform', + apiKey: 'sk-kimi-legacy', authStrategy: 'auth_token', baseUrl: 'https://api.moonshot.cn/anthropic', apiFormat: 'anthropic', @@ -284,17 +321,15 @@ describe('providerRuntimeEnv', () => { ], }) - const kimiEnv = readActiveProviderManagedEnv(tmpDir) + const legacyKimiEnv = readActiveProviderManagedEnv(tmpDir) - expect(kimiEnv).toMatchObject({ + expect(legacyKimiEnv).toMatchObject({ ANTHROPIC_BASE_URL: 'https://api.moonshot.cn/anthropic', + ANTHROPIC_API_KEY: '', + ANTHROPIC_AUTH_TOKEN: 'sk-kimi-legacy', ANTHROPIC_MODEL: 'kimi-k2.7-code', ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES: 'thinking,required_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', diff --git a/src/server/config/providerPresets.json b/src/server/config/providerPresets.json index 9ac241de..86ae6415 100644 --- a/src/server/config/providerPresets.json +++ b/src/server/config/providerPresets.json @@ -73,24 +73,27 @@ { "id": "kimi", "name": "Kimi", - "baseUrl": "https://api.moonshot.cn/anthropic", + "baseUrl": "https://api.kimi.com/coding/", "apiFormat": "anthropic", "defaultModels": { - "main": "kimi-k2.7-code", - "haiku": "kimi-k2.7-code", - "sonnet": "kimi-k2.7-code", - "opus": "kimi-k2.7-code" + "main": "k3", + "haiku": "k3", + "sonnet": "k3", + "opus": "k3" }, "needsApiKey": true, - "websiteUrl": "https://platform.kimi.com", - "apiKeyUrl": "https://platform.kimi.com/console/api-keys", - "authStrategy": "auth_token", + "websiteUrl": "https://www.kimi.com/code", + "apiKeyUrl": "https://www.kimi.com/code/console", + "authStrategy": "api_key", "defaultEnv": { - "ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES": "thinking,required_thinking", - "ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES": "thinking,required_thinking", - "ANTHROPIC_DEFAULT_OPUS_MODEL_SUPPORTED_CAPABILITIES": "thinking,required_thinking" + "ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES": "thinking,required_thinking,effort,max_effort", + "ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES": "thinking,required_thinking,effort,max_effort", + "ANTHROPIC_DEFAULT_OPUS_MODEL_SUPPORTED_CAPABILITIES": "thinking,required_thinking,effort,max_effort" }, "modelContextWindows": { + "k3": 262144, + "kimi-for-coding": 262144, + "kimi-for-coding-highspeed": 262144, "kimi-k2.7-code": 262144, "kimi-k2.7-code-highspeed": 262144, "kimi-k2.6": 262144, diff --git a/src/server/services/providerRuntimeEnv.ts b/src/server/services/providerRuntimeEnv.ts index c1e44388..c278c238 100644 --- a/src/server/services/providerRuntimeEnv.ts +++ b/src/server/services/providerRuntimeEnv.ts @@ -53,6 +53,8 @@ export const MANAGED_PROVIDER_ENV_KEYS = [ const CUSTOM_PROVIDER_MODEL_CAPABILITIES = 'thinking,effort,adaptive_thinking,max_effort' const XIAOMI_MIMO_MODEL_CAPABILITIES = 'thinking' +const KIMI_K3_MODEL_CAPABILITIES = 'thinking,required_thinking,effort,max_effort' +const KIMI_CODING_FALLBACK_MODEL_CAPABILITIES = 'thinking,required_thinking' const AUTH_ENV_KEYS = new Set(['ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN']) const MODEL_SLOTS = ['main', 'haiku', 'sonnet', 'opus'] as const @@ -288,6 +290,39 @@ function getCustomProviderModelCapabilities( return CUSTOM_PROVIDER_MODEL_CAPABILITIES } +function getKimiModelCapabilities(model: string): string { + const normalized = model + .trim() + .replace(/\[1m\]$/i, '') + .replace(/:1m$/i, '') + .toLowerCase() + return normalized === 'k3' + ? KIMI_K3_MODEL_CAPABILITIES + : KIMI_CODING_FALLBACK_MODEL_CAPABILITIES +} + +function getProviderCapabilityEnv( + provider: SavedProvider, + models: SavedProvider['models'], +): Record { + if (provider.presetId === 'custom') { + const capabilities = getCustomProviderModelCapabilities(provider, models) + return { + ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES: capabilities, + ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES: capabilities, + ANTHROPIC_DEFAULT_OPUS_MODEL_SUPPORTED_CAPABILITIES: capabilities, + } + } + if (provider.presetId === 'kimi') { + return { + ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES: getKimiModelCapabilities(models.haiku), + ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES: getKimiModelCapabilities(models.sonnet), + ANTHROPIC_DEFAULT_OPUS_MODEL_SUPPORTED_CAPABILITIES: getKimiModelCapabilities(models.opus), + } + } + return {} +} + export function buildProviderAuthEnv( provider: SavedProvider, presetDefaultEnv: Record, @@ -353,19 +388,11 @@ export function buildProviderManagedEnv( } const presetDefaultEnv = getPresetDefaultEnv(provider.presetId) - const customProviderCapabilities = getCustomProviderModelCapabilities(provider, models) - const customProviderCapabilityEnv = - provider.presetId === 'custom' - ? { - ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES: customProviderCapabilities, - ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES: customProviderCapabilities, - ANTHROPIC_DEFAULT_OPUS_MODEL_SUPPORTED_CAPABILITIES: customProviderCapabilities, - } - : {} + const providerCapabilityEnv = getProviderCapabilityEnv(provider, models) return { ...omitAuthEnv(presetDefaultEnv), - ...customProviderCapabilityEnv, + ...providerCapabilityEnv, ...(provider.autoCompactWindow !== undefined && { CLAUDE_CODE_AUTO_COMPACT_WINDOW: String(provider.autoCompactWindow), }), diff --git a/src/services/api/claudeRequiredThinking.test.ts b/src/services/api/claudeRequiredThinking.test.ts index 50031c62..679b9666 100644 --- a/src/services/api/claudeRequiredThinking.test.ts +++ b/src/services/api/claudeRequiredThinking.test.ts @@ -17,7 +17,7 @@ function successfulResponse(): string { id: 'msg_required_thinking', type: 'message', role: 'assistant', - model: 'kimi-k2.7-code', + model: 'k3', content: [], stop_reason: null, stop_sequence: null, @@ -87,25 +87,25 @@ test('keeps required-thinking models enabled when the caller requests disabled t delete process.env.CLAUDE_CODE_USE_VERTEX delete process.env.CLAUDE_CODE_USE_FOUNDRY process.env.ANTHROPIC_BASE_URL = `http://127.0.0.1:${server.port}` - process.env.ANTHROPIC_AUTH_TOKEN = 'loopback-test-key' - process.env.ANTHROPIC_API_KEY = '' - process.env.ANTHROPIC_MODEL = 'kimi-k2.7-code' - process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL = 'kimi-k2.7-code' - process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'kimi-k2.7-code' - process.env.ANTHROPIC_DEFAULT_OPUS_MODEL = 'kimi-k2.7-code' + delete process.env.ANTHROPIC_AUTH_TOKEN + process.env.ANTHROPIC_API_KEY = 'loopback-test-key' + process.env.ANTHROPIC_MODEL = 'k3' + process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL = 'k3' + process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'k3' + process.env.ANTHROPIC_DEFAULT_OPUS_MODEL = 'k3' process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL_SUPPORTED_CAPABILITIES = - 'thinking,required_thinking' + 'thinking,required_thinking,effort,max_effort' process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES = - 'thinking,required_thinking' + 'thinking,required_thinking,effort,max_effort' process.env.ANTHROPIC_DEFAULT_OPUS_MODEL_SUPPORTED_CAPABILITIES = - 'thinking,required_thinking' + 'thinking,required_thinking,effort,max_effort' enableConfigs() const result = await queryWithModel({ userPrompt: 'Reply exactly OK', signal: new AbortController().signal, options: { - model: 'kimi-k2.7-code', + model: 'k3', querySource: 'insights', agents: [], isNonInteractiveSession: true, @@ -116,7 +116,7 @@ test('keeps required-thinking models enabled when the caller requests disabled t expect(result.message.content).toEqual([{ type: 'text', text: 'OK' }]) expect(requests).toHaveLength(1) - expect(requests[0]?.model).toBe('kimi-k2.7-code') + expect(requests[0]?.model).toBe('k3') expect(requests[0]?.thinking).toMatchObject({ type: 'enabled' }) } finally { for (const key of ENV_KEYS) { diff --git a/src/services/compact/autoCompact.test.ts b/src/services/compact/autoCompact.test.ts index bd17ffd5..86cca1cf 100644 --- a/src/services/compact/autoCompact.test.ts +++ b/src/services/compact/autoCompact.test.ts @@ -31,6 +31,8 @@ describe('model context window resolution', () => { test('uses built-in windows for current third-party coding models', () => { expect(getContextWindowForModel('deepseek-v4-pro')).toBe(1_000_000) expect(getContextWindowForModel('MiniMax-M2.7')).toBe(204_800) + expect(getContextWindowForModel('k3')).toBe(262_144) + expect(getContextWindowForModel('k3[1m]')).toBe(1_000_000) expect(getContextWindowForModel('kimi-k2.6')).toBe(262_144) expect(getContextWindowForModel('zai-org/GLM-5.2')).toBe(1_000_000) expect(getContextWindowForModel('glm-5.1')).toBe(200_000) diff --git a/src/utils/__tests__/thinking.test.ts b/src/utils/__tests__/thinking.test.ts index 12d340b3..989f9fdb 100644 --- a/src/utils/__tests__/thinking.test.ts +++ b/src/utils/__tests__/thinking.test.ts @@ -108,25 +108,25 @@ describe('provider-aware thinking support', () => { 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' + test('Kimi K3 preset requires thinking and supports effort passthrough', () => { + process.env.ANTHROPIC_BASE_URL = 'https://api.kimi.com/coding/' + process.env.ANTHROPIC_DEFAULT_SONNET_MODEL = 'k3' process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES = - 'thinking,required_thinking' + 'thinking,required_thinking,effort,max_effort' clearCapabilityCache() - expect(modelSupportsThinking('kimi-k2.7-code')).toBe(true) - expect(modelSupportsAdaptiveThinking('kimi-k2.7-code')).toBe(false) - expect(modelRequiresThinking('kimi-k2.7-code')).toBe(true) - expect(resolveModelThinkingEnabled('kimi-k2.7-code', false)).toBe(true) - expect(modelSupportsEffort('kimi-k2.7-code')).toBe(false) - expect(modelSupportsMaxEffort('kimi-k2.7-code')).toBe(false) + expect(modelSupportsThinking('k3')).toBe(true) + expect(modelSupportsAdaptiveThinking('k3')).toBe(false) + expect(modelRequiresThinking('k3')).toBe(true) + expect(resolveModelThinkingEnabled('k3', false)).toBe(true) + expect(modelSupportsEffort('k3')).toBe(true) + expect(modelSupportsMaxEffort('k3')).toBe(true) expect(modelRequiresThinking('kimi-k2.6')).toBe(false) expect(resolveModelThinkingEnabled('kimi-k2.6', false)).toBe(false) }) test('third-party base URLs do not default unknown model names to effort support', () => { - process.env.ANTHROPIC_BASE_URL = 'https://api.moonshot.cn/anthropic' + process.env.ANTHROPIC_BASE_URL = 'https://api.kimi.com/coding/' delete process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES clearCapabilityCache() diff --git a/src/utils/model/modelContextWindows.test.ts b/src/utils/model/modelContextWindows.test.ts index 3789e43d..33bd3b1e 100644 --- a/src/utils/model/modelContextWindows.test.ts +++ b/src/utils/model/modelContextWindows.test.ts @@ -7,6 +7,10 @@ import { describe('model context windows', () => { test('recognizes updated domestic coding model context windows', () => { + expect(getConfiguredOrBuiltInModelContextWindow('k3')).toBe(262_144) + expect(getConfiguredOrBuiltInModelContextWindow('k3[1m]')).toBe(262_144) + expect(getConfiguredOrBuiltInModelContextWindow('kimi-for-coding')).toBe(262_144) + expect(getConfiguredOrBuiltInModelContextWindow('kimi-for-coding-highspeed')).toBe(262_144) 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) diff --git a/src/utils/model/modelContextWindows.ts b/src/utils/model/modelContextWindows.ts index 23810bce..0ed6d615 100644 --- a/src/utils/model/modelContextWindows.ts +++ b/src/utils/model/modelContextWindows.ts @@ -10,6 +10,9 @@ const DIRECT_MODEL_CONTEXT_WINDOWS: Record = { 'deepseek-v4-flash': 1_000_000, 'deepseek-chat': 1_000_000, 'deepseek-reasoner': 1_000_000, + 'k3': 262_144, + 'kimi-for-coding': 262_144, + 'kimi-for-coding-highspeed': 262_144, 'kimi-k2.7-code': 262_144, 'kimi-k2.7-code-highspeed': 262_144, 'kimi-k2.6': 262_144,