From dbd0bae22d0069a41a72cf0cbb389061feed7199 Mon Sep 17 00:00:00 2001 From: Philip Mischenko Date: Wed, 13 May 2026 12:02:20 +0100 Subject: [PATCH 1/5] feat(embeddings): support custom OpenAI baseURL for Ollama / OpenAI-compatible providers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds an optional `base_url` field under `embedding.openai` in the config schema (and `OPENAI_BASE_URL` env var fallback). When set, it is passed to the OpenAI SDK constructor as `baseURL`, allowing doc2vec to embed documents via any OpenAI-compatible endpoint — Ollama, LM Studio, vLLM, llama.cpp server, internal LLM gateways, etc. Conditional spread keeps the default behaviour identical when no base URL is provided; existing configs continue to hit api.openai.com. The chosen endpoint is now revealed in the startup log line for clearer diagnostics ("Using OpenAI ... via http://localhost:11434/v1"). Signed-off-by: Philip Mischenko --- doc2vec.ts | 12 ++++++++---- types.ts | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/doc2vec.ts b/doc2vec.ts index fe107b7..13e7352 100644 --- a/doc2vec.ts +++ b/doc2vec.ts @@ -89,15 +89,19 @@ export class Doc2Vec { } else { const openaiApiKey = embeddingConfig.openai?.api_key || process.env.OPENAI_API_KEY; const openaiModel = embeddingConfig.openai?.model || process.env.OPENAI_MODEL || 'text-embedding-3-large'; - + const openaiBaseURL = embeddingConfig.openai?.base_url || process.env.OPENAI_BASE_URL; + if (!openaiApiKey) { this.logger.error('OpenAI requires api_key to be configured'); process.exit(1); } - - this.openai = new OpenAI({ apiKey: openaiApiKey }); + + this.openai = new OpenAI({ + apiKey: openaiApiKey, + ...(openaiBaseURL && { baseURL: openaiBaseURL }), + }); this.embeddingModel = openaiModel; - this.logger.info(`Using OpenAI with model: ${openaiModel} (${this.embeddingDimension} dimensions)`); + this.logger.info(`Using OpenAI with model: ${openaiModel} (${this.embeddingDimension} dimensions)${openaiBaseURL ? ` via ${openaiBaseURL}` : ''}`); } this.contentProcessor = new ContentProcessor(this.logger); diff --git a/types.ts b/types.ts index 67d359c..995c022 100644 --- a/types.ts +++ b/types.ts @@ -99,8 +99,9 @@ export interface EmbeddingConfig { provider: 'openai' | 'azure'; dimension?: number; openai?: { - api_key?: string; // Can also use OPENAI_API_KEY env var - model?: string; // Default: text-embedding-3-large + api_key?: string; // Can also use OPENAI_API_KEY env var + model?: string; // Default: text-embedding-3-large + base_url?: string; // Override OpenAI API base URL — useful for Ollama or other OpenAI-compatible endpoints. Can also use OPENAI_BASE_URL env var. }; azure?: { api_key?: string; // Can also use AZURE_OPENAI_KEY env var From f7c100a34a29395ae468707116b65e265d0c8e3a Mon Sep 17 00:00:00 2001 From: Philip Mischenko Date: Wed, 13 May 2026 12:17:57 +0100 Subject: [PATCH 2/5] fix(docker): rebuild better-sqlite3 native bindings after --ignore-scripts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `npm install --ignore-scripts` (security best-practice — blocks malicious postinstall scripts) skips node-gyp compilation for native modules. The better-sqlite3 binding is therefore never built unless a prebuilt binary exists for the target arch/Node combination. On linux/arm64 (Apple Silicon, ARM Linux runners) no prebuild ships, so runtime fails with "Could not locate the bindings file" the moment any SQLite source tries to open a database. Adding an explicit `npm rebuild better-sqlite3` after install keeps the security guarantee for unrelated scripts while compiling the one native module the tool actually needs. Signed-off-by: Philip Mischenko --- Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Dockerfile b/Dockerfile index ffec336..4eb8a3c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,6 +32,12 @@ RUN apt-get update && apt-get install -y \ COPY package*.json ./ RUN npm install --ignore-scripts +# --ignore-scripts skips node-gyp rebuild for native modules +# (security best-practice, blocks malicious postinstall scripts). +# Explicitly rebuild better-sqlite3 so its arm64/amd64 .node binding +# is compiled — otherwise the runtime fails with "Could not locate +# the bindings file" on architectures lacking a prebuild. +RUN npm rebuild better-sqlite3 # Install Chrome via Puppeteer as fallback (system Chromium will be used first) RUN npx puppeteer browsers install chrome || true COPY . . From f3d54890f419f83a9480dac755df8c8e490f0d39 Mon Sep 17 00:00:00 2001 From: Philip Mischenko Date: Wed, 13 May 2026 12:31:13 +0100 Subject: [PATCH 3/5] feat(mcp): support custom OpenAI baseURL in the MCP server too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reader-side MCP server (mcp/src/index.ts) also instantiated the OpenAI client with apiKey only. It now reads OPENAI_BASE_URL from the environment and threads it into the constructor via conditional spread, mirroring the writer-side fix introduced earlier on this branch. This lets users point both halves of the doc2vec pipeline (the writer CLI for building vector DBs and the MCP server for querying them) at any OpenAI-compatible endpoint — Ollama, LM Studio, vLLM, llama.cpp server, internal LLM gateways — through a single env var per process. Default behaviour unchanged when OPENAI_BASE_URL is unset. Signed-off-by: Philip Mischenko --- mcp/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mcp/src/index.ts b/mcp/src/index.ts index 7f48875..7273cf2 100644 --- a/mcp/src/index.ts +++ b/mcp/src/index.ts @@ -34,6 +34,7 @@ const embeddingProvider = process.env.EMBEDDING_PROVIDER || 'openai'; // OpenAI configuration const openAIApiKey = process.env.OPENAI_API_KEY; const openAIModel = process.env.OPENAI_MODEL || 'text-embedding-3-large'; +const openAIBaseURL = process.env.OPENAI_BASE_URL; // Optional: override API base URL for Ollama / other OpenAI-compatible endpoints // Azure OpenAI configuration const azureApiKey = process.env.AZURE_OPENAI_KEY; @@ -110,6 +111,7 @@ async function createEmbeddings(text: string): Promise { case 'openai': { const openai = new OpenAI({ apiKey: openAIApiKey, + ...(openAIBaseURL && { baseURL: openAIBaseURL }), }); const response = await openai.embeddings.create({ model: openAIModel, From 17790b42769a4f34019e7d98d20feb7c121006c8 Mon Sep 17 00:00:00 2001 From: Philip Mischenko Date: Mon, 8 Jun 2026 14:07:05 +0100 Subject: [PATCH 4/5] docs: document OPENAI_BASE_URL env var and openai.base_url config Add the new override knob to both the .env example and the config.yaml example so users following the README discover it through the same path as OPENAI_API_KEY / OPENAI_MODEL. Two short usage hints (Ollama, generic gateway) cover the common reasons to set it. Signed-off-by: Philip Mischenko --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 79ca99e..253fb27 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,16 @@ Configuration is managed through two files: OPENAI_API_KEY="sk-..." OPENAI_MODEL="text-embedding-3-large" # Optional, defaults to text-embedding-3-large + # Optional: Override the OpenAI API base URL. Useful for pointing the + # OpenAI SDK at an OpenAI-compatible endpoint such as Ollama, LM Studio, + # llama.cpp, vLLM, or a proxy gateway. When unset, the SDK uses the + # default OpenAI endpoint. Equivalent to the `embedding.openai.base_url` + # field in config.yaml; the env var wins if both are set. + # Example values: + # OPENAI_BASE_URL="http://localhost:11434/v1" # Ollama + # OPENAI_BASE_URL="https://gateway.example.com/v1" # proxy / gateway + OPENAI_BASE_URL="http://localhost:11434/v1" + # Optional: Embedding dimension size (defaults to 3072) EMBEDDING_DIMENSION="3072" @@ -277,6 +287,7 @@ Configuration is managed through two files: openai: api_key: '${OPENAI_API_KEY}' # Optional, uses env var by default model: 'text-embedding-3-large' # Optional, defaults to text-embedding-3-large + # base_url: 'http://localhost:11434/v1' # Optional, override OpenAI API base URL for Ollama / other OpenAI-compatible endpoints. Falls back to OPENAI_BASE_URL env var. # For Azure OpenAI, use this instead: # azure: # api_key: '${AZURE_OPENAI_KEY}' From bf94f2b49bba08722200b6400fefac696e2173e6 Mon Sep 17 00:00:00 2001 From: Philip Mischenko Date: Mon, 8 Jun 2026 14:18:58 +0100 Subject: [PATCH 5/5] chore: bump version (root 2.10.3, mcp 2.1.1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patch-level bump per maintainer request — matches the convention used у the most recent merged feature PR (#87). Signed-off-by: Philip Mischenko --- mcp/package.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mcp/package.json b/mcp/package.json index 1869fc5..253edb2 100644 --- a/mcp/package.json +++ b/mcp/package.json @@ -1,6 +1,6 @@ { "name": "sqlite-vec-mcp-server", - "version": "2.1.0", + "version": "2.1.1", "description": "MCP Server for querying documentation with sqlite-vec", "main": "build/index.js", "type": "module", diff --git a/package.json b/package.json index 4ba2cd6..ae29d6a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doc2vec", - "version": "2.10.2", + "version": "2.10.3", "type": "commonjs", "description": "", "main": "dist/doc2vec.js",