9be8f76bc7
- Lane Queue: per-session FIFO queue in gateway replacing reject-when-busy (9 tests) - Credential Redaction: redactConfig() expanded to cover 18+ secret fields (16 tests) - Web UI Token Dashboard: system.tokenUsage endpoint + Usage page with summary cards - xAI (Grok) Provider: OpenAI-compatible client with model pricing - Voyage AI Embeddings: new embedding provider with configurable dimensions (5 tests) - Update gap analysis: 90→95 match (70%→74%), Tier 3 section marked DONE - Update state.json: test count 1001→1034, add tier3_completion entry Total: 1034 tests passing across 85 files, typecheck clean
230 lines
6.4 KiB
TypeScript
230 lines
6.4 KiB
TypeScript
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);
|
|
});
|
|
});
|