Add configurable embedding provider support#134
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an env-driven configuration layer to the embedding subsystem so deployments can switch embedding provider/model/dimensions (defaulting to the current OpenAI setup) and records the embedding model used when writing chunk updates.
Changes:
- Introduce
getEmbeddingConfig()and wireembedBatchto supportopenai(default) andvoyageproviders. - Persist the configured embedding model onto chunk updates in the
gbrain embedcommand. - Add docs and tests covering the new configuration path.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| test/embed.test.ts | Adds unit tests for embedding config defaults/overrides and extends env cleanup. |
| src/core/embedding.ts | Implements env-driven embedding config and adds Voyage embeddings implementation. |
| src/commands/embed.ts | Records embedding model on chunk upserts during embedding runs. |
| README.md | Notes embedding provider/model/dimensions env vars in CLI help. |
| INSTALL_FOR_AGENTS.md | Documents optional embedding provider overrides and Voyage API key. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export function getEmbeddingConfig(): EmbeddingConfig { | ||
| const providerRaw = (process.env.EMBEDDING_PROVIDER || DEFAULT_PROVIDER).toLowerCase(); | ||
| const model = process.env.EMBEDDING_MODEL || DEFAULT_MODEL; | ||
| const dimensionsRaw = process.env.EMBEDDING_DIMENSIONS; | ||
| const dimensions = dimensionsRaw ? parseInt(dimensionsRaw, 10) : DEFAULT_DIMENSIONS; | ||
|
|
||
| if (providerRaw !== 'openai' && providerRaw !== 'voyage') { | ||
| throw new Error(`Unsupported embedding provider: ${providerRaw}. Expected openai or voyage.`); | ||
| } | ||
|
|
||
| if (dimensionsRaw && Number.isNaN(dimensions)) { | ||
| throw new Error(`Invalid EMBEDDING_DIMENSIONS: ${dimensionsRaw}`); | ||
| } | ||
| return client; | ||
|
|
||
| return { | ||
| provider: providerRaw, | ||
| model, | ||
| dimensions, | ||
| }; |
| const updated: ChunkInput[] = chunks.map(c => ({ | ||
| chunk_index: c.chunk_index, | ||
| chunk_text: c.chunk_text, | ||
| chunk_source: c.chunk_source, | ||
| embedding: embeddingMap.get(c.chunk_index), | ||
| model: embeddingConfig.model, | ||
| token_count: c.token_count || Math.ceil(c.chunk_text.length / 4), | ||
| })); |
| const updated: ChunkInput[] = chunks.map(c => ({ | ||
| chunk_index: c.chunk_index, | ||
| chunk_text: c.chunk_text, | ||
| chunk_source: c.chunk_source, | ||
| embedding: embeddingMap.get(c.chunk_index) ?? undefined, | ||
| model: embeddingConfig.model, | ||
| token_count: c.token_count || Math.ceil(c.chunk_text.length / 4), | ||
| })); |
| import { getEmbeddingConfig } from '../src/core/embedding.ts'; | ||
| import type { BrainEngine } from '../src/core/engine.ts'; |
| const providerRaw = (process.env.EMBEDDING_PROVIDER || DEFAULT_PROVIDER).toLowerCase(); | ||
| const model = process.env.EMBEDDING_MODEL || DEFAULT_MODEL; | ||
| const dimensionsRaw = process.env.EMBEDDING_DIMENSIONS; | ||
| const dimensions = dimensionsRaw ? parseInt(dimensionsRaw, 10) : DEFAULT_DIMENSIONS; | ||
|
|
|
Closing as superseded by current upstream provider gateway work. GBrain now has the v0.27+ provider recipe/gateway architecture with OpenAI, Gemini, Ollama, Voyage, LiteLLM/OpenAI-compatible providers, model discovery, and provider tests. Any remaining provider gaps should be filed as narrow issues/PRs against the current recipe architecture rather than this old configurable-provider branch. |
Summary
Validation
Closes #133