Merge pull request #585 from kaitranntt/kai/fix/kimi-missing-models

fix(cliproxy): add Kimi model catalog, sync, and pricing to dashboard
This commit is contained in:
Kai (Tam Nhu) Tran
2026-02-19 10:49:00 +07:00
committed by GitHub
6 changed files with 108 additions and 19 deletions
+2 -1
View File
@@ -23,6 +23,7 @@ const CHANNEL_TO_PROVIDER: Record<string, CLIProxyProvider> = {
codex: 'codex',
qwen: 'qwen',
iflow: 'iflow',
kimi: 'kimi',
};
/** CCS provider → channel name mapping (reverse) */
@@ -31,7 +32,7 @@ export const PROVIDER_TO_CHANNEL: Record<string, string> = Object.fromEntries(
);
/** Providers to sync from CLIProxyAPI */
export const SYNCABLE_PROVIDERS: CLIProxyProvider[] = ['agy', 'gemini', 'codex', 'claude'];
export const SYNCABLE_PROVIDERS: CLIProxyProvider[] = ['agy', 'gemini', 'codex', 'claude', 'kimi'];
function getCacheFilePath(): string {
return path.join(getCcsDir(), CACHE_FILE_NAME);
+1 -1
View File
@@ -205,7 +205,7 @@ export const MODEL_CATALOG: Partial<Record<CLIProxyProvider, ProviderCatalog>> =
{
id: 'kimi-k2.5',
name: 'Kimi K2.5',
description: 'Latest Moonshot coding model',
description: 'Latest multimodal model (262K context)',
thinking: {
type: 'budget',
min: 1024,
+30 -17
View File
@@ -450,37 +450,50 @@ const PRICING_REGISTRY: Record<string, ModelPricing> = {
},
// ---------------------------------------------------------------------------
// Kimi Models (Moonshot AI) - Source: better-ccusage
// Kimi Models (Moonshot AI) - Source: Official Kimi Platform pricing
// inputPerMillion = cache miss price, cacheReadPerMillion = cache hit price
// ---------------------------------------------------------------------------
'kimi-for-coding': {
inputPerMillion: 0.15,
outputPerMillion: 0.6,
'kimi-k2.5': {
inputPerMillion: 0.6,
outputPerMillion: 3.0,
cacheCreationPerMillion: 0.0,
cacheReadPerMillion: 0.0,
cacheReadPerMillion: 0.1,
},
'kimi-for-coding': {
inputPerMillion: 0.6,
outputPerMillion: 2.5,
cacheCreationPerMillion: 0.0,
cacheReadPerMillion: 0.15,
},
'kimi-k2-0905-preview': {
inputPerMillion: 0.15,
outputPerMillion: 0.6,
inputPerMillion: 0.6,
outputPerMillion: 2.5,
cacheCreationPerMillion: 0.0,
cacheReadPerMillion: 0.0,
cacheReadPerMillion: 0.15,
},
'kimi-k2-turbo-preview': {
inputPerMillion: 0.15,
outputPerMillion: 1.15,
inputPerMillion: 1.15,
outputPerMillion: 8.0,
cacheCreationPerMillion: 0.0,
cacheReadPerMillion: 0.0,
cacheReadPerMillion: 0.15,
},
'kimi-k2-thinking': {
inputPerMillion: 0.15,
outputPerMillion: 0.6,
inputPerMillion: 0.6,
outputPerMillion: 2.5,
cacheCreationPerMillion: 0.0,
cacheReadPerMillion: 0.0,
cacheReadPerMillion: 0.15,
},
'kimi-k2-thinking-turbo': {
inputPerMillion: 0.15,
outputPerMillion: 1.15,
inputPerMillion: 1.15,
outputPerMillion: 8.0,
cacheCreationPerMillion: 0.0,
cacheReadPerMillion: 0.0,
cacheReadPerMillion: 0.15,
},
'kimi-k2': {
inputPerMillion: 0.6,
outputPerMillion: 2.5,
cacheCreationPerMillion: 0.0,
cacheReadPerMillion: 0.15,
},
'kimi-k2-instruct': {
inputPerMillion: 1.0,
+40
View File
@@ -36,6 +36,33 @@ describe('Model Catalog', () => {
});
});
describe('Kimi models', () => {
it('contains Kimi provider catalog', () => {
const { MODEL_CATALOG } = modelCatalog;
assert(MODEL_CATALOG.kimi, 'Should have kimi provider');
assert.strictEqual(MODEL_CATALOG.kimi.provider, 'kimi');
assert.strictEqual(MODEL_CATALOG.kimi.displayName, 'Kimi (Moonshot)');
});
it('has correct default model', () => {
const { MODEL_CATALOG } = modelCatalog;
assert.strictEqual(MODEL_CATALOG.kimi.defaultModel, 'kimi-k2.5');
});
it('includes K2.5, K2 Thinking, K2', () => {
const { MODEL_CATALOG } = modelCatalog;
const ids = MODEL_CATALOG.kimi.models.map((m) => m.id);
assert(ids.includes('kimi-k2.5'), 'Should include kimi-k2.5');
assert(ids.includes('kimi-k2-thinking'), 'Should include kimi-k2-thinking');
assert(ids.includes('kimi-k2'), 'Should include kimi-k2');
});
it('has 3 models total', () => {
const { MODEL_CATALOG } = modelCatalog;
assert.strictEqual(MODEL_CATALOG.kimi.models.length, 3);
});
});
describe('AGY models', () => {
it('has correct default model', () => {
const { MODEL_CATALOG } = modelCatalog;
@@ -126,6 +153,11 @@ describe('Model Catalog', () => {
assert.strictEqual(supportsModelConfig('codex'), true);
});
it('returns true for kimi', () => {
const { supportsModelConfig } = modelCatalog;
assert.strictEqual(supportsModelConfig('kimi'), true);
});
it('returns false for qwen', () => {
const { supportsModelConfig } = modelCatalog;
assert.strictEqual(supportsModelConfig('qwen'), false);
@@ -155,6 +187,14 @@ describe('Model Catalog', () => {
assert.strictEqual(catalog.provider, 'codex');
assert(Array.isArray(catalog.models));
});
it('returns catalog for kimi', () => {
const { getProviderCatalog } = modelCatalog;
const catalog = getProviderCatalog('kimi');
assert(catalog, 'Should return catalog');
assert.strictEqual(catalog.provider, 'kimi');
assert(Array.isArray(catalog.models));
});
});
describe('findModel', () => {
@@ -70,6 +70,7 @@ export function ProviderEditor({
iflow: ['iflow'],
kiro: ['kiro', 'aws'],
ghcp: ['github', 'copilot'],
kimi: ['kimi', 'moonshot'],
};
const owners = ownerMap[modelFilterProvider.toLowerCase()] || [
modelFilterProvider.toLowerCase(),
+34
View File
@@ -275,6 +275,40 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
},
],
},
kimi: {
provider: 'kimi',
displayName: 'Kimi (Moonshot)',
defaultModel: 'kimi-k2.5',
models: [
{
id: 'kimi-k2.5',
name: 'Kimi K2.5',
description: 'Latest multimodal model (262K context)',
presetMapping: {
default: 'kimi-k2.5',
opus: 'kimi-k2.5',
sonnet: 'kimi-k2-thinking',
haiku: 'kimi-k2',
},
},
{
id: 'kimi-k2-thinking',
name: 'Kimi K2 Thinking',
description: 'Extended reasoning model',
presetMapping: {
default: 'kimi-k2-thinking',
opus: 'kimi-k2.5',
sonnet: 'kimi-k2-thinking',
haiku: 'kimi-k2',
},
},
{
id: 'kimi-k2',
name: 'Kimi K2',
description: 'Flagship coding model',
},
],
},
kiro: {
provider: 'kiro',
displayName: 'Kiro (AWS)',