🌙 feat: Moonshot Provider Support (#11621)

*  feat: Add Moonshot Provider Support

- Updated the `isKnownCustomProvider` function to include `Providers.MOONSHOT` in the list of recognized custom providers.
- Enhanced the `providerConfigMap` to initialize `MOONSHOT` with the custom initialization function.
- Introduced `MoonshotIcon` component for visual representation in the UI, integrated into the `UnknownIcon` component.
- Updated various files across the API and client to support the new `MOONSHOT` provider, including configuration and response handling.

This update expands the capabilities of the application by integrating support for the Moonshot provider, enhancing both backend and frontend functionalities.

*  feat: Add Moonshot/Kimi Model Pricing and Tests

- Introduced new pricing configurations for Moonshot and Kimi models in `tx.js`, including various model variations and their respective prompt and completion values.
- Expanded unit tests in `tx.spec.js` and `tokens.spec.js` to validate pricing and token limits for the newly added Moonshot/Kimi models, ensuring accurate calculations and handling of model variations.
- Updated utility functions to support the new model structures and ensure compatibility with existing functionalities.

This update enhances the pricing model capabilities and improves test coverage for the Moonshot/Kimi integration.

*  feat: Enhance Token Pricing Documentation and Configuration

- Added comprehensive documentation for token pricing configuration in `tx.js` and `tokens.ts`, emphasizing the importance of key ordering for pattern matching.
- Clarified the process for defining base and specific patterns to ensure accurate pricing retrieval based on model names.
- Improved code comments to guide future additions of model families, enhancing maintainability and understanding of the pricing structure.

This update improves the clarity and usability of the token pricing configuration, facilitating better integration and future enhancements.

* chore: import order

* chore: linting
This commit is contained in:
Danny Avila 2026-02-04 10:53:57 +01:00 committed by GitHub
parent 56a1b28293
commit f34052c6bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 492 additions and 40 deletions

View file

@ -1064,44 +1064,149 @@ describe('Claude Model Tests', () => {
});
});
describe('Kimi Model Tests', () => {
describe('Moonshot/Kimi Model Tests', () => {
describe('getModelMaxTokens', () => {
test('should return correct tokens for Kimi models', () => {
expect(getModelMaxTokens('kimi')).toBe(131000);
expect(getModelMaxTokens('kimi-k2')).toBe(131000);
expect(getModelMaxTokens('kimi-vl')).toBe(131000);
test('should return correct tokens for kimi-k2.5 (multi-modal)', () => {
expect(getModelMaxTokens('kimi-k2.5')).toBe(maxTokensMap[EModelEndpoint.openAI]['kimi-k2.5']);
expect(getModelMaxTokens('kimi-k2.5-latest')).toBe(
maxTokensMap[EModelEndpoint.openAI]['kimi-k2.5'],
);
});
test('should return correct tokens for Kimi models with provider prefix', () => {
expect(getModelMaxTokens('moonshotai/kimi-k2')).toBe(131000);
expect(getModelMaxTokens('moonshotai/kimi')).toBe(131000);
expect(getModelMaxTokens('moonshotai/kimi-vl')).toBe(131000);
test('should return correct tokens for kimi-k2 series models', () => {
expect(getModelMaxTokens('kimi')).toBe(maxTokensMap[EModelEndpoint.openAI]['kimi']);
expect(getModelMaxTokens('kimi-k2')).toBe(maxTokensMap[EModelEndpoint.openAI]['kimi-k2']);
expect(getModelMaxTokens('kimi-k2-turbo')).toBe(
maxTokensMap[EModelEndpoint.openAI]['kimi-k2-turbo'],
);
expect(getModelMaxTokens('kimi-k2-turbo-preview')).toBe(
maxTokensMap[EModelEndpoint.openAI]['kimi-k2-turbo-preview'],
);
expect(getModelMaxTokens('kimi-k2-0905')).toBe(
maxTokensMap[EModelEndpoint.openAI]['kimi-k2-0905'],
);
expect(getModelMaxTokens('kimi-k2-0905-preview')).toBe(
maxTokensMap[EModelEndpoint.openAI]['kimi-k2-0905-preview'],
);
expect(getModelMaxTokens('kimi-k2-thinking')).toBe(
maxTokensMap[EModelEndpoint.openAI]['kimi-k2-thinking'],
);
expect(getModelMaxTokens('kimi-k2-thinking-turbo')).toBe(
maxTokensMap[EModelEndpoint.openAI]['kimi-k2-thinking-turbo'],
);
});
test('should handle partial matches for Kimi models', () => {
expect(getModelMaxTokens('kimi-k2-latest')).toBe(131000);
expect(getModelMaxTokens('kimi-vl-preview')).toBe(131000);
expect(getModelMaxTokens('kimi-2024')).toBe(131000);
test('should return correct tokens for kimi-k2-0711 (smaller context)', () => {
expect(getModelMaxTokens('kimi-k2-0711')).toBe(
maxTokensMap[EModelEndpoint.openAI]['kimi-k2-0711'],
);
expect(getModelMaxTokens('kimi-k2-0711-preview')).toBe(
maxTokensMap[EModelEndpoint.openAI]['kimi-k2-0711-preview'],
);
});
test('should return correct tokens for kimi-latest', () => {
expect(getModelMaxTokens('kimi-latest')).toBe(
maxTokensMap[EModelEndpoint.openAI]['kimi-latest'],
);
});
test('should return correct tokens for moonshot-v1 series models', () => {
expect(getModelMaxTokens('moonshot')).toBe(maxTokensMap[EModelEndpoint.openAI]['moonshot']);
expect(getModelMaxTokens('moonshot-v1')).toBe(
maxTokensMap[EModelEndpoint.openAI]['moonshot-v1'],
);
expect(getModelMaxTokens('moonshot-v1-auto')).toBe(
maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-auto'],
);
expect(getModelMaxTokens('moonshot-v1-8k')).toBe(
maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-8k'],
);
expect(getModelMaxTokens('moonshot-v1-8k-vision')).toBe(
maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-8k-vision'],
);
expect(getModelMaxTokens('moonshot-v1-8k-vision-preview')).toBe(
maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-8k-vision-preview'],
);
expect(getModelMaxTokens('moonshot-v1-32k')).toBe(
maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-32k'],
);
expect(getModelMaxTokens('moonshot-v1-32k-vision')).toBe(
maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-32k-vision'],
);
expect(getModelMaxTokens('moonshot-v1-32k-vision-preview')).toBe(
maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-32k-vision-preview'],
);
expect(getModelMaxTokens('moonshot-v1-128k')).toBe(
maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-128k'],
);
expect(getModelMaxTokens('moonshot-v1-128k-vision')).toBe(
maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-128k-vision'],
);
expect(getModelMaxTokens('moonshot-v1-128k-vision-preview')).toBe(
maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-128k-vision-preview'],
);
});
test('should return correct tokens for Bedrock moonshot models', () => {
expect(getModelMaxTokens('moonshot.kimi', EModelEndpoint.bedrock)).toBe(
maxTokensMap[EModelEndpoint.bedrock]['moonshot.kimi'],
);
expect(getModelMaxTokens('moonshot.kimi-k2', EModelEndpoint.bedrock)).toBe(
maxTokensMap[EModelEndpoint.bedrock]['moonshot.kimi-k2'],
);
expect(getModelMaxTokens('moonshot.kimi-k2.5', EModelEndpoint.bedrock)).toBe(
maxTokensMap[EModelEndpoint.bedrock]['moonshot.kimi-k2.5'],
);
expect(getModelMaxTokens('moonshot.kimi-k2-thinking', EModelEndpoint.bedrock)).toBe(
maxTokensMap[EModelEndpoint.bedrock]['moonshot.kimi-k2-thinking'],
);
expect(getModelMaxTokens('moonshot.kimi-k2-0711', EModelEndpoint.bedrock)).toBe(
maxTokensMap[EModelEndpoint.bedrock]['moonshot.kimi-k2-0711'],
);
});
test('should handle Moonshot/Kimi models with provider prefixes', () => {
expect(getModelMaxTokens('openrouter/kimi-k2')).toBe(
maxTokensMap[EModelEndpoint.openAI]['kimi-k2'],
);
expect(getModelMaxTokens('openrouter/kimi-k2.5')).toBe(
maxTokensMap[EModelEndpoint.openAI]['kimi-k2.5'],
);
expect(getModelMaxTokens('openrouter/kimi-k2-turbo')).toBe(
maxTokensMap[EModelEndpoint.openAI]['kimi-k2-turbo'],
);
expect(getModelMaxTokens('openrouter/moonshot-v1-128k')).toBe(
maxTokensMap[EModelEndpoint.openAI]['moonshot-v1-128k'],
);
});
});
describe('matchModelName', () => {
test('should match exact Kimi model names', () => {
expect(matchModelName('kimi')).toBe('kimi');
expect(matchModelName('kimi-k2')).toBe('kimi');
expect(matchModelName('kimi-vl')).toBe('kimi');
expect(matchModelName('kimi-k2')).toBe('kimi-k2');
expect(matchModelName('kimi-k2.5')).toBe('kimi-k2.5');
expect(matchModelName('kimi-k2-turbo')).toBe('kimi-k2-turbo');
expect(matchModelName('kimi-k2-0711')).toBe('kimi-k2-0711');
});
test('should match moonshot model names', () => {
expect(matchModelName('moonshot')).toBe('moonshot');
expect(matchModelName('moonshot-v1-8k')).toBe('moonshot-v1-8k');
expect(matchModelName('moonshot-v1-32k')).toBe('moonshot-v1-32k');
expect(matchModelName('moonshot-v1-128k')).toBe('moonshot-v1-128k');
});
test('should match Kimi model variations with provider prefix', () => {
expect(matchModelName('moonshotai/kimi')).toBe('kimi');
expect(matchModelName('moonshotai/kimi-k2')).toBe('kimi');
expect(matchModelName('moonshotai/kimi-vl')).toBe('kimi');
expect(matchModelName('openrouter/kimi')).toBe('kimi');
expect(matchModelName('openrouter/kimi-k2')).toBe('kimi-k2');
expect(matchModelName('openrouter/kimi-k2.5')).toBe('kimi-k2.5');
});
test('should match Kimi model variations with suffixes', () => {
expect(matchModelName('kimi-k2-latest')).toBe('kimi');
expect(matchModelName('kimi-vl-preview')).toBe('kimi');
expect(matchModelName('kimi-2024')).toBe('kimi');
expect(matchModelName('kimi-k2-latest')).toBe('kimi-k2');
expect(matchModelName('kimi-k2.5-preview')).toBe('kimi-k2.5');
});
});
});