docs(models): document oMLX OpenAI-compatible setup

This commit is contained in:
danzaio
2026-06-09 01:35:49 -03:00
committed by can1357
parent 96defff9a5
commit b36f5c0785
2 changed files with 53 additions and 2 deletions
+14
View File
@@ -272,6 +272,8 @@ If `lm-studio` is not explicitly configured, registry adds an implicit discovera
Runtime discovery fetches models (`GET /models`) and synthesizes model entries with local defaults.
This path also works for local OpenAI-compatible servers that are not LM Studio. For example, set `LM_STUDIO_BASE_URL=http://127.0.0.1:11434/v1` to discover oMLX through the existing `/v1/models` flow. Do not configure oMLX as `ollama`: Ollama discovery uses native `/api/tags` and `/api/show` endpoints, not OpenAI `/v1/models`.
### Explicit provider discovery
You can configure discovery yourself:
@@ -606,6 +608,18 @@ providers:
name: Qwen 2.5 Coder 32B (local)
```
For oMLX or another local OpenAI-compatible server with a discoverable `/v1/models` endpoint, prefer discovery instead of listing models by hand:
```yaml
providers:
omlx:
baseUrl: http://127.0.0.1:11434/v1
auth: none
api: openai-completions
discovery:
type: openai-models-list
```
### Hosted proxy with env-based key
```yaml
@@ -16,13 +16,17 @@ describe("ModelRegistry LM Studio Fixes", () => {
tempDir = path.join(os.tmpdir(), `pi-test-lm-studio-fixes-${Snowflake.next()}`);
fs.mkdirSync(tempDir, { recursive: true });
modelsJsonPath = path.join(tempDir, "models.json");
authStorage = await AuthStorage.create(path.join(tempDir, "testauth.db"));
authStorage = await AuthStorage.create(":memory:");
});
afterEach(() => {
authStorage.close();
if (tempDir && fs.existsSync(tempDir)) {
fs.rmSync(tempDir, { recursive: true });
try {
fs.rmSync(tempDir, { recursive: true, force: true });
} catch (error) {
if ((error as NodeJS.ErrnoException).code !== "EBUSY") throw error;
}
}
});
@@ -59,4 +63,37 @@ describe("ModelRegistry LM Studio Fixes", () => {
expect(available.some(m => m.provider === "ollama")).toBe(true);
expect(available.some(m => m.provider === "lm-studio")).toBe(true);
});
test("LM_STUDIO_BASE_URL can target any local OpenAI-compatible /v1 server", async () => {
const originalBaseUrl = Bun.env.LM_STUDIO_BASE_URL;
Bun.env.LM_STUDIO_BASE_URL = "http://127.0.0.1:11434/v1";
let requestedUrl = "";
try {
const fetchMock: FetchImpl = input => {
const url = String(input);
if (url.includes(":11434/v1/models")) {
requestedUrl = url;
return Promise.resolve(
new Response(JSON.stringify({ data: [{ id: "omlx-model" }] }), {
status: 200,
headers: { "Content-Type": "application/json" },
}),
);
}
return Promise.resolve(new Response(null, { status: 404 }));
};
const registry = new ModelRegistry(authStorage, modelsJsonPath, { fetch: fetchMock });
await registry.refresh();
expect(requestedUrl).toBe("http://127.0.0.1:11434/v1/models");
expect(registry.getAll().some(m => m.provider === "lm-studio" && m.id === "omlx-model")).toBe(true);
} finally {
if (originalBaseUrl === undefined) {
delete Bun.env.LM_STUDIO_BASE_URL;
} else {
Bun.env.LM_STUDIO_BASE_URL = originalBaseUrl;
}
}
});
});