fix(provider): update Kimi Code preset to K3

This commit is contained in:
程序员阿江(Relakkes) 2026-07-20 19:25:05 +08:00
parent 36560c09d5
commit 71dc2fd4cf
9 changed files with 132 additions and 58 deletions

View File

@ -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 折')

View File

@ -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',

View File

@ -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,

View File

@ -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<string, string> {
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<string, string>,
@ -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),
}),

View File

@ -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) {

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -10,6 +10,9 @@ const DIRECT_MODEL_CONTEXT_WINDOWS: Record<string, number> = {
'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,