From 8ecd52022e9dc86036439f024bfaa199953a16f4 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Wed, 12 Aug 2026 11:18:32 -0700 Subject: [PATCH] fix(ai): match hyphenated Qwen3-Embedding ids for dimensions passthrough (#3909) Wave-assembled from PR #3909 by @mikez93. Co-Authored-By: Mike Williamson --- src/core/ai/dims.ts | 14 ++++++++++---- test/ai/dims-qwen3-native.test.ts | 25 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/core/ai/dims.ts b/src/core/ai/dims.ts index 1dcb8b687..b71529d19 100644 --- a/src/core/ai/dims.ts +++ b/src/core/ai/dims.ts @@ -309,9 +309,12 @@ export function dimsProviderOptions( // 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:')) { + // widths hard-fail with a dim-mismatch error. Two naming schemes reach + // this path: Ollama's colon-tag form (`qwen3-embedding:4b`) and the + // hyphenated hub form used by OpenRouter/HF-style routers + // (`qwen/qwen3-embedding-8b` — org prefix stripped to + // `qwen3-embedding-8b` above). Match both. + if (bareModelId === 'qwen3-embedding' || bareModelId.startsWith('qwen3-embedding:') || bareModelId.startsWith('qwen3-embedding-')) { // Only send `dimensions` when it actually differs from the model's // native width. Fixed-dim OpenAI-compatible backends serving this // family (e.g. vLLM) reject the parameter outright with HTTP 400 @@ -323,8 +326,11 @@ export function dimsProviderOptions( 'qwen3-embedding:0.6b': 1024, 'qwen3-embedding:4b': 2560, 'qwen3-embedding:8b': 4096, + 'qwen3-embedding-0.6b': 1024, + 'qwen3-embedding-4b': 2560, + 'qwen3-embedding-8b': 4096, }; - if (QWEN3_EMBEDDING_NATIVE_DIMS[modelId] === dims) return undefined; + if (QWEN3_EMBEDDING_NATIVE_DIMS[bareModelId] === dims) return undefined; return { openaiCompatible: { dimensions: dims } }; } // MiniMax embo-01 takes a `type: 'db' | 'query'` field for asymmetric diff --git a/test/ai/dims-qwen3-native.test.ts b/test/ai/dims-qwen3-native.test.ts index 259dd4a0d..0c7bae488 100644 --- a/test/ai/dims-qwen3-native.test.ts +++ b/test/ai/dims-qwen3-native.test.ts @@ -38,3 +38,28 @@ describe('qwen3-embedding native-width suppression', () => { .toEqual({ openaiCompatible: { dimensions: 1024 } }); }); }); + +describe('qwen3-embedding hyphenated hub-form ids (OpenRouter et al.)', () => { + test('org-prefixed hub id requests Matryoshka truncation at non-native dim', () => { + expect(dimsProviderOptions('openai-compatible', 'qwen/qwen3-embedding-8b', 1536)) + .toEqual({ openaiCompatible: { dimensions: 1536 } }); + expect(dimsProviderOptions('openai-compatible', 'qwen/qwen3-embedding-4b', 1024)) + .toEqual({ openaiCompatible: { dimensions: 1024 } }); + }); + + test('hub id at native width emits no dimensions param', () => { + expect(dimsProviderOptions('openai-compatible', 'qwen/qwen3-embedding-8b', 4096)).toBeUndefined(); + expect(dimsProviderOptions('openai-compatible', 'qwen/qwen3-embedding-4b', 2560)).toBeUndefined(); + expect(dimsProviderOptions('openai-compatible', 'qwen/qwen3-embedding-0.6b', 1024)).toBeUndefined(); + }); + + test('bare hyphenated id (no org prefix) also matches', () => { + expect(dimsProviderOptions('openai-compatible', 'qwen3-embedding-8b', 2000)) + .toEqual({ openaiCompatible: { dimensions: 2000 } }); + }); + + test('unknown hyphenated variant falls through to sending the configured dim', () => { + expect(dimsProviderOptions('openai-compatible', 'qwen3-embedding-32b', 1024)) + .toEqual({ openaiCompatible: { dimensions: 1024 } }); + }); +});