From 02ba4b4fc2cc4fea9729fe124250faa7056f2f9e Mon Sep 17 00:00:00 2001 From: Michael Gandal Date: Wed, 22 Jul 2026 15:38:30 -0400 Subject: [PATCH] dims: thread Matryoshka dimensions for Qwen3-Embedding on Ollama (#1072) Qwen3-Embedding family on Ollama supports Matryoshka truncation via the 'dimensions' field on /v1/embeddings. Without this passthrough, gbrain ignores user-selected reduced dims and the provider returns its native size, causing dim-mismatch errors against brains configured for narrower widths (e.g. existing 1536-dim brains). Matches by bare name 'qwen3-embedding' or any tag variant 'qwen3-embedding:0.6b' / ':4b' / ':8b'. Native dims: 0.6B=1024, 4B=2560, 8B=4096. All MRL-truncatable. 5 new tests; full AI suite 137/137 green. Co-authored-by: Claude Opus 4.7 (1M context) Co-authored-by: Time Attakc <89218912+time-attack@users.noreply.github.com> --- src/core/ai/dims.ts | 9 +++++++ test/ai/recipe-ollama-dims.test.ts | 41 ++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 test/ai/recipe-ollama-dims.test.ts diff --git a/src/core/ai/dims.ts b/src/core/ai/dims.ts index 7961516a5..b88a4e175 100644 --- a/src/core/ai/dims.ts +++ b/src/core/ai/dims.ts @@ -263,6 +263,15 @@ export function dimsProviderOptions( if (modelId === 'text-embedding-v3' || modelId === 'embedding-3') { return { openaiCompatible: { dimensions: dims } }; } + // Qwen3-Embedding family on Ollama (and any other openai-compatible + // provider serving it) supports Matryoshka truncation via `dimensions`. + // Native sizes: 0.6B=1024, 4B=2560, 8B=4096. Without `dimensions`, + // Ollama returns the native size and brains configured for narrower + // widths hard-fail with a dim-mismatch error. Pattern match the bare + // model name + any `:tag` (e.g. `qwen3-embedding:4b`, `qwen3-embedding:0.6b`). + if (modelId === 'qwen3-embedding' || modelId.startsWith('qwen3-embedding:')) { + return { openaiCompatible: { dimensions: dims } }; + } // MiniMax embo-01 takes a `type: 'db' | 'query'` field for asymmetric // retrieval. Today still hardcoded to 'db' for back-compat — opting // into the new inputType seam is a follow-up (see plan's deferred diff --git a/test/ai/recipe-ollama-dims.test.ts b/test/ai/recipe-ollama-dims.test.ts new file mode 100644 index 000000000..4f1d86ce8 --- /dev/null +++ b/test/ai/recipe-ollama-dims.test.ts @@ -0,0 +1,41 @@ +/** + * Ollama Matryoshka dims passthrough. + * + * Several embedding models served via Ollama (Qwen3-Embedding family) support + * Matryoshka truncation through the `dimensions` field on /v1/embeddings. + * Without this passthrough, gbrain ignores user-selected reduced dims and the + * provider returns its native size, causing dim-mismatch failures against + * brains configured for smaller widths. + */ + +import { describe, expect, test } from 'bun:test'; +import { dimsProviderOptions } from '../../src/core/ai/dims.ts'; + +describe('dims: ollama Matryoshka models', () => { + test('qwen3-embedding:4b threads dimensions=1536', () => { + expect(dimsProviderOptions('openai-compatible', 'qwen3-embedding:4b', 1536)) + .toEqual({ openaiCompatible: { dimensions: 1536 } }); + }); + + test('qwen3-embedding:0.6b threads dimensions=512', () => { + expect(dimsProviderOptions('openai-compatible', 'qwen3-embedding:0.6b', 512)) + .toEqual({ openaiCompatible: { dimensions: 512 } }); + }); + + test('qwen3-embedding:8b threads dimensions=2048', () => { + expect(dimsProviderOptions('openai-compatible', 'qwen3-embedding:8b', 2048)) + .toEqual({ openaiCompatible: { dimensions: 2048 } }); + }); + + test('bare qwen3-embedding (no quant tag) also recognized', () => { + expect(dimsProviderOptions('openai-compatible', 'qwen3-embedding', 1024)) + .toEqual({ openaiCompatible: { dimensions: 1024 } }); + }); + + test('unrelated openai-compat model returns undefined (regression guard)', () => { + expect(dimsProviderOptions('openai-compatible', 'nomic-embed-text', 768)) + .toBeUndefined(); + expect(dimsProviderOptions('openai-compatible', 'mxbai-embed-large', 1024)) + .toBeUndefined(); + }); +});