@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
text/typescript
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
});
});
});