mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-14 10:52:17 +03:00
On dashboard/memory?tab=engine the Embedding Model quick-select (and the rerank selector) built their lists from a keyword heuristic over the CHAT catalog (AI_MODELS) plus OpenRouter live discovery. Providers whose embedding models are not in that catalog never appeared — mistral, gemini, nvidia nim, groq, vercel-ai-gateway and others that serve embeddings on a standard OpenAI-compatible /embeddings endpoint — and typing such a model by hand failed at runtime with "Unknown embedding provider". The fix is one generic mechanism rather than a list of per-provider patches: deriveEmbeddingProviderForChatProvider() turns any chat-registry entry with a /chat/completions base into an OpenAI-compatible /embeddings config, with curated EMBEDDING_PROVIDERS entries always winning; the embeddings service resolves a derived config for unknown-but-configured providers instead of rejecting them; deriveRerankProviderForChatProvider() does the same for Cohere-compatible /rerank; and both memory selectors fall back to a free-text provider/model input when no static catalog exists. No provider is special-cased by name, so adding one to the chat registry now makes it embedding- and rerank-capable here automatically. Verified on the current release tip: merged clean, typecheck:core clean, check:cycles OK across 417 files, and 35/35 across the PR's five new suites (qdrant-quick-select-catalog, memory-provider-listings, rerank-provider-listings, embedding-generic-provider-fallback, rerank-generic-provider-fallback) plus the updated hard-session-lease-bypass-inventory and embeddings-handler. Note: the base-red disclaimer in the description referenced #9985 against release/v3.8.50 — that window is closed and the current tip carries no open base-red, so nothing was inherited here. Thanks @rqzbeh — deriving the capability instead of enumerating providers is the version of this that stays correct as the registry grows.
84 lines
3.2 KiB
TypeScript
84 lines
3.2 KiB
TypeScript
/**
|
|
* Issue: dashboard/memory?tab=engine "Quick select" only listed models found by a
|
|
* text heuristic over the CHAT catalog (AI_MODELS) plus live OpenRouter discovery.
|
|
* Curated embedding-registry providers (EMBEDDING_PROVIDERS) never appeared — e.g.
|
|
* configured providers with embedding models (mistral, gemini, nvidia nim,
|
|
* groq, ...) was missing even though the provider
|
|
* serves embeddings via a standard OpenAI-compatible /embeddings endpoint.
|
|
*
|
|
* These tests pin the pure catalog helper the route now uses: registry models must
|
|
* be merged into the option list with provider-prefixed values, deduped against
|
|
* heuristic/live options.
|
|
*/
|
|
import { describe, it } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { EMBEDDING_PROVIDERS } from "@omniroute/open-sse/config/embeddingRegistry.ts";
|
|
import {
|
|
buildRegistryEmbeddingOptions,
|
|
mergeEmbeddingOptions,
|
|
} from "../../src/app/api/settings/qdrant/embedding-models/catalog";
|
|
|
|
describe("qdrant quick-select: registry catalog helpers", () => {
|
|
it("emits one option per registered embedding model, provider-prefixed", () => {
|
|
const options = buildRegistryEmbeddingOptions();
|
|
assert.ok(options.length > 0, "registry should contribute options");
|
|
|
|
const byValue = new Map(options.map((o) => [o.value, o.label]));
|
|
for (const [providerId, cfg] of Object.entries(EMBEDDING_PROVIDERS)) {
|
|
for (const m of cfg.models) {
|
|
const value = `${providerId}/${m.id}`;
|
|
assert.ok(byValue.has(value), `missing quick-select option for ${value}`);
|
|
}
|
|
}
|
|
});
|
|
|
|
it("skips providers without static curated models (dynamic-only)", () => {
|
|
const options = buildRegistryEmbeddingOptions();
|
|
assert.equal(
|
|
options.filter((o) => o.value.startsWith("lmstudio/")).length,
|
|
0,
|
|
"lmstudio has no curated models; nothing to list"
|
|
);
|
|
});
|
|
|
|
it("labels include dimensions when known", () => {
|
|
const options = buildRegistryEmbeddingOptions();
|
|
const hit = options.find((o) => o.value === "deepinfra/BAAI/bge-m3");
|
|
assert.ok(hit, "deepinfra BAAI/bge-m3 expected in registry");
|
|
assert.match(hit.label, /\b1024d\b/);
|
|
});
|
|
});
|
|
|
|
describe("qdrant quick-select: merge with existing options", () => {
|
|
it("dedupes by value and keeps first-seen label (heuristic wins ties)", () => {
|
|
const merged = mergeEmbeddingOptions(
|
|
[{ value: "openai/text-embedding-3-small", label: "heuristic-label" }],
|
|
[{ value: "openai/text-embedding-3-small", label: "registry-label" }]
|
|
);
|
|
assert.equal(merged.length, 1);
|
|
assert.equal(merged[0].label, "heuristic-label");
|
|
});
|
|
|
|
it("appends unseen registry options", () => {
|
|
const merged = mergeEmbeddingOptions(
|
|
[{ value: "a/x", label: "A" }],
|
|
[{ value: "b/y", label: "B" }, { value: "b/z", label: "C" }]
|
|
);
|
|
assert.deepEqual(
|
|
merged.map((o) => o.value),
|
|
["a/x", "b/y", "b/z"]
|
|
);
|
|
});
|
|
|
|
it("output is sorted by value for stable UI ordering", () => {
|
|
const merged = mergeEmbeddingOptions(
|
|
[{ value: "z/1", label: "Z" }],
|
|
[{ value: "a/1", label: "A" }, { value: "m/1", label: "M" }]
|
|
);
|
|
assert.deepEqual(
|
|
merged.map((o) => o.value),
|
|
["a/1", "m/1", "z/1"]
|
|
);
|
|
});
|
|
});
|