/** * provider.ts - Embedding provider abstraction * * Defines the EmbeddingProvider interface that allows qmd to use either: * - LocalLlamaCppProvider (legacy, GGUF via node-llama-cpp) * - OpenAIEmbeddingsProvider (HTTP, OpenAI-compatible endpoint like ai.mm.mk) * * The factory in `./factory.ts` selects an implementation based on env vars, * a CLI flag, or `~/.config/qmd/config.json`. */ /** * Error thrown when the provider's reported model id does not match the * model id baked into existing `content_vectors` rows. Forces user to * re-embed (`qmd embed -f`) or pin the matching model id. */ export class ModelMismatchError extends Error { providerModel; existingModels; constructor(providerModel, existingModels) { const list = existingModels.join(", "); super(`Embedding model mismatch: existing vectors use model(s) [${list}] ` + `but the configured provider reports "${providerModel}". ` + `Run \`qmd embed -f\` (or \`--rebuild\`) to re-embed everything with ` + `the new model, or set QMD_EMBED_MODEL_ID="${existingModels[0] ?? ""}" ` + `to keep the existing vectors.`); this.name = "ModelMismatchError"; this.providerModel = providerModel; this.existingModels = existingModels; } } /** * Verify that the provider's model id is compatible with the existing * `content_vectors` entries. Pass-through (no-op) if the table is empty * (fresh DB) or if the model id appears in the distinct set. * * Caller passes `existingModels` (typically result of * `SELECT DISTINCT model FROM content_vectors`). */ export function assertModelCompatible(providerModel, existingModels) { // Empty DB — nothing to compare against, anything goes. if (existingModels.length === 0) return; if (existingModels.includes(providerModel)) return; throw new ModelMismatchError(providerModel, existingModels); }