mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-28 14:59:47 +00:00
#2271: a new trust_custom_dims flag adds a passthrough tier so ollama / llama-server / litellm accept a user-supplied --embedding-dimensions instead of being hard-rejected. Fail-closed for fixed-dim providers (openai/voyage/ zeroentropy) and excludes openrouter (declares dims_options). Register modern ollama embed model names. #2209: litellm setup_hint now states the /v1 path convention and the docs pointer is corrected to docs/integrations/embedding-providers.md.
This commit is contained in:
@@ -6,7 +6,7 @@ import type { Recipe } from '../types.ts';
|
||||
* gbrain at it via `LITELLM_BASE_URL`. The proxy normalizes to
|
||||
* OpenAI-compatible API.
|
||||
*
|
||||
* See docs/guides/litellm-proxy.md for the setup recipe.
|
||||
* See docs/integrations/embedding-providers.md for the setup recipe.
|
||||
*/
|
||||
export const litellmProxy: Recipe = {
|
||||
id: 'litellm',
|
||||
@@ -25,6 +25,7 @@ export const litellmProxy: Recipe = {
|
||||
models: [],
|
||||
user_provided_models: true, // v0.32 D8=A wire-through for the litellm hardcode
|
||||
default_dims: 0, // user must declare --embedding-dimensions explicitly
|
||||
trust_custom_dims: true, // #2271: proxy-backed model dim is user-declared
|
||||
cost_per_1m_tokens_usd: undefined,
|
||||
price_last_verified: '2026-04-20',
|
||||
// LiteLLM's batch capacity is determined by the backend it proxies;
|
||||
@@ -41,5 +42,5 @@ export const litellmProxy: Recipe = {
|
||||
supports_multimodal: true,
|
||||
},
|
||||
},
|
||||
setup_hint: 'Run LiteLLM (https://docs.litellm.ai) in front of any provider; set LITELLM_BASE_URL + pass --embedding-model litellm:<model> and --embedding-dimensions <N>.',
|
||||
setup_hint: 'Run LiteLLM (https://docs.litellm.ai) in front of any provider; set LITELLM_BASE_URL (include the /v1 suffix if your proxy serves the OpenAI route there, e.g. http://localhost:4000/v1) + pass --embedding-model litellm:<model> and --embedding-dimensions <N>.',
|
||||
};
|
||||
|
||||
@@ -32,6 +32,7 @@ export const llamaServer: Recipe = {
|
||||
models: [], // user-driven; whatever model the server was launched with
|
||||
user_provided_models: true,
|
||||
default_dims: 0, // forces explicit --embedding-dimensions
|
||||
trust_custom_dims: true, // #2271: user knows the launched model's native dim
|
||||
cost_per_1m_tokens_usd: 0,
|
||||
price_last_verified: '2026-05-10',
|
||||
// llama-server's batch capacity is set by `--ctx-size` at launch
|
||||
|
||||
@@ -13,8 +13,20 @@ export const ollama: Recipe = {
|
||||
},
|
||||
touchpoints: {
|
||||
embedding: {
|
||||
models: ['nomic-embed-text', 'mxbai-embed-large', 'all-minilm'],
|
||||
// #2271: modern local embed models added so assertTouchpoint accepts them.
|
||||
// Each carries its own native dim (qwen3-embed-8b=4096, arctic-l-v2=1024);
|
||||
// the recipe-wide default_dims below is only the nomic fallback, so users
|
||||
// of the larger models pass --embedding-dimensions (allowed via
|
||||
// trust_custom_dims). Per-model dims metadata is a tracked follow-up.
|
||||
models: [
|
||||
'nomic-embed-text',
|
||||
'mxbai-embed-large',
|
||||
'all-minilm',
|
||||
'qwen3-embed-8b',
|
||||
'snowflake-arctic-embed-l-v2',
|
||||
],
|
||||
default_dims: 768, // nomic-embed-text native dim
|
||||
trust_custom_dims: true, // #2271: local models carry varied native dims
|
||||
cost_per_1m_tokens_usd: 0,
|
||||
price_last_verified: '2026-04-20',
|
||||
// Ollama's batch capacity depends on the locally loaded model + the
|
||||
|
||||
@@ -87,6 +87,17 @@ export interface EmbeddingTouchpoint {
|
||||
* for shorthand `--model <provider>` and prints a setup hint.
|
||||
*/
|
||||
user_provided_models?: true;
|
||||
/**
|
||||
* #2271: trust a user-supplied `--embedding-dimensions` for this recipe even
|
||||
* when it's not in the known-Matryoshka allowlist. Set ONLY on local /
|
||||
* bring-your-own-backend recipes where the user knows their model's native dim
|
||||
* and we can't enumerate every model (ollama, llama-server, litellm). The
|
||||
* provider's `/embeddings` response-dim validation catches a genuine mismatch
|
||||
* pre-storage. Must NOT be set on fixed-dim hosted providers (openai/voyage/
|
||||
* zeroentropy stay fail-closed) or on recipes that declare recipe-wide
|
||||
* `dims_options` (e.g. openrouter, whose Tier-1 options legitimately govern).
|
||||
*/
|
||||
trust_custom_dims?: true;
|
||||
/**
|
||||
* v0.32 (#779 reworked): explicit opt-out of the missing-max_batch_tokens
|
||||
* startup warning. Set to `true` for recipes whose batch capacity is
|
||||
|
||||
@@ -451,6 +451,18 @@ function isCustomDimValidForProvider(
|
||||
};
|
||||
}
|
||||
|
||||
// Passthrough tier (#2271): local / bring-your-own-backend recipes (ollama,
|
||||
// llama-server, litellm) flag trust_custom_dims because the user knows their
|
||||
// model's native dim and we can't enumerate every locally-pulled model. Trust
|
||||
// the requested dim; the provider's /embeddings response-dim validation catches
|
||||
// a genuine mismatch pre-storage. Runs AFTER Tier 1 (recipe dims_options) and
|
||||
// Tier 2 (provider Matryoshka allowlists) so a recipe that DOES declare fixed
|
||||
// options (e.g. openrouter) is still governed by those, and fixed-dim hosted
|
||||
// providers (openai/voyage/zeroentropy) never reach here as valid.
|
||||
if (recipe.touchpoints.embedding?.trust_custom_dims === true) {
|
||||
return { valid: true, error: '' };
|
||||
}
|
||||
|
||||
// Tier 3: provider not known to support custom dims at all.
|
||||
return {
|
||||
valid: false,
|
||||
|
||||
@@ -257,6 +257,43 @@ describe('resolveSchemaEmbeddingDim', () => {
|
||||
if (got.ok) expect(got.dim).toBe(768);
|
||||
});
|
||||
|
||||
// #2271 — trust_custom_dims passthrough for local / BYO-backend recipes.
|
||||
test('ollama accepts a custom dim for a modern model via trust_custom_dims', () => {
|
||||
const got = resolveSchemaEmbeddingDim({
|
||||
embedding_model: 'ollama:qwen3-embed-8b',
|
||||
embedding_dimensions: 4096,
|
||||
});
|
||||
expect(got.ok).toBe(true);
|
||||
if (got.ok) expect(got.dim).toBe(4096);
|
||||
});
|
||||
|
||||
test('litellm accepts a user-declared custom dim via trust_custom_dims', () => {
|
||||
const got = resolveSchemaEmbeddingDim({
|
||||
embedding_model: 'litellm:bge-large',
|
||||
embedding_dimensions: 1024,
|
||||
});
|
||||
expect(got.ok).toBe(true);
|
||||
if (got.ok) expect(got.dim).toBe(1024);
|
||||
});
|
||||
|
||||
test('llama-server accepts a user-declared custom dim via trust_custom_dims', () => {
|
||||
const got = resolveSchemaEmbeddingDim({
|
||||
embedding_model: 'llama-server:nomic-embed-text-v1.5',
|
||||
embedding_dimensions: 2560,
|
||||
});
|
||||
expect(got.ok).toBe(true);
|
||||
if (got.ok) expect(got.dim).toBe(2560);
|
||||
});
|
||||
|
||||
test('[REGRESSION] openrouter (declares dims_options, NOT flagged) still fail-closed on an unlisted dim', () => {
|
||||
const got = resolveSchemaEmbeddingDim({
|
||||
embedding_model: 'openrouter:openai/text-embedding-3-small',
|
||||
embedding_dimensions: 4096,
|
||||
});
|
||||
expect(got.ok).toBe(false);
|
||||
if (!got.ok) expect(got.error).toMatch(/rejects custom dimensions 4096|does not support custom dimensions/);
|
||||
});
|
||||
|
||||
test('unknown provider rejected with provider list hint', () => {
|
||||
const got = resolveSchemaEmbeddingDim({ embedding_model: 'notarealprovider:foo' });
|
||||
expect(got.ok).toBe(false);
|
||||
|
||||
Reference in New Issue
Block a user