mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-28 06:23:01 +00:00
OpenRouter (and potentially other proxy providers) expose OpenAI's
text-embedding-3 models with a provider prefix in the model ID, e.g.
`openai/text-embedding-3-large` rather than bare `text-embedding-3-large`.
`dimsProviderOptions()` checks `modelId.startsWith('text-embedding-3')`
which fails for the prefixed form, so the `dimensions` parameter is never
sent. The upstream provider returns its native dimensionality (3072 for
-large) instead of the configured value (e.g. 1536), causing an immediate
"dim mismatch" error on first embed.
The default OpenRouter embedding (`text-embedding-3-small` at 1536d)
masked this because its native size happens to match the default config.
The bug surfaces when using `-large`, or `-small` with a non-1536 dim
(512, 768, 1024 — all listed in the recipe's `dims_options`).
Fix: strip the provider prefix before the `startsWith` check. The full
prefixed ID is preserved in the error message for user clarity.
Co-authored-by: Noetherly <280958447+noetherly@users.noreply.github.com>
This commit is contained in:
+4
-3
@@ -285,9 +285,10 @@ export function dimsProviderOptions(
|
||||
// configured for a smaller width (e.g. 1536) hard-fail at first embed.
|
||||
// Azure/OpenAI-compat embeddings are symmetric — inputType ignored.
|
||||
// v0.36.0.0 (D13): same range validation as native-openai path.
|
||||
if (modelId.startsWith('text-embedding-3')) {
|
||||
if (isOpenAITextEmbedding3Model(modelId) && !isValidOpenAITextEmbedding3Dim(modelId, dims)) {
|
||||
const max = maxOpenAITextEmbedding3Dim(modelId)!;
|
||||
const bareModelId = modelId.includes('/') ? modelId.split('/').pop()! : modelId;
|
||||
if (bareModelId.startsWith('text-embedding-3')) {
|
||||
if (isOpenAITextEmbedding3Model(bareModelId) && !isValidOpenAITextEmbedding3Dim(bareModelId, dims)) {
|
||||
const max = maxOpenAITextEmbedding3Dim(bareModelId)!;
|
||||
throw new AIConfigError(
|
||||
`OpenAI model "${modelId}" supports embedding_dimensions in 1..${max}, got ${dims}.`,
|
||||
`Set \`embedding_dimensions\` to a value between 1 and ${max} ` +
|
||||
|
||||
@@ -134,3 +134,30 @@ describe('dimsProviderOptions — OpenAI on openai-compatible adapter (Azure cas
|
||||
expect(JSON.stringify(opts)).not.toContain('input_type');
|
||||
});
|
||||
});
|
||||
|
||||
describe('dimsProviderOptions — prefixed model IDs (OpenRouter / proxy providers)', () => {
|
||||
test('openai/text-embedding-3-large at 1536d returns dimensions=1536', () => {
|
||||
const opts = dimsProviderOptions('openai-compatible', 'openai/text-embedding-3-large', 1536);
|
||||
expect(opts).toEqual({ openaiCompatible: { dimensions: 1536 } });
|
||||
});
|
||||
|
||||
test('openai/text-embedding-3-small at 768d returns dimensions=768', () => {
|
||||
const opts = dimsProviderOptions('openai-compatible', 'openai/text-embedding-3-small', 768);
|
||||
expect(opts).toEqual({ openaiCompatible: { dimensions: 768 } });
|
||||
});
|
||||
|
||||
test('openai/text-embedding-3-large at 5000d throws AIConfigError', () => {
|
||||
expect(() => dimsProviderOptions('openai-compatible', 'openai/text-embedding-3-large', 5000))
|
||||
.toThrow(AIConfigError);
|
||||
});
|
||||
|
||||
test('error message preserves full prefixed model ID for clarity', () => {
|
||||
try {
|
||||
dimsProviderOptions('openai-compatible', 'openai/text-embedding-3-large', 5000);
|
||||
throw new Error('should have thrown');
|
||||
} catch (err) {
|
||||
expect(err).toBeInstanceOf(AIConfigError);
|
||||
expect((err as Error).message).toContain('openai/text-embedding-3-large');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user