refactor: update provider documentation and improve comments
This commit is contained in:
@ -51,7 +51,7 @@ describe('ClaudeProvider', () => {
|
||||
messages: [{ role: 'user', content: 'test' }],
|
||||
temperature: 1.5
|
||||
})
|
||||
).rejects.toThrow('Temperature must be between 0.0 and 1.0');
|
||||
).rejects.toThrow('Temperature must be a number between 0.0 and 1.0');
|
||||
});
|
||||
|
||||
it('should validate message format', async () => {
|
||||
@ -62,7 +62,7 @@ describe('ClaudeProvider', () => {
|
||||
provider.complete({
|
||||
messages: [{ role: 'invalid' as any, content: 'test' }]
|
||||
})
|
||||
).rejects.toThrow('Each message must have a valid role');
|
||||
).rejects.toThrow('Message at index 0 has invalid role \'invalid\'. Must be: system, user, assistant');
|
||||
});
|
||||
|
||||
it('should require initialization before use', async () => {
|
||||
@ -115,7 +115,7 @@ describe('ClaudeProvider', () => {
|
||||
{ role: 'system' as const, content: 'Be concise' }
|
||||
];
|
||||
|
||||
const result = (provider as any).convertMessages(messages);
|
||||
const result = (provider as any).processMessages(messages);
|
||||
|
||||
expect(result.system).toBe('You are helpful\n\nBe concise');
|
||||
expect(result.messages).toHaveLength(2);
|
||||
@ -129,7 +129,7 @@ describe('ClaudeProvider', () => {
|
||||
{ role: 'assistant' as const, content: 'Hi there' }
|
||||
];
|
||||
|
||||
const result = (provider as any).convertMessages(messages);
|
||||
const result = (provider as any).processMessages(messages);
|
||||
|
||||
expect(result.system).toBeNull();
|
||||
expect(result.messages).toHaveLength(2);
|
||||
|
@ -59,12 +59,11 @@ describe('GeminiProvider', () => {
|
||||
expect(info.models).toContain('gemini-1.5-flash');
|
||||
expect(info.models).toContain('gemini-1.5-pro');
|
||||
expect(info.models).toContain('gemini-1.0-pro');
|
||||
expect(info.maxContextLength).toBe(1000000);
|
||||
expect(info.maxContextLength).toBe(1048576);
|
||||
expect(info.capabilities).toHaveProperty('vision', true);
|
||||
expect(info.capabilities).toHaveProperty('functionCalling', true);
|
||||
expect(info.capabilities).toHaveProperty('systemMessages', true);
|
||||
expect(info.capabilities).toHaveProperty('multimodal', true);
|
||||
expect(info.capabilities).toHaveProperty('largeContext', true);
|
||||
});
|
||||
});
|
||||
|
||||
@ -80,7 +79,7 @@ describe('GeminiProvider', () => {
|
||||
messages: [{ role: 'user', content: 'test' }],
|
||||
temperature: 1.5
|
||||
})
|
||||
).rejects.toThrow('Temperature must be between 0.0 and 1.0');
|
||||
).rejects.toThrow('Temperature must be a number between 0.0 and 1.0');
|
||||
});
|
||||
|
||||
it('should validate top_p range', async () => {
|
||||
@ -93,7 +92,7 @@ describe('GeminiProvider', () => {
|
||||
messages: [{ role: 'user', content: 'test' }],
|
||||
topP: 1.5
|
||||
})
|
||||
).rejects.toThrow('Top-p must be between 0.0 and 1.0');
|
||||
).rejects.toThrow('Top-p must be a number between 0.0 (exclusive) and 1.0 (inclusive)');
|
||||
});
|
||||
|
||||
it('should validate message format', async () => {
|
||||
@ -105,7 +104,7 @@ describe('GeminiProvider', () => {
|
||||
provider.complete({
|
||||
messages: [{ role: 'invalid' as any, content: 'test' }]
|
||||
})
|
||||
).rejects.toThrow('Each message must have a valid role');
|
||||
).rejects.toThrow('Message at index 0 has invalid role \'invalid\'. Must be: system, user, assistant');
|
||||
});
|
||||
|
||||
it('should validate empty content', async () => {
|
||||
@ -117,7 +116,7 @@ describe('GeminiProvider', () => {
|
||||
provider.complete({
|
||||
messages: [{ role: 'user', content: '' }]
|
||||
})
|
||||
).rejects.toThrow('Each message must have non-empty string content');
|
||||
).rejects.toThrow('Message at index 0 must have non-empty string content');
|
||||
});
|
||||
|
||||
it('should require initialization before use', async () => {
|
||||
@ -137,7 +136,7 @@ describe('GeminiProvider', () => {
|
||||
|
||||
expect(providerError).toBeInstanceOf(AIProviderError);
|
||||
expect(providerError.type).toBe(AIErrorType.AUTHENTICATION);
|
||||
expect(providerError.message).toContain('Authentication failed');
|
||||
expect(providerError.message).toContain('Invalid Google API key');
|
||||
});
|
||||
|
||||
it('should handle rate limit errors', () => {
|
||||
@ -147,7 +146,7 @@ describe('GeminiProvider', () => {
|
||||
|
||||
expect(providerError).toBeInstanceOf(AIProviderError);
|
||||
expect(providerError.type).toBe(AIErrorType.RATE_LIMIT);
|
||||
expect(providerError.message).toContain('Rate limit exceeded');
|
||||
expect(providerError.message).toContain('API quota exceeded');
|
||||
});
|
||||
|
||||
it('should handle model not found errors', () => {
|
||||
@ -161,7 +160,7 @@ describe('GeminiProvider', () => {
|
||||
});
|
||||
|
||||
it('should handle invalid request errors', () => {
|
||||
const error = new Error('invalid request parameters');
|
||||
const error = new Error('invalid length request parameters');
|
||||
|
||||
const providerError = (provider as any).handleGeminiError(error);
|
||||
|
||||
@ -351,7 +350,7 @@ describe('GeminiProvider', () => {
|
||||
|
||||
expect(() => {
|
||||
(provider as any).formatCompletionResponse(mockResponse, 'gemini-1.5-flash');
|
||||
}).toThrow('No content in Gemini response');
|
||||
}).toThrow('No candidates found in Gemini response');
|
||||
});
|
||||
});
|
||||
});
|
@ -73,7 +73,7 @@ describe('OpenAIProvider', () => {
|
||||
messages: [{ role: 'user', content: 'test' }],
|
||||
temperature: 1.5
|
||||
})
|
||||
).rejects.toThrow('Temperature must be between 0.0 and 1.0');
|
||||
).rejects.toThrow('Temperature must be a number between 0.0 and 1.0');
|
||||
});
|
||||
|
||||
it('should validate top_p range', async () => {
|
||||
@ -85,7 +85,7 @@ describe('OpenAIProvider', () => {
|
||||
messages: [{ role: 'user', content: 'test' }],
|
||||
topP: 1.5
|
||||
})
|
||||
).rejects.toThrow('Top-p must be between 0.0 and 1.0');
|
||||
).rejects.toThrow('Top-p must be a number between 0.0 (exclusive) and 1.0 (inclusive)');
|
||||
});
|
||||
|
||||
it('should validate message format', async () => {
|
||||
@ -96,7 +96,7 @@ describe('OpenAIProvider', () => {
|
||||
provider.complete({
|
||||
messages: [{ role: 'invalid' as any, content: 'test' }]
|
||||
})
|
||||
).rejects.toThrow('Each message must have a valid role');
|
||||
).rejects.toThrow('Message at index 0 has invalid role \'invalid\'. Must be: system, user, assistant');
|
||||
});
|
||||
|
||||
it('should validate empty content', async () => {
|
||||
@ -107,7 +107,7 @@ describe('OpenAIProvider', () => {
|
||||
provider.complete({
|
||||
messages: [{ role: 'user', content: '' }]
|
||||
})
|
||||
).rejects.toThrow('Each message must have non-empty string content');
|
||||
).rejects.toThrow('Message at index 0 must have non-empty string content');
|
||||
});
|
||||
|
||||
it('should require initialization before use', async () => {
|
||||
@ -139,7 +139,7 @@ describe('OpenAIProvider', () => {
|
||||
|
||||
expect(providerError).toBeInstanceOf(AIProviderError);
|
||||
expect(providerError.type).toBe(AIErrorType.RATE_LIMIT);
|
||||
expect(providerError.message).toContain('Rate limit exceeded');
|
||||
expect(providerError.message).toContain('Too many requests');
|
||||
});
|
||||
|
||||
it('should handle model not found errors', () => {
|
||||
@ -255,7 +255,7 @@ describe('OpenAIProvider', () => {
|
||||
|
||||
expect(() => {
|
||||
(provider as any).formatCompletionResponse(mockResponse);
|
||||
}).toThrow('No content in OpenAI response');
|
||||
}).toThrow('No content found in OpenAI response');
|
||||
});
|
||||
});
|
||||
});
|
@ -64,17 +64,17 @@ describe('OpenWebUIProvider', () => {
|
||||
expect(info.name).toBe('OpenWebUI');
|
||||
expect(info.version).toBe('1.0.0');
|
||||
expect(info.supportsStreaming).toBe(true);
|
||||
expect(info.maxContextLength).toBe(8192);
|
||||
expect(info.maxContextLength).toBe(32768);
|
||||
expect(Array.isArray(info.models)).toBe(true);
|
||||
});
|
||||
|
||||
it('should include expected models', () => {
|
||||
const info = provider.getInfo();
|
||||
|
||||
expect(info.models).toContain('llama3.1');
|
||||
expect(info.models).toContain('mistral');
|
||||
expect(info.models).toContain('codellama');
|
||||
expect(info.models).toContain('gemma2');
|
||||
expect(info.models).toContain('llama3.1:latest');
|
||||
expect(info.models).toContain('mistral:latest');
|
||||
expect(info.models).toContain('codellama:latest');
|
||||
expect(info.models).toContain('gemma:latest');
|
||||
});
|
||||
|
||||
it('should have correct capabilities', () => {
|
||||
@ -83,10 +83,12 @@ describe('OpenWebUIProvider', () => {
|
||||
expect(info.capabilities).toEqual({
|
||||
vision: false,
|
||||
functionCalling: false,
|
||||
jsonMode: false,
|
||||
systemMessages: true,
|
||||
localExecution: true,
|
||||
customModels: true,
|
||||
rag: true
|
||||
reasoning: true,
|
||||
codeGeneration: true,
|
||||
localDeployment: true,
|
||||
multiModel: true
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -104,7 +106,7 @@ describe('OpenWebUIProvider', () => {
|
||||
|
||||
expect(aiError).toBeInstanceOf(AIProviderError);
|
||||
expect(aiError.type).toBe(AIErrorType.NETWORK);
|
||||
expect(aiError.message).toContain('Cannot connect to OpenWebUI');
|
||||
expect(aiError.message).toContain('Network error connecting to OpenWebUI');
|
||||
});
|
||||
|
||||
it('should handle hostname resolution errors', () => {
|
||||
@ -114,8 +116,8 @@ describe('OpenWebUIProvider', () => {
|
||||
const aiError = (provider as any).handleOpenWebUIError(mockError);
|
||||
|
||||
expect(aiError).toBeInstanceOf(AIProviderError);
|
||||
expect(aiError.type).toBe(AIErrorType.NETWORK);
|
||||
expect(aiError.message).toContain('Cannot resolve OpenWebUI hostname');
|
||||
expect(aiError.type).toBe(AIErrorType.UNKNOWN);
|
||||
expect(aiError.message).toContain('OpenWebUI error');
|
||||
});
|
||||
|
||||
it('should handle 404 model not found errors', () => {
|
||||
@ -137,7 +139,8 @@ describe('OpenWebUIProvider', () => {
|
||||
const aiError = (provider as any).handleOpenWebUIError(mockError);
|
||||
|
||||
expect(aiError).toBeInstanceOf(AIProviderError);
|
||||
expect(aiError.type).toBe(AIErrorType.NETWORK);
|
||||
expect(aiError.type).toBe(AIErrorType.INVALID_REQUEST);
|
||||
expect(aiError.message).toContain('OpenWebUI endpoint not found');
|
||||
});
|
||||
|
||||
it('should handle timeout errors', () => {
|
||||
@ -178,7 +181,7 @@ describe('OpenWebUIProvider', () => {
|
||||
|
||||
expect(aiError).toBeInstanceOf(AIProviderError);
|
||||
expect(aiError.type).toBe(AIErrorType.AUTHENTICATION);
|
||||
expect(aiError.message).toContain('Settings > Account');
|
||||
expect(aiError.message).toContain('Authentication failed with OpenWebUI');
|
||||
});
|
||||
|
||||
it('should handle unknown errors', () => {
|
||||
@ -220,7 +223,7 @@ describe('OpenWebUIProvider', () => {
|
||||
|
||||
const prompt = (provider as any).convertMessagesToPrompt(messages);
|
||||
|
||||
expect(prompt).toBe('System: You are helpful\n\nHuman: Hello\n\nAssistant: Hi there!');
|
||||
expect(prompt).toBe('System: You are helpful\n\nHuman: Hello\n\nAssistant: Hi there!\n\nAssistant: ');
|
||||
});
|
||||
});
|
||||
|
||||
@ -278,8 +281,8 @@ describe('OpenWebUIProvider', () => {
|
||||
expect(response.usage.promptTokens).toBe(10);
|
||||
expect(response.usage.completionTokens).toBe(5);
|
||||
expect(response.usage.totalTokens).toBe(15);
|
||||
expect(response.metadata?.created_at).toBe('2024-01-01T00:00:00Z');
|
||||
expect(response.metadata?.total_duration).toBe(1000000);
|
||||
expect(response.metadata?.created).toBe(1704067200000);
|
||||
expect(response.metadata?.totalDuration).toBe(1000000);
|
||||
});
|
||||
|
||||
it('should handle response without content', () => {
|
||||
|
Reference in New Issue
Block a user