fix(embeddings): add lmstudio to embedding provider registry (#7614)

* fix(embeddings): add lmstudio to embedding provider registry

LM Studio is already registered as a local provider in the provider
catalog (src/shared/constants/providers/local.ts) but was missing from
EMBEDDING_PROVIDERS in open-sse/config/embeddingRegistry.ts. This
caused /v1/embeddings requests targeting lmstudio models to fail with
'Unknown embedding provider: lmstudio'.

Follows the same pattern as deepinfra (#2298) and openrouter (#960),
but with authType: 'none' since LM Studio is a local server.

Fixes #7601

* test(embeddings): add lmstudio regression test + changelog (#7601)

Adds the regression test and changelog fragment required by the
contribution guidelines (Hard Rule #18) for the new lmstudio entry in
EMBEDDING_PROVIDERS, mirroring the precedent set by the mixedbread
(#6660) and openrouter-embeddings (#6976) provider-registry additions:

- tests/unit/lmstudio-embedding-provider-7601.test.ts: asserts
  getEmbeddingProvider('lmstudio').baseUrl/authType/authHeader and
  parseEmbeddingModel('lmstudio/<model>') passthrough resolution
  (including namespaced model ids). Verified red without the registry
  entry (assert.ok(provider) fails), green with it.
- changelog.d/features/7601-lmstudio-embeddings.md: changelog fragment
  referencing issue #7601 and the new test.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: Erick Kinnee <erickinnee@gmail.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
This commit is contained in:
Erick Kinnee
2026-07-18 19:20:05 -05:00
committed by GitHub
parent d6e86f413b
commit 2ad7da5151
3 changed files with 54 additions and 0 deletions

View File

@@ -0,0 +1 @@
- **feat(providers):** register `lmstudio` in the embedding provider registry (`open-sse/config/embeddingRegistry.ts`) — LM Studio's local OpenAI-compatible `/v1/embeddings` endpoint, no auth required, passthrough model list (a user-configured provider_node still takes priority). Previously any `lmstudio/<model>` embedding request failed with `"Unknown embedding provider: lmstudio"` even though the model appeared fine in `/v1/models` ([#7601](https://github.com/diegosouzapw/OmniRoute/issues/7601) — thanks @ekinnee). Regression guard: `tests/unit/lmstudio-embedding-provider-7601.test.ts`.

View File

@@ -297,6 +297,18 @@ export const EMBEDDING_PROVIDERS: Record<string, EmbeddingProvider> = {
],
},
// LM Studio — local OpenAI-compatible server. No auth required.
// Models are passthrough (LM Studio exposes its own model list), so the
// models array is empty. The baseUrl is the default LM Studio endpoint;
// users with a configured provider_node will use that URL instead.
lmstudio: {
id: "lmstudio",
baseUrl: "http://localhost:1234/v1/embeddings",
authType: "none",
authHeader: "none",
models: [],
},
// Issue #6660: Mixedbread AI — OpenAI-compatible /v1/embeddings, free tier
// available (API key via signup, no card required). Model ids are the
// upstream-qualified "mixedbread-ai/<model>" form, mirroring how `together`/

View File

@@ -0,0 +1,41 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
getEmbeddingProvider,
parseEmbeddingModel,
getEmbeddingDimension,
} from "../../open-sse/config/embeddingRegistry.ts";
// Issue #7601: LM Studio was missing from EMBEDDING_PROVIDERS, so any
// "lmstudio/<model>" embedding request failed with "Unknown embedding
// provider: lmstudio" even though the model is listed fine elsewhere.
test("lmstudio embedding registry exposes the local no-auth endpoint", () => {
const provider = getEmbeddingProvider("lmstudio");
assert.ok(provider);
assert.equal(provider.baseUrl, "http://localhost:1234/v1/embeddings");
assert.equal(provider.authType, "none");
assert.equal(provider.authHeader, "none");
// LM Studio exposes its own model list dynamically, so the static
// registry entry is passthrough (empty models array) by design — a
// user-configured provider_node still takes priority over this entry.
assert.deepEqual(provider.models, []);
});
test("lmstudio model strings resolve via parseEmbeddingModel (passthrough)", () => {
const parsed = parseEmbeddingModel("lmstudio/text-embedding-qwen3-embedding-0.6b");
assert.equal(parsed.provider, "lmstudio");
assert.equal(parsed.model, "text-embedding-qwen3-embedding-0.6b");
// Nested/namespaced model ids must not be mangled by passthrough parsing.
const parsedNested = parseEmbeddingModel("lmstudio/nomic-ai/nomic-embed-text-v1.5");
assert.equal(parsedNested.provider, "lmstudio");
assert.equal(parsedNested.model, "nomic-ai/nomic-embed-text-v1.5");
});
test("lmstudio has no known static dimension (passthrough models aren't enumerated)", () => {
// Callers must treat this as "can't assert", never "zero" — see
// getEmbeddingDimension's own doc comment.
assert.equal(getEmbeddingDimension("lmstudio/text-embedding-qwen3-embedding-0.6b"), undefined);
});