UNPKG

@lobehub/chat

Version:

Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.

194 lines (168 loc) • 6.81 kB
import { vi } from 'vitest'; import { getModelPropertyWithFallback } from './getFallbackModelProperty'; // Mock LOBE_DEFAULT_MODEL_LIST for testing vi.mock('@/config/aiModels', () => ({ LOBE_DEFAULT_MODEL_LIST: [ { id: 'gpt-4', providerId: 'openai', type: 'chat', displayName: 'GPT-4', contextWindowTokens: 8192, enabled: true, abilities: { functionCall: true, vision: true, }, parameters: { temperature: 0.7, maxTokens: 4096, }, }, { id: 'gpt-4', providerId: 'azure', type: 'chat', displayName: 'GPT-4 Azure', contextWindowTokens: 8192, enabled: true, abilities: { functionCall: true, }, }, { id: 'claude-3', providerId: 'anthropic', type: 'chat', displayName: 'Claude 3', contextWindowTokens: 200000, enabled: false, }, { id: 'dall-e-3', providerId: 'openai', type: 'image', displayName: 'DALL-E 3', enabled: true, parameters: { size: '1024x1024', quality: 'standard', }, }, ], })); describe('getModelPropertyWithFallback', () => { describe('when providerId is specified', () => { it('should return exact match value when model exists with specified provider', () => { const result = getModelPropertyWithFallback('gpt-4', 'displayName', 'openai'); expect(result).toBe('GPT-4'); }); it('should return exact match type when model exists with specified provider', () => { const result = getModelPropertyWithFallback('gpt-4', 'type', 'openai'); expect(result).toBe('chat'); }); it('should return exact match contextWindowTokens when model exists with specified provider', () => { const result = getModelPropertyWithFallback('gpt-4', 'contextWindowTokens', 'azure'); expect(result).toBe(8192); }); it('should fall back to other provider when exact provider match not found', () => { const result = getModelPropertyWithFallback('gpt-4', 'displayName', 'fake-provider'); expect(result).toBe('GPT-4'); // Falls back to openai provider }); it('should return nested property like abilities', () => { const result = getModelPropertyWithFallback('gpt-4', 'abilities', 'openai'); expect(result).toEqual({ functionCall: true, vision: true, }); }); it('should return parameters property correctly', () => { const result = getModelPropertyWithFallback('dall-e-3', 'parameters', 'openai'); expect(result).toEqual({ size: '1024x1024', quality: 'standard', }); }); }); describe('when providerId is not specified', () => { it('should return fallback match value when model exists', () => { const result = getModelPropertyWithFallback('claude-3', 'displayName'); expect(result).toBe('Claude 3'); }); it('should return fallback match type when model exists', () => { const result = getModelPropertyWithFallback('claude-3', 'type'); expect(result).toBe('chat'); }); it('should return fallback match enabled property', () => { const result = getModelPropertyWithFallback('claude-3', 'enabled'); expect(result).toBe(false); }); }); describe('when model is not found', () => { it('should return default value "chat" for type property', () => { const result = getModelPropertyWithFallback('non-existent-model', 'type'); expect(result).toBe('chat'); }); it('should return default value "chat" for type property even with providerId', () => { const result = getModelPropertyWithFallback('non-existent-model', 'type', 'fake-provider'); expect(result).toBe('chat'); }); it('should return undefined for non-type properties when model not found', () => { const result = getModelPropertyWithFallback('non-existent-model', 'displayName'); expect(result).toBeUndefined(); }); it('should return undefined for contextWindowTokens when model not found', () => { const result = getModelPropertyWithFallback('non-existent-model', 'contextWindowTokens'); expect(result).toBeUndefined(); }); it('should return undefined for enabled property when model not found', () => { const result = getModelPropertyWithFallback('non-existent-model', 'enabled'); expect(result).toBeUndefined(); }); }); describe('provider precedence logic', () => { it('should prioritize exact provider match over general match', () => { // gpt-4 exists in both openai and azure providers with different displayNames const openaiResult = getModelPropertyWithFallback('gpt-4', 'displayName', 'openai'); const azureResult = getModelPropertyWithFallback('gpt-4', 'displayName', 'azure'); expect(openaiResult).toBe('GPT-4'); expect(azureResult).toBe('GPT-4 Azure'); }); it('should fall back to first match when specified provider not found', () => { // When asking for 'fake-provider', should fall back to first match (openai) const result = getModelPropertyWithFallback('gpt-4', 'displayName', 'fake-provider'); expect(result).toBe('GPT-4'); }); }); describe('property existence handling', () => { it('should handle undefined properties gracefully', () => { // claude-3 doesn't have abilities property defined const result = getModelPropertyWithFallback('claude-3', 'abilities'); expect(result).toBeUndefined(); }); it('should handle properties that exist but have falsy values', () => { // claude-3 has enabled: false const result = getModelPropertyWithFallback('claude-3', 'enabled'); expect(result).toBe(false); }); it('should distinguish between undefined and null values', () => { // Testing that we check for undefined specifically, not just falsy values const result = getModelPropertyWithFallback('claude-3', 'contextWindowTokens'); expect(result).toBe(200000); // Should find the defined value }); }); describe('edge cases', () => { it('should handle empty string modelId', () => { const result = getModelPropertyWithFallback('', 'type'); expect(result).toBe('chat'); // Should fall back to default }); it('should handle empty string providerId', () => { const result = getModelPropertyWithFallback('gpt-4', 'type', ''); expect(result).toBe('chat'); // Should still find the model via fallback }); it('should handle case-sensitive modelId correctly', () => { const result = getModelPropertyWithFallback('GPT-4', 'type'); // Wrong case expect(result).toBe('chat'); // Should fall back to default since no match }); }); });