feat(TRUEREF-0007): implement pluggable embedding generation and vector storage

Add EmbeddingProvider interface with OpenAI-compatible, local (optional
@xenova/transformers via dynamic import), and Noop (FTS5-only fallback)
implementations. EmbeddingService batches requests and persists Float32Array
blobs to snippet_embeddings. GET/PUT /api/v1/settings/embedding endpoints
read and write embedding config from the settings table.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Giancarmine Salucci
2026-03-22 18:07:26 +01:00
parent 3d1bef5003
commit bf4caf5e3b
7 changed files with 927 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
/**
* Factory — create an EmbeddingProvider from a persisted EmbeddingConfig.
*/
import type { EmbeddingProvider } from './provider.js';
import { NoopEmbeddingProvider } from './provider.js';
import { OpenAIEmbeddingProvider } from './openai.provider.js';
import { LocalEmbeddingProvider } from './local.provider.js';
export interface EmbeddingConfig {
provider: 'openai' | 'local' | 'none';
openai?: {
baseUrl: string;
apiKey: string;
model: string;
dimensions?: number;
maxBatchSize?: number;
};
}
/** The settings table key used to persist the embedding configuration. */
export const EMBEDDING_CONFIG_KEY = 'embedding_config';
/**
* Construct the appropriate EmbeddingProvider for the given config.
* Falls back to NoopEmbeddingProvider for unknown or missing providers.
*/
export function createProviderFromConfig(config: EmbeddingConfig): EmbeddingProvider {
switch (config.provider) {
case 'openai': {
if (!config.openai) {
throw new Error('OpenAI provider selected but no openai config provided.');
}
return new OpenAIEmbeddingProvider(config.openai);
}
case 'local': {
return new LocalEmbeddingProvider();
}
case 'none':
default:
return new NoopEmbeddingProvider();
}
}
/**
* Return a default (noop) config when nothing has been stored yet.
*/
export function defaultEmbeddingConfig(): EmbeddingConfig {
return { provider: 'none' };
}
export type { EmbeddingProvider };