Files
gbrain/docs/integrations/embedding-providers.md
T
d0d0e2a64a v0.37.11.0: fresh-install PGLite embedding setup fix wave (#1286)
* chore(test): preload gateway to OpenAI/1536 so 1536-dim test fixtures keep working

The v0.37 fix wave changes the canonical gateway defaults to
zeroentropyai:zembed-1 / 1280 (matching what v0.36 already chose as the
system default). 20+ test files have hardcoded new Float32Array(1536)
fixtures that match the OLD schema default. Without this preload, those
tests fail with a vector-dim-mismatch on insert.

The preload is gateway-only — it doesn't change which model gbrain ships
to production users. Tests that want the new ZE/1280 defaults call
configureGateway() explicitly in their own beforeAll.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(ai): canonical embedding defaults + sweep across schema/engines/registry

Closes the v0.36 defaults drift bug class. The gateway shipped
zeroentropyai:zembed-1 / 1280 as the system default in v0.36 but eight
other places kept hardcoding 1536 / text-embedding-3-large. Fresh
gbrain init --pglite sized the column to 1536, the embed pipeline used
ZE/1280, and every page failed with dim mismatch.

- New src/core/ai/defaults.ts leaf module is the canonical source for
  DEFAULT_EMBEDDING_MODEL / DEFAULT_EMBEDDING_DIMENSIONS. Schema and
  registry helpers import from this lean module instead of pulling the
  full gateway (which loads every provider SDK).
- src/core/ai/gateway.ts re-exports the constants for back-compat.
- src/core/pglite-schema.ts getPGLiteSchema() defaults track gateway.
- src/core/postgres-engine.ts getPostgresSchema() default args track
  gateway (same drift on the Postgres path — codex round 1 CDX-1).
- Both engine.initSchema() fallbacks track gateway constants (no more
  stale OpenAI/1536 catch-block defaults).
- Schema seed stops stripping the provider prefix; full provider:model
  is stored in the DB config table (codex round 1 CDX-4).
- Chunk-row INSERT defaults track gateway (codex round 2 CDX2-4 —
  pglite-engine:1611 + postgres-engine:1647 were production write
  sites previously hardcoded to text-embedding-3-large).
- src/core/search/embedding-column.ts loadRegistry + isCacheSafe gain
  the cfg > gateway > DEFAULT resolution chain (codex round 2 CDX2-3).
  The gateway tier matters because callers that configure the gateway
  (init paths, tests, programmatic SDK) expect the registry to mirror
  that state when cfg doesn't have an explicit embedding_model.

Tests:
- schema-templating: default expectation flips to ZE/1280 (v0.37 truth).
- embedding-dim-check: 3 new engine-kind branching cases + updated
  fresh-brain expectation (under legacy preload).
- embedding-column: registry + isCacheSafe expectations match new chain.
- v0_28_5-fix-wave E2E: engineKind required arg propagated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(init+config+cli): always-configure gateway, file-only loader, honest config-set, sync/reinit help

Closes the "fresh init doesn't work + config-set silently lies" bug
class end-to-end. Six related changes that ship together because the
file-plane/DB-plane contract only holds when init paths, config-set,
the gateway env mapping, and the recipe text all agree.

Lane B (init paths):
- initPGLite, initPostgres, initMigrateOnly always configureGateway()
  before engine.initSchema(). Pre-fix the call was gated on flags, so
  bare `gbrain init --pglite` left the gateway unconfigured and the
  engine fell through to stale OpenAI/1536 defaults instead of the
  ZE/1280 the gateway would have resolved.
- New configureGatewayWithMergedPrecedence() helper applies the locked
  precedence chain `CLI > env > existing file > gateway internal`.
- printResolvedAIChoice() shows the resolved model/dim at init time +
  surfaces a ZE setup hint inline when the API key is missing.
- B.4: saveConfig merge uses loadConfigFileOnly() so transient env
  state (DATABASE_URL, etc.) never poisons ~/.gbrain/config.json
  (codex round 2 CDX-5).
- B.5: extend the v0.28.5 dim-mismatch detector so it fires when the
  gateway-resolved dim differs from the existing column, not only
  when --embedding-dimensions is explicit (codex round 2 CDX-6).

Lane C (config plane):
- New `loadConfigFileOnly()` reads ~/.gbrain/config.json only — no env
  merge, no DATABASE_URL inference. Safe write-back source for init.
- GBrainConfig gains `zeroentropy_api_key?: string`. loadConfig merges
  process.env.ZEROENTROPY_API_KEY. buildGatewayConfig at cli.ts:1401
  maps it into env.ZEROENTROPY_API_KEY so ZE recipes finally see it
  (codex round 2 CDX2-5+6 — the v1 fix landed in the wrong file).
- `gbrain config set embedding_model` and `... embedding_dimensions`
  refuse unconditionally and print a paste-ready wipe-and-reinit
  recipe. No --force escape (codex round 2 CDX2-13).
- migrate-engine.ts adds a contract comment at the DB-plane write
  site documenting "DB stores schema-applied metadata; file plane is
  canonical for runtime gateway config" + preserves the existing
  file-plane config across engine migration.

Lane D.1 (recipe text):
- embeddingMismatchMessage() takes an `engineKind` arg. PGLite branch
  emits a wipe-and-reinit recipe using gbrainPath('brain.pglite') or
  the caller's databasePath override. Postgres branch keeps the SQL
  ALTER recipe.
- The PGLite recipe recommends `gbrain reinit-pglite` (new sugar
  command below) as the one-line path before falling back to the
  by-hand mv + init + sync sequence.

Lane D.4 (sync help dispatch):
- `sync` and `reinit-pglite` added to CLI_ONLY_SELF_HELP so their own
  --help branches reach the user (pre-fix the generic short-circuit
  fired first and the dedicated usage was unreachable; codex round 2
  CDX2-12).
- `gbrain sync --help` short-circuits BEFORE engine bind so users on
  a fresh tmpdir (no config) can read the help without hitting
  no-such-config errors.

Sugar:
- New `gbrain reinit-pglite --embedding-model X --embedding-dimensions N`
  wraps the wipe + init + sync dance into one command. Backs up the
  brain to <path>.bak. TTY confirmation unless --yes. --no-sync to
  defer the resync. --json for scripts.

Tests:
- test/cli.test.ts sync-help test rewritten for the new
  per-command-usage output (lists --no-embed which is the v0.37
  user-visible flag the wave wanted to surface).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(embed+sync): pre-flight dim-mismatch guard + sync hint at both catch sites

embedding-pipeline error UX. Pre-fix, a fresh-install dim mismatch
produced raw Postgres "expected N dimensions, not M" errors page after
page, surfacing only after the worker pool drained the entire corpus.
Sync swallowed embed errors at TWO catch sites and never surfaced
the recovery recipe.

embed.ts:
- New `EmbeddingDimMismatchError` tagged class with the paste-ready
  recipe baked in.
- `runEmbedCore` pre-flights via `readContentChunksEmbeddingDim` +
  gateway.getEmbeddingDimensions() before the worker pool spins up.
  On mismatch, throws the typed error which the CLI wrapper catches
  and prints. Dry-run skips the check (no embed risk).
- Catches the headline fresh-install bug class at first call instead
  of letting it hammer N parallel API calls into dim-rejected inserts.

sync.ts:
- Both embed catches at sync.ts:990 (incremental) and sync.ts:1129
  (first-sync) detect EmbeddingDimMismatchError and surface the recipe
  + a `--no-embed` tip on stderr (codex round 2 CDX2-8: incremental
  path was previously silent; only the first-sync path was flagged).
- Non-mismatch embed failures still stay best-effort (rate limits,
  transient network) — those shouldn't break sync.
- Sync calls runEmbedCore directly instead of runEmbed (which calls
  process.exit on error and bypasses sync's catch).
- Sync gets a proper --help block listing every meaningful flag:
  --no-embed, --workers, --source, --skip-failed, --retry-failed,
  --watch, --interval, --no-pull, --all, --json, --yes, --dry-run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(doctor): read gateway for schema-sizing checks + provider-aware key lookup

Doctor's embedding checks were reading the DB config table for
embedding_model / embedding_dimensions / zeroentropy_api_key. Post
v0.37 the file plane is canonical (the DB plane is schema-applied
metadata, not runtime gateway config) so those reads produced stale
verdicts on fresh installs whose DB row hadn't been written.

- checkEmbeddingWidthConsistency reads gateway.getEmbeddingDimensions()
  and gateway.getEmbeddingModel() instead of engine.getConfig(...).
  Reuses readContentChunksEmbeddingDim from the same shared helper
  init + embed use. On mismatch, the fix hint threads engineKind +
  databasePath into the new branched recipe (codex round 1 CDX-8 +
  Lane E.1/E.2).
- checkZeEmbeddingHealth reads gateway for the model + loadConfigFileOnly
  for the key. Fires when (a) resolved model starts with zeroentropyai:
  AND (b) ZEROENTROPY_API_KEY is unset in env AND (c) file plane has
  no zeroentropy_api_key (codex round 2 CDX2-10).
- loadRecommendationContext reads gateway for both fields and
  recognizes the ZE key alongside OpenAI/Anthropic in the
  hasEmbeddingApiKey check, so brains on ZE no longer look "healthy"
  just because OPENAI_API_KEY happens to be set (codex round 2 CDX2-11).

Tests rewritten for the gateway-source-of-truth contract via
configureGateway() in beforeAll. Added a "gateway unconfigured: skips
with ok" case so doctor doesn't false-warn on cold-boot brains.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test+docs(v0.37): fix-wave unit coverage + PGLite-first migration recipe + TODOS

Lands the v0.37 PGLite fresh-install fix wave's structural tests and
the user-facing migration recipe overhaul.

test/v0_37_fix_wave.test.ts (new): 22 unit cases pinning the lanes:
- Lane A: defaults module exports, getPGLiteSchema/getPostgresSchema
  default-args, registry + isCacheSafe under the `cfg > gateway >
  DEFAULT` chain (both gateway-set and gateway-reset branches).
- Lane B: loadConfigFileOnly env isolation + DATABASE_URL inference
  refusal + null-on-missing.
- Lane C.3: buildGatewayConfig maps zeroentropy_api_key + process.env
  wins over config (operator escape hatch contract).
- Lane D.2: EmbeddingDimMismatchError shape + tag.
- Lane D.4: structural assertion that `sync` is in CLI_ONLY_SELF_HELP.
- Deferred-TODO ship: reinit-pglite is registered correctly +
  embeddingMismatchMessage PGLite branch recommends it.

docs/embedding-migrations.md: PGLite section moved to top (the default
install). The recommended path is `gbrain reinit-pglite` one-liner;
the by-hand mv + init + sync sequence stays as the fallback recipe.
Postgres SQL ALTER recipe preserved. New section on `gbrain config
set` refusal explains the file-plane vs DB-plane contract so users
don't follow stale documentation.

TODOS.md: 4 deferred follow-ups filed with concrete file pointers:
- gbrain embed --try-fallback (provider auto-switch with consent gate)
- Full plane unification for non-schema-sizing fields
- Worker-pool shared AbortController for mid-run dim drift
- Cleanup of back-compat constants in src/core/embedding.ts

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(v0.37): fill behavior gaps + headline fresh-install E2E

The structural fix-wave tests in test/v0_37_fix_wave.test.ts pin lane-level
invariants (exports, registry chain, signature shapes). The audit found 10+
END-TO-END behaviors that the structural tests didn't actually reach.
This file fills the highest-leverage gaps.

Unit coverage (test/v0_37_gap_fill.test.ts, 12 cases):
- Lane A.7: chunk-row INSERT default tracks DEFAULT_EMBEDDING_MODEL
  constant (pre-fix this was the literal 'text-embedding-3-large' at
  pglite-engine.ts:1611 + postgres-engine.ts:1647 — production write
  sites that were never directly tested; codex round 2 CDX2-4).
- Lane A.8: schema seed stores full provider:model in DB config
  (pre-fix the .split(':') strip dropped the prefix; codex round 1
  CDX-4). Asserts a fresh ZE init stores `zeroentropyai:zembed-1`
  in the config table, not bare `zembed-1`.
- Lane B precedence: explicit CLI > env > existing file > default
  test (codex round 2 CDX2-7 contradiction guard).
- Lane C.3 env merge: process.env.ZEROENTROPY_API_KEY threads through
  loadConfig → cfg.zeroentropy_api_key; loadConfigFileOnly does NOT.
- Lane D.2 end-to-end: schema=1536 + gateway=1280 →
  EmbeddingDimMismatchError fires AND the embed transport is never
  called (the whole point of pre-flight). Plus dry-run skips the
  check.
- Lane D.3 source-text grep: both sync.ts catch sites detect the
  typed error + the `--no-embed` tip is present (CDX2-8).
- Lane E.4 source-text grep: loadRecommendationContext is
  provider-aware (reads gateway + branches on ZE/OpenAI key).
- reinit-pglite contract: refuses on non-PGLite engines + refuses
  when required flags are missing.

E2E (test/e2e/fresh-install-pglite.test.ts, 2 cases):
- Bare `gbrain init --pglite` produces a `vector(1280)` schema, prints
  the resolved choice, persists defaults to config.json — the headline
  scenario that v0.37 ships to fix.
- init → seed page → embed end-to-end: chunks have non-null
  embeddings; no dim mismatch despite the wave's defaults change.

Both E2E cases are IN-PROCESS (per CDX2-12: CLI-subprocess E2E can't
inherit `__setEmbedTransportForTests`). They run with stubbed transport
returning synthetic 1280-dim vectors so we never hit real provider APIs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(v0.37): defensive gateway restore in reinit-pglite describe block

Adds an afterAll that restores the gateway to OpenAI/1536 (matching the
bunfig preload) at the end of the reinit-pglite describe. Belt-and-
suspenders: earlier describe blocks in this file already restore, but
if the reinit-pglite tests ever start mutating the gateway in the
future, this protects downstream test files in the same bun-test shard
from inheriting a non-default state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: bump version and changelog (v0.37.10.0)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* docs: scrub stale config-set recipes for embedding model (v0.37.10.0)

README + topologies + embedding-providers were still pointing users at
`gbrain config set embedding_model X` / `embedding_dimensions N`. As of
v0.37.10.0 those writes are refused — the schema column has to resize
alongside the config. Point at `gbrain reinit-pglite` (PGLite) and the
SQL recipe in `docs/embedding-migrations.md` (Postgres) instead.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* chore: bump version to v0.37.11.0

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test: quarantine v0.37 fix-wave tests to .serial.test.ts

CI's `check:test-isolation` lint flagged R1 violations (direct
`process.env.GBRAIN_HOME` mutation) in both new fix-wave test files.
Per the documented quarantine pattern in CLAUDE.md, rename to
`*.serial.test.ts` instead of refactoring through `withEnv()` — both
files use beforeEach/afterEach env wiring that's already serial-safe.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 22:11:00 -07:00

15 KiB
Raw Blame History

Embedding providers

GBrain ships with 16 embedding-provider recipes covering OpenAI, ZeroEntropy, Voyage, OpenRouter (single key, many hosted models), the major hosted alternatives, three local options, and a universal escape hatch (LiteLLM proxy). Run gbrain providers list to see the live registry; gbrain providers explain --json emits a machine-readable matrix for agents.

This page is the human-readable counterpart: capability per provider, env-var setup, dimensions, cost, and known constraints.

Quick start

gbrain providers list                          # see all providers
gbrain providers env <provider-id>             # see required env vars
gbrain providers test --model openai:text-embedding-3-large   # smoke-test
gbrain init --pglite --model voyage            # use a non-default provider

Init resolves your provider from env keys

As of v0.37, gbrain init --pglite auto-detects which provider to use from your env vars. With OPENAI_API_KEY set, you get OpenAI. With ZEROENTROPY_API_KEY set, you get ZeroEntropy. If multiple provider keys are set, init fires an interactive picker. If no provider keys are set in a non-TTY context (CI, Docker build), init exits 1 with a paste-ready setup hint. Explicit flags (--embedding-model, --no-embedding) always win over env detection.

The resolved provider + dimensions get persisted to ~/.gbrain/config.json atomically, so subsequent runs are deterministic across releases.

TL;DR table

Provider env vars default dims cost ($/1M tokens) local? multimodal?
zeroentropyai ZEROENTROPY_API_KEY 2560 (Matryoshka to 1280/640/320/...) 0.05 no no
openai OPENAI_API_KEY 1536 0.13 no no
openrouter OPENROUTER_API_KEY 1536 0.02 no model-dependent
voyage VOYAGE_API_KEY 1024 0.18 no yes (voyage-multimodal-3)
google GOOGLE_GENERATIVE_AI_API_KEY 768 0.025 no no
azure-openai AZURE_OPENAI_API_KEY, AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_DEPLOYMENT 1536 0.13 no no
minimax MINIMAX_API_KEY 1536 0.07 no no
dashscope DASHSCOPE_API_KEY 1024 varies no no
zhipu ZHIPUAI_API_KEY 1024 varies no no
ollama (none — runs locally) 768 0 yes no
llama-server (none — runs locally) user-set 0 yes no
litellm LITELLM_API_KEY (optional) user-set varies yes (proxy) no
together TOGETHER_API_KEY 768 varies no no
anthropic (no embedding model — chat only)
deepseek (no embedding model — chat only)
groq (no embedding model — chat only)

Note on local providers. Ollama and llama-server have no required API key, so they don't show up in env-detection auto-pick. Pick them explicitly with --embedding-model ollama:<model> to avoid silently routing to a daemon that may not be running.

If first import fails

If gbrain import fails with expected N dimensions, not M, run gbrain doctor. The output will print the exact gbrain config set ... or gbrain retrieval-upgrade command to repair the mismatch. You should not need to delete ~/.gbrain. The bug-class that historically forced rm -rf recoveries is closed as of v0.37.

The doctor distinguishes two repair paths:

  • Empty brain (no embedded chunks yet) — drop and re-init at the right dim:

    gbrain init --force --pglite --embedding-model <provider>:<model> --embedding-dimensions <N>
    
  • Non-empty brain — migrate cleanly with the supported reindex path:

    gbrain retrieval-upgrade --to <provider>:<model> --reindex
    

Decision tree

  • Cost-sensitive, English-only: Ollama (free, local) or Voyage (paid, best quality per dollar).
  • Quality-first: Voyage voyage-4-large (1024-2048 dims, ~3-4× more dense tokens than OpenAI tiktoken).
  • Code-heavy brain (gstack per-worktree, source repos): Voyage voyage-code-3 (1024 default; supports 256/512/1024/2048). Tuned on programming languages. Voyage publishes head-to-head numbers showing it outperforms their general flagships on code retrieval (voyageai.com/blog). For gstack's per-worktree pglite-backed code brain, this is the right default — see Topology 3 in docs/architecture/topologies.md.
  • Reranking pair: Voyage (their reranker rerank-2.5 pairs cleanly with Voyage embeddings).
  • One key for many hosted models: OpenRouter. Set OPENROUTER_API_KEY and use openrouter:<provider>/<model> for chat against GPT-5.2, Claude 4.x, Gemini 3, DeepSeek, and dozens more without juggling per-provider keys. Embedding catalog includes OpenAI, Google, Qwen, BGE-M3.
  • Enterprise compliance: Azure OpenAI (data residency + private endpoints) or self-hosted via llama-server / Ollama.
  • China region: DashScope (Alibaba) or Zhipu (BigModel). DashScope's international endpoint at dashscope-intl.aliyuncs.com; override provider_base_urls.dashscope for the China endpoint.
  • OSS local, full control: llama-server (llama.cpp) for any GGUF model; Ollama for the curated catalog.
  • Anything else: LiteLLM proxy. Run LiteLLM in front of any provider (Bedrock, Vertex, Cohere, Jina, Fireworks, etc.) and point gbrain at it via LITELLM_BASE_URL.

Per-provider details

OpenAI

Default. Set OPENAI_API_KEY. Models: text-embedding-3-large (3072 max, 1536 default), text-embedding-3-small (1536). Matryoshka via the dimensions field — gbrain pins it from embedding_dimensions config so existing 1536-dim brains stay aligned across SDK upgrades.

Voyage AI

Best-in-class quality on the Voyage 4 family (Jan 2026 release). Set VOYAGE_API_KEY. Models: voyage-4-large, voyage-4, voyage-4-lite, voyage-4-nano, voyage-3.5, voyage-code-3 (code-tuned), voyage-finance-2, voyage-law-2, voyage-multimodal-3 (text + image).

Voyage 4 family shares an embedding space across all variants, so you can index with voyage-4-large and query with voyage-4-lite without reindexing. Dims: 256, 512, 1024, 2048. 2048 exceeds pgvector's HNSW cap of 2000 — those brains fall back to exact vector scans (still correct, just slower).

For brains that index source code (gstack's per-worktree pglite-backed code brain — see Topology 3 in docs/architecture/topologies.md), prefer voyage-code-3 over voyage-4-large. Voyage tunes it on programming languages and publishes head-to-head numbers vs their general flagships on code retrieval. Configure at install time:

gbrain init --pglite --embedding-model voyage:voyage-code-3 --embedding-dimensions 1024

To switch an existing brain, use gbrain reinit-pglite --embedding-model voyage:voyage-code-3 --embedding-dimensions 1024 (PGLite) or follow docs/embedding-migrations.md (Postgres). gbrain config set embedding_model is refused — the schema column has to resize.

gbrain reindex --code will print a recommendation when run against a brain whose configured embedding model isn't code-tuned; suppress with GBRAIN_NO_CODE_MODEL_NUDGE=1 if you've intentionally chosen another model (single-vendor procurement, compliance, etc.).

Google Gemini

Set GOOGLE_GENERATIVE_AI_API_KEY (the AI Studio public API key). Model: gemini-embedding-001. Default 768 dims; Matryoshka up to 3072. Cheap.

For GCP service-account / Vertex AI auth (production deployments), see the v0.32.x follow-up — Vertex ADC is on the roadmap.

OpenRouter

Single OpenAI-compatible API for fan-out to OpenAI, Anthropic, Google, DeepSeek, Meta Llama, Qwen, and dozens of other hosted providers. One key, many models. Set OPENROUTER_API_KEY and use openrouter:<provider>/<model> (e.g. openrouter:openai/gpt-5.2, openrouter:anthropic/claude-sonnet-4.6).

Embedding: openai/text-embedding-3-small (1536d default, Matryoshka shrink to 512/768/1024). OR's embedding catalog also includes text-embedding-3-large, google/gemini-embedding-2-preview, qwen/qwen3-embedding-8b, bge-m3 — opt in via --embedding-model openrouter:<id>. Pricing matches the upstream provider (OR adds a small markup).

Chat: every chat model OR proxies works through /v1/chat/completions. The recipe lists 8 curated entry points (GPT-5.2 family, Claude 4.5/4.6/4.7, Gemini 3 Flash Preview, DeepSeek); any other OR catalog ID also works. Tool-calling envelope is supported by the OR endpoint, but per-model capability varies — check https://openrouter.ai/models before counting on tools for a specific slug.

Optional env:

  • OPENROUTER_BASE_URL — point at a self-hosted OR-compatible proxy.
  • OPENROUTER_REFERER (default https://gbrain.ai) and OPENROUTER_TITLE (default gbrain) — attribution headers for OR's leaderboard. Forks running gbrain inside a different agent stack (OpenClaw deployments etc.) should set these so their traffic gets attributed to them, not gbrain.

Subagent loops: gbrain's subagent infrastructure hard-pins to Anthropic-direct (stable tool_use_id across crashes/replays). OR-routed Anthropic is rejected at submit time regardless of the recipe flag. If you want the price/availability story OR offers for tool-calling, use it for chat only and keep an Anthropic key for subagent work.

Azure OpenAI

Enterprise OpenAI behind Azure tenancy. Required env: AZURE_OPENAI_API_KEY, AZURE_OPENAI_ENDPOINT (e.g. https://my-resource.openai.azure.com), AZURE_OPENAI_DEPLOYMENT (the deployment name from your Azure portal). Optional: AZURE_OPENAI_API_VERSION (defaults to 2024-10-21).

Unlike vanilla OpenAI, Azure uses api-key: header (not Authorization: Bearer) and a templated URL with ?api-version= query param — gbrain handles both via the recipe's resolveAuth + resolveOpenAICompatConfig overrides.

Models: text-embedding-3-large, text-embedding-3-small, text-embedding-ada-002 (your Azure deployment must serve the requested model).

MiniMax (海螺AI)

Set MINIMAX_API_KEY. Optional MINIMAX_GROUP_ID for org-scoped accounts. Model: embo-01 (1536 dims).

MiniMax's API takes a type: 'db' | 'query' field for asymmetric retrieval. v0.32 routes everything as type='db' (symmetric retrieval — same vector space for indexing and queries). Asymmetric query support is a v0.32.x follow-up.

DashScope (Alibaba)

Set DASHSCOPE_API_KEY. International endpoint at dashscope-intl.aliyuncs.com by default; override provider_base_urls.dashscope for the China endpoint. Models: text-embedding-v3 (current; Matryoshka 64-1024 dims), text-embedding-v2.

CJK-dominant content tokenizes denser than OpenAI tiktoken; gbrain declares chars_per_token: 2 so the batch pre-split leaves headroom.

Zhipu AI (BigModel)

Set ZHIPUAI_API_KEY. Models: embedding-3 (current; Matryoshka 256-2048 dims), embedding-2. v0.32 default is 1024 (HNSW-compatible). The 2048-dim option works but falls into the exact-scan branch (see Voyage 4 Large note above).

Ollama (local)

No env required — Ollama runs unauthenticated locally. Optional OLLAMA_BASE_URL (default http://localhost:11434/v1) and OLLAMA_API_KEY (for auth-enabled deployments).

Recipe ships with nomic-embed-text (768d, recommended), mxbai-embed-large (1024d), all-minilm (384d). gbrain providers test --model ollama:nomic-embed-text smoke-tests the local install.

llama-server (local, llama.cpp)

llama.cpp's llama-server --embeddings endpoint. No env required. Optional LLAMA_SERVER_BASE_URL (default http://localhost:8080/v1) and LLAMA_SERVER_API_KEY.

User-driven models: launch llama-server with --model <gguf-path> --embeddings, then run gbrain init --embedding-model llama-server:<your-id> --embedding-dimensions <N>. The recipe refuses the implicit shorthand --model llama-server because there's no canonical first model.

LiteLLM proxy (universal escape hatch)

Run LiteLLM in front of any provider — Bedrock, Vertex, Cohere, Jina, Fireworks, OctoAI, etc. The proxy normalizes everything to the OpenAI-compatible API; gbrain points at the proxy via LITELLM_BASE_URL and proxies the call.

This is the catch-all for "my provider isn't in the list above." Set up LiteLLM, then gbrain init --embedding-model litellm:<your-model-id> --embedding-dimensions <N>.

Choosing dimensions

Three numbers matter:

  1. Provider's native dims: each model has a "true" output dim (e.g. OpenAI text-embedding-3-large is 3072 native).
  2. Matryoshka reductions: most modern providers let you request a smaller vector via the dimensions field.
  3. HNSW cap: pgvector's HNSW index supports up to 2000 dims. Brains above that fall back to exact vector scans (slower but correct; gbrain handles the SQL automatically via chunkEmbeddingIndexSql in src/core/vector-index.ts).

For most users: stay at 1024 or 1536. Bigger isn't better below the noise floor; smaller saves disk + RAM with marginal recall loss on Matryoshka providers.

My provider isn't listed

Four options:

  1. Use OpenRouter when the provider/model is available through OR's OpenAI-compatible API (covers most hosted chat models + a growing embedding catalog).
  2. Use LiteLLM proxy (above) — the universal escape hatch. Works for 100+ providers.
  3. Open a feature request at github.com/garrytan/gbrain/issues with the provider's API docs URL and a setup snippet. Recipes are ~30-40 lines of TypeScript.
  4. Submit a recipe: clone, copy src/core/ai/recipes/voyage.ts as the gold-standard openai-compat template, register in src/core/ai/recipes/index.ts, add a per-recipe smoke test under test/ai/recipe-<name>.test.ts. The recipe contract test (test/ai/recipes-contract.test.ts) and IRON RULE regression test pin the structural invariants.

Switching providers on an existing brain

Embedding dimensions are baked into the schema at gbrain init time. As of v0.37.11.0, gbrain config set embedding_model and gbrain config set embedding_dimensions are refused — the schema column has to resize alongside the config, and config set only touches the config row.

The supported paths:

  • PGLite (default install): gbrain reinit-pglite --embedding-model <provider>:<model> --embedding-dimensions <N> — one-command wipe-and-reinit that preserves every other config field (chat model, expansion model, API keys), backs up the prior brain to <path>.bak, runs gbrain init with the new flags, and re-syncs your brain repo. Add --no-sync to skip the resync, --yes to skip the TTY confirmation, --json for scripts.
  • Postgres (Supabase / self-hosted): follow the SQL recipe in docs/embedding-migrations.md (drop the HNSW index, ALTER COLUMN TYPE, clear stale embeddings, recreate the index conditionally, then gbrain init --supabase --embedding-model X --embedding-dimensions N to update the file plane and re-embed).

gbrain doctor 8c "alternative_providers" surfaces unconfigured providers whose env is already set — useful when you've configured OpenAI but also have e.g. VOYAGE_API_KEY exported and want to know you can switch without extra setup.

gbrain doctor 8c "alternative_providers" surfaces unconfigured providers whose env is already set — useful when you've configured OpenAI but also have e.g. VOYAGE_API_KEY exported and want to know you can switch without extra setup.