import { describe, it, expect } from 'vitest'; import { createEmbeddingProvider, OpenAIEmbeddingProvider, GeminiEmbeddingProvider, OllamaEmbeddingProvider, LlamaCppEmbeddingProvider, VoyageAIEmbeddingProvider, } from './embeddings.js'; import type { EmbeddingConfig } from '../config/schema.js'; describe('createEmbeddingProvider', () => { const baseConfig: EmbeddingConfig = { enabled: true, provider: 'openai', model: 'text-embedding-3-small', chunk_size: 512, chunk_overlap: 50, top_k: 5, hybrid_weight: 0.7, }; it('creates OpenAI provider', () => { const provider = createEmbeddingProvider({ ...baseConfig, provider: 'openai' }); expect(provider).toBeInstanceOf(OpenAIEmbeddingProvider); }); it('creates Gemini provider', () => { const provider = createEmbeddingProvider({ ...baseConfig, provider: 'gemini' }); expect(provider).toBeInstanceOf(GeminiEmbeddingProvider); }); it('creates Ollama provider', () => { const provider = createEmbeddingProvider({ ...baseConfig, provider: 'ollama' }); expect(provider).toBeInstanceOf(OllamaEmbeddingProvider); }); it('creates LlamaCpp provider', () => { const provider = createEmbeddingProvider({ ...baseConfig, provider: 'llamacpp' }); expect(provider).toBeInstanceOf(LlamaCppEmbeddingProvider); }); it('creates Voyage provider', () => { const provider = createEmbeddingProvider({ ...baseConfig, provider: 'voyage' }); expect(provider).toBeInstanceOf(VoyageAIEmbeddingProvider); }); it('throws on unknown provider', () => { expect(() => createEmbeddingProvider({ ...baseConfig, provider: 'unknown' as never })).toThrow('Unknown embedding provider'); }); }); describe('OpenAIEmbeddingProvider', () => { it('reports configured dimensions', () => { const config: EmbeddingConfig = { enabled: true, provider: 'openai', model: 'text-embedding-3-small', dimensions: 512, chunk_size: 512, chunk_overlap: 50, top_k: 5, hybrid_weight: 0.7, }; const provider = new OpenAIEmbeddingProvider(config); expect(provider.dimensions).toBe(512); }); it('defaults to 1536 dimensions', () => { const config: EmbeddingConfig = { enabled: true, provider: 'openai', model: 'text-embedding-3-small', chunk_size: 512, chunk_overlap: 50, top_k: 5, hybrid_weight: 0.7, }; const provider = new OpenAIEmbeddingProvider(config); expect(provider.dimensions).toBe(1536); }); }); describe('GeminiEmbeddingProvider', () => { it('reports configured dimensions', () => { const config: EmbeddingConfig = { enabled: true, provider: 'gemini', model: 'text-embedding-004', dimensions: 256, chunk_size: 512, chunk_overlap: 50, top_k: 5, hybrid_weight: 0.7, }; const provider = new GeminiEmbeddingProvider(config); expect(provider.dimensions).toBe(256); }); it('defaults to 768 dimensions', () => { const config: EmbeddingConfig = { enabled: true, provider: 'gemini', model: 'text-embedding-004', chunk_size: 512, chunk_overlap: 50, top_k: 5, hybrid_weight: 0.7, }; const provider = new GeminiEmbeddingProvider(config); expect(provider.dimensions).toBe(768); }); }); describe('OllamaEmbeddingProvider', () => { it('reports configured dimensions', () => { const config: EmbeddingConfig = { enabled: true, provider: 'ollama', model: 'nomic-embed-text', dimensions: 384, endpoint: 'http://localhost:11434', chunk_size: 512, chunk_overlap: 50, top_k: 5, hybrid_weight: 0.7, }; const provider = new OllamaEmbeddingProvider(config); expect(provider.dimensions).toBe(384); }); }); describe('LlamaCppEmbeddingProvider', () => { it('reports configured dimensions', () => { const config: EmbeddingConfig = { enabled: true, provider: 'llamacpp', model: 'unused', dimensions: 768, endpoint: 'http://localhost:8080', chunk_size: 512, chunk_overlap: 50, top_k: 5, hybrid_weight: 0.7, }; const provider = new LlamaCppEmbeddingProvider(config); expect(provider.dimensions).toBe(768); }); it('defaults endpoint to localhost:8080', () => { const config: EmbeddingConfig = { enabled: true, provider: 'llamacpp', model: 'unused', dimensions: 768, chunk_size: 512, chunk_overlap: 50, top_k: 5, hybrid_weight: 0.7, }; // Provider should be constructable without endpoint const provider = new LlamaCppEmbeddingProvider(config); expect(provider.dimensions).toBe(768); }); }); describe('VoyageAIEmbeddingProvider', () => { it('defaults to 1024 dimensions', () => { const config: EmbeddingConfig = { enabled: true, provider: 'voyage', model: 'voyage-3', chunk_size: 512, chunk_overlap: 50, top_k: 5, hybrid_weight: 0.7, }; const provider = new VoyageAIEmbeddingProvider(config); expect(provider.dimensions).toBe(1024); }); it('reports configured dimensions', () => { const config: EmbeddingConfig = { enabled: true, provider: 'voyage', model: 'voyage-3-lite', dimensions: 512, chunk_size: 512, chunk_overlap: 50, top_k: 5, hybrid_weight: 0.7, }; const provider = new VoyageAIEmbeddingProvider(config); expect(provider.dimensions).toBe(512); }); it('uses custom endpoint if provided', () => { const config: EmbeddingConfig = { enabled: true, provider: 'voyage', model: 'voyage-3', endpoint: 'https://custom.proxy.example.com/v1', api_key: 'test-key', chunk_size: 512, chunk_overlap: 50, top_k: 5, hybrid_weight: 0.7, }; // Should not throw when constructing with custom endpoint const provider = new VoyageAIEmbeddingProvider(config); expect(provider.dimensions).toBe(1024); }); it('uses api_key from config', () => { const config: EmbeddingConfig = { enabled: true, provider: 'voyage', model: 'voyage-3', api_key: 'voy-test-key-123', chunk_size: 512, chunk_overlap: 50, top_k: 5, hybrid_weight: 0.7, }; // Should construct without error when api_key is provided const provider = new VoyageAIEmbeddingProvider(config); expect(provider.dimensions).toBe(1024); }); });